Fix #102 Implement AccountCreationRequestToken

This commit is contained in:
Timothée Jaussoin 2023-05-23 14:49:03 +00:00
parent 716789592e
commit 8570aaae15
33 changed files with 424 additions and 107 deletions

View file

@ -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);
}
/**

View file

@ -30,6 +30,6 @@ class AccountAction extends Model
public function account()
{
return $this->belongsTo('App\Account');
return $this->belongsTo(Account::class);
}
}

View file

@ -0,0 +1,35 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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');
}
}

View file

@ -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');
}
}

View file

@ -30,6 +30,6 @@ class AccountType extends Model
public function accounts()
{
return $this->belongsToMany('App\Account');
return $this->belongsToMany(Account::class);
}
}

View file

@ -33,7 +33,7 @@ class ActivationExpiration extends Model
public function account()
{
return $this->belongsTo('App\Account');
return $this->belongsTo(Account::class);
}
public function isExpired()

View file

@ -0,0 +1,46 @@
<?php
namespace App\Http\Controllers\Account;
use App\AccountCreationRequestToken;
use App\Http\Controllers\Controller;
use App\Rules\AccountCreationRequestToken as RulesAccountCreationRequestToken;
use Carbon\Carbon;
use Illuminate\Http\Request;
class CreationRequestTokenController extends Controller
{
public function check(Request $request, string $creationRequestToken)
{
$request->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');
}
}

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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();

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Account;
use App\AuthToken;
use App\Http\Controllers\Controller;

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Account;
use App\AuthToken;
use App\Http\Controllers\Controller;

View file

@ -17,13 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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'];

View file

@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Api\Account;
use App\AccountCreationRequestToken;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
use App\Http\Controllers\Controller;
class CreationRequestToken extends Controller
{
public function create(Request $request)
{
$creationRequestToken = new AccountCreationRequestToken;
$creationRequestToken->token = Str::random(WebAuthenticateController::$emailCodeSize);
$creationRequestToken->save();
return $creationRequestToken;
}
}

View file

@ -17,8 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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);
}
}

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Account;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Account;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Account;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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)
{

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Api;
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;

View file

@ -0,0 +1,38 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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';
}
}

View file

@ -1,4 +1,21 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Rules;

View file

@ -1,4 +1,21 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Rules;

View file

@ -0,0 +1,29 @@
<?php
use App\AccountCreationToken;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class MakePnAttributesNullableAccountCreationTokensTable extends Migration
{
public function up()
{
Schema::table('account_creation_tokens', function (Blueprint $table) {
$table->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();
});
}
}

View file

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAccountCreationRequestTokensTable extends Migration
{
public function up()
{
Schema::create('account_creation_request_tokens', function (Blueprint $table) {
$table->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');
}
}

View file

@ -29,6 +29,10 @@ body > div {
max-width: 800px;
}
.container.large {
max-width: 1024px;
}
body > footer::before {
background-color: white;
background-position: bottom center;

View file

@ -0,0 +1,13 @@
@extends('layouts.main')
@section('content')
<div class="card mt-3">
<div class="card-body">
{!! 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() !!}
</div>
</div>
@endsection

View file

@ -0,0 +1,6 @@
@extends('layouts.main')
@section('content')
<h3 class="text-center mt-5">Thanks for the validation</h3>
<p class="text-center">You can now continue your registration process in the application</p>
@endsection

View file

@ -1,4 +1,4 @@
@extends('layouts.main')
@extends('layouts.main', ['large' => true])
@section('content')
{{-- This view is only a wrapper for the markdown page --}}

View file

@ -78,9 +78,19 @@ You can find more documentation on the related [IETF RFC-7616](https://tools.iet
<span class="badge badge-success">Public</span>
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`
<span class="badge badge-success">Public</span>
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`
<span class="badge badge-success">Public</span>
@ -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`
<span class="badge badge-success">Public</span>
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`
<span class="badge badge-warning">Admin</span>

View file

@ -33,7 +33,7 @@
@endsection
@section('body')
<div class="container pt-4">
<div class="container @if (isset($large) && $large) large @endif pt-4">
@include('parts.errors')
@yield('content')
</div>

View file

@ -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');

View file

@ -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');

View file

@ -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
);
}
}