diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index c5d456a..ccf1e4f 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -108,62 +108,62 @@ class Account extends Authenticatable public function activationExpiration() { - return $this->hasOne('App\ActivationExpiration'); + return $this->hasOne(ActivationExpiration::class); } public function admin() { - return $this->hasOne('App\Admin'); + return $this->hasOne(Admin::class); } public function alias() { - return $this->hasOne('App\Alias'); + return $this->hasOne(Alias::class); } public function apiKey() { - return $this->hasOne('App\ApiKey'); + return $this->hasOne(ApiKey::class); } public function externalAccount() { - return $this->hasOne('App\ExternalAccount'); + return $this->hasOne(ExternalAccount::class); } public function contacts() { - return $this->belongsToMany('App\Account', 'contacts', 'account_id', 'contact_id'); + return $this->belongsToMany(Account::class, 'contacts', 'account_id', 'contact_id'); } public function emailChanged() { - return $this->hasOne('App\EmailChanged'); + return $this->hasOne(EmailChanged::class); } public function nonces() { - return $this->hasMany('App\DigestNonce'); + return $this->hasMany(DigestNonce::class); } public function authTokens() { - return $this->hasMany('App\AuthToken'); + return $this->hasMany(AuthToken::class); } public function passwords() { - return $this->hasMany('App\Password'); + return $this->hasMany(Password::class); } public function phoneChangeCode() { - return $this->hasOne('App\PhoneChangeCode'); + return $this->hasOne(PhoneChangeCode::class); } public function types() { - return $this->belongsToMany('App\AccountType'); + return $this->belongsToMany(AccountType::class); } /** diff --git a/flexiapi/app/AccountAction.php b/flexiapi/app/AccountAction.php index 3e70055..7851dd3 100644 --- a/flexiapi/app/AccountAction.php +++ b/flexiapi/app/AccountAction.php @@ -30,6 +30,6 @@ class AccountAction extends Model public function account() { - return $this->belongsTo('App\Account'); + return $this->belongsTo(Account::class); } } diff --git a/flexiapi/app/AccountCreationRequestToken.php b/flexiapi/app/AccountCreationRequestToken.php new file mode 100644 index 0000000..ddf51e8 --- /dev/null +++ b/flexiapi/app/AccountCreationRequestToken.php @@ -0,0 +1,35 @@ +. +*/ + +namespace App; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class AccountCreationRequestToken extends Model +{ + use HasFactory; + + protected $hidden = ['id', 'updated_at', 'created_at']; + + public function accountCreationToken() + { + return $this->belongsTo(AccountCreationToken::class, 'acc_creation_token_id'); + } +} diff --git a/flexiapi/app/AccountCreationToken.php b/flexiapi/app/AccountCreationToken.php index 3f3d458..754224a 100644 --- a/flexiapi/app/AccountCreationToken.php +++ b/flexiapi/app/AccountCreationToken.php @@ -25,4 +25,11 @@ use Illuminate\Database\Eloquent\Model; class AccountCreationToken extends Model { use HasFactory; + + protected $hidden = ['id', 'updated_at', 'created_at']; + + public function accountCreationRequestToken() + { + return $this->hasOne(AccountCreationRequestToken::class, 'acc_creation_token_id'); + } } diff --git a/flexiapi/app/AccountType.php b/flexiapi/app/AccountType.php index f85408b..2592b3d 100644 --- a/flexiapi/app/AccountType.php +++ b/flexiapi/app/AccountType.php @@ -30,6 +30,6 @@ class AccountType extends Model public function accounts() { - return $this->belongsToMany('App\Account'); + return $this->belongsToMany(Account::class); } } diff --git a/flexiapi/app/ActivationExpiration.php b/flexiapi/app/ActivationExpiration.php index 4ec9a27..362ed98 100644 --- a/flexiapi/app/ActivationExpiration.php +++ b/flexiapi/app/ActivationExpiration.php @@ -33,7 +33,7 @@ class ActivationExpiration extends Model public function account() { - return $this->belongsTo('App\Account'); + return $this->belongsTo(Account::class); } public function isExpired() diff --git a/flexiapi/app/Http/Controllers/Account/CreationRequestTokenController.php b/flexiapi/app/Http/Controllers/Account/CreationRequestTokenController.php new file mode 100644 index 0000000..449b37d --- /dev/null +++ b/flexiapi/app/Http/Controllers/Account/CreationRequestTokenController.php @@ -0,0 +1,46 @@ +merge(['account_creation_request_token' => $creationRequestToken]); + $request->validate([ + 'account_creation_request_token' => [ + 'required', + new RulesAccountCreationRequestToken + ] + ]); + + $accountCreationRequestToken = AccountCreationRequestToken::where('token', $request->get('account_creation_request_token'))->firstOrFail(); + + return view('account.creation_request_token.check', [ + 'account_creation_request_token' => $accountCreationRequestToken + ]); + } + + public function validateToken(Request $request) + { + $request->validate([ + 'account_creation_request_token' => [ + 'required', + new RulesAccountCreationRequestToken + ], + 'g-recaptcha-response' => 'required|captcha', + ]); + + $accountCreationRequestToken = AccountCreationRequestToken::where('token', $request->get('account_creation_request_token'))->firstOrFail(); + $accountCreationRequestToken->validated_at = Carbon::now(); + $accountCreationRequestToken->save(); + + return view('account.creation_request_token.valid'); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/AccountController.php b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php similarity index 97% rename from flexiapi/app/Http/Controllers/Api/AccountController.php rename to flexiapi/app/Http/Controllers/Api/Account/AccountController.php index ce2c0a7..4751361 100644 --- a/flexiapi/app/Http/Controllers/Api/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use Illuminate\Http\Request; use Illuminate\Validation\Rule; @@ -253,20 +253,15 @@ class AccountController extends Controller 'password' => 'required|filled', 'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(), 'account_creation_token' => [ - 'required_without:token', + 'required', new RulesAccountCreationToken ], 'email' => config('app.account_email_unique') ? 'nullable|email|unique:accounts,email' : 'nullable|email', - // For retro-compatibility - 'token' => [ - 'required_without:account_creation_token', - new RulesAccountCreationToken - ], ]); - $token = AccountCreationToken::where('token', $request->get('token') ?? $request->get('account_creation_token'))->first(); + $token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first(); $token->used = true; $token->save(); diff --git a/flexiapi/app/Http/Controllers/Api/ApiKeyController.php b/flexiapi/app/Http/Controllers/Api/Account/ApiKeyController.php similarity index 96% rename from flexiapi/app/Http/Controllers/Api/ApiKeyController.php rename to flexiapi/app/Http/Controllers/Api/Account/ApiKeyController.php index 324f5a3..7d121f9 100644 --- a/flexiapi/app/Http/Controllers/Api/ApiKeyController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/ApiKeyController.php @@ -1,6 +1,6 @@ . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use Illuminate\Http\Request; use App\Http\Controllers\Controller; -class AccountContactController extends Controller +class ContactController extends Controller { private $selected = ['id', 'username', 'domain', 'activated', 'dtmf_protocol']; diff --git a/flexiapi/app/Http/Controllers/Api/Account/CreationRequestToken.php b/flexiapi/app/Http/Controllers/Api/Account/CreationRequestToken.php new file mode 100644 index 0000000..f346748 --- /dev/null +++ b/flexiapi/app/Http/Controllers/Api/Account/CreationRequestToken.php @@ -0,0 +1,21 @@ +token = Str::random(WebAuthenticateController::$emailCodeSize); + $creationRequestToken->save(); + + return $creationRequestToken; + } +} diff --git a/flexiapi/app/Http/Controllers/Api/AccountCreationTokenController.php b/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php similarity index 62% rename from flexiapi/app/Http/Controllers/Api/AccountCreationTokenController.php rename to flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php index 3944886..3cc3eb9 100644 --- a/flexiapi/app/Http/Controllers/Api/AccountCreationTokenController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php @@ -17,8 +17,9 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; +use App\AccountCreationRequestToken; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Str; @@ -27,8 +28,9 @@ use Illuminate\Support\Facades\Log; use App\AccountCreationToken; use App\Libraries\FlexisipPusherConnector; use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController; +use App\Rules\AccountCreationRequestToken as RulesAccountCreationRequestToken; -class AccountCreationTokenController extends Controller +class CreationTokenController extends Controller { public function sendByPush(Request $request) { @@ -55,4 +57,32 @@ class AccountCreationTokenController extends Controller abort(503, "Token not sent"); } + + public function usingAccountRequestToken(Request $request) + { + $request->validate([ + 'account_creation_request_token' => [ + 'required', + new RulesAccountCreationRequestToken + ] + ]); + + $creationRequestToken = AccountCreationRequestToken::where('token', $request->get('account_creation_request_token')) + ->where('used', false) + ->first(); + + if ($creationRequestToken && $creationRequestToken->validated_at != null) { + $accountCreationToken = new AccountCreationToken; + $accountCreationToken->token = Str::random(WebAuthenticateController::$emailCodeSize); + $accountCreationToken->save(); + + $creationRequestToken->used = true; + $creationRequestToken->acc_creation_token_id = $accountCreationToken->id; + $creationRequestToken->save(); + + return $accountCreationToken; + } + + return abort(403); + } } diff --git a/flexiapi/app/Http/Controllers/Api/DeviceController.php b/flexiapi/app/Http/Controllers/Api/Account/DeviceController.php similarity index 96% rename from flexiapi/app/Http/Controllers/Api/DeviceController.php rename to flexiapi/app/Http/Controllers/Api/Account/DeviceController.php index 644c987..27450d3 100644 --- a/flexiapi/app/Http/Controllers/Api/DeviceController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/DeviceController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use App\Http\Controllers\Controller; use Illuminate\Http\Request; diff --git a/flexiapi/app/Http/Controllers/Api/EmailController.php b/flexiapi/app/Http/Controllers/Api/Account/EmailController.php similarity index 96% rename from flexiapi/app/Http/Controllers/Api/EmailController.php rename to flexiapi/app/Http/Controllers/Api/Account/EmailController.php index bb664b9..e5ee106 100644 --- a/flexiapi/app/Http/Controllers/Api/EmailController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/EmailController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use App\Http\Controllers\Controller; use Illuminate\Http\Request; diff --git a/flexiapi/app/Http/Controllers/Api/PasswordController.php b/flexiapi/app/Http/Controllers/Api/Account/PasswordController.php similarity index 98% rename from flexiapi/app/Http/Controllers/Api/PasswordController.php rename to flexiapi/app/Http/Controllers/Api/Account/PasswordController.php index 58dabe6..103205d 100644 --- a/flexiapi/app/Http/Controllers/Api/PasswordController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/PasswordController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use App\Http\Controllers\Controller; use Illuminate\Http\Request; diff --git a/flexiapi/app/Http/Controllers/Api/AccountPhoneController.php b/flexiapi/app/Http/Controllers/Api/Account/PhoneController.php similarity index 97% rename from flexiapi/app/Http/Controllers/Api/AccountPhoneController.php rename to flexiapi/app/Http/Controllers/Api/Account/PhoneController.php index b790af9..5655c2c 100644 --- a/flexiapi/app/Http/Controllers/Api/AccountPhoneController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/PhoneController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Account; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -29,7 +29,7 @@ use App\Libraries\OvhSMS; use App\PhoneChangeCode; use App\Alias; -class AccountPhoneController extends Controller +class PhoneController extends Controller { public function requestUpdate(Request $request) { diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountCreationTokenController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountCreationTokenController.php index 16e7d95..bbdc76e 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountCreationTokenController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountCreationTokenController.php @@ -17,7 +17,7 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; diff --git a/flexiapi/app/Http/Controllers/Api/MessageController.php b/flexiapi/app/Http/Controllers/Api/Admin/MessageController.php similarity index 97% rename from flexiapi/app/Http/Controllers/Api/MessageController.php rename to flexiapi/app/Http/Controllers/Api/Admin/MessageController.php index 2f66724..fbeaa43 100644 --- a/flexiapi/app/Http/Controllers/Api/MessageController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/MessageController.php @@ -1,6 +1,6 @@ . +*/ + +namespace App\Rules; + +use App\AccountCreationRequestToken as AppAccountCreationRequestToken; +use App\Http\Controllers\Account\AuthenticateController; +use Illuminate\Contracts\Validation\Rule; + +class AccountCreationRequestToken implements Rule +{ + public function passes($attribute, $value) + { + return AppAccountCreationRequestToken::where('token', $value)->where('used', false)->exists() + && strlen($value) == AuthenticateController::$emailCodeSize; + } + + public function message() + { + return 'Please provide a valid account_creation_request_token'; + } +} diff --git a/flexiapi/app/Rules/AccountCreationToken.php b/flexiapi/app/Rules/AccountCreationToken.php index 39679fb..c1b815a 100644 --- a/flexiapi/app/Rules/AccountCreationToken.php +++ b/flexiapi/app/Rules/AccountCreationToken.php @@ -1,4 +1,21 @@ . +*/ namespace App\Rules; diff --git a/flexiapi/app/Rules/BlacklistedUsername.php b/flexiapi/app/Rules/BlacklistedUsername.php index b731a4b..6092c57 100644 --- a/flexiapi/app/Rules/BlacklistedUsername.php +++ b/flexiapi/app/Rules/BlacklistedUsername.php @@ -1,4 +1,21 @@ . +*/ namespace App\Rules; diff --git a/flexiapi/database/migrations/2023_05_22_120505_make_pn_attributes_nullable_account_creation_tokens_table.php b/flexiapi/database/migrations/2023_05_22_120505_make_pn_attributes_nullable_account_creation_tokens_table.php new file mode 100644 index 0000000..1ae21e5 --- /dev/null +++ b/flexiapi/database/migrations/2023_05_22_120505_make_pn_attributes_nullable_account_creation_tokens_table.php @@ -0,0 +1,29 @@ +string('pn_provider')->nullable(true)->change(); + $table->string('pn_param')->nullable(true)->change(); + $table->string('pn_prid')->nullable(true)->change(); + }); + } + + public function down() + { + AccountCreationToken::whereNull('pn_provider')->delete(); + + Schema::table('account_creation_tokens', function (Blueprint $table) { + $table->string('pn_provider')->nullable(false)->change(); + $table->string('pn_param')->nullable(false)->change(); + $table->string('pn_prid')->nullable(false)->change(); + }); + } +} diff --git a/flexiapi/database/migrations/2023_05_22_123231_create_account_creation_request_tokens_table.php b/flexiapi/database/migrations/2023_05_22_123231_create_account_creation_request_tokens_table.php new file mode 100644 index 0000000..51b84a0 --- /dev/null +++ b/flexiapi/database/migrations/2023_05_22_123231_create_account_creation_request_tokens_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('token', 16)->index(); + $table->boolean('used')->default(false); + $table->dateTime('validated_at')->nullable(); + + $table->bigInteger('acc_creation_token_id')->unsigned()->nullable(); + $table->foreign('acc_creation_token_id')->references('id') + ->on('account_creation_tokens')->onDelete('cascade'); + + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('account_creation_request_tokens'); + } +} diff --git a/flexiapi/public/css/style.css b/flexiapi/public/css/style.css index 6632bbc..e82238a 100644 --- a/flexiapi/public/css/style.css +++ b/flexiapi/public/css/style.css @@ -29,6 +29,10 @@ body > div { max-width: 800px; } +.container.large { + max-width: 1024px; +} + body > footer::before { background-color: white; background-position: bottom center; diff --git a/flexiapi/resources/views/account/creation_request_token/check.blade.php b/flexiapi/resources/views/account/creation_request_token/check.blade.php new file mode 100644 index 0000000..bc2c421 --- /dev/null +++ b/flexiapi/resources/views/account/creation_request_token/check.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.main') + +@section('content') +
+
+ {!! Form::open(['route' => 'account.creation_request_token.validate']) !!} + {!! Form::hidden('account_creation_request_token', $account_creation_request_token->token) !!} + @include('parts.captcha') + {!! Form::submit('I\'m not a robot', ['class' => 'btn btn-primary btn-centered']) !!} + {!! Form::close() !!} +
+
+@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/account/creation_request_token/valid.blade.php b/flexiapi/resources/views/account/creation_request_token/valid.blade.php new file mode 100644 index 0000000..997814b --- /dev/null +++ b/flexiapi/resources/views/account/creation_request_token/valid.blade.php @@ -0,0 +1,6 @@ +@extends('layouts.main') + +@section('content') +

Thanks for the validation

+

You can now continue your registration process in the application

+@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/api/documentation.blade.php b/flexiapi/resources/views/api/documentation.blade.php index 2ef60d1..b5f4edf 100644 --- a/flexiapi/resources/views/api/documentation.blade.php +++ b/flexiapi/resources/views/api/documentation.blade.php @@ -1,4 +1,4 @@ -@extends('layouts.main') +@extends('layouts.main', ['large' => true]) @section('content') {{-- This view is only a wrapper for the markdown page --}} diff --git a/flexiapi/resources/views/api/documentation_markdown.blade.php b/flexiapi/resources/views/api/documentation_markdown.blade.php index dd81bad..a75df97 100644 --- a/flexiapi/resources/views/api/documentation_markdown.blade.php +++ b/flexiapi/resources/views/api/documentation_markdown.blade.php @@ -78,9 +78,19 @@ You can find more documentation on the related [IETF RFC-7616](https://tools.iet Public Returns `pong` +## Account Creation Request Tokens + +An `account_creation_request_token` is a unique token that can be validated and then used to generate a valid `account_creation_token`. + +### `POST /account_creation_request_tokens` +Public + +Create and return an `account_creation_request_token` that should then be validated to be used. + + ## Account Creation Tokens -An account creation token is a unique token that allow the creation of a **unique** account. +An `account_creation_token` is a unique token that allow the creation of a **unique** account. ### `POST /account_creation_tokens/send-by-push` Public @@ -94,6 +104,16 @@ JSON parameters: * `pn_param` the push notification parameter * `pn_prid` the push notification unique id +### `POST /account_creation_tokens/using-account-creation-request-token` +Public +Create an `account_creation_token` using an `account_creation_request_token`. +Return an `account_creation_token`. +Return `403` if the `account_creation_request_token` provided is not valid or expired otherwise. + +JSON parameters: + +* `account_creation_request_token` required + ### `POST /account_creation_tokens` Admin diff --git a/flexiapi/resources/views/layouts/main.blade.php b/flexiapi/resources/views/layouts/main.blade.php index a8e8676..68d12e3 100644 --- a/flexiapi/resources/views/layouts/main.blade.php +++ b/flexiapi/resources/views/layouts/main.blade.php @@ -33,7 +33,7 @@ @endsection @section('body') -
+
@include('parts.errors') @yield('content')
diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php index 92e6190..e8508f8 100644 --- a/flexiapi/routes/api.php +++ b/flexiapi/routes/api.php @@ -26,59 +26,60 @@ Route::middleware('auth:api')->get('/user', function (Request $request) { }); Route::get('ping', 'Api\PingController@ping'); -Route::post('account_creation_tokens/send-by-push', 'Api\AccountCreationTokenController@sendByPush'); -// Old URL, for retro-compatibility -Route::post('tokens', 'Api\AccountCreationTokenController@sendByPush'); -Route::get('accounts/{sip}/info', 'Api\AccountController@info'); +Route::post('account_creation_request_tokens', 'Api\Account\CreationRequestToken@create'); +Route::post('account_creation_tokens/send-by-push', 'Api\Account\CreationTokenController@sendByPush'); +Route::post('account_creation_tokens/using-account-creation-request-token', 'Api\Account\CreationTokenController@usingAccountRequestToken'); +Route::post('accounts/with-account-creation-token', 'Api\Account\AccountController@store'); -Route::post('accounts/with-account-creation-token', 'Api\AccountController@store'); -// Old URL, for retro-compatibility -Route::post('accounts/with-token', 'Api\AccountController@store'); +Route::get('accounts/{sip}/info', 'Api\Account\AccountController@info'); -Route::post('accounts/{sip}/activate/email', 'Api\AccountController@activateEmail'); -Route::post('accounts/{sip}/activate/phone', 'Api\AccountController@activatePhone'); +Route::post('accounts/{sip}/activate/email', 'Api\Account\AccountController@activateEmail'); +Route::post('accounts/{sip}/activate/phone', 'Api\Account\AccountController@activatePhone'); // /!\ Dangerous endpoints -Route::post('accounts/public', 'Api\AccountController@storePublic'); -Route::get('accounts/{sip}/recover/{recovery_key}', 'Api\AccountController@recoverUsingKey'); -Route::post('accounts/recover-by-phone', 'Api\AccountController@recoverByPhone'); -Route::get('accounts/{phone}/info-by-phone', 'Api\AccountController@phoneInfo'); +Route::post('accounts/public', 'Api\Account\AccountController@storePublic'); +Route::get('accounts/{sip}/recover/{recovery_key}', 'Api\Account\AccountController@recoverUsingKey'); +Route::post('accounts/recover-by-phone', 'Api\Account\AccountController@recoverByPhone'); +Route::get('accounts/{phone}/info-by-phone', 'Api\Account\AccountController@phoneInfo'); -Route::post('accounts/auth_token', 'Api\AuthTokenController@store'); +Route::post('accounts/auth_token', 'Api\Account\AuthTokenController@store'); -Route::get('accounts/me/api_key/{auth_token}', 'Api\ApiKeyController@generateFromToken')->middleware('cookie', 'cookie.encrypt'); +Route::get('accounts/me/api_key/{auth_token}', 'Api\Account\ApiKeyController@generateFromToken')->middleware('cookie', 'cookie.encrypt'); Route::group(['middleware' => ['auth.digest_or_key']], function () { Route::get('statistic/month', 'Api\StatisticController@month'); Route::get('statistic/week', 'Api\StatisticController@week'); Route::get('statistic/day', 'Api\StatisticController@day'); - Route::get('accounts/auth_token/{auth_token}/attach', 'Api\AuthTokenController@attach'); + Route::get('accounts/auth_token/{auth_token}/attach', 'Api\Account\AuthTokenController@attach'); - Route::get('accounts/me/api_key', 'Api\ApiKeyController@generate')->middleware('cookie', 'cookie.encrypt'); + Route::get('accounts/me/api_key', 'Api\Account\ApiKeyController@generate')->middleware('cookie', 'cookie.encrypt'); - Route::get('accounts/me', 'Api\AccountController@show'); - Route::delete('accounts/me', 'Api\AccountController@delete'); - Route::get('accounts/me/provision', 'Api\AccountController@provision'); + Route::get('accounts/me', 'Api\Account\AccountController@show'); + Route::delete('accounts/me', 'Api\Account\AccountController@delete'); + Route::get('accounts/me/provision', 'Api\Account\AccountController@provision'); - Route::post('accounts/me/phone/request', 'Api\AccountPhoneController@requestUpdate'); - Route::post('accounts/me/phone', 'Api\AccountPhoneController@update'); + Route::post('accounts/me/phone/request', 'Api\Account\PhoneController@requestUpdate'); + Route::post('accounts/me/phone', 'Api\Account\PhoneController@update'); - Route::get('accounts/me/devices', 'Api\DeviceController@index'); - Route::delete('accounts/me/devices/{uuid}', 'Api\DeviceController@destroy'); + Route::get('accounts/me/devices', 'Api\Account\DeviceController@index'); + Route::delete('accounts/me/devices/{uuid}', 'Api\Account\DeviceController@destroy'); - Route::post('accounts/me/email/request', 'Api\EmailController@requestUpdate'); - Route::post('accounts/me/password', 'Api\PasswordController@update'); + Route::post('accounts/me/email/request', 'Api\Account\EmailController@requestUpdate'); + Route::post('accounts/me/password', 'Api\Account\PasswordController@update'); - Route::get('accounts/me/contacts/{sip}', 'Api\AccountContactController@show'); - Route::get('accounts/me/contacts', 'Api\AccountContactController@index'); + Route::get('accounts/me/contacts/{sip}', 'Api\Account\ContactController@show'); + Route::get('accounts/me/contacts', 'Api\Account\ContactController@index'); Route::group(['middleware' => ['auth.admin']], function () { if (!empty(config('app.linphone_daemon_unix_pipe'))) { - Route::post('messages', 'Api\MessageController@send'); + Route::post('messages', 'Api\Admin\MessageController@send'); } + // Account creation token + Route::post('account_creation_tokens', 'Api\Admin\AccountCreationTokenController@create'); + // Accounts Route::get('accounts/{id}/activate', 'Api\Admin\AccountController@activate'); Route::get('accounts/{id}/deactivate', 'Api\Admin\AccountController@deactivate'); diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index c2a896d..ed94521 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -36,6 +36,9 @@ if (config('app.web_panel')) { Route::get('authenticate/qrcode/{token?}', 'Account\AuthenticateController@loginAuthToken')->name('account.authenticate.auth_token'); } +Route::get('creation_token/check/{token}', 'Account\CreationRequestTokenController@check')->name('account.creation_request_token.check'); +Route::post('creation_token/validate', 'Account\CreationRequestTokenController@validateToken')->name('account.creation_request_token.validate'); + Route::group(['middleware' => 'auth.digest_or_key'], function () { Route::get('provisioning/me', 'Account\ProvisioningController@me')->name('provisioning.me'); diff --git a/flexiapi/tests/Feature/ApiAccountCreationTokenTest.php b/flexiapi/tests/Feature/ApiAccountCreationTokenTest.php index f1db9a7..9a3a0ae 100644 --- a/flexiapi/tests/Feature/ApiAccountCreationTokenTest.php +++ b/flexiapi/tests/Feature/ApiAccountCreationTokenTest.php @@ -19,17 +19,23 @@ namespace Tests\Feature; +use App\AccountCreationRequestToken; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; use App\AccountCreationToken; +use App\Admin; +use Carbon\Carbon; class ApiAccountCreationTokenTest extends TestCase { use RefreshDatabase; protected $tokenRoute = '/api/account_creation_tokens/send-by-push'; + protected $tokenRequestRoute = '/api/account_creation_request_tokens'; + protected $tokenUsingCreationTokenRoute = '/api/account_creation_tokens/using-account-creation-request-token'; protected $accountRoute = '/api/accounts/with-account-creation-token'; + protected $adminRoute = '/api/account_creation_tokens'; protected $method = 'POST'; protected $pnProvider = 'provider'; @@ -52,51 +58,24 @@ class ApiAccountCreationTokenTest extends TestCase $response->assertStatus(503); } - /** - * For retro-compatibility only - */ - public function testRetrocopatibilityToken() + public function testAdminEndpoint() { - $token = AccountCreationToken::factory()->create(); + $admin = Admin::factory()->create(); + $admin->account->generateApiKey(); - $response = $this->json($this->method, '/api/tokens', [ - 'pn_provider' => $token->pn_provider, - 'pn_param' => $token->pn_param, - 'pn_prid' => $token->pn_prid + $response = $this->keyAuthenticated($admin->account) + ->json($this->method, $this->adminRoute) + ->assertStatus(201); + + $this->assertDatabaseHas('account_creation_tokens', [ + 'token' => $response->json()['token'] ]); - $response->assertStatus(503); } public function testInvalidToken() { $token = AccountCreationToken::factory()->create(); - // Valid token - $response = $this->json($this->method, '/api/accounts/with-token', [ - 'username' => 'username', - 'algorithm' => 'SHA-256', - 'password' => '2', - 'token' => $token->token - ]); - $response->assertStatus(200); - - // Expired token - $response = $this->json($this->method, '/api/accounts/with-token', [ - 'username' => 'username2', - 'algorithm' => 'SHA-256', - 'password' => '2', - 'token' => $token->token - ]); - $response->assertStatus(422); - } - - /** - * For retrocompatibility only - */ - public function testRetrocompatibilityInvalidToken() - { - $token = AccountCreationToken::factory()->create(); - // Invalid token $response = $this->json($this->method, $this->accountRoute, [ 'username' => 'username', @@ -125,9 +104,6 @@ class ApiAccountCreationTokenTest extends TestCase $response->assertStatus(422); } - /** - * Test username blacklist - */ public function testBlacklistedUsername() { $token = AccountCreationToken::factory()->create(); @@ -165,4 +141,34 @@ class ApiAccountCreationTokenTest extends TestCase $response->assertStatus(200); } + + public function testAccountCreationRequestToken() + { + $response = $this->json($this->method, $this->tokenRequestRoute); + $response->assertStatus(201); + $creationRequestToken = $response->json()['token']; + + // Validate the creation request token + AccountCreationRequestToken::where('token', $creationRequestToken)->update(['validated_at' => Carbon::now()]); + + $response = $this->json($this->method, $this->tokenUsingCreationTokenRoute, [ + 'account_creation_request_token' => $creationRequestToken + ])->assertStatus(201); + + $creationToken = $response->json()['token']; + + $this->assertDatabaseHas('account_creation_request_tokens', [ + 'token' => $creationRequestToken, + 'used' => true + ]); + + $this->assertDatabaseHas('account_creation_tokens', [ + 'token' => $creationToken + ]); + + $this->assertSame( + AccountCreationRequestToken::where('token', $creationRequestToken)->first()->accountCreationToken->id, + AccountCreationToken::where('token', $creationToken)->first()->id + ); + } }