diff --git a/Makefile b/Makefile index 578fdcf..9561768 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ $(eval GIT_DESCRIBE = $(shell sh -c "git describe")) OUTPUT_DIR = ${CURDIR} prepare: - cd flexiapi && composer install --no-dev + cd flexiapi && php composer.phar install --no-dev prepare-dev: - cd flexiapi && composer install + cd flexiapi && php composer.phar install package-common: rm -rf $(OUTPUT_DIR)/flexisip-account-manager diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index f9a84e3..91b1e37 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -31,6 +31,7 @@ use App\Password; use App\EmailChanged; use App\Helpers\Utils; use App\Mail\ChangingEmail; +use Illuminate\Database\Eloquent\Relations\HasMany; class Account extends Authenticatable { @@ -45,6 +46,8 @@ class Account extends Authenticatable ]; public $timestamps = false; + public static $dtmfProtocols = ['sipinfo' => 'SIPInfo', 'rfc2833' => 'RFC2833']; + /** * Scopes */ @@ -79,7 +82,11 @@ class Account extends Authenticatable */ public function actions() { - return $this->hasMany('App\AccountAction'); + return $this->hasMany('App\AccountAction')->whereIn('account_id', function ($query) { + $query->select('id') + ->from('accounts') + ->whereNotNull('dtmf_protocol'); + }); } public function activationExpiration() @@ -173,6 +180,16 @@ class Account extends Authenticatable return $this->passwords()->where('algorithm', 'SHA-256')->exists(); } + public static function dtmfProtocolsRule() + { + return implode(',', array_keys(self::$dtmfProtocols)); + } + + public function getResolvedDtmfProtocolAttribute() + { + return self::$dtmfProtocols[$this->attributes['dtmf_protocol']]; + } + /** * Utils */ @@ -249,6 +266,11 @@ FN:'.$this->attributes['display_name']; FN:'.$this->getIdentifierAttribute(); } + if ($this->dtmf_protocol) { + $vcard .= ' +X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:'.$this->dtmf_protocol; + } + if ($this->types->count() > 0) { $vcard .= ' X-LINPHONE-ACCOUNT-TYPE:'.$this->types->implode('key', ','); @@ -256,7 +278,7 @@ X-LINPHONE-ACCOUNT-TYPE:'.$this->types->implode('key', ','); foreach ($this->actions as $action) { $vcard .= ' -X-LINPHONE-ACCOUNT-ACTION:'.$action->key.';'.$action->code.';'.$action->protocol; +X-LINPHONE-ACCOUNT-ACTION:'.$action->key.';'.$action->code; } return $vcard . ' diff --git a/flexiapi/app/AccountAction.php b/flexiapi/app/AccountAction.php index 327cafd..af1d4ae 100644 --- a/flexiapi/app/AccountAction.php +++ b/flexiapi/app/AccountAction.php @@ -9,18 +9,6 @@ class AccountAction extends Model { use HasFactory; - public static $protocols = ['sipinfo' => 'SIPInfo', 'rfc2833' => 'RFC2833']; - - public static function protocolsRule() - { - return implode(',', array_keys(self::$protocols)); - } - - public function getResolvedProtocolAttribute() - { - return self::$protocols[$this->attributes['protocol']]; - } - public function account() { return $this->belongsTo('App\Account'); diff --git a/flexiapi/app/Http/Controllers/Admin/AccountActionController.php b/flexiapi/app/Http/Controllers/Admin/AccountActionController.php index 835ba3e..de94fae 100644 --- a/flexiapi/app/Http/Controllers/Admin/AccountActionController.php +++ b/flexiapi/app/Http/Controllers/Admin/AccountActionController.php @@ -35,8 +35,7 @@ class AccountActionController extends Controller return view('admin.account.action.create_edit', [ 'action' => new AccountAction, - 'account' => $account, - 'protocols' => AccountAction::$protocols + 'account' => $account ]); } @@ -46,15 +45,13 @@ class AccountActionController extends Controller $request->validate([ 'key' => ['required', 'alpha_dash', new NoUppercase], - 'code' => ['required', 'alpha_num', new NoUppercase], - 'protocol' => 'required|in:' . AccountAction::protocolsRule() + 'code' => ['required', 'alpha_num', new NoUppercase] ]); $accountAction = new AccountAction; $accountAction->account_id = $account->id; $accountAction->key = $request->get('key'); $accountAction->code = $request->get('code'); - $accountAction->protocol = $request->get('protocol'); $accountAction->save(); $request->session()->flash('success', 'Action successfully created'); @@ -73,8 +70,7 @@ class AccountActionController extends Controller return view('admin.account.action.create_edit', [ 'action' => $accountAction, - 'account' => $account, - 'protocols' => AccountAction::$protocols + 'account' => $account ]); } @@ -84,8 +80,7 @@ class AccountActionController extends Controller $request->validate([ 'key' => ['alpha_dash', new NoUppercase], - 'code' => ['alpha_num', new NoUppercase], - 'protocol' => 'in:' . AccountAction::protocolsRule() + 'code' => ['alpha_num', new NoUppercase] ]); $accountAction = $account->actions() @@ -93,7 +88,6 @@ class AccountActionController extends Controller ->firstOrFail(); $accountAction->key = $request->get('key'); $accountAction->code = $request->get('code'); - $accountAction->protocol = $request->get('protocol'); $accountAction->save(); $request->session()->flash('success', 'Action successfully updated'); diff --git a/flexiapi/app/Http/Controllers/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Admin/AccountController.php index a919015..8374346 100644 --- a/flexiapi/app/Http/Controllers/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Admin/AccountController.php @@ -58,7 +58,8 @@ class AccountController extends Controller public function create(Request $request) { return view('admin.account.create_edit', [ - 'account' => new Account + 'account' => new Account, + 'protocols' => [null => 'None'] + Account::$dtmfProtocols ]); } @@ -74,6 +75,7 @@ class AccountController extends Controller $account->ip_address = $request->ip(); $account->creation_time = Carbon::now(); $account->user_agent = config('app.name'); + $account->dtmf_protocol = $request->get('dtmf_protocol'); $account->save(); $this->fillPassword($request, $account); @@ -87,7 +89,8 @@ class AccountController extends Controller public function edit(int $id) { return view('admin.account.create_edit', [ - 'account' => Account::findOrFail($id) + 'account' => Account::findOrFail($id), + 'protocols' => [null => 'None'] + Account::$dtmfProtocols ]); } @@ -97,6 +100,7 @@ class AccountController extends Controller $account->username = $request->get('username'); $account->email = $request->get('email'); $account->display_name = $request->get('display_name'); + $account->dtmf_protocol = $request->get('dtmf_protocol'); $account->save(); $this->fillPassword($request, $account); @@ -201,20 +205,16 @@ class AccountController extends Controller return redirect()->back(); } - private function fillPassword(Request $request, int $id) + private function fillPassword(Request $request, Account $account) { - $account = Account::findOrFail($id); - if ($request->filled('password')) { $algorithm = $request->has('password_sha256') ? 'SHA-256' : 'MD5'; $account->updatePassword($request->get('password'), $algorithm); } } - private function fillPhone(Request $request, int $id) + private function fillPhone(Request $request, Account $account) { - $account = Account::findOrFail($id); - if ($request->filled('phone')) { $account->alias()->delete(); diff --git a/flexiapi/app/Http/Controllers/Api/AccountController.php b/flexiapi/app/Http/Controllers/Api/AccountController.php index 1bdf100..71356f0 100644 --- a/flexiapi/app/Http/Controllers/Api/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/AccountController.php @@ -67,6 +67,7 @@ class AccountController extends Controller ], 'algorithm' => 'required|in:SHA-256,MD5', 'password' => 'required|filled', + 'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(), 'domain' => 'min:3', 'token' => [ 'required', @@ -91,6 +92,7 @@ class AccountController extends Controller $account->ip_address = $request->ip(); $account->creation_time = Carbon::now(); $account->user_agent = config('app.name'); + $account->dtmf_protocol = $request->get('dtmf_protocol'); $account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize); $account->save(); diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountActionController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountActionController.php index e3dca69..154ddb5 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountActionController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountActionController.php @@ -30,12 +30,12 @@ class AccountActionController extends Controller { public function index(int $id) { - return Account::findOrFail($id)->actions; + return $this->resolveAccount($id)->actions; } public function get(int $id, int $actionId) { - return Account::findOrFail($id) + return $this->resolveAccount($id) ->actions() ->where('id', $actionId) ->firstOrFail(); @@ -43,17 +43,17 @@ class AccountActionController extends Controller public function store(Request $request, int $id) { + $account = $this->resolveAccount($id); + $request->validate([ 'key' => ['required', 'alpha_dash', new NoUppercase], - 'code' => ['required', 'alpha_num', new NoUppercase], - 'protocol' => 'required|in:' . AccountAction::protocolsRule() + 'code' => ['required', 'alpha_num', new NoUppercase] ]); $accountAction = new AccountAction; - $accountAction->account_id = Account::findOrFail($id)->id; + $accountAction->account_id = $account->id; $accountAction->key = $request->get('key'); $accountAction->code = $request->get('code'); - $accountAction->protocol = $request->get('protocol'); $accountAction->save(); return $accountAction; @@ -61,19 +61,19 @@ class AccountActionController extends Controller public function update(Request $request, int $id, int $actionId) { + $account = $this->resolveAccount($id); + $request->validate([ 'key' => ['alpha_dash', new NoUppercase], - 'code' => ['alpha_num', new NoUppercase], - 'protocol' => 'in:' . AccountAction::protocolsRule() + 'code' => ['alpha_num', new NoUppercase] ]); - $accountAction = Account::findOrFail($id) + $accountAction = $account ->actions() ->where('id', $actionId) ->firstOrFail(); $accountAction->key = $request->get('key'); $accountAction->code = $request->get('code'); - $accountAction->protocol = $request->get('protocol'); $accountAction->save(); return $accountAction; @@ -81,9 +81,17 @@ class AccountActionController extends Controller public function destroy(int $id, int $actionId) { - return Account::findOrFail($id) + return $this->resolveAccount($id) ->actions() ->where('id', $actionId) ->delete(); } + + private function resolveAccount(int $id) + { + $account = Account::findOrFail($id); + if ($account->dtmf_protocol == null) abort(403, 'DTMF Protocol must be configured'); + + return $account; + } } diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php index b76e408..bf01821 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php @@ -108,6 +108,7 @@ class AccountController extends Controller 'email' => 'email', 'admin' => 'boolean|nullable', 'activated' => 'boolean|nullable', + 'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(), 'confirmation_key_expires' => [ 'date_format:Y-m-d H:i:s', 'nullable', @@ -127,6 +128,7 @@ class AccountController extends Controller ? (bool)$request->get('activated') : false; $account->ip_address = $request->ip(); + $account->dtmf_protocol = $request->get('dtmf_protocol'); $account->creation_time = Carbon::now(); $account->domain = $request->has('domain') && config('app.admins_manage_multi_domains') ? $request->get('domain') diff --git a/flexiapi/app/Http/Requests/CreateAccountRequest.php b/flexiapi/app/Http/Requests/CreateAccountRequest.php index 9d3fecf..22a1471 100644 --- a/flexiapi/app/Http/Requests/CreateAccountRequest.php +++ b/flexiapi/app/Http/Requests/CreateAccountRequest.php @@ -3,8 +3,9 @@ namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; - use Illuminate\Validation\Rule; + +use App\Account; use App\Rules\WithoutSpaces; class CreateAccountRequest extends FormRequest @@ -27,6 +28,7 @@ class CreateAccountRequest extends FormRequest 'domain' => config('app.admins_manage_multi_domains') ? 'required' : '', 'password' => 'required|min:3', 'email' => 'nullable|email', + 'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(), 'phone' => [ 'nullable', 'unique:aliases,alias', diff --git a/flexiapi/app/Http/Requests/UpdateAccountRequest.php b/flexiapi/app/Http/Requests/UpdateAccountRequest.php index c66dc4c..fbab93b 100644 --- a/flexiapi/app/Http/Requests/UpdateAccountRequest.php +++ b/flexiapi/app/Http/Requests/UpdateAccountRequest.php @@ -3,8 +3,9 @@ namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; - use Illuminate\Validation\Rule; + +use App\Account; use App\Rules\WithoutSpaces; class UpdateAccountRequest extends FormRequest @@ -27,6 +28,7 @@ class UpdateAccountRequest extends FormRequest 'domain' => config('app.admins_manage_multi_domains') ? 'required' : '', 'email' => 'nullable|email', 'password_sha256' => 'nullable|min:3', + 'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(), 'phone' => [ 'nullable', Rule::unique('accounts', 'username')->where(function ($query) { diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index f855e72..38efe76 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -183,79 +183,6 @@ ], "time": "2021-08-15T20:50:18+00:00" }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.4", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b174585d1fe49ceed21928a945138948cb394600" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600", - "reference": "b174585d1fe49ceed21928a945138948cb394600", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-09-13T08:41:34+00:00" - }, { "name": "dasprid/enum", "version": "1.0.3", @@ -404,20 +331,20 @@ }, { "name": "doctrine/dbal", - "version": "3.2.1", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "4caf37acf14b513a91dd4f087f7eda424fa25542" + "reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/4caf37acf14b513a91dd4f087f7eda424fa25542", - "reference": "4caf37acf14b513a91dd4f087f7eda424fa25542", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/a4b37db6f186b6843474189b424aed6a7cc5de4b", + "reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b", "shasum": "" }, "require": { - "composer/package-versions-deprecated": "^1.11.99", + "composer-runtime-api": "^2", "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", @@ -428,13 +355,13 @@ "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "1.3.0", + "phpstan/phpstan": "1.4.0", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "9.5.11", "psalm/plugin-phpunit": "0.16.1", "squizlabs/php_codesniffer": "3.6.2", "symfony/cache": "^5.2|^6.0", - "symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0", + "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0", "vimeo/psalm": "4.16.1" }, "suggest": { @@ -495,7 +422,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.2.1" + "source": "https://github.com/doctrine/dbal/tree/3.3.0" }, "funding": [ { @@ -511,7 +438,7 @@ "type": "tidelift" } ], - "time": "2022-01-05T08:52:06+00:00" + "time": "2022-01-18T00:13:52+00:00" }, { "name": "doctrine/deprecations", @@ -819,16 +746,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.0", + "version": "v3.3.1", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313" + "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/63f2a76a045bac6ec93cc2daf2b534b412aa0313", - "reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/be85b3f05b46c39bbc0d95f6c071ddff669510fa", + "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa", "shasum": "" }, "require": { @@ -868,7 +795,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.1" }, "funding": [ { @@ -876,7 +803,7 @@ "type": "github" } ], - "time": "2022-01-14T16:02:05+00:00" + "time": "2022-01-18T15:43:28+00:00" }, { "name": "egulias/email-validator", @@ -1455,16 +1382,16 @@ }, { "name": "laravel/framework", - "version": "v8.79.0", + "version": "v8.80.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "8091f07558ff4a890435ff9d25fa9aca0189ad63" + "reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/8091f07558ff4a890435ff9d25fa9aca0189ad63", - "reference": "8091f07558ff4a890435ff9d25fa9aca0189ad63", + "url": "https://api.github.com/repos/laravel/framework/zipball/8949a2e46b0f274f39c61eee8d5de1dc6a1f686b", + "reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b", "shasum": "" }, "require": { @@ -1624,7 +1551,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-01-12T16:12:41+00:00" + "time": "2022-01-18T15:51:42+00:00" }, { "name": "laravel/serializable-closure", diff --git a/flexiapi/composer.phar b/flexiapi/composer.phar index 208773a..0cd534b 100755 Binary files a/flexiapi/composer.phar and b/flexiapi/composer.phar differ diff --git a/flexiapi/database/factories/AccountFactory.php b/flexiapi/database/factories/AccountFactory.php index c378b33..694d52f 100644 --- a/flexiapi/database/factories/AccountFactory.php +++ b/flexiapi/database/factories/AccountFactory.php @@ -38,6 +38,7 @@ class AccountFactory extends Factory 'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize), 'ip_address' => $this->faker->ipv4, 'creation_time' => $this->faker->dateTime, + 'dtmf_protocol' => Account::$dtmfProtocols[array_rand(Account::$dtmfProtocols)], 'activated' => true ]; } diff --git a/flexiapi/database/migrations/2021_10_13_092937_create_contacts_table.php b/flexiapi/database/migrations/2021_10_13_092937_create_contacts_table.php index d22c967..4aa9f77 100644 --- a/flexiapi/database/migrations/2021_10_13_092937_create_contacts_table.php +++ b/flexiapi/database/migrations/2021_10_13_092937_create_contacts_table.php @@ -3,6 +3,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; class CreateContactsTable extends Migration { @@ -47,7 +48,15 @@ class CreateContactsTable extends Migration ->on('accounts')->onDelete('cascade'); $table->string('key'); $table->string('code'); - $table->string('protocol'); + + /** + * See 2022_01_19_160606_move_protocol_from_account_actions_to_account.php + * SQLite can't handle the migration in the testing pipeline, so we must + * prevent the column to be created in the first place + **/ + if (DB::getDriverName() !== 'sqlite') { + $table->string('protocol'); + } $table->timestamps(); }); } diff --git a/flexiapi/database/migrations/2022_01_19_160606_move_protocol_from_account_actions_to_account.php b/flexiapi/database/migrations/2022_01_19_160606_move_protocol_from_account_actions_to_account.php new file mode 100644 index 0000000..199ed8a --- /dev/null +++ b/flexiapi/database/migrations/2022_01_19_160606_move_protocol_from_account_actions_to_account.php @@ -0,0 +1,36 @@ +string('dtmf_protocol')->nullable(); + }); + + // See 2021_10_13_092937_create_contacts_table.php + Schema::table('account_actions', function (Blueprint $table) { + if (DB::getDriverName() !== 'sqlite') { + $table->dropColumn('protocol'); + } + }); + } + + public function down() + { + Schema::table('accounts', function (Blueprint $table) { + if (DB::getDriverName() !== 'sqlite') { + $table->dropColumn('dtmf_protocol'); + } + }); + + Schema::table('account_actions', function (Blueprint $table) { + $table->string('protocol'); + }); + } +} diff --git a/flexiapi/resources/views/admin/account/action/create_edit.blade.php b/flexiapi/resources/views/admin/account/action/create_edit.blade.php index 7370897..9bcc766 100644 --- a/flexiapi/resources/views/admin/account/action/create_edit.blade.php +++ b/flexiapi/resources/views/admin/account/action/create_edit.blade.php @@ -37,10 +37,6 @@ {!! Form::label('code', 'Code') !!} {!! Form::text('code', $action->code, ['class' => 'form-control', 'placeholder' => '12ab45']); !!} -
- {!! Form::label('protocol', 'Protocol') !!} - {!! Form::select('protocol', $protocols, $action->protocol, ['class' => 'form-control']); !!} -
{!! Form::submit(($action->id) ? 'Update' : 'Create', ['class' => 'btn btn-success btn-centered']) !!} diff --git a/flexiapi/resources/views/admin/account/create_edit.blade.php b/flexiapi/resources/views/admin/account/create_edit.blade.php index 0110701..1d9abf3 100644 --- a/flexiapi/resources/views/admin/account/create_edit.blade.php +++ b/flexiapi/resources/views/admin/account/create_edit.blade.php @@ -43,7 +43,7 @@
@
- {!! Form::text('username', $account->domain ?? config('app.sip_domain'), ['class' => 'form-control', 'placeholder' => 'domain.com', 'required' => 'required']); !!} + {!! Form::text('domain', $account->domain ?? config('app.sip_domain'), ['class' => 'form-control', 'placeholder' => 'domain.com', 'required' => 'required']); !!} @else
@ {{ config('app.sip_domain') }} @@ -70,6 +70,7 @@

Optional

+
{!! Form::label('email', 'Email') !!} {!! Form::email('email', $account->email, ['class' => 'form-control', 'placeholder' => 'Email']); !!} @@ -84,6 +85,11 @@ {!! Form::label('phone', 'Phone') !!} {!! Form::text('phone', $account->phone, ['class' => 'form-control', 'placeholder' => '+12123123']); !!}
+ +
+ {!! Form::label('dtmf_protocol', 'DTMF Protocol') !!} + {!! Form::select('dtmf_protocol', $protocols, $account->dtmf_protocol, ['class' => 'form-control']); !!} +
{!! Form::submit(($account->id) ? 'Update' : 'Create', ['class' => 'btn btn-success btn-centered']) !!} diff --git a/flexiapi/resources/views/admin/account/show.blade.php b/flexiapi/resources/views/admin/account/show.blade.php index 217f8e0..47724ba 100644 --- a/flexiapi/resources/views/admin/account/show.blade.php +++ b/flexiapi/resources/views/admin/account/show.blade.php @@ -20,6 +20,7 @@ Id: {{ $account->id }}
Identifier: {{ $account->identifier }}
Email: {{ $account->email }}
+ DTMF Protocol: @if ($account->dtmf_protocol) {{ $account->resolvedDtmfProtocol }}@endif
@if ($account->alias)Phone number: {{ $account->phone }}
@endif @if ($account->display_name)Display name: {{ $account->display_name }}
@endif

@@ -63,13 +64,14 @@

Actions

+@if (!$account->dtmf_protocol) + @foreach ($account->actions as $action) -
{{ $action->key }} {{ $action->code }}{{ $action->resolvedProtocol }} Edit Delete @@ -81,6 +83,10 @@ Add +@else +

To manage actions, you must configure the DTMF protocol in the account settings.

+@endif +

Types

diff --git a/flexiapi/resources/views/api/documentation_markdown.blade.php b/flexiapi/resources/views/api/documentation_markdown.blade.php index 443a86a..1642717 100644 --- a/flexiapi/resources/views/api/documentation_markdown.blade.php +++ b/flexiapi/resources/views/api/documentation_markdown.blade.php @@ -82,6 +82,7 @@ JSON parameters: * `algorithm` required, values can be `SHA-256` or `MD5` * `domain` **not configurable except during test deployments** the value is enforced to the default registration domain set in the global configuration * `token` the unique token +* `dtmf_protocol` optional, values must be `sipinfo` or `rfc2833` #### `GET /accounts/{sip}/info` Retrieve public information about the account. @@ -179,6 +180,7 @@ The `domain` field is taken into account ONLY when `app.admins_manage_multi_doma * `display_name` optional, string * `admin` optional, a boolean, set to `false` by default, create an admin account * `phone` optional, a phone number, set a phone number to the account +* `dtmf_protocol` optional, values must be `sipinfo` or `rfc2833` * `confirmation_key_expires` optional, a datetime of this format: Y-m-d H:i:s. Only used when `activated` is not used or `false`. Enforces an expiration date on the returned `confirmation_key`. After that datetime public email or phone activation endpoints will return `403`. #### `GET /accounts` @@ -212,6 +214,8 @@ Remove a contact from the list. ### Account Actions +The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured. + #### `GET /accounts/{id}/actions/` Show an account related actions. @@ -225,7 +229,6 @@ JSON parameters: * `key` required, alpha numeric with dashes, lowercase * `code` required, alpha numeric, lowercase -* `protocol` required, values must be `sipinfo` or `rfc2833` #### `PUT /accounts/{id}/actions/{action_id}` Create an account action. @@ -234,7 +237,6 @@ JSON parameters: * `key` required, alpha numeric with dashes, lowercase * `code` required, alpha numeric, lowercase -* `protocol` required, values must be `sipinfo` or `rfc2833` #### `DELETE /accounts/{id}/actions/{action_id}` Delete an account related action. @@ -311,5 +313,26 @@ Return the same base content as the previous URL and the account related informa ### `GET /contacts/vcard` Return the authenticated user contacts list, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350). +Here is the format of the vCard list returned by the endpoint: + +``` + BEGIN:VCARD + VERSION:4.0 + KIND:individual + IMPP:sip:schoen.tatyana@sip.linphone.org + FN:schoen.tatyana@sip.linphone.org + X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:SIPInfo + X-LINPHONE-ACCOUNT-TYPE:phone + X-LINPHONE-ACCOUNT-ACTION:action_key;123 + END:VCARD + BEGIN:VCARD + VERSION:4.0 + KIND:individual + IMPP:sip:dhand@sip.linphone.org + FN:dhand@sip.linphone.org + X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:SIPInfo + END:VCARD +``` + ### `GET /contacts/vcard/{sip}` Return a specific user authenticated contact, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350). \ No newline at end of file diff --git a/flexiapi/tests/Feature/AccountActionTest.php b/flexiapi/tests/Feature/AccountActionTest.php index b0bbd9b..bb74a3f 100644 --- a/flexiapi/tests/Feature/AccountActionTest.php +++ b/flexiapi/tests/Feature/AccountActionTest.php @@ -43,8 +43,7 @@ class AccountActionTest extends TestCase $this->keyAuthenticated($admin->account) ->json($this->method, $this->route.'/'.$password->account->id.'/actions', [ 'key' => '123', - 'code' => '123', - 'protocol' => 'sipinfo' + 'code' => '123' ]) ->assertStatus(201); @@ -53,17 +52,7 @@ class AccountActionTest extends TestCase // Missing key $this->keyAuthenticated($admin->account) ->json($this->method, $this->route.'/'.$password->account->id.'/actions', [ - 'code' => '123', - 'protocol' => 'sipinfo' - ]) - ->assertStatus(422); - - // Invalid protocol - $this->keyAuthenticated($admin->account) - ->json($this->method, $this->route.'/'.$password->account->id.'/actions', [ - 'key' => 'abc1234', - 'code' => '123', - 'protocol' => 'wrong' + 'code' => '123' ]) ->assertStatus(422); @@ -71,8 +60,7 @@ class AccountActionTest extends TestCase $this->keyAuthenticated($admin->account) ->json($this->method, $this->route.'/'.$password->account->id.'/actions', [ 'key' => 'Abc1234', - 'code' => '123', - 'protocol' => 'wrong' + 'code' => '123' ]) ->assertStatus(422); @@ -81,10 +69,29 @@ class AccountActionTest extends TestCase ->assertJson([ [ 'key' => '123', - 'code' => '123', - 'protocol' => 'sipinfo' + 'code' => '123' ] ]); + + // No protocol + $password->account->dtmf_protocol = null; + $password->account->save(); + + $this->keyAuthenticated($admin->account) + ->json($this->method, $this->route.'/'.$password->account->id.'/actions', [ + 'key' => 'abc1234', + 'code' => '123' + ]) + ->assertStatus(403); + + $this->keyAuthenticated($admin->account) + ->get($this->route.'/'.$password->account->id.'/actions') + ->assertStatus(403); + + $this->keyAuthenticated($admin->account) + ->get($this->route.'/'.$password->account->id) + ->assertStatus(200) + ->assertJsonPath('actions', []); } public function testDelete() diff --git a/flexiapi/tests/Feature/AccountContactsTest.php b/flexiapi/tests/Feature/AccountContactsTest.php index e31ed5c..0085b24 100644 --- a/flexiapi/tests/Feature/AccountContactsTest.php +++ b/flexiapi/tests/Feature/AccountContactsTest.php @@ -121,13 +121,15 @@ class AccountContactTest extends TestCase ->get('/contacts/vcard') ->assertStatus(200) ->assertSeeText($typeKey) - ->assertSeeText($actionKey.';'.$actionCode.';'.$actionProtocol); + ->assertSeeText($password2->dtmf_protocol) + ->assertSeeText($actionKey.';'.$actionCode); $this->keyAuthenticated($password1->account) ->get('/contacts/vcard/'.$password2->account->identifier) ->assertStatus(200) ->assertSeeText($typeKey) - ->assertSeeText($actionKey.';'.$actionCode.';'.$actionProtocol); + ->assertSeeText($password2->dtmf_protocol) + ->assertSeeText($actionKey.';'.$actionCode); $this->keyAuthenticated($password1->account) ->get($this->route.'/me/contacts/'.$password2->account->identifier) diff --git a/flexisip-account-manager.spec b/flexisip-account-manager.spec index 725fbd0..daea546 100644 --- a/flexisip-account-manager.spec +++ b/flexisip-account-manager.spec @@ -8,7 +8,7 @@ #%define _datadir %{_datarootdir} #%define _docdir %{_datadir}/doc -%define build_number 123 +%define build_number 124 %define var_dir /var/opt/belledonne-communications %define opt_dir /opt/belledonne-communications/share/flexisip-account-manager