diff --git a/README.md b/README.md index e101733..257a4b2 100644 --- a/README.md +++ b/README.md @@ -203,26 +203,6 @@ This command will set the admin role to any available Flexisip account. You need Once one account is declared as administrator, you can directly configure the other ones using the web panel. -### Generate External Accounts - -Generate `amount` accounts defined by the `group` label. -The generated accounts will have a random username suffixed by the group name. - - accounts:generate-external {amount} {group} - -### Export External Accounts - -Export all the accounts defined by the `group` label. -The command generates a JSON file containing the accounts ready to by imported as External Accounts in the current directory. A specific path can be defined using the `--o|output` optional parameter. - - accounts:export-to-externals {group} {--o|output=} - -### Import External Accounts - -Import accounts previously exported as a JSON file. Accounts previously imported will be skipped in the process. - - accounts:import-externals {file_path} - ## Custom email templaces Some email templates can be customized. diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index bd5e081..91d0fa8 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -77,21 +77,6 @@ class Account extends Authenticatable $builder->where('domain', config('app.sip_domain')); }); - - /** - * External account handling - */ - static::creating(function ($account) { - if (config('app.consume_external_account_on_create') && !getAvailableExternalAccount()) { - abort(403, 'Accounts cannot be created on the server'); - } - }); - - static::created(function ($account) { - if (config('app.consume_external_account_on_create')) { - $account->attachExternalAccount(); - } - }); } public function scopeSip($query, string $sip) @@ -138,11 +123,6 @@ class Account extends Authenticatable return $this->hasOne(ApiKey::class); } - public function externalAccount() - { - return $this->hasOne(ExternalAccount::class); - } - public function contacts() { return $this->belongsToMany(Account::class, 'contacts', 'account_id', 'contact_id'); @@ -284,17 +264,6 @@ class Account extends Authenticatable return ($this->activationExpiration && $this->activationExpiration->isExpired()); } - public function attachExternalAccount(): bool - { - $externalAccount = getAvailableExternalAccount(); - - if (!$externalAccount) abort(403, 'No External Account left'); - - $externalAccount->account_id = $this->id; - $externalAccount->used = true; - return $externalAccount->save(); - } - public function generateApiKey(): ApiKey { $this->apiKey()->delete(); diff --git a/flexiapi/app/Console/Commands/ExportToExternalAccounts.php b/flexiapi/app/Console/Commands/ExportToExternalAccounts.php deleted file mode 100644 index 02467cc..0000000 --- a/flexiapi/app/Console/Commands/ExportToExternalAccounts.php +++ /dev/null @@ -1,51 +0,0 @@ -argument('group')) - ->with('passwords') - ->get(); - - if ($accounts->count() == 0) { - $this->error('Nothing to export'); - return; - } - - $this->info('Exporting '.$accounts->count().' accounts'); - - $data = []; - - foreach ($accounts as $account) { - array_push($data, [ - 'username' => $account->username, - 'domain' => $account->domain, - 'group' => $account->group, - 'password' => $account->passwords->first()->password, - 'algorithm' => $account->passwords->first()->algorithm, - ]); - } - - file_put_contents( - $this->option('output') ?? getcwd() . '/exported_accounts.json', - json_encode($data) - ); - - $this->info('Exported'); - } -} diff --git a/flexiapi/app/Console/Commands/GenerateExternalAccounts.php b/flexiapi/app/Console/Commands/GenerateExternalAccounts.php deleted file mode 100644 index 553d5c2..0000000 --- a/flexiapi/app/Console/Commands/GenerateExternalAccounts.php +++ /dev/null @@ -1,101 +0,0 @@ - $this->argument('amount'), - 'group' => $this->argument('group'), - ], [ - 'amount' => ['required', 'integer'], - 'group' => ['required', 'alpha-dash', new NoUppercase] - ]); - - if ($validator->fails()) { - $this->info('External accounts no created:'); - - foreach ($validator->errors()->all() as $error) { - $this->error($error); - } - - return 1; - } - - $groups = Account::distinct('group') - ->whereNotNull('group') - ->get('group') - ->pluck('group') - ->toArray(); - - if (!in_array($this->argument('group'), $groups)) { - $this->info('Existing groups: '.implode(',', $groups)); - - if (!$this->confirm('You are creating a new group of External Account, are you sure?', false)) { - $this->info('Creation aborted'); - return 0; - } - } - - $accounts = collect(); - $passwords = collect(); - $algorithm = 'SHA-256'; - - $i = 0; - - while ($i < $this->argument('amount')) { - $account = new Account; - $account->username = Str::random(12); - $account->domain = config('app.sip_domain'); - $account->activated = 1; - $account->ip_address = '127.0.0.1'; - $account->user_agent = 'External Account Generator'; - $account->group = $this->argument('group'); - $account->created_at = Carbon::now(); - $i++; - - $account->push($account->toArray()); - } - - Account::insert($accounts->toArray()); - - $insertedAccounts = Account::where('group', $this->argument('group')) - ->latest() - ->take($this->argument('amount')) - ->get(); - - foreach ($insertedAccounts as $account) { - $password = new Password; - $password->account_id = $account->id; - $password->password = bchash($account->username, $account->resolvedRealm, Str::random(6), $algorithm); - $password->algorithm = $algorithm; - $passwords->push($password->only(['account_id', 'password', 'algorithm'])); - } - - Password::insert($passwords->toArray()); - - $this->info($this->argument('amount') . ' accounts created under the "' . $this->argument('group') . '" group'); - - return 0; - } -} diff --git a/flexiapi/app/Console/Commands/ImportExternalAccounts.php b/flexiapi/app/Console/Commands/ImportExternalAccounts.php deleted file mode 100644 index 598cab1..0000000 --- a/flexiapi/app/Console/Commands/ImportExternalAccounts.php +++ /dev/null @@ -1,68 +0,0 @@ -argument('file_path'))) { - $this->error('The file does not exists'); - return 1; - } - - $json = json_decode(file_get_contents($this->argument('file_path'))); - - if (empty($json)) { - $this->error('Nothing to import or incorrect file'); - return 1; - } - - $existingUsernames = ExternalAccount::select('username') - ->from('external_accounts') - ->get() - ->pluck('username'); - $existingCounter = 0; - $importedCounter = 0; - - $externalAccounts = collect(); - foreach ($json as $account) { - if ($existingUsernames->contains($account->username)) { - $existingCounter++; - continue; - } - - $externalAccount = new ExternalAccount; - $externalAccount->username = $account->username; - $externalAccount->domain = $account->domain; - $externalAccount->group = $account->group; - $externalAccount->password = $account->password; - $externalAccount->algorithm = $account->algorithm; - - $externalAccounts->push($externalAccount->toArray()); - $importedCounter++; - } - - ExternalAccount::insert($externalAccounts->toArray()); - - $this->info($importedCounter . ' accounts imported'); - - if ($existingCounter > 0) { - $this->info($existingCounter . ' accounts already in the database'); - } - - return 0; - } -} diff --git a/flexiapi/app/ExternalAccount.php b/flexiapi/app/ExternalAccount.php deleted file mode 100644 index 70b4747..0000000 --- a/flexiapi/app/ExternalAccount.php +++ /dev/null @@ -1,26 +0,0 @@ -belongsTo('App\Account'); - } - - public function getIdentifierAttribute() - { - return $this->attributes['username'].'@'.$this->attributes['domain']; - } - - public function getResolvedRealmAttribute() - { - return $this->attributes['domain']; - } -} diff --git a/flexiapi/app/Helpers/Utils.php b/flexiapi/app/Helpers/Utils.php index 99a2f8a..cca810a 100644 --- a/flexiapi/app/Helpers/Utils.php +++ b/flexiapi/app/Helpers/Utils.php @@ -21,7 +21,6 @@ use Illuminate\Support\Str; use App\Account; use App\DigestNonce; -use App\ExternalAccount; use Illuminate\Http\Request; use Illuminate\Support\Facades\Schema; use League\CommonMark\CommonMarkConverter; @@ -87,28 +86,9 @@ function markdownDocumentationView($view): string ); } -function getAvailableExternalAccount(): ?ExternalAccount -{ - if (Schema::hasTable('external_accounts')) { - return ExternalAccount::where('used', false) - ->where('account_id', null) - ->first(); - } - - return null; -} - function publicRegistrationEnabled(): bool { - if (config('app.public_registration')) { - if (config('app.consume_external_account_on_create')) { - return (bool)getAvailableExternalAccount(); - } - - return true; - } - - return false; + return (config('app.public_registration')); } function isRegularExpression($string): bool diff --git a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php index f4cb89e..d533979 100644 --- a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php +++ b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php @@ -182,8 +182,6 @@ class ProvisioningController extends Controller $config->appendChild($section); if ($account) { - $externalAccount = $account->externalAccount; - $section = $dom->createElement('section'); $section->setAttribute('name', 'proxy_' . $proxyConfigIndex); @@ -204,12 +202,6 @@ class ProvisioningController extends Controller provisioningProxyHook($section, $request, $account); } - if ($externalAccount) { - $entry = $dom->createElement('entry', 'external_account'); - $entry->setAttribute('name', 'depends_on'); - $section->appendChild($entry); - } - $config->appendChild($section); $passwords = $account->passwords()->get(); @@ -249,55 +241,6 @@ class ProvisioningController extends Controller } $proxyConfigIndex++; - - // External Account handling - if ($externalAccount) { - $section = $dom->createElement('section'); - $section->setAttribute('name', 'proxy_' . $proxyConfigIndex); - - $entry = $dom->createElement('entry', 'identifier . '>'); - $entry->setAttribute('name', 'reg_identity'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', 1); - $entry->setAttribute('name', 'reg_sendregister'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', 'push_notification'); - $entry->setAttribute('name', 'refkey'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', 'external_account'); - $entry->setAttribute('name', 'idkey'); - $section->appendChild($entry); - - $config->appendChild($section); - - $section = $dom->createElement('section'); - $section->setAttribute('name', 'auth_info_' . $authInfoIndex); - - $entry = $dom->createElement('entry', $externalAccount->username); - $entry->setAttribute('name', 'username'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', $externalAccount->domain); - $entry->setAttribute('name', 'domain'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', $externalAccount->password); - $entry->setAttribute('name', 'ha1'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', $externalAccount->resolvedRealm); - $entry->setAttribute('name', 'realm'); - $section->appendChild($entry); - - $entry = $dom->createElement('entry', $externalAccount->algorithm); - $entry->setAttribute('name', 'algorithm'); - $section->appendChild($entry); - - $config->appendChild($section); - } } // Complete the section with the Auth hook diff --git a/flexiapi/app/Http/Controllers/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Admin/AccountController.php index b9319b6..386a051 100644 --- a/flexiapi/app/Http/Controllers/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Admin/AccountController.php @@ -26,7 +26,6 @@ use Carbon\Carbon; use App\Account; use App\ContactsList; -use App\ExternalAccount; use App\Http\Requests\CreateAccountRequest; use App\Http\Requests\UpdateAccountRequest; @@ -39,7 +38,7 @@ class AccountController extends Controller 'order_sort' => 'in:asc,desc', ]); - $accounts = Account::with('externalAccount', 'contactsLists') + $accounts = Account::with('contactsLists') ->orderBy($request->get('order_by', 'updated_at'), $request->get('order_sort', 'desc')); if ($request->has('search')) { @@ -110,7 +109,6 @@ class AccountController extends Controller return view('admin.account.create_edit', [ 'account' => Account::findOrFail($id), 'protocols' => [null => 'None'] + Account::$dtmfProtocols, - 'external_accounts_count' => ExternalAccount::where('used', false)->count(), 'contacts_lists' => ContactsList::whereNotIn('id', function ($query) use ($id) { $query->select('contacts_list_id') ->from('account_contacts_list') @@ -145,16 +143,6 @@ class AccountController extends Controller return redirect()->route('admin.account.edit', $id); } - public function attachExternalAccount(int $id) - { - $account = Account::findOrFail($id); - $account->attachExternalAccount(); - - Log::channel('events')->info('Web Admin: ExternalAccount attached', ['id' => $account->identifier]); - - return redirect()->back(); - } - public function provision(int $id) { $account = Account::findOrFail($id); diff --git a/flexiapi/app/Http/Controllers/Admin/ContactsListContactController.php b/flexiapi/app/Http/Controllers/Admin/ContactsListContactController.php index a8bb18f..5d1fb7a 100644 --- a/flexiapi/app/Http/Controllers/Admin/ContactsListContactController.php +++ b/flexiapi/app/Http/Controllers/Admin/ContactsListContactController.php @@ -28,8 +28,7 @@ class ContactsListContactController extends Controller { public function add(Request $request, int $contactsListId) { - $accounts = Account::orderBy('updated_at', $request->get('updated_at_order', 'desc')) - ->with('externalAccount'); + $accounts = Account::orderBy('updated_at', $request->get('updated_at_order', 'desc')); if ($request->has('search')) { $accounts = $accounts->where('username', 'like', '%' . $request->get('search') . '%'); diff --git a/flexiapi/config/app.php b/flexiapi/config/app.php index c56dae2..45c91a1 100644 --- a/flexiapi/config/app.php +++ b/flexiapi/config/app.php @@ -29,7 +29,6 @@ return [ 'transport_protocol_text' => env('ACCOUNT_TRANSPORT_PROTOCOL_TEXT', 'TLS (recommended), TCP or UDP'), 'account_email_unique' => env('ACCOUNT_EMAIL_UNIQUE', false), - 'consume_external_account_on_create' => env('ACCOUNT_CONSUME_EXTERNAL_ACCOUNT_ON_CREATE', false), 'blacklisted_usernames' => env('ACCOUNT_BLACKLISTED_USERNAMES', ''), 'account_username_regex' => env('ACCOUNT_USERNAME_REGEX', '^[a-z0-9+_.-]*$'), diff --git a/flexiapi/database/factories/ExternalAccountFactory.php b/flexiapi/database/factories/ExternalAccountFactory.php deleted file mode 100644 index d4cbf48..0000000 --- a/flexiapi/database/factories/ExternalAccountFactory.php +++ /dev/null @@ -1,25 +0,0 @@ -faker->username; - $realm = config('app.realm') ?? config('app.sip_domain'); - - return [ - 'username' => $username, - 'domain' => config('app.sip_domain'), - 'group' => 'test', - 'password' => hash('sha256', $username.':'.$realm.':testtest'), - 'algorithm' => 'SHA-256', - ]; - } -} diff --git a/flexiapi/database/migrations/2023_10_04_132708_drop_external_accounts_table.php b/flexiapi/database/migrations/2023_10_04_132708_drop_external_accounts_table.php new file mode 100644 index 0000000..cc4879a --- /dev/null +++ b/flexiapi/database/migrations/2023_10_04_132708_drop_external_accounts_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('username', 64); + $table->string('domain', 64); + $table->string('group', 16); + $table->string('password', 255); + $table->string('algorithm', 10)->default('MD5'); + $table->boolean('used')->default(false); + + $table->integer('account_id')->unsigned()->nullable(); + $table->foreign('account_id')->references('id') + ->on('accounts')->onDelete('set null'); + + $table->timestamps(); + }); + } +}; diff --git a/flexiapi/resources/views/account/documentation_markdown.blade.php b/flexiapi/resources/views/account/documentation_markdown.blade.php index 86d0e67..f0076e7 100644 --- a/flexiapi/resources/views/account/documentation_markdown.blade.php +++ b/flexiapi/resources/views/account/documentation_markdown.blade.php @@ -100,14 +100,6 @@ Administrators can create and edit accounts directly from the admin panel. Durin The deletion of an account is definitive, all the database related data (password, aliases…) will be destroyed after the deletion. -### Attach the account to an External Account - -@if (config('app.consume_external_account_on_create') == false) -*The feature is not enabled on this instance.* -@endif - -It is possible to import external accounts in the application. If this feature is enabled those External Accounts can be attached during the account creation process or afterward using the Account page dedicated button. - ### Create, edit and delete account types An adminisator can create, edit and delete account types. Those can be used to categorize accounts in clients, they are often used for Internet of Things related devices. diff --git a/flexiapi/resources/views/admin/account/create_edit.blade.php b/flexiapi/resources/views/admin/account/create_edit.blade.php index 6146b85..c83f0a4 100644 --- a/flexiapi/resources/views/admin/account/create_edit.blade.php +++ b/flexiapi/resources/views/admin/account/create_edit.blade.php @@ -203,18 +203,6 @@

@endif -

External Account

- - @if ($account->externalAccount) -

- Identifier: {{ $account->externalAccount->identifier }}
-

- @else - Attach an External Account - ({{ $external_accounts_count }} left) - @endif -

Actions

@if ($account->dtmf_protocol) diff --git a/flexiapi/resources/views/admin/account/index.blade.php b/flexiapi/resources/views/admin/account/index.blade.php index 379abcf..dd3385c 100644 --- a/flexiapi/resources/views/admin/account/index.blade.php +++ b/flexiapi/resources/views/admin/account/index.blade.php @@ -98,9 +98,6 @@ @endif - @if ($account->externalAccount) - EA - @endif @if ($account->email) Email @endif diff --git a/flexiapi/resources/views/provisioning/documentation_markdown.blade.php b/flexiapi/resources/views/provisioning/documentation_markdown.blade.php index de7df5d..4f633d9 100644 --- a/flexiapi/resources/views/provisioning/documentation_markdown.blade.php +++ b/flexiapi/resources/views/provisioning/documentation_markdown.blade.php @@ -21,7 +21,6 @@ The general idea is to allow the clients to access a unique URL returning a cust * Public Expose the linphonerc INI file configuration * User Inject the authentication information to allow the application to authenticate on the server directly if a valid account is detected using the `provisioning` token - * A similar information is also injected if an external account is linked to the main one, the application will then be able to authenticate on both accounts at the same time * Public User Using __Custom Hooks__ an admin is also able to have access to the authenticated User internal object and inject custom XML during the provisioning. See the specific section in the `README.md` to learn more about that feature. ### Features diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index 2d03c18..fa5b68a 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -138,8 +138,6 @@ if (config('app.web_panel')) { Route::name('account.')->prefix('accounts')->group(function () { Route::controller(AdminAccountController::class)->group(function () { - Route::get('{account_id}/external_account/attach', 'attachExternalAccount')->name('external_account.attach'); - Route::get('{account_id}/provision', 'provision')->name('provision'); Route::get('create', 'create')->name('create'); diff --git a/flexiapi/tests/Feature/ApiExternalAccountTest.php b/flexiapi/tests/Feature/ApiExternalAccountTest.php deleted file mode 100644 index 746bdcd..0000000 --- a/flexiapi/tests/Feature/ApiExternalAccountTest.php +++ /dev/null @@ -1,84 +0,0 @@ -. -*/ - -namespace Tests\Feature; - -use App\Admin; -use App\Account; -use App\ExternalAccount; -use Illuminate\Foundation\Testing\RefreshDatabase; -use Tests\TestCase; - -class ApiExternalAccountTest extends TestCase -{ - use RefreshDatabase; - - protected $route = '/api/accounts'; - protected $provisioningRoute = '/provisioning/me'; - protected $method = 'POST'; - - public function testExternalAccountAttachOnCreate() - { - $admin = Admin::factory()->create(); - $password = $admin->account->passwords()->first(); - $password->account->generateApiKey(); - $password->account->save(); - - config()->set('app.consume_external_account_on_create', true); - - // Seed an ExternalAccount - $externalAccount = ExternalAccount::factory()->create(); - $externalAccount->save(); - - $response = $this->keyAuthenticated($password->account) - ->json($this->method, $this->route, [ - 'username' => 'test', - 'domain' => 'example.com', - 'algorithm' => 'SHA-256', - 'password' => '123456', - 'activated' => true, - ]); - - $response->assertStatus(200); - - // No ExternalAccount left - $response = $this->keyAuthenticated($password->account) - ->json($this->method, $this->route, [ - 'username' => 'test2', - 'domain' => 'example.com', - 'algorithm' => 'SHA-256', - 'password' => '123456', - ]); - - $response->assertStatus(403); - - $createdAccount = Account::where('username', 'test')->first(); - $createdAccount->generateApiKey(); - $createdAccount->save(); - - $response = $this->keyAuthenticated($createdAccount) - ->get($this->provisioningRoute) - ->assertStatus(200) - ->assertHeader('Content-Type', 'application/xml') - ->assertSee($externalAccount->identifier) - ->assertSee('ha1') - ->assertSee('idkey') - ->assertSee('depends_on'); - } -}