diff --git a/CHANGELOG.md b/CHANGELOG.md
index 083683b..c589e68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Flexisip Account Manager Changelog
+v1.6
+----
+- Fix FLEXIAPI-192 Add DotEnv configuration to allow the expiration of tokens and codes in the app
+
v1.5
---
- Fix FLEXIAPI-195 Fix LiblinphoneTesterAccoutSeeder to fit with the latest Account related changes
diff --git a/flexiapi/.env.example b/flexiapi/.env.example
index 379d983..4d7ab4d 100644
--- a/flexiapi/.env.example
+++ b/flexiapi/.env.example
@@ -9,7 +9,6 @@ APP_LINPHONE_DAEMON_UNIX_PATH=
APP_FLEXISIP_PUSHER_PATH=
APP_FLEXISIP_PUSHER_FIREBASE_KEYSMAP= # Each pair is separated using a space and defined as a key:value
-APP_API_KEY_EXPIRATION_MINUTES=60 # Number of minutes the generated API Keys are valid
APP_API_ACCOUNT_CREATION_TOKEN_RETRY_MINUTES=60 # Number of minutes between two consecutive account_creation_token creation
APP_ALLOW_PHONE_NUMBER_USERNAME_ADMIN_API=false # Allow phone numbers to be set as username in admin account creation endpoints
@@ -22,9 +21,16 @@ ACCOUNT_PROXY_REGISTRAR_ADDRESS=sip.example.com # Proxy registrar address, can b
ACCOUNT_TRANSPORT_PROTOCOL_TEXT="TLS (recommended), TCP or UDP" # Simple text, to explain how the SIP server can be reached
ACCOUNT_REALM=null # Default realm for the accounts, fallback to the domain if not set, enforce null by default
+# Expiration time for tokens and code, in minutes, 0 means no expiration
+APP_ACCOUNT_CREATION_TOKEN_EXPIRATION_MINUTES=0
+APP_EMAIL_CHANGE_CODE_EXPIRATION_MINUTES=10
+APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES=10
+APP_RECOVERY_CODE_EXPIRATION_MINUTES=10
+APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES=0
+APP_API_KEY_EXPIRATION_MINUTES=60 # Number of minutes the unused API Keys are valid
+
# Account creation
ACCOUNT_EMAIL_UNIQUE=false # Emails are unique between all the accounts
-ACCOUNT_CONSUME_EXTERNAL_ACCOUNT_ON_CREATE=false
ACCOUNT_BLACKLISTED_USERNAMES=
ACCOUNT_USERNAME_REGEX="^[a-z0-9+_.-]*$"
ACCOUNT_DEFAULT_PASSWORD_ALGORITHM=SHA-256 # Can ONLY be MD5 or SHA-256 in capital, default to SHA-256
@@ -45,12 +51,12 @@ INSTANCE_CUSTOM_THEME=false
INSTANCE_CONFIRMED_REGISTRATION_TEXT= # Markdown text displayed when an account is confirmed
WEB_PANEL=true # Fully enable/disable the web panels
-NEWSLETTER_REGISTRATION_ADDRESS= # Address to contact when a user wants to register to the newsletter
PUBLIC_REGISTRATION=true # Toggle to enable/disable the public registration forms
PHONE_AUTHENTICATION=true # Toggle to enable/disable the SMS support, requires public registration
DEVICES_MANAGEMENT=false # Toggle to enable/disable the devices management supporttrue
INTERCOM_FEATURES=false # Toggle to enable/disable the intercom related features
+NEWSLETTER_REGISTRATION_ADDRESS= # Address to contact when a user wants to register to the newsletter
TERMS_OF_USE_URL= # A URL pointing to the Terms of Use
PRIVACY_POLICY_URL= # A URL pointing to the Privacy Policy
APP_PROJECT_URL= # A URL pointing to the project information page
diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php
index 9832b04..d3bfcbd 100644
--- a/flexiapi/app/Account.php
+++ b/flexiapi/app/Account.php
@@ -38,7 +38,7 @@ class Account extends Authenticatable
protected $with = ['passwords', 'activationExpiration', 'emailChangeCode', 'types', 'actions', 'dictionaryEntries'];
protected $hidden = ['expire_time', 'confirmation_key', 'pivot', 'currentProvisioningToken', 'currentRecoveryCode', 'dictionaryEntries'];
- protected $appends = ['realm', 'confirmation_key_expires', 'provisioning_token', 'dictionary'];
+ protected $appends = ['realm', 'confirmation_key_expires', 'provisioning_token', 'provisioning_token_expire_at', 'dictionary'];
protected $casts = [
'activated' => 'boolean',
];
@@ -272,6 +272,15 @@ class Account extends Authenticatable
return null;
}
+ public function getProvisioningTokenExpireAtAttribute(): ?string
+ {
+ if ($this->currentProvisioningToken) {
+ return $this->currentProvisioningToken->expire_at;
+ }
+
+ return null;
+ }
+
public function getIdentifierAttribute(): string
{
return $this->attributes['username'] . '@' . $this->attributes['domain'];
diff --git a/flexiapi/app/AccountCreationToken.php b/flexiapi/app/AccountCreationToken.php
index 1105830..cafaa94 100644
--- a/flexiapi/app/AccountCreationToken.php
+++ b/flexiapi/app/AccountCreationToken.php
@@ -26,6 +26,8 @@ class AccountCreationToken extends Consommable
use HasFactory;
protected $hidden = ['id', 'updated_at', 'created_at'];
+ protected $appends = ['expire_at'];
+ protected ?string $configExpirationMinutesKey = 'account_creation_token_expiration_minutes';
public function accountCreationRequestToken()
{
diff --git a/flexiapi/app/Console/Commands/ClearOldAccountsTombstones.php b/flexiapi/app/Console/Commands/Accounts/ClearAccountsTombstones.php
similarity index 94%
rename from flexiapi/app/Console/Commands/ClearOldAccountsTombstones.php
rename to flexiapi/app/Console/Commands/Accounts/ClearAccountsTombstones.php
index 83e2e95..9deac53 100644
--- a/flexiapi/app/Console/Commands/ClearOldAccountsTombstones.php
+++ b/flexiapi/app/Console/Commands/Accounts/ClearAccountsTombstones.php
@@ -17,14 +17,14 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\AccountTombstone;
-class ClearOldAccountsTombstones extends Command
+class ClearAccountsTombstones extends Command
{
protected $signature = 'accounts:clear-accounts-tombstones {days} {--apply}';
protected $description = 'Clear deleted accounts tombstones after n days';
diff --git a/flexiapi/app/Console/Commands/ClearApiKeys.php b/flexiapi/app/Console/Commands/Accounts/ClearApiKeys.php
similarity index 90%
rename from flexiapi/app/Console/Commands/ClearApiKeys.php
rename to flexiapi/app/Console/Commands/Accounts/ClearApiKeys.php
index cb83dfd..e7ef164 100644
--- a/flexiapi/app/Console/Commands/ClearApiKeys.php
+++ b/flexiapi/app/Console/Commands/Accounts/ClearApiKeys.php
@@ -17,7 +17,7 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use Carbon\Carbon;
@@ -38,6 +38,11 @@ class ClearApiKeys extends Command
{
$minutes = $this->argument('minutes') ?? config('app.api_key_expiration_minutes');
+ if ($minutes == 0) {
+ $this->info('Expiration time is set to 0, nothing to clear');
+ return 0;
+ }
+
$this->info('Deleting api keys unused after ' . $minutes . ' minutes');
$count = ApiKey::where(
diff --git a/flexiapi/app/Console/Commands/RemoveUnconfirmedAccounts.php b/flexiapi/app/Console/Commands/Accounts/ClearUnconfirmed.php
similarity index 95%
rename from flexiapi/app/Console/Commands/RemoveUnconfirmedAccounts.php
rename to flexiapi/app/Console/Commands/Accounts/ClearUnconfirmed.php
index a6c7f15..a362934 100644
--- a/flexiapi/app/Console/Commands/RemoveUnconfirmedAccounts.php
+++ b/flexiapi/app/Console/Commands/Accounts/ClearUnconfirmed.php
@@ -17,14 +17,14 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Account;
-class RemoveUnconfirmedAccounts extends Command
+class ClearUnconfirmed extends Command
{
protected $signature = 'accounts:clear-unconfirmed {days} {--apply} {--and-confirmed}';
protected $description = 'Clear unconfirmed accounts after n days';
diff --git a/flexiapi/app/Console/Commands/CreateAdminAccount.php b/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php
similarity index 98%
rename from flexiapi/app/Console/Commands/CreateAdminAccount.php
rename to flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php
index edb88ee..98335f2 100644
--- a/flexiapi/app/Console/Commands/CreateAdminAccount.php
+++ b/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php
@@ -17,7 +17,7 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use Carbon\Carbon;
diff --git a/flexiapi/app/Console/Commands/CreateAdminAccountTest.php b/flexiapi/app/Console/Commands/Accounts/CreateAdminTest.php
similarity index 95%
rename from flexiapi/app/Console/Commands/CreateAdminAccountTest.php
rename to flexiapi/app/Console/Commands/Accounts/CreateAdminTest.php
index dc02764..cfd4921 100644
--- a/flexiapi/app/Console/Commands/CreateAdminAccountTest.php
+++ b/flexiapi/app/Console/Commands/Accounts/CreateAdminTest.php
@@ -17,16 +17,15 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Account;
use App\ApiKey;
-use App\SipDomain;
-class CreateAdminAccountTest extends Command
+class CreateAdminTest extends Command
{
protected $signature = 'accounts:create-admin-test';
protected $description = 'Create a test admin account, only for tests purpose';
diff --git a/flexiapi/app/Console/Commands/RunAccountSeeder.php b/flexiapi/app/Console/Commands/Accounts/Seed.php
similarity index 96%
rename from flexiapi/app/Console/Commands/RunAccountSeeder.php
rename to flexiapi/app/Console/Commands/Accounts/Seed.php
index de512e9..f54cbf6 100644
--- a/flexiapi/app/Console/Commands/RunAccountSeeder.php
+++ b/flexiapi/app/Console/Commands/Accounts/Seed.php
@@ -17,13 +17,13 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Database\Seeders\LiblinphoneTesterAccoutSeeder;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\App;
-class RunAccountSeeder extends Command
+class Seed extends Command
{
protected $signature = 'accounts:seed {json-file-path}';
protected $description = 'Seed some accounts from a JSON file';
diff --git a/flexiapi/app/Console/Commands/SetAccountAdmin.php b/flexiapi/app/Console/Commands/Accounts/SetAdmin.php
similarity index 95%
rename from flexiapi/app/Console/Commands/SetAccountAdmin.php
rename to flexiapi/app/Console/Commands/Accounts/SetAdmin.php
index 306da26..cb6671d 100644
--- a/flexiapi/app/Console/Commands/SetAccountAdmin.php
+++ b/flexiapi/app/Console/Commands/Accounts/SetAdmin.php
@@ -17,13 +17,13 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Accounts;
use Illuminate\Console\Command;
use App\Account;
-class SetAccountAdmin extends Command
+class SetAdmin extends Command
{
protected $signature = 'accounts:set-admin {id}';
protected $description = 'Give the admin role to an account';
diff --git a/flexiapi/app/Console/Commands/ClearNonces.php b/flexiapi/app/Console/Commands/Digest/ClearNonces.php
similarity index 97%
rename from flexiapi/app/Console/Commands/ClearNonces.php
rename to flexiapi/app/Console/Commands/Digest/ClearNonces.php
index 02e7fb7..8532902 100644
--- a/flexiapi/app/Console/Commands/ClearNonces.php
+++ b/flexiapi/app/Console/Commands/Digest/ClearNonces.php
@@ -17,7 +17,7 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\Digest;
use Illuminate\Console\Command;
use Carbon\Carbon;
diff --git a/flexiapi/app/Console/Commands/CreateSipDomain.php b/flexiapi/app/Console/Commands/SipDomains/CreateUpdate.php
similarity index 95%
rename from flexiapi/app/Console/Commands/CreateSipDomain.php
rename to flexiapi/app/Console/Commands/SipDomains/CreateUpdate.php
index 0544c35..13e0883 100644
--- a/flexiapi/app/Console/Commands/CreateSipDomain.php
+++ b/flexiapi/app/Console/Commands/SipDomains/CreateUpdate.php
@@ -17,12 +17,12 @@
along with this program. If not, see .
*/
-namespace App\Console\Commands;
+namespace App\Console\Commands\SipDomains;
use App\SipDomain;
use Illuminate\Console\Command;
-class CreateSipDomain extends Command
+class CreateUpdate extends Command
{
protected $signature = 'sip_domains:create-update {domain} {--super}';
protected $description = 'Create a SIP Domain';
diff --git a/flexiapi/app/Consommable.php b/flexiapi/app/Consommable.php
index 13f9bfe..d52d0b5 100644
--- a/flexiapi/app/Consommable.php
+++ b/flexiapi/app/Consommable.php
@@ -2,12 +2,18 @@
namespace App;
+use Carbon\Carbon;
+use DateTime;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
abstract class Consommable extends Model
{
protected string $consommableAttribute = 'code';
+ protected ?string $configExpirationMinutesKey = null;
+ protected $casts = [
+ 'expire_at' => 'datetime'
+ ];
public function consume()
{
@@ -25,4 +31,26 @@ abstract class Consommable extends Model
{
return $this->{$this->consommableAttribute} == null;
}
+
+ public function getExpireAtAttribute(): ?string
+ {
+ if ($this->isExpirable()) {
+ return $this->created_at->addMinutes(config('app.' . $this->configExpirationMinutesKey))->toJSON();
+ }
+
+ return null;
+ }
+
+ public function expired(): bool
+ {
+ return ($this->isExpirable()
+ && Carbon::now()->subMinutes(config('app.' . $this->configExpirationMinutesKey))->isAfter($this->created_at));
+ }
+
+ private function isExpirable(): bool
+ {
+ return $this->configExpirationMinutesKey != null
+ && config('app.' . $this->configExpirationMinutesKey) != null
+ && config('app.' . $this->configExpirationMinutesKey) > 0;
+ }
}
diff --git a/flexiapi/app/EmailChangeCode.php b/flexiapi/app/EmailChangeCode.php
index 198e613..0331340 100644
--- a/flexiapi/app/EmailChangeCode.php
+++ b/flexiapi/app/EmailChangeCode.php
@@ -25,6 +25,7 @@ class EmailChangeCode extends Consommable
{
use HasFactory;
+ protected ?string $configExpirationMinutesKey = 'email_change_code_expiration_minutes';
protected $hidden = ['id', 'account_id', 'code'];
public function account()
diff --git a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
index cb8b0a1..1b3670e 100644
--- a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
+++ b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
@@ -128,7 +128,11 @@ class ProvisioningController extends Controller
->firstOrFail();
if ($account->activationExpired() || ($provisioningToken != $account->provisioning_token)) {
- abort(404);
+ return abort(404);
+ }
+
+ if ($account->currentProvisioningToken->expired()) {
+ return abort(410, 'Expired');
}
$account->activated = true;
diff --git a/flexiapi/app/Http/Controllers/Account/RecoveryController.php b/flexiapi/app/Http/Controllers/Account/RecoveryController.php
index 08497e7..243cfc0 100644
--- a/flexiapi/app/Http/Controllers/Account/RecoveryController.php
+++ b/flexiapi/app/Http/Controllers/Account/RecoveryController.php
@@ -120,6 +120,14 @@ class RecoveryController extends Controller
$account = Account::where('id', Crypt::decryptString($request->get('account_id')))->firstOrFail();
+ if ($account->currentRecoveryCode->expired()) {
+ return redirect()->route($request->get('method') == 'phone'
+ ? 'account.recovery.show.phone'
+ : 'account.recovery.show.email')->withErrors([
+ 'code' => 'The code is expired'
+ ]);
+ }
+
if ($account->recovery_code != $code) {
return redirect()->route($request->get('method') == 'phone'
? 'account.recovery.show.phone'
diff --git a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
index 53bc0ee..4f25c14 100644
--- a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
+++ b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
@@ -36,6 +36,7 @@ use App\Libraries\OvhSMS;
use App\Mail\RegisterConfirmation;
use App\Rules\AccountCreationToken as RulesAccountCreationToken;
+use App\Rules\AccountCreationTokenNotExpired;
use App\Rules\BlacklistedUsername;
use App\Rules\NoUppercase;
use App\Rules\SIPUsername;
@@ -43,7 +44,6 @@ use App\Rules\WithoutSpaces;
use App\Rules\PasswordAlgorithm;
use App\Services\AccountService;
-use App\SipDomain;
class AccountController extends Controller
{
@@ -122,7 +122,8 @@ class AccountController extends Controller
],
'account_creation_token' => [
'required',
- new RulesAccountCreationToken
+ new RulesAccountCreationToken,
+ new AccountCreationTokenNotExpired
]
]);
@@ -192,7 +193,8 @@ class AccountController extends Controller
],
'account_creation_token' => [
'required',
- new RulesAccountCreationToken
+ new RulesAccountCreationToken,
+ new AccountCreationTokenNotExpired
]
]);
diff --git a/flexiapi/app/Http/Requests/Account/Create/Api/AsAdminRequest.php b/flexiapi/app/Http/Requests/Account/Create/Api/AsAdminRequest.php
index bc09724..ac809b1 100644
--- a/flexiapi/app/Http/Requests/Account/Create/Api/AsAdminRequest.php
+++ b/flexiapi/app/Http/Requests/Account/Create/Api/AsAdminRequest.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Create\Api;
@@ -7,7 +24,6 @@ use App\Http\Requests\Api as RequestsApi;
use App\Http\Requests\AsAdmin;
use App\Rules\IsNotPhoneNumber;
use App\Rules\PasswordAlgorithm;
-use App\SipDomain;
class AsAdminRequest extends Request
{
diff --git a/flexiapi/app/Http/Requests/Account/Create/Api/Request.php b/flexiapi/app/Http/Requests/Account/Create/Api/Request.php
index c37e90f..f948298 100644
--- a/flexiapi/app/Http/Requests/Account/Create/Api/Request.php
+++ b/flexiapi/app/Http/Requests/Account/Create/Api/Request.php
@@ -1,10 +1,28 @@
.
+*/
namespace App\Http\Requests\Account\Create\Api;
use App\Http\Requests\Account\Create\Request as CreateRequest;
use App\Http\Requests\Api as RequestsApi;
use App\Rules\AccountCreationToken;
+use App\Rules\AccountCreationTokenNotExpired;
class Request extends CreateRequest
{
@@ -18,7 +36,7 @@ class Request extends CreateRequest
public function rules()
{
$rules = parent::rules();
- $rules['account_creation_token'] = ['required', new AccountCreationToken()];
+ $rules['account_creation_token'] = ['required', new AccountCreationToken, new AccountCreationTokenNotExpired];
return $rules;
}
diff --git a/flexiapi/app/Http/Requests/Account/Create/Request.php b/flexiapi/app/Http/Requests/Account/Create/Request.php
index 67c8c26..e4e3eba 100644
--- a/flexiapi/app/Http/Requests/Account/Create/Request.php
+++ b/flexiapi/app/Http/Requests/Account/Create/Request.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Create;
diff --git a/flexiapi/app/Http/Requests/Account/Create/Web/AsAdminRequest.php b/flexiapi/app/Http/Requests/Account/Create/Web/AsAdminRequest.php
index f340b12..b03a3b3 100644
--- a/flexiapi/app/Http/Requests/Account/Create/Web/AsAdminRequest.php
+++ b/flexiapi/app/Http/Requests/Account/Create/Web/AsAdminRequest.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Create\Web;
diff --git a/flexiapi/app/Http/Requests/Account/Create/Web/Request.php b/flexiapi/app/Http/Requests/Account/Create/Web/Request.php
index a700ff4..3572eee 100644
--- a/flexiapi/app/Http/Requests/Account/Create/Web/Request.php
+++ b/flexiapi/app/Http/Requests/Account/Create/Web/Request.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Create\Web;
diff --git a/flexiapi/app/Http/Requests/Account/Update/Api/AsAdminRequest.php b/flexiapi/app/Http/Requests/Account/Update/Api/AsAdminRequest.php
index fb887e1..2345dc9 100644
--- a/flexiapi/app/Http/Requests/Account/Update/Api/AsAdminRequest.php
+++ b/flexiapi/app/Http/Requests/Account/Update/Api/AsAdminRequest.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Update\Api;
diff --git a/flexiapi/app/Http/Requests/Account/Update/Request.php b/flexiapi/app/Http/Requests/Account/Update/Request.php
index 561a1d9..f55c895 100644
--- a/flexiapi/app/Http/Requests/Account/Update/Request.php
+++ b/flexiapi/app/Http/Requests/Account/Update/Request.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Update;
diff --git a/flexiapi/app/Http/Requests/Account/Update/Web/AsAdminRequest.php b/flexiapi/app/Http/Requests/Account/Update/Web/AsAdminRequest.php
index 035fc1d..644848f 100644
--- a/flexiapi/app/Http/Requests/Account/Update/Web/AsAdminRequest.php
+++ b/flexiapi/app/Http/Requests/Account/Update/Web/AsAdminRequest.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests\Account\Update\Web;
diff --git a/flexiapi/app/Http/Requests/Api.php b/flexiapi/app/Http/Requests/Api.php
index 55772ed..4cee262 100644
--- a/flexiapi/app/Http/Requests/Api.php
+++ b/flexiapi/app/Http/Requests/Api.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests;
diff --git a/flexiapi/app/Http/Requests/AsAdmin.php b/flexiapi/app/Http/Requests/AsAdmin.php
index 7cbdd92..0d854a3 100644
--- a/flexiapi/app/Http/Requests/AsAdmin.php
+++ b/flexiapi/app/Http/Requests/AsAdmin.php
@@ -1,4 +1,21 @@
.
+*/
namespace App\Http\Requests;
diff --git a/flexiapi/app/Mail/RecoverByCode.php b/flexiapi/app/Mail/RecoverByCode.php
index 188ae82..116d2c3 100644
--- a/flexiapi/app/Mail/RecoverByCode.php
+++ b/flexiapi/app/Mail/RecoverByCode.php
@@ -45,6 +45,7 @@ class RecoverByCode extends Mailable
? 'mails.authentication_text_custom'
: 'mails.authentication_text')
->with([
+ 'expiration_minutes' => config('app.recovery_code_expiration_minutes'),
'recovery_code' => $this->account->recovery_code,
'provisioning_link' => route('provisioning.provision', [
'provisioning_token' => $this->account->provisioning_token,
diff --git a/flexiapi/app/PhoneChangeCode.php b/flexiapi/app/PhoneChangeCode.php
index dec68bf..9d8dc0b 100644
--- a/flexiapi/app/PhoneChangeCode.php
+++ b/flexiapi/app/PhoneChangeCode.php
@@ -25,6 +25,7 @@ class PhoneChangeCode extends Consommable
{
use HasFactory;
+ protected ?string $configExpirationMinutesKey = 'phone_change_code_expiration_minutes';
protected $hidden = ['id', 'account_id', 'code'];
public function account()
diff --git a/flexiapi/app/ProvisioningToken.php b/flexiapi/app/ProvisioningToken.php
index 4e51af7..6c36623 100644
--- a/flexiapi/app/ProvisioningToken.php
+++ b/flexiapi/app/ProvisioningToken.php
@@ -25,6 +25,7 @@ class ProvisioningToken extends Consommable
{
use HasFactory;
+ protected ?string $configExpirationMinutesKey = 'provisioning_token_expiration_minutes';
protected $casts = [
'used' => 'boolean',
];
diff --git a/flexiapi/app/RecoveryCode.php b/flexiapi/app/RecoveryCode.php
index 4a154f3..8f01edc 100644
--- a/flexiapi/app/RecoveryCode.php
+++ b/flexiapi/app/RecoveryCode.php
@@ -7,4 +7,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
class RecoveryCode extends Consommable
{
use HasFactory;
+
+ protected ?string $configExpirationMinutesKey = 'recovery_code_expiration_minutes';
}
diff --git a/flexiapi/app/Rules/AccountCreationTokenNotExpired.php b/flexiapi/app/Rules/AccountCreationTokenNotExpired.php
new file mode 100644
index 0000000..5406574
--- /dev/null
+++ b/flexiapi/app/Rules/AccountCreationTokenNotExpired.php
@@ -0,0 +1,38 @@
+.
+*/
+
+namespace App\Rules;
+
+use App\AccountCreationToken as AppAccountCreationToken;
+use Illuminate\Contracts\Validation\Rule;
+
+class AccountCreationTokenNotExpired implements Rule
+{
+ public function passes($attribute, $value)
+ {
+ $token = AppAccountCreationToken::where('token', $value)->where('used', false)->first();
+
+ return $token && !$token->expired();
+ }
+
+ public function message()
+ {
+ return 'The provided token is expired';
+ }
+}
diff --git a/flexiapi/app/Services/AccountService.php b/flexiapi/app/Services/AccountService.php
index bc8c723..2d74d79 100644
--- a/flexiapi/app/Services/AccountService.php
+++ b/flexiapi/app/Services/AccountService.php
@@ -262,6 +262,10 @@ class AccountService
$phoneChangeCode = $account->phoneChangeCode()->firstOrFail();
+ if ($phoneChangeCode->expired()) {
+ return abort(410, 'Expired code');
+ }
+
if ($phoneChangeCode->code == $code) {
$account->phone = $phoneChangeCode->phone;
$account->activated = true;
@@ -329,6 +333,11 @@ class AccountService
$account = $request->user();
$emailChangeCode = $account->emailChangeCode()->firstOrFail();
+
+ if ($emailChangeCode->expired()) {
+ return abort(410, 'Expired code');
+ }
+
if ($emailChangeCode->validate($code)) {
$account->email = $emailChangeCode->email;
$account->save();
@@ -371,8 +380,14 @@ class AccountService
{
$account = $this->recoverAccount($account);
+ $message = 'Your ' . config('app.name') . ' validation code is ' . $account->recovery_code . ' .';
+
+ if (config('app.recovery_code_expiration_minutes') > 0) {
+ $message .= 'The code is available for ' . config('app.recovery_code_expiration_minutes') . ' minutes';
+ }
+
$ovhSMS = new OvhSMS();
- $ovhSMS->send($account->phone, 'Your ' . config('app.name') . ' validation code is ' . $account->recovery_code);
+ $ovhSMS->send($account->phone, $message);
Log::channel('events')->info('Account Service: Sending recovery SMS', ['id' => $account->identifier]);
@@ -383,7 +398,6 @@ class AccountService
{
$account->recover();
$account->provision();
-
$account->refresh();
return $account;
diff --git a/flexiapi/config/app.php b/flexiapi/config/app.php
index 187de49..68a613e 100644
--- a/flexiapi/config/app.php
+++ b/flexiapi/config/app.php
@@ -40,7 +40,11 @@ return [
* Time limit before the API Key and related cookie are expired
*/
'api_key_expiration_minutes' => env('APP_API_KEY_EXPIRATION_MINUTES', 60),
-
+ 'account_creation_token_expiration_minutes' => env('APP_ACCOUNT_CREATION_TOKEN_EXPIRATION_MINUTES', 0),
+ 'email_change_code_expiration_minutes' => env('APP_EMAIL_CHANGE_CODE_EXPIRATION_MINUTES', 10),
+ 'phone_change_code_expiration_minutes' => env('APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES', 10),
+ 'recovery_code_expiration_minutes' => env('APP_RECOVERY_CODE_EXPIRATION_MINUTES', 10),
+ 'provisioning_token_expiration_minutes' => env('APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES', 0),
/**
* Amount of minutes before re-authorizing the generation of a new account creation token
*/
diff --git a/flexiapi/config/rcfile b/flexiapi/config/rcfile
new file mode 100644
index 0000000..d76bcd4
--- /dev/null
+++ b/flexiapi/config/rcfile
@@ -0,0 +1,5 @@
+[auth_info_0]
+test=foobar
+
+[auth_info_1]
+blabla=gnap
diff --git a/flexiapi/database/factories/AccountCreationTokenFactory.php b/flexiapi/database/factories/AccountCreationTokenFactory.php
index 6482685..e5b4308 100644
--- a/flexiapi/database/factories/AccountCreationTokenFactory.php
+++ b/flexiapi/database/factories/AccountCreationTokenFactory.php
@@ -43,4 +43,11 @@ class AccountCreationTokenFactory extends Factory
'created_at' => Carbon::now()
];
}
+
+ public function expired()
+ {
+ return $this->state(fn (array $attributes) => [
+ 'created_at' => Carbon::now()->subMinutes(1000)
+ ]);
+ }
}
diff --git a/flexiapi/resources/views/account/recovery/show.blade.php b/flexiapi/resources/views/account/recovery/show.blade.php
index 730390e..6fc5326 100644
--- a/flexiapi/resources/views/account/recovery/show.blade.php
+++ b/flexiapi/resources/views/account/recovery/show.blade.php
@@ -9,7 +9,12 @@
@if ($method == 'email')
-
Enter your email account to recover it.
+
+ Enter your email account to recover it.
+ @if (config('app.recovery_code_expiration_minutes') > 0)
+ The code will be available {{ config('app.recovery_code_expiration_minutes') }} minutes.
+ @endif
+
@include('parts.errors', ['name' => 'code'])
@@ -29,7 +34,12 @@
@endif
@elseif($method == 'phone')
-
Enter your phone number to recover your account.
+
+ Enter your phone number to recover your account.
+ @if (config('app.recovery_code_expiration_minutes') > 0)
+ The code will be available {{ config('app.recovery_code_expiration_minutes') }} minutes.
+ @endif
+
diff --git a/flexiapi/resources/views/errors/410.blade.php b/flexiapi/resources/views/errors/410.blade.php
new file mode 100644
index 0000000..8cc7181
--- /dev/null
+++ b/flexiapi/resources/views/errors/410.blade.php
@@ -0,0 +1,5 @@
+@extends('errors::minimal')
+
+@section('title', __('Expired resource'))
+@section('code', '410')
+@section('message', __('The resource you requested is expired'))
diff --git a/flexiapi/resources/views/errors/minimal.blade.php b/flexiapi/resources/views/errors/minimal.blade.php
index c6f9cc1..be74c4b 100644
--- a/flexiapi/resources/views/errors/minimal.blade.php
+++ b/flexiapi/resources/views/errors/minimal.blade.php
@@ -6,7 +6,7 @@
@yield('message')
-
+
Go back to the homepage
diff --git a/flexiapi/resources/views/mails/authentication.blade.php b/flexiapi/resources/views/mails/authentication.blade.php
index d55ed25..cc7e60b 100644
--- a/flexiapi/resources/views/mails/authentication.blade.php
+++ b/flexiapi/resources/views/mails/authentication.blade.php
@@ -11,6 +11,11 @@
{{ $recovery_code }}
+ @if ($expiration_minutes > 0)
+
+ The code is only available {{ $expiration_minutes }} minutes.
+