From b493e9006e7998503f0c219f4c5a6fa6eb5519b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Wed, 26 Mar 2025 10:25:42 +0000 Subject: [PATCH] Fix FLEXIAPI-281 Restrict external_domains unicity on username, domain --- .../Controllers/Admin/SpaceController.php | 9 ++++---- .../Controllers/Api/Admin/SpaceController.php | 5 +++-- .../Requests/ExternalAccount/CreateUpdate.php | 14 +++++++++++-- flexiapi/app/Rules/Domain.php | 21 +++++++++++++++++++ flexiapi/app/Space.php | 2 +- ...7_create_again_external_accounts_table.php | 2 ++ .../views/admin/account/create_edit.blade.php | 2 +- .../admin/account/external/show.blade.php | 1 + .../admin/account/import/create.blade.php | 1 - .../Feature/ApiAccountExternalAccountTest.php | 14 ++++++------- 10 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 flexiapi/app/Rules/Domain.php diff --git a/flexiapi/app/Http/Controllers/Admin/SpaceController.php b/flexiapi/app/Http/Controllers/Admin/SpaceController.php index ebe3de3..72528f3 100644 --- a/flexiapi/app/Http/Controllers/Admin/SpaceController.php +++ b/flexiapi/app/Http/Controllers/Admin/SpaceController.php @@ -19,11 +19,12 @@ namespace App\Http\Controllers\Admin; -use Illuminate\Http\Request; - use App\Http\Controllers\Controller; use App\Space; use App\Rules\Ini; +use App\Rules\Domain; + +use Illuminate\Http\Request; use Illuminate\Validation\Rule; class SpaceController extends Controller @@ -63,9 +64,9 @@ class SpaceController extends Controller $request->merge(['full_host' => $fullHost]); $request->validate([ 'name' => 'required|unique:spaces', - 'domain' => 'required|unique:spaces|regex:/'. Space::DOMAIN_REGEX . '/', + 'domain' => ['required', 'unique:spaces', new Domain()], 'host' => 'nullable|regex:/'. Space::HOST_REGEX . '/', - 'full_host' => 'required|unique:spaces,host', + 'full_host' => ['required', 'unique:spaces,host', new Domain()], ]); $space = new Space(); diff --git a/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php b/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php index 697491a..5deb6fe 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php @@ -20,6 +20,7 @@ namespace App\Http\Controllers\Api\Admin; use App\Space; +use App\Rules\Domain; use App\Http\Controllers\Controller; use Illuminate\Http\Request; @@ -36,8 +37,8 @@ class SpaceController extends Controller { $request->validate([ 'name' => 'required|unique:spaces', - 'domain' => 'required|unique:spaces', - 'host' => 'required|unique:spaces', + 'domain' => ['required', 'unique:spaces', new Domain()], + 'host' => ['required', 'unique:spaces', new Domain()], 'max_accounts' => 'nullable|integer', 'expire_at' => 'nullable|date|after_or_equal:today' ]); diff --git a/flexiapi/app/Http/Requests/ExternalAccount/CreateUpdate.php b/flexiapi/app/Http/Requests/ExternalAccount/CreateUpdate.php index fa8631a..aacd771 100644 --- a/flexiapi/app/Http/Requests/ExternalAccount/CreateUpdate.php +++ b/flexiapi/app/Http/Requests/ExternalAccount/CreateUpdate.php @@ -23,14 +23,24 @@ use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; use App\ExternalAccount; +use App\Rules\SIPUsername; +use App\Rules\Domain; class CreateUpdate extends FormRequest { public function rules() { + $usernameValidation = Rule::unique('external_accounts')->where(function ($query) { + return $query->where('username', $this->username)->where('domain', $this->domain); + }); + + if ($this->method() == 'POST') { + $usernameValidation = $usernameValidation->ignore($this->route('account'), 'account_id'); + } + return [ - 'username' => 'required', - 'domain' => 'required', + 'username' => ['required', $usernameValidation, new SIPUsername()], + 'domain' => ['required', new Domain()], 'realm' => 'different:domain', 'registrar' => 'different:domain', 'outbound_proxy' => 'different:domain', diff --git a/flexiapi/app/Rules/Domain.php b/flexiapi/app/Rules/Domain.php new file mode 100644 index 0000000..a471e91 --- /dev/null +++ b/flexiapi/app/Rules/Domain.php @@ -0,0 +1,21 @@ +validate($value); + } + + public function message() + { + return 'The :attribute should be a valid domain'; + } +} diff --git a/flexiapi/app/Space.php b/flexiapi/app/Space.php index 3069a82..a66254f 100644 --- a/flexiapi/app/Space.php +++ b/flexiapi/app/Space.php @@ -28,7 +28,7 @@ class Space extends Model ]; public const HOST_REGEX = '[\w\-]+'; - public const DOMAIN_REGEX = '[\w\-\.]+'; + public const DOMAIN_REGEX = '(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?foreign('account_id')->references('id') ->on('accounts')->onDelete('cascade'); + $table->unique(['username', 'domain']); + $table->timestamps(); }); } diff --git a/flexiapi/resources/views/admin/account/create_edit.blade.php b/flexiapi/resources/views/admin/account/create_edit.blade.php index a37adf6..b294074 100644 --- a/flexiapi/resources/views/admin/account/create_edit.blade.php +++ b/flexiapi/resources/views/admin/account/create_edit.blade.php @@ -82,7 +82,7 @@ @include('parts.errors', ['name' => __('email')]) @if (!empty($account->email)) -

+

{{ __('Send an email to the user to reset the password') }} diff --git a/flexiapi/resources/views/admin/account/external/show.blade.php b/flexiapi/resources/views/admin/account/external/show.blade.php index 6ed8b90..95fe79f 100644 --- a/flexiapi/resources/views/admin/account/external/show.blade.php +++ b/flexiapi/resources/views/admin/account/external/show.blade.php @@ -34,6 +34,7 @@ + @include('parts.errors', ['name' => 'domain'])

diff --git a/flexiapi/resources/views/admin/account/import/create.blade.php b/flexiapi/resources/views/admin/account/import/create.blade.php index abd12a4..65de0d3 100644 --- a/flexiapi/resources/views/admin/account/import/create.blade.php +++ b/flexiapi/resources/views/admin/account/import/create.blade.php @@ -41,7 +41,6 @@
  • {{ __('Realm') }} (different than domain)
  • {{ __('Registrar') }} (different than domain)
  • {{ __('Outbound Proxy') }} (different than domain)
  • -
  • {{ __('Encrypted') }} (yes or no)
  • {{ __('Protocol') }} (UDP, TCP or TLS)
  • diff --git a/flexiapi/tests/Feature/ApiAccountExternalAccountTest.php b/flexiapi/tests/Feature/ApiAccountExternalAccountTest.php index a7ad876..8867952 100644 --- a/flexiapi/tests/Feature/ApiAccountExternalAccountTest.php +++ b/flexiapi/tests/Feature/ApiAccountExternalAccountTest.php @@ -42,16 +42,16 @@ class ApiAccountExternalAccountTest extends TestCase $this->keyAuthenticated($admin) ->json($this->method, $this->route . '/' . $account->id . '/external/', [ 'username' => $username, - 'domain' => 'bar', + 'domain' => 'bar.dev', 'password' => 'password', 'protocol' => 'UDP' ])->assertStatus(201); $this->keyAuthenticated($admin) ->json($this->method, $this->route . '/' . $account->id . '/external/', [ - 'username' => $username, - 'domain' => 'bar', - 'registrar' => 'bar', + 'username' => $username . '_two', + 'domain' => 'bar.dev', + 'registrar' => 'bar.dev', 'password' => 'password', 'protocol' => 'UDP' ])->assertJsonValidationErrors(['registrar']); @@ -70,14 +70,14 @@ class ApiAccountExternalAccountTest extends TestCase $this->keyAuthenticated($admin) ->json($this->method, $this->route . '/' . $account->id . '/external/', [ 'username' => $username . '2', - 'domain' => 'bar', + 'domain' => 'bar.dev', 'protocol' => 'UDP' ])->assertStatus(200); $this->keyAuthenticated($admin) ->json($this->method, $this->route . '/' . $account->id . '/external/', [ - 'username' => $username . '2', - 'domain' => 'bar', + 'username' => $username . '3', + 'domain' => 'bar.dev', 'realm' => 'newrealm', 'protocol' => 'UDP' ])->assertJsonValidationErrors(['password']);