mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Fix #94 Implement the deprecated endpoint changes + tests + documentation
This commit is contained in:
parent
3f35954071
commit
e11d55e3f9
5 changed files with 133 additions and 15 deletions
|
|
@ -30,4 +30,16 @@ class Alias extends Model
|
|||
{
|
||||
return $this->belongsTo('App\Account');
|
||||
}
|
||||
|
||||
public function scopeSip($query, string $sip)
|
||||
{
|
||||
if (\str_contains($sip, '@')) {
|
||||
list($usernane, $domain) = explode('@', $sip);
|
||||
|
||||
return $query->where('alias', $usernane)
|
||||
->where('domain', $domain);
|
||||
};
|
||||
|
||||
return $query->where('id', '<', 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use App\Alias;
|
|||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use App\Libraries\OvhSMS;
|
||||
use App\Mail\RegisterConfirmation;
|
||||
use App\Rules\AccountCreationToken as RulesAccountCreationToken;
|
||||
use App\Rules\BlacklistedUsername;
|
||||
use App\Rules\IsNotPhoneNumber;
|
||||
use App\Rules\NoUppercase;
|
||||
|
|
@ -70,11 +71,13 @@ class AccountController extends Controller
|
|||
$alias = Alias::where('alias', $phone)->first();
|
||||
$account = $alias
|
||||
? $alias->account
|
||||
: Account::sip($phone)->firstOrFail();
|
||||
// Injecting the default sip domain to try to resolve the account
|
||||
: Account::sip($phone . '@' . config('app.sip_domain'))->firstOrFail();
|
||||
|
||||
return \response()->json([
|
||||
'activated' => $account->activated,
|
||||
'realm' => $account->realm
|
||||
'realm' => $account->realm,
|
||||
'phone' => (bool)$alias
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +116,10 @@ class AccountController extends Controller
|
|||
'unique:aliases,alias',
|
||||
'unique:accounts,username',
|
||||
new WithoutSpaces, 'starts_with:+'
|
||||
],
|
||||
'account_creation_token' => [
|
||||
'required',
|
||||
new RulesAccountCreationToken
|
||||
]
|
||||
]);
|
||||
|
||||
|
|
@ -178,13 +185,17 @@ class AccountController extends Controller
|
|||
$request->validate([
|
||||
'phone' => [
|
||||
'required', new WithoutSpaces, 'starts_with:+'
|
||||
],
|
||||
'account_creation_token' => [
|
||||
'required',
|
||||
new RulesAccountCreationToken
|
||||
]
|
||||
]);
|
||||
|
||||
$alias = Alias::where('alias', $request->get('phone'))->first();
|
||||
$account = $alias
|
||||
? $alias->account
|
||||
: Account::sip($request->get('phone'))->firstOrFail();
|
||||
: Account::sip($request->get('phone') . '@' . config('app.sip_domain'))->firstOrFail();
|
||||
|
||||
$account->confirmation_key = generatePin();
|
||||
$account->save();
|
||||
|
|
@ -202,9 +213,12 @@ class AccountController extends Controller
|
|||
{
|
||||
if (!config('app.dangerous_endpoints')) return abort(404);
|
||||
|
||||
$account = Account::sip($sip)
|
||||
->where('confirmation_key', $recoveryKey)
|
||||
->firstOrFail();
|
||||
$alias = Alias::sip($sip)->first();
|
||||
$account = $alias
|
||||
? $alias->account
|
||||
: Account::sip($sip)->firstOrFail();
|
||||
|
||||
if ($account->confirmation_key != $recoveryKey) abort(404);
|
||||
|
||||
if ($account->activationExpired()) abort(403, 'Activation expired');
|
||||
|
||||
|
|
@ -241,10 +255,7 @@ class AccountController extends Controller
|
|||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'account_creation_token' => [
|
||||
'required_without:token',
|
||||
Rule::exists('account_creation_tokens', 'token')->where(function ($query) {
|
||||
$query->where('used', false);
|
||||
}),
|
||||
'size:' . WebAuthenticateController::$emailCodeSize
|
||||
new RulesAccountCreationToken
|
||||
],
|
||||
'email' => config('app.account_email_unique')
|
||||
? 'nullable|email|unique:accounts,email'
|
||||
|
|
@ -252,10 +263,7 @@ class AccountController extends Controller
|
|||
// For retro-compatibility
|
||||
'token' => [
|
||||
'required_without:account_creation_token',
|
||||
Rule::exists('account_creation_tokens', 'token')->where(function ($query) {
|
||||
$query->where('used', false);
|
||||
}),
|
||||
'size:' . WebAuthenticateController::$emailCodeSize
|
||||
new RulesAccountCreationToken
|
||||
],
|
||||
]);
|
||||
|
||||
|
|
|
|||
21
flexiapi/app/Rules/AccountCreationToken.php
Normal file
21
flexiapi/app/Rules/AccountCreationToken.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\AccountCreationToken as AppAccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class AccountCreationToken implements Rule
|
||||
{
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
return AppAccountCreationToken::where('token', $value)->where('used', false)->exists()
|
||||
&& strlen($value) == AuthenticateController::$emailCodeSize;
|
||||
}
|
||||
|
||||
public function message()
|
||||
{
|
||||
return 'Please provide a valid account_creation_token';
|
||||
}
|
||||
}
|
||||
|
|
@ -134,6 +134,7 @@ JSON parameters:
|
|||
* `domain` if not set the value is enforced to the default registration domain set in the global configuration
|
||||
* `email` optional if `phone` set, an email, set an email to the account, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
|
||||
* `phone` required if `username` not set, optional if `email` set, a phone number, set a phone number to the account
|
||||
* `account_creation_token` the unique `account_creation_token`
|
||||
|
||||
### `POST /accounts/with-account-creation-token`
|
||||
<span class="badge badge-success">Public</span>
|
||||
|
|
@ -162,6 +163,8 @@ Return `404` if the account doesn't exists.
|
|||
Retrieve public information about the account.
|
||||
Return `404` if the account doesn't exists.
|
||||
|
||||
Return `phone: true` if the returned account has a phone number.
|
||||
|
||||
### `POST /accounts/recover-by-phone`
|
||||
@if(config('app.dangerous_endpoints'))**Enabled on this instance**@else**Not enabled on this instance**@endif
|
||||
|
||||
|
|
@ -174,6 +177,7 @@ Return `404` if the account doesn't exists.
|
|||
JSON parameters:
|
||||
|
||||
* `phone` required the phone number to send the SMS to
|
||||
* `account_creation_token` the unique `account_creation_token`
|
||||
|
||||
### `GET /accounts/{sip}/recover/{recover_key}`
|
||||
@if(config('app.dangerous_endpoints'))**Enabled on this instance**@else**Not enabled on this instance**@endif
|
||||
|
|
@ -182,6 +186,9 @@ JSON parameters:
|
|||
<span class="badge badge-success">Public</span>
|
||||
<span class="badge badge-warning">Unsecure endpoint</span>
|
||||
Activate the account if the correct `recover_key` is provided.
|
||||
|
||||
The `sip` parameter can be the default SIP account or the phone based one.
|
||||
|
||||
Return the account information (including the hashed password) if valid.
|
||||
|
||||
Return `404` if the account doesn't exists.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace Tests\Feature;
|
|||
|
||||
use App\Password;
|
||||
use App\Account;
|
||||
use App\AccountCreationToken;
|
||||
use App\AccountTombstone;
|
||||
use App\ActivationExpiration;
|
||||
use App\Admin;
|
||||
|
|
@ -565,8 +566,31 @@ class ApiAccountTest extends TestCase
|
|||
$this->assertDatabaseHas('accounts', [
|
||||
'username' => $password->account->username,
|
||||
'domain' => $password->account->domain,
|
||||
'confirmation_key' => null,
|
||||
'activated' => true
|
||||
]);
|
||||
|
||||
// Recover by alias
|
||||
|
||||
$newConfirmationKey = '1345';
|
||||
|
||||
$password->account->confirmation_key = $newConfirmationKey;
|
||||
$password->account->save();
|
||||
|
||||
$phone = '+1234';
|
||||
|
||||
$alias = new AppAlias;
|
||||
$alias->alias = $phone;
|
||||
$alias->domain = $password->account->domain;
|
||||
$alias->account_id = $password->account->id;
|
||||
$alias->save();
|
||||
|
||||
$this->get($this->route . '/' . $phone . '@' . $alias->domain . '/recover/' . $newConfirmationKey)
|
||||
->assertJson(['passwords' => [[
|
||||
'password' => $password->password,
|
||||
'algorithm' => $password->algorithm
|
||||
]]])
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -591,6 +615,22 @@ class ApiAccountTest extends TestCase
|
|||
|
||||
$this->json($this->method, $this->route . '/recover-by-phone', [
|
||||
'phone' => $phone
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['account_creation_token']);
|
||||
|
||||
|
||||
$this->json($this->method, $this->route . '/recover-by-phone', [
|
||||
'phone' => $phone,
|
||||
'account_creation_token' => 'wrong'
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['account_creation_token']);
|
||||
$token = AccountCreationToken::factory()->create();
|
||||
|
||||
$this->json($this->method, $this->route . '/recover-by-phone', [
|
||||
'phone' => $phone,
|
||||
'account_creation_token' => $token->token
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
|
|
@ -605,7 +645,8 @@ class ApiAccountTest extends TestCase
|
|||
$this->get($this->route . '/' . $phone . '/info-by-phone')
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'activated' => true
|
||||
'activated' => true,
|
||||
'phone' => true
|
||||
]);
|
||||
|
||||
$this->get($this->route . '/+1234/info-by-phone')
|
||||
|
|
@ -614,11 +655,25 @@ class ApiAccountTest extends TestCase
|
|||
$this->json('GET', $this->route . '/' . $password->account->identifier . '/info-by-phone')
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['phone']);
|
||||
|
||||
// Check the mixed username/phone resolution...
|
||||
$password->account->username = $phone;
|
||||
$password->account->save();
|
||||
|
||||
$alias->delete();
|
||||
|
||||
$this->get($this->route . '/' . $phone . '/info-by-phone')
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'activated' => true,
|
||||
'phone' => false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* /!\ Dangerous endpoints
|
||||
*/
|
||||
|
||||
public function testCreatePublic()
|
||||
{
|
||||
$username = 'publicuser';
|
||||
|
|
@ -639,6 +694,18 @@ class ApiAccountTest extends TestCase
|
|||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'email' => 'john@doe.tld',
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['account_creation_token']);
|
||||
|
||||
$token = AccountCreationToken::factory()->create();
|
||||
|
||||
$this->json($this->method, $this->route . '/public', [
|
||||
'username' => $username,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'email' => 'john@doe.tld',
|
||||
'account_creation_token' => $token->token
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
|
|
@ -700,11 +767,14 @@ class ApiAccountTest extends TestCase
|
|||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['phone']);
|
||||
|
||||
$token = AccountCreationToken::factory()->create();
|
||||
|
||||
$this->json($this->method, $this->route . '/public', [
|
||||
'phone' => $phone,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'email' => 'john@doe.tld',
|
||||
'account_creation_token' => $token->token
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue