mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Add account expirations table
Complete POST /accounts admin endpoints Handle expiration in email and phone endpoints Complete documentation Add related tests Bump package version
This commit is contained in:
parent
cd32657d21
commit
46af75fea3
9 changed files with 176 additions and 13 deletions
|
|
@ -38,10 +38,10 @@ class Account extends Authenticatable
|
|||
use HasFactory;
|
||||
|
||||
protected $connection = 'external';
|
||||
protected $with = ['passwords', 'admin', 'emailChanged', 'alias'];
|
||||
protected $with = ['passwords', 'admin', 'emailChanged', 'alias', 'activationExpiration'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key'];
|
||||
protected $dateTimes = ['creation_time'];
|
||||
protected $appends = ['realm', 'phone'];
|
||||
protected $appends = ['realm', 'phone', 'confirmation_key_expires'];
|
||||
protected $casts = [
|
||||
'activated' => 'boolean',
|
||||
];
|
||||
|
|
@ -97,6 +97,11 @@ class Account extends Authenticatable
|
|||
return $this->hasOne('App\Admin');
|
||||
}
|
||||
|
||||
public function activationExpiration()
|
||||
{
|
||||
return $this->hasOne('App\ActivationExpiration');
|
||||
}
|
||||
|
||||
public function apiKey()
|
||||
{
|
||||
return $this->hasOne('App\ApiKey');
|
||||
|
|
@ -131,6 +136,20 @@ class Account extends Authenticatable
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getConfirmationKeyExpiresAttribute()
|
||||
{
|
||||
if ($this->activationExpiration) {
|
||||
return $this->activationExpiration->expires->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function activationExpired(): bool
|
||||
{
|
||||
return ($this->activationExpiration && $this->activationExpiration->isExpired());
|
||||
}
|
||||
|
||||
public function requestEmailUpdate(string $newEmail)
|
||||
{
|
||||
// Remove all the old requests
|
||||
|
|
|
|||
28
flexiapi/app/ActivationExpiration.php
Normal file
28
flexiapi/app/ActivationExpiration.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ActivationExpiration extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $connection = 'local';
|
||||
protected $casts = [
|
||||
'expires' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo('App\Account');
|
||||
}
|
||||
|
||||
public function isExpired()
|
||||
{
|
||||
$now = Carbon::now();
|
||||
return $this->expires->lessThan($now);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ class AccountDeleting
|
|||
{
|
||||
$account->alias()->delete();
|
||||
$account->passwords()->delete();
|
||||
$account->activationExpiration()->delete();
|
||||
$account->nonces()->delete();
|
||||
$account->admin()->delete();
|
||||
$account->apiKey()->delete();
|
||||
|
|
|
|||
|
|
@ -100,9 +100,11 @@ class AccountController extends Controller
|
|||
$account = Account::sip($sip)
|
||||
->where('confirmation_key', $request->get('code'))
|
||||
->firstOrFail();
|
||||
|
||||
if ($account->activationExpired()) abort(403, 'Activation expired');
|
||||
|
||||
$account->activated = true;
|
||||
$account->confirmation_key = null;
|
||||
|
||||
$account->save();
|
||||
|
||||
return $account;
|
||||
|
|
@ -117,6 +119,9 @@ class AccountController extends Controller
|
|||
$account = Account::sip($sip)
|
||||
->where('confirmation_key', $request->get('code'))
|
||||
->firstOrFail();
|
||||
|
||||
if ($account->activationExpired()) abort(403, 'Activation expired');
|
||||
|
||||
$account->activated = true;
|
||||
$account->confirmation_key = null;
|
||||
$account->save();
|
||||
|
|
|
|||
|
|
@ -26,10 +26,9 @@ use Illuminate\Validation\Rule;
|
|||
use Carbon\Carbon;
|
||||
|
||||
use App\Account;
|
||||
use App\ActivationExpiration;
|
||||
use App\Admin;
|
||||
use App\Password;
|
||||
use App\Rules\WithoutSpaces;
|
||||
use App\Helpers\Utils;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class AccountController extends Controller
|
||||
|
|
@ -84,6 +83,10 @@ class AccountController extends Controller
|
|||
'domain' => 'min:3',
|
||||
'admin' => 'boolean|nullable',
|
||||
'activated' => 'boolean|nullable',
|
||||
'confirmation_key_expires' => [
|
||||
'date_format:Y-m-d H:i:s',
|
||||
'nullable',
|
||||
]
|
||||
]);
|
||||
|
||||
$account = new Account;
|
||||
|
|
@ -105,6 +108,14 @@ class AccountController extends Controller
|
|||
|
||||
$account->save();
|
||||
|
||||
if ((!$request->has('activated') || !(bool)$request->get('activated'))
|
||||
&& $request->has('confirmation_key_expires')) {
|
||||
$actionvationExpiration = new ActivationExpiration;
|
||||
$actionvationExpiration->account_id = $account->id;
|
||||
$actionvationExpiration->expires = $request->get('confirmation_key_expires');
|
||||
$actionvationExpiration->save();
|
||||
}
|
||||
|
||||
$account->updatePassword($request->get('password'), $request->get('algorithm'));
|
||||
|
||||
if ($request->has('admin') && (bool)$request->get('admin')) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateActivationExpirationsTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::connection('local')->create('activation_expirations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('account_id')->unsigned();
|
||||
$table->dateTime('expires');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::connection('local')->dropIfExists('activation_expirations');
|
||||
}
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
|
|||
|
||||
<h4><code>POST /accounts</code></h4>
|
||||
<p>To create an account directly from the API.</p>
|
||||
<p>If <code>activated</code> is set to <code>false</code> a random generated <code>confirmation_key</code> will be returned to allow further activation using the public endpoints.</p>
|
||||
<p>If <code>activated</code> is set to <code>false</code> a random generated <code>confirmation_key</code> will be returned to allow further activation using the public endpoints. Check <code>confirmation_key_expires</code> to also set an expiration date on that <code>confirmation_key</code>.</p>
|
||||
|
||||
<p>JSON parameters:</p>
|
||||
<ul>
|
||||
|
|
@ -167,6 +167,7 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
|
|||
<li><code>domain</code> optional, the value is set to the default registration domain if not set</li>
|
||||
<li><code>activated</code> optional, a boolean, set to <code>false</code> by default</li>
|
||||
<li><code>admin</code> optional, a boolean, set to <code>false</code> by default, create an admin account</li>
|
||||
<li><code>confirmation_key_expires</code> optional, a datetime of this format: Y-m-d H:i:s. Only used when <code>activated</code> is not used or <code>false</code>. Enforces an expiration date on the returned <code>confirmation_key</code>. After that datetime public email or phone activation endpoints will return <code>403</code>.</li>
|
||||
</ul>
|
||||
|
||||
<h4><code>GET /accounts</code></h4>
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ namespace Tests\Feature;
|
|||
|
||||
use App\Password;
|
||||
use App\Account;
|
||||
use App\ActivationExpiration;
|
||||
use App\Admin;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
|
@ -226,8 +227,7 @@ class AccountApiTest extends TestCase
|
|||
'activated' => false,
|
||||
]);
|
||||
|
||||
$response1
|
||||
->assertStatus(200)
|
||||
$response1->assertStatus(200)
|
||||
->assertJson([
|
||||
'id' => 2,
|
||||
'username' => $username,
|
||||
|
|
@ -296,6 +296,11 @@ class AccountApiTest extends TestCase
|
|||
$password->account->activated = false;
|
||||
$password->account->save();
|
||||
|
||||
$expiration = new ActivationExpiration;
|
||||
$expiration->account_id = $password->account->id;
|
||||
$expiration->expires = Carbon::now()->subYear();
|
||||
$expiration->save();
|
||||
|
||||
$this->get($this->route.'/'.$password->account->identifier.'/info')
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
|
|
@ -308,20 +313,31 @@ class AccountApiTest extends TestCase
|
|||
])
|
||||
->assertStatus(404);
|
||||
|
||||
$activateEmailRoute = $this->route.'/'.$password->account->identifier.'/activate/email';
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->identifier.'/activate/email', [
|
||||
->json($this->method, $activateEmailRoute, [
|
||||
'code' => $confirmationKey.'longer'
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->identifier.'/activate/email', [
|
||||
->json($this->method, $activateEmailRoute, [
|
||||
'code' => 'X123456789abc'
|
||||
])
|
||||
->assertStatus(404);
|
||||
|
||||
// Expired
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->identifier.'/activate/email', [
|
||||
->json($this->method, $activateEmailRoute, [
|
||||
'code' => $confirmationKey
|
||||
])
|
||||
->assertStatus(403);
|
||||
|
||||
$expiration->delete();
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $activateEmailRoute, [
|
||||
'code' => $confirmationKey
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
|
@ -342,12 +358,26 @@ class AccountApiTest extends TestCase
|
|||
$password->account->activated = false;
|
||||
$password->account->save();
|
||||
|
||||
$expiration = new ActivationExpiration;
|
||||
$expiration->account_id = $password->account->id;
|
||||
$expiration->expires = Carbon::now()->subYear();
|
||||
$expiration->save();
|
||||
|
||||
$this->get($this->route.'/'.$password->account->identifier.'/info')
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'activated' => false
|
||||
]);
|
||||
|
||||
// Expired
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->identifier.'/activate/phone', [
|
||||
'code' => $confirmationKey
|
||||
])
|
||||
->assertStatus(403);
|
||||
|
||||
$expiration->delete();
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->identifier.'/activate/phone', [
|
||||
'code' => $confirmationKey
|
||||
|
|
@ -544,6 +574,51 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
}
|
||||
|
||||
public function testCodeExpires()
|
||||
{
|
||||
$admin = Admin::factory()->create();
|
||||
$admin->account->generateApiKey();
|
||||
|
||||
// Activated, no no confirmation_key
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'foobar',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
'activated' => true,
|
||||
'confirmation_key_expires' => '2040-12-12 12:12:12'
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'confirmation_key_expires' => null
|
||||
]);
|
||||
|
||||
// Bad datetime format
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'foobar2',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
'activated' => false,
|
||||
'confirmation_key_expires' => 'abc'
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
// Bad datetime format
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'foobar2',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
'activated' => false,
|
||||
'confirmation_key_expires' => '2040-12-12 12:12:12'
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'confirmation_key_expires' => '2040-12-12 12:12:12'
|
||||
]);;
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$password = Password::factory()->create();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#%define _datadir %{_datarootdir}
|
||||
#%define _docdir %{_datadir}/doc
|
||||
|
||||
%define build_number 52
|
||||
%define build_number 53
|
||||
%define var_dir /var/opt/belledonne-communications
|
||||
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager
|
||||
%define env_file "$RPM_BUILD_ROOT/etc/flexisip-account-manager/flexiapi.env"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue