mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Rename tokens to account_creation_token and the related table, tests, controllers, endpoints
Add a new endpoint to allow the creation of an account_creation_token by an admin Split the confirmation_key in two, create a provisioning_token Refactor the documentation Bump the package number
This commit is contained in:
parent
1c32935ad7
commit
3225e11ffc
23 changed files with 563 additions and 372 deletions
|
|
@ -80,7 +80,7 @@ We advise you to copy the `style.css` file and rename it to make your custom CSS
|
|||
|
||||
#### Flexisip Push notifications pusher
|
||||
|
||||
The API endpoint `POST /tokens` uses the `flexisip_pusher` binary delivered by the [Flexisip](https://gitlab.linphone.org/BC/public/flexisip) project (and related package). You must configure the `APP_FLEXISIP_PUSHER_PATH` environement variable to point to the correct binary.
|
||||
The API endpoint `POST /account_creation_tokens/send-by-push` uses the `flexisip_pusher` binary delivered by the [Flexisip](https://gitlab.linphone.org/BC/public/flexisip) project (and related package). You must configure the `APP_FLEXISIP_PUSHER_PATH` environement variable to point to the correct binary.
|
||||
|
||||
APP_FLEXISIP_PUSHER_PATH=/opt/belledonne-communications/bin/flexisip_pusher
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class Account extends Authenticatable
|
|||
use HasFactory;
|
||||
|
||||
protected $with = ['passwords', 'admin', 'emailChanged', 'alias', 'activationExpiration', 'types', 'actions'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'pivot'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'provisioning_token', 'pivot'];
|
||||
protected $dateTimes = ['creation_time'];
|
||||
protected $appends = ['realm', 'phone', 'confirmation_key_expires'];
|
||||
protected $casts = [
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace App;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Token extends Model
|
||||
class AccountCreationToken extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
|
|
@ -31,17 +31,17 @@ use Endroid\QrCode\Writer\PngWriter;
|
|||
|
||||
class ProvisioningController extends Controller
|
||||
{
|
||||
public function qrcode(Request $request, $confirmationKey)
|
||||
public function qrcode(Request $request, $provisioningToken)
|
||||
{
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('confirmation_key', $confirmationKey)
|
||||
->where('provisioning_token', $provisioningToken)
|
||||
->firstOrFail();
|
||||
|
||||
if ($account->activationExpired()) abort(404);
|
||||
|
||||
$result = Builder::create()
|
||||
->writer(new PngWriter())
|
||||
->data(route('provisioning.show', ['confirmation' => $confirmationKey]))
|
||||
->data(route('provisioning.show', ['provisioning_token' => $provisioningToken]))
|
||||
->encoding(new Encoding('UTF-8'))
|
||||
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
|
||||
->size(300)
|
||||
|
|
@ -59,7 +59,7 @@ class ProvisioningController extends Controller
|
|||
return $this->show($request, null, $request->user());
|
||||
}
|
||||
|
||||
public function show(Request $request, $confirmationKey = null, Account $requestAccount = null)
|
||||
public function show(Request $request, $provisioningToken = null, Account $requestAccount = null)
|
||||
{
|
||||
// Load the hooks if they exists
|
||||
$provisioningHooks = config_path('provisioning_hooks.php');
|
||||
|
|
@ -109,9 +109,9 @@ class ProvisioningController extends Controller
|
|||
// Account handling
|
||||
if ($requestAccount) {
|
||||
$account = $requestAccount;
|
||||
} else if ($confirmationKey) {
|
||||
} else if ($provisioningToken) {
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('confirmation_key', $confirmationKey)
|
||||
->where('provisioning_token', $provisioningToken)
|
||||
->first();
|
||||
}
|
||||
|
||||
|
|
@ -184,14 +184,14 @@ class ProvisioningController extends Controller
|
|||
|
||||
}
|
||||
|
||||
if ($confirmationKey) {
|
||||
if ($provisioningToken) {
|
||||
// Activate the account
|
||||
if ($account->activated == false
|
||||
&& $confirmationKey == $account->confirmation_key) {
|
||||
&& $provisioningToken == $account->provisioning_token) {
|
||||
$account->activated = true;
|
||||
}
|
||||
|
||||
$account->confirmation_key = null;
|
||||
$account->provisioning_token = null;
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class AccountController extends Controller
|
|||
public function provision(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->provisioning_token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->save();
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account provisioned', ['id' => $account->identifier]);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use Carbon\Carbon;
|
|||
|
||||
use App\Account;
|
||||
use App\AccountTombstone;
|
||||
use App\Token;
|
||||
use App\AccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use App\Rules\IsNotPhoneNumber;
|
||||
use App\Rules\NoUppercase;
|
||||
|
|
@ -72,16 +72,16 @@ class AccountController extends Controller
|
|||
'password' => 'required|filled',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'domain' => 'min:3',
|
||||
'token' => [
|
||||
'account_creation_token' => [
|
||||
'required',
|
||||
Rule::exists('tokens', 'token')->where(function ($query) {
|
||||
Rule::exists('account_creation_tokens', 'token')->where(function ($query) {
|
||||
$query->where('used', false);
|
||||
}),
|
||||
'size:'.WebAuthenticateController::$emailCodeSize
|
||||
]
|
||||
]);
|
||||
|
||||
$token = Token::where('token', $request->get('token'))->first();
|
||||
$token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first();
|
||||
$token->used = true;
|
||||
$token->save();
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ class AccountController extends Controller
|
|||
$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->provisioning_token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->save();
|
||||
|
||||
$account->updatePassword($request->get('password'), $request->get('algorithm'));
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ use Illuminate\Http\Request;
|
|||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Token;
|
||||
use App\AccountCreationToken;
|
||||
use App\Libraries\FlexisipPusherConnector;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class TokenController extends Controller
|
||||
class AccountCreationTokenController extends Controller
|
||||
{
|
||||
public function create(Request $request)
|
||||
public function sendByPush(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'pn_provider' => 'required',
|
||||
|
|
@ -38,7 +38,7 @@ class TokenController extends Controller
|
|||
'pn_prid' => 'required',
|
||||
]);
|
||||
|
||||
if (Token::where('pn_provider', $request->get('pn_provider'))
|
||||
if (AccountCreationToken::where('pn_provider', $request->get('pn_provider'))
|
||||
->where('pn_param', $request->get('pn_param'))
|
||||
->where('pn_prid', $request->get('pn_prid'))
|
||||
->where('used', false)
|
||||
|
|
@ -46,14 +46,14 @@ class TokenController extends Controller
|
|||
abort(403, 'A similar token was already used');
|
||||
}
|
||||
|
||||
if (Token::where('pn_provider', $request->get('pn_provider'))
|
||||
if (AccountCreationToken::where('pn_provider', $request->get('pn_provider'))
|
||||
->where('pn_param', $request->get('pn_param'))
|
||||
->where('pn_prid', $request->get('pn_prid'))
|
||||
->count() > 3) {
|
||||
abort(403, 'The limit of tokens generated for this device has been reached');
|
||||
}
|
||||
|
||||
$token = new Token;
|
||||
$token = new AccountCreationToken;
|
||||
$token->token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$token->pn_provider = $request->get('pn_provider');
|
||||
$token->pn_param = $request->get('pn_param');
|
||||
|
|
@ -46,7 +46,7 @@ class AccountController extends Controller
|
|||
|
||||
public function show($id)
|
||||
{
|
||||
return Account::without(['passwords', 'admin'])->findOrFail($id)->makeVisible(['confirmation_key']);
|
||||
return Account::without(['passwords', 'admin'])->findOrFail($id)->makeVisible(['confirmation_key', 'provisioning_token']);
|
||||
}
|
||||
|
||||
public function search(string $sip)
|
||||
|
|
@ -95,12 +95,12 @@ class AccountController extends Controller
|
|||
public function provision(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->provisioning_token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->save();
|
||||
|
||||
Log::channel('events')->info('API Admin: Account provisioned', ['id' => $account->identifier]);
|
||||
|
||||
return $account->makeVisible(['confirmation_key']);
|
||||
return $account->makeVisible(['provisioning_token']);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
|
|
@ -152,6 +152,7 @@ class AccountController extends Controller
|
|||
|
||||
if (!$request->has('activated') || !(bool)$request->get('activated')) {
|
||||
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->provisioning_token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
}
|
||||
|
||||
$account->save();
|
||||
|
|
@ -185,7 +186,7 @@ class AccountController extends Controller
|
|||
|
||||
Log::channel('events')->info('API: Admin: Account created', ['id' => $account->identifier]);
|
||||
|
||||
return response()->json($account->makeVisible(['confirmation_key']));
|
||||
return response()->json($account->makeVisible(['confirmation_key', 'provisioning_token']));
|
||||
}
|
||||
|
||||
public function typeAdd(int $id, int $typeId)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 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\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use App\AccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class AccountCreationTokenController extends Controller
|
||||
{
|
||||
public function create(Request $request)
|
||||
{
|
||||
$token = new AccountCreationToken;
|
||||
$token->token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$token->save();
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
460
flexiapi/composer.lock
generated
460
flexiapi/composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -22,12 +22,12 @@ namespace Database\Factories;
|
|||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use App\Token;
|
||||
use App\AccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class TokenFactory extends Factory
|
||||
class AccountCreationTokenFactory extends Factory
|
||||
{
|
||||
protected $model = Token::class;
|
||||
protected $model = AccountCreationToken::class;
|
||||
|
||||
public function definition()
|
||||
{
|
||||
|
|
@ -36,6 +36,7 @@ class AccountFactory extends Factory
|
|||
'email' => $this->faker->email,
|
||||
'user_agent' => $this->faker->userAgent,
|
||||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'provisioning_token' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
'creation_time' => $this->faker->dateTime,
|
||||
'dtmf_protocol' => array_rand(Account::$dtmfProtocols),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class RenameTokensToAccountCreationTokens extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::rename('tokens', 'account_creation_tokens');
|
||||
|
||||
Schema::table('account_creation_tokens', function (Blueprint $table) {
|
||||
$table->integer('account_id')->unsigned()->nullable();
|
||||
$table->foreign('account_id')->references('id')
|
||||
->on('accounts')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::disableForeignKeyConstraints();
|
||||
|
||||
Schema::table('account_creation_tokens', function (Blueprint $table) {
|
||||
$table->dropForeign(['account_id']);
|
||||
$table->dropColumn('account_id');
|
||||
});
|
||||
|
||||
Schema::rename('account_creation_tokens', 'tokens');
|
||||
|
||||
Schema::enableForeignKeyConstraints();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddProvisioningTokenToAccountsTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->string('provisioning_token')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropColumn('provisioning_token');
|
||||
});
|
||||
}
|
||||
}
|
||||
2
flexiapi/public/css/style.css
vendored
2
flexiapi/public/css/style.css
vendored
|
|
@ -76,7 +76,7 @@ input.form-control {
|
|||
|
||||
@media screen and (min-width: 1025px) {
|
||||
.table-of-contents {
|
||||
width: 50%;
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,14 +108,14 @@
|
|||
|
||||
<h3 class="mt-3">Provisioning</h3>
|
||||
|
||||
@if ($account->confirmation_key)
|
||||
@if ($account->provisioning_token)
|
||||
<p>Share the following picture with the user or the one-time-use link bellow.</p>
|
||||
|
||||
<img src="{{ route('provisioning.qrcode', $account->confirmation_key) }}"><br />
|
||||
<img src="{{ route('provisioning.qrcode', $account->provisioning_token) }}"><br />
|
||||
|
||||
<br />
|
||||
<p>The following link can only be visited once</p>
|
||||
<input class="form-control" type="text" readonly value="{{ route('provisioning.show', $account->confirmation_key) }}">
|
||||
<input class="form-control" type="text" readonly value="{{ route('provisioning.show', $account->provisioning_token) }}">
|
||||
<p class="mt-3">
|
||||
<a class="btn btn-light mr-2" href="{{ route('admin.account.provision', $account->id) }}">Renew the provision link</a>
|
||||
The current one will be unavailable
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@ A `from` (consisting of the user SIP address, prefixed with `sip:`), `content-ty
|
|||
|
||||
Restricted endpoints are protected using a DIGEST authentication or an API Key mechanisms.
|
||||
|
||||
## Access model
|
||||
|
||||
The endpoints are accessible using three different models:
|
||||
|
||||
- <span class="badge badge-success">Public</span> publicly accessible
|
||||
- <span class="badge badge-info">User</span> the endpoint can only be accessed by an authenticated user
|
||||
- <span class="badge badge-warning">Admin</span> the endpoint can be only be accessed by an authenticated admin user
|
||||
|
||||
## Using the API Key
|
||||
|
||||
You can retrieve an API Key from @if (config('app.web_panel')) [your account panel]({{ route('account.login') }}) @else your account panel @endif or using <a href="#get-accountsmeapikey">the dedicated API endpoint</a>.
|
||||
|
|
@ -59,17 +67,19 @@ You can find more documentation on the related [IETF RFC-7616](https://tools.iet
|
|||
|
||||
# Endpoints
|
||||
|
||||
## Public endpoints
|
||||
## Ping
|
||||
|
||||
### General
|
||||
|
||||
#### `GET /ping`
|
||||
### `GET /ping`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Returns `pong`
|
||||
|
||||
### Accounts
|
||||
## Account Creation Tokens
|
||||
|
||||
#### `POST /tokens`
|
||||
Send a token using a push notification to the device.
|
||||
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>
|
||||
Create and send an `account_creation_token` using a push notification to the device.
|
||||
Return `403` if a token was already sent, or if the tokens limit is reached for this device.
|
||||
Return `503` if the token was not successfully sent.
|
||||
|
||||
|
|
@ -79,8 +89,16 @@ JSON parameters:
|
|||
* `pn_param` the push notification parameter
|
||||
* `pn_prid` the push notification unique id
|
||||
|
||||
#### `POST /accounts/with-token`
|
||||
Create an account using a token.
|
||||
### `POST /account_creation_tokens`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
|
||||
Create and return an `account_creation_token`.
|
||||
|
||||
## Accounts
|
||||
|
||||
### `POST /accounts/with-account-creation-token`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Create an account using an `account_creation_token`.
|
||||
Return `422` if the parameters are invalid or if the token is expired.
|
||||
|
||||
JSON parameters:
|
||||
|
|
@ -89,49 +107,52 @@ JSON parameters:
|
|||
* `password` required minimum 6 characters
|
||||
* `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
|
||||
* `account_creation_token` the unique `account_creation_token`
|
||||
* `dtmf_protocol` optional, values must be `sipinfo` or `rfc2833`
|
||||
|
||||
#### `GET /accounts/{sip}/info`
|
||||
### `GET /accounts/{sip}/info`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Retrieve public information about the account.
|
||||
Return `404` if the account doesn't exists.
|
||||
|
||||
#### `POST /accounts/{sip}/activate/email`
|
||||
### `POST /accounts/{sip}/activate/email`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Activate an account using a secret code received by email.
|
||||
Return `404` if the account doesn't exists or if the code is incorrect, the validated account otherwise.
|
||||
JSON parameters:
|
||||
|
||||
* `code` the code
|
||||
|
||||
#### `POST /accounts/{sip}/activate/phone`
|
||||
### `POST /accounts/{sip}/activate/phone`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Activate an account using a pin code received by phone.
|
||||
Return `404` if the account doesn't exists or if the code is incorrect, the validated account otherwise.
|
||||
JSON parameters:
|
||||
|
||||
* `code` the PIN code
|
||||
|
||||
## User authenticated endpoints
|
||||
Those endpoints are authenticated and requires an activated account.
|
||||
|
||||
### Accounts
|
||||
|
||||
#### `GET /accounts/me/api_key`
|
||||
### `GET /accounts/me/api_key`
|
||||
<span class="badge badge-info">User</span>
|
||||
Generate and retrieve a fresh API Key.
|
||||
This endpoint is also setting the API Key as a Cookie.
|
||||
|
||||
#### `GET /accounts/me`
|
||||
### `GET /accounts/me`
|
||||
<span class="badge badge-info">User</span>
|
||||
Retrieve the account information.
|
||||
|
||||
#### `DELETE /accounts/me`
|
||||
### `DELETE /accounts/me`
|
||||
<span class="badge badge-info">User</span>
|
||||
Delete the account.
|
||||
|
||||
#### `POST /accounts/me/email/request`
|
||||
### `POST /accounts/me/email/request`
|
||||
<span class="badge badge-info">User</span>
|
||||
Change the account email. An email will be sent to the new email address to confirm the operation.
|
||||
JSON parameters:
|
||||
|
||||
* `email` the new email address
|
||||
|
||||
#### `POST /accounts/me/password`
|
||||
### `POST /accounts/me/password`
|
||||
<span class="badge badge-info">User</span>
|
||||
Change the account password.
|
||||
JSON parameters:
|
||||
|
||||
|
|
@ -139,47 +160,10 @@ JSON parameters:
|
|||
* `old_password` required if the password is already set, the old password
|
||||
* `password` required, the new password
|
||||
|
||||
### Accounts phone number
|
||||
|
||||
#### `POST /accounts/me/phone/request`
|
||||
Request a specific code by SMS
|
||||
JSON parameters:
|
||||
|
||||
* `phone` the phone number to send the SMS
|
||||
|
||||
#### `POST /accounts/me/phone`
|
||||
Confirm the code received and change the phone number
|
||||
JSON parameters:
|
||||
|
||||
* `code` the received SMS code
|
||||
|
||||
Return the updated account
|
||||
|
||||
### Accounts devices
|
||||
|
||||
#### `GET /accounts/me/devices`
|
||||
Return the user registered devices.
|
||||
|
||||
#### `DELETE /accounts/me/devices/{uuid}`
|
||||
Remove one of the user registered devices.
|
||||
|
||||
### Accounts contacts
|
||||
|
||||
#### `GET /accounts/me/contacts`
|
||||
Return the user contacts.
|
||||
|
||||
#### `GET /accounts/me/contacts/{sip}`
|
||||
Return a user contact.
|
||||
|
||||
## Admin endpoints
|
||||
|
||||
Those endpoints are authenticated and requires an admin account.
|
||||
|
||||
### Accounts
|
||||
|
||||
#### `POST /accounts`
|
||||
### `POST /accounts`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
To create an account directly from the API.
|
||||
If `activated` is set to `false` a random generated `confirmation_key` will be returned to allow further activation using the public endpoints. Check `confirmation_key_expires` to also set an expiration date on that `confirmation_key`.
|
||||
If `activated` is set to `false` a random generated `confirmation_key` and `provisioning_token` will be returned to allow further activation using the public endpoints and provision the account. Check `confirmation_key_expires` to also set an expiration date on that `confirmation_key`.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
|
|
@ -195,49 +179,100 @@ The `domain` field is taken into account ONLY when `app.admins_manage_multi_doma
|
|||
* `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`
|
||||
### `GET /accounts`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Retrieve all the accounts, paginated.
|
||||
|
||||
#### `GET /accounts/{id}`
|
||||
### `GET /accounts/{id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Retrieve a specific account.
|
||||
|
||||
#### `GET /accounts/{sip}/search`
|
||||
### `GET /accounts/{sip}/search`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Search for a specific account by sip address.
|
||||
|
||||
#### `DELETE /accounts/{id}`
|
||||
### `DELETE /accounts/{id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Delete a specific account and its related information.
|
||||
|
||||
#### `GET /accounts/{id}/activate`
|
||||
### `GET /accounts/{id}/activate`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Activate an account.
|
||||
|
||||
#### `GET /accounts/{id}/deactivate`
|
||||
### `GET /accounts/{id}/deactivate`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Deactivate an account.
|
||||
|
||||
#### `GET /accounts/{id}/provision`
|
||||
Re-provision an account by generating a fresh `confirmation_key`.
|
||||
### `GET /accounts/{id}/provision`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Re-provision an account by generating a fresh `provisioning_token`.
|
||||
|
||||
### Contacts
|
||||
## Accounts phone number
|
||||
|
||||
#### `GET /accounts/{id}/contacts/`
|
||||
### `POST /accounts/me/phone/request`
|
||||
<span class="badge badge-info">User</span>
|
||||
Request a specific code by SMS
|
||||
JSON parameters:
|
||||
|
||||
* `phone` the phone number to send the SMS
|
||||
|
||||
### `POST /accounts/me/phone`
|
||||
<span class="badge badge-info">User</span>
|
||||
Confirm the code received and change the phone number
|
||||
JSON parameters:
|
||||
|
||||
* `code` the received SMS code
|
||||
|
||||
Return the updated account
|
||||
|
||||
## Accounts devices
|
||||
|
||||
### `GET /accounts/me/devices`
|
||||
<span class="badge badge-info">User</span>
|
||||
Return the user registered devices.
|
||||
|
||||
### `DELETE /accounts/me/devices/{uuid}`
|
||||
<span class="badge badge-info">User</span>
|
||||
Remove one of the user registered devices.
|
||||
|
||||
## Accounts contacts
|
||||
|
||||
### `GET /accounts/me/contacts`
|
||||
<span class="badge badge-info">User</span>
|
||||
Return the user contacts.
|
||||
|
||||
### `GET /accounts/me/contacts/{sip}`
|
||||
<span class="badge badge-info">User</span>
|
||||
Return a user contact.
|
||||
|
||||
## Contacts
|
||||
|
||||
### `GET /accounts/{id}/contacts/`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Get all the account contacts.
|
||||
|
||||
#### `POST /accounts/{id}/contacts/{contact_id}`
|
||||
### `POST /accounts/{id}/contacts/{contact_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Add a contact to the list.
|
||||
|
||||
#### `DELETE /accounts/{id}/contacts/{contact_id}`
|
||||
### `DELETE /accounts/{id}/contacts/{contact_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Remove a contact from the list.
|
||||
|
||||
### Account Actions
|
||||
## Account Actions
|
||||
|
||||
The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured.
|
||||
|
||||
#### `GET /accounts/{id}/actions/`
|
||||
### `GET /accounts/{id}/actions/`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Show an account related actions.
|
||||
|
||||
#### `GET /accounts/{id}/actions/{action_id}`
|
||||
### `GET /accounts/{id}/actions/{action_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Show an account related action.
|
||||
|
||||
#### `POST /accounts/{id}/actions/`
|
||||
### `POST /accounts/{id}/actions/`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Create an account action.
|
||||
|
||||
JSON parameters:
|
||||
|
|
@ -245,7 +280,8 @@ JSON parameters:
|
|||
* `key` required, alpha numeric with dashes, lowercase
|
||||
* `code` required, alpha numeric, lowercase
|
||||
|
||||
#### `PUT /accounts/{id}/actions/{action_id}`
|
||||
### `PUT /accounts/{id}/actions/{action_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Create an account action.
|
||||
|
||||
JSON parameters:
|
||||
|
|
@ -253,43 +289,52 @@ JSON parameters:
|
|||
* `key` required, alpha numeric with dashes, lowercase
|
||||
* `code` required, alpha numeric, lowercase
|
||||
|
||||
#### `DELETE /accounts/{id}/actions/{action_id}`
|
||||
### `DELETE /accounts/{id}/actions/{action_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Delete an account related action.
|
||||
|
||||
### Account Types
|
||||
## Account Types
|
||||
|
||||
#### `GET /account_types/`
|
||||
### `GET /account_types/`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Show all the account types.
|
||||
|
||||
#### `GET /account_types/{id}`
|
||||
### `GET /account_types/{id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Show an account type.
|
||||
|
||||
#### `POST /account_types/`
|
||||
### `POST /account_types/`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Create an account type.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `key` required, alpha numeric with dashes, lowercase
|
||||
|
||||
#### `PUT /account_types/{id}`
|
||||
### `PUT /account_types/{id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Update an account type.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `key` required, alpha numeric with dashes, lowercase
|
||||
|
||||
#### `DELETE /account_types/{id}`
|
||||
### `DELETE /account_types/{id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Delete an account type.
|
||||
|
||||
#### `POST /accounts/{id}/types/{type_id}`
|
||||
### `POST /accounts/{id}/types/{type_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Add a type to the account.
|
||||
|
||||
#### `DELETE /accounts/{id}/contacts/{type_id}`
|
||||
### `DELETE /accounts/{id}/contacts/{type_id}`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Remove a a type from the account.
|
||||
|
||||
### Messages
|
||||
## Messages
|
||||
|
||||
#### `POST /messages`
|
||||
### `POST /messages`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Send a message over SIP.
|
||||
|
||||
JSON parameters:
|
||||
|
|
@ -297,15 +342,18 @@ JSON parameters:
|
|||
* `to` required, SIP address of the receiver
|
||||
* `body` required, content of the message
|
||||
|
||||
### Statistics
|
||||
## Statistics
|
||||
|
||||
#### `GET /statistics/day`
|
||||
### `GET /statistics/day`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Retrieve registrations statistics for 24 hours.
|
||||
|
||||
#### `GET /statistics/week`
|
||||
### `GET /statistics/week`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Retrieve registrations statistics for a week.
|
||||
|
||||
#### `GET /statistics/month`
|
||||
### `GET /statistics/month`
|
||||
<span class="badge badge-warning">Admin</span>
|
||||
Retrieve registrations statistics for a month.
|
||||
|
||||
# Non-API Endpoints
|
||||
|
|
@ -314,28 +362,31 @@ The following URLs are **not API endpoints** they are not returning `JSON` conte
|
|||
|
||||
## Provisioning
|
||||
|
||||
When an account is having an available `confirmation_key` it can be provisioned using the two following URL.
|
||||
When an account is having an available `provisioning_token` it can be provisioned using the two following URL.
|
||||
|
||||
### `GET /provisioning/`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Return the provisioning information available in the liblinphone configuration file (if correctly configured).
|
||||
|
||||
### `GET /provisioning/{confirmation_key}`
|
||||
### `GET /provisioning/{provisioning_token}`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Return the provisioning information available in the liblinphone configuration file.
|
||||
If the `confirmation_key` is valid the related account information are added to the returned XML. The account is then considered as "provisioned" and those account related information will be removed in the upcoming requests (the content will be the same as the previous url).
|
||||
If the `provisioning_token` is valid the related account information are added to the returned XML. The account is then considered as "provisioned" and those account related information will be removed in the upcoming requests (the content will be the same as the previous url).
|
||||
|
||||
If the account is not activated and the `confirmation_key` is valid. The account will be activated.
|
||||
If the account is not activated and the `provisioning_token` is valid. The account will be activated.
|
||||
|
||||
### `GET /provisioning/qrcode/{confirmation_key}`
|
||||
### `GET /provisioning/qrcode/{provisioning_token}`
|
||||
<span class="badge badge-success">Public</span>
|
||||
Return a QRCode that points to the provisioning URL.
|
||||
|
||||
## Authenticated provisioning
|
||||
|
||||
### `GET /provisioning/me`
|
||||
Return the same base content as the previous URL and the account related information, similar to the `confirmation_key` endpoint. However this endpoint will always return those information.
|
||||
<span class="badge badge-info">User</span>
|
||||
Return the same base content as the previous URL and the account related information, similar to the `provisioning_token` endpoint. However this endpoint will always return those information.
|
||||
|
||||
## Authenticated contact list
|
||||
## Contacts list
|
||||
|
||||
### `GET /contacts/vcard`
|
||||
<span class="badge badge-info">User</span>
|
||||
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:
|
||||
|
|
@ -360,4 +411,5 @@ Here is the format of the vCard list returned by the endpoint:
|
|||
```
|
||||
|
||||
### `GET /contacts/vcard/{sip}`
|
||||
<span class="badge badge-info">User</span>
|
||||
Return a specific user authenticated contact, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350).
|
||||
|
|
@ -26,9 +26,9 @@ Route::middleware('auth:api')->get('/user', function (Request $request) {
|
|||
});
|
||||
|
||||
Route::get('ping', 'Api\PingController@ping');
|
||||
Route::post('tokens', 'Api\TokenController@create');
|
||||
Route::post('account_creation_tokens/send-by-push', 'Api\AccountCreationTokenController@sendByPush');
|
||||
Route::get('accounts/{sip}/info', 'Api\AccountController@info');
|
||||
Route::post('accounts/with-token', 'Api\AccountController@store');
|
||||
Route::post('accounts/with-account-creation-token', 'Api\AccountController@store');
|
||||
Route::post('accounts/{sip}/activate/email', 'Api\AccountController@activateEmail');
|
||||
Route::post('accounts/{sip}/activate/phone', 'Api\AccountController@activatePhone');
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ Route::group(['middleware' => 'auth.digest_or_key'], function () {
|
|||
Route::get('contacts/vcard', 'Account\ContactVcardController@index')->name('account.contacts.vcard.index');
|
||||
});
|
||||
|
||||
Route::get('provisioning/qrcode/{confirmation}', 'Account\ProvisioningController@qrcode')->name('provisioning.qrcode');
|
||||
Route::get('provisioning/{confirmation?}', 'Account\ProvisioningController@show')->name('provisioning.show');
|
||||
Route::get('provisioning/qrcode/{provisioning_token}', 'Account\ProvisioningController@qrcode')->name('provisioning.qrcode');
|
||||
Route::get('provisioning/{provisioning_token?}', 'Account\ProvisioningController@show')->name('provisioning.show');
|
||||
|
||||
if (config('app.public_registration')) {
|
||||
if (config('app.phone_authentication')) {
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertFalse(empty($response1['confirmation_key']));
|
||||
$this->assertFalse(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testAdminMultiDomains()
|
||||
|
|
@ -235,6 +236,7 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertFalse(empty($response1['confirmation_key']));
|
||||
$this->assertFalse(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testUsernameNoDomain()
|
||||
|
|
@ -305,6 +307,7 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertTrue(!empty($response1['confirmation_key']));
|
||||
$this->assertFalse(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testActivated()
|
||||
|
|
@ -334,6 +337,7 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertTrue(empty($response1['confirmation_key']));
|
||||
$this->assertTrue(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testNotActivated()
|
||||
|
|
@ -362,6 +366,7 @@ class AccountApiTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertFalse(empty($response1['confirmation_key']));
|
||||
$this->assertFalse(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testSimpleAccount()
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ namespace Tests\Feature;
|
|||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
use App\Token;
|
||||
use App\AccountCreationToken;
|
||||
|
||||
class AccountTokenTest extends TestCase
|
||||
class AccountCreationTokenTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $tokenRoute = '/api/tokens';
|
||||
protected $accountRoute = '/api/accounts/with-token';
|
||||
protected $tokenRoute = '/api/account_creation_tokens/send-by-push';
|
||||
protected $accountRoute = '/api/accounts/with-account-creation-token';
|
||||
protected $method = 'POST';
|
||||
|
||||
protected $pnProvider = 'provider';
|
||||
|
|
@ -54,7 +54,7 @@ class AccountTokenTest extends TestCase
|
|||
|
||||
public function testLimit()
|
||||
{
|
||||
$token = Token::factory()->create();
|
||||
$token = AccountCreationToken::factory()->create();
|
||||
|
||||
$response = $this->json($this->method, $this->tokenRoute, [
|
||||
'pn_provider' => $token->pn_provider,
|
||||
|
|
@ -66,14 +66,14 @@ class AccountTokenTest extends TestCase
|
|||
|
||||
public function testInvalidToken()
|
||||
{
|
||||
$token = Token::factory()->create();
|
||||
$token = AccountCreationToken::factory()->create();
|
||||
|
||||
// Invalid token
|
||||
$response = $this->json($this->method, $this->accountRoute, [
|
||||
'username' => 'username',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'token' => '0123456789abc'
|
||||
'account_creation_token' => '0123456789abc'
|
||||
]);
|
||||
$response->assertStatus(422);
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ class AccountTokenTest extends TestCase
|
|||
'username' => 'username',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'token' => $token->token
|
||||
'account_creation_token' => $token->token
|
||||
]);
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ class AccountTokenTest extends TestCase
|
|||
'username' => 'username2',
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '2',
|
||||
'token' => $token->token
|
||||
'account_creation_token' => $token->token
|
||||
]);
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
|
@ -83,7 +83,7 @@ class AccountProvisioningTest extends TestCase
|
|||
$password->account->save();
|
||||
|
||||
// Ensure that we get the authentication password once
|
||||
$response = $this->get($this->route.'/'.$password->account->confirmation_key)
|
||||
$response = $this->get($this->route.'/'.$password->account->provisioning_token)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertSee('ha1');
|
||||
|
|
@ -92,31 +92,31 @@ class AccountProvisioningTest extends TestCase
|
|||
$this->assertEquals(true, DBAccount::where('id', $password->account->id)->first()->activated);
|
||||
|
||||
// And then twice
|
||||
$response = $this->get($this->route.'/'.$password->account->confirmation_key)
|
||||
$response = $this->get($this->route.'/'.$password->account->provisioning_token)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertDontSee('ha1');
|
||||
|
||||
$password->account->refresh();
|
||||
|
||||
$confirmationKey = $password->account->confirmation_key;
|
||||
$provisioningToken = $password->account->provisioning_token;
|
||||
|
||||
// Refresh the confirmation_key
|
||||
// Refresh the provisioning_token
|
||||
$admin = Admin::factory()->create();
|
||||
$admin->account->generateApiKey();
|
||||
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, '/api/accounts/'.$password->account->id.'/provision')
|
||||
->assertStatus(200)
|
||||
->assertSee('confirmation_key')
|
||||
->assertDontSee($confirmationKey);
|
||||
->assertSee('provisioning_token')
|
||||
->assertDontSee($provisioningToken);
|
||||
|
||||
$password->account->refresh();
|
||||
|
||||
$this->assertNotEquals($confirmationKey, $password->account->confirmation_key);
|
||||
$this->assertNotEquals($provisioningToken, $password->account->provisioning_token);
|
||||
|
||||
// And then provision one last time
|
||||
$this->get($this->route.'/'.$password->account->confirmation_key)
|
||||
$this->get($this->route.'/'.$password->account->provisioning_token)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertSee('ha1');
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#%define _datadir %{_datarootdir}
|
||||
#%define _docdir %{_datadir}/doc
|
||||
|
||||
%define build_number 137
|
||||
%define build_number 138
|
||||
%define var_dir /var/opt/belledonne-communications
|
||||
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue