mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Fix #132 Move the provisioning_tokens and recovery_codes to dedicated table
This commit is contained in:
parent
b409e37ab1
commit
5717994ab8
18 changed files with 472 additions and 53 deletions
|
|
@ -38,9 +38,9 @@ class Account extends Authenticatable
|
|||
use HasFactory;
|
||||
use Compoships;
|
||||
|
||||
protected $with = ['passwords', 'admin', 'alias', 'activationExpiration', 'emailChangeCode', 'types', 'actions'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'provisioning_token', 'pivot'];
|
||||
protected $appends = ['realm', 'phone', 'confirmation_key_expires'];
|
||||
protected $with = ['passwords', 'admin', 'alias', 'currentRecoveryCode', 'activationExpiration', 'emailChangeCode', 'types', 'actions'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'pivot'];
|
||||
protected $appends = ['realm', 'phone', 'confirmation_key_expires', 'provisioning_token'];
|
||||
protected $casts = [
|
||||
'activated' => 'boolean',
|
||||
];
|
||||
|
|
@ -52,15 +52,20 @@ class Account extends Authenticatable
|
|||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleted(function ($item) {
|
||||
StatisticsMessage::where('from_username', $item->username)
|
||||
->where('from_domain', $item->domain)
|
||||
static::deleted(function (Account $account) {
|
||||
StatisticsMessage::where('from_username', $account->username)
|
||||
->where('from_domain', $account->domain)
|
||||
->delete();
|
||||
|
||||
StatisticsCall::where('from_username', $item->username)
|
||||
->where('from_domain', $item->domain)
|
||||
StatisticsCall::where('from_username', $account->username)
|
||||
->where('from_domain', $account->domain)
|
||||
->delete();
|
||||
});
|
||||
|
||||
static::created(function (Account $account) {
|
||||
$account->provision();
|
||||
$account->refresh();
|
||||
});
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
|
|
@ -182,14 +187,44 @@ class Account extends Authenticatable
|
|||
/**
|
||||
* Tokens and codes
|
||||
*/
|
||||
public function currentRecoveryCode()
|
||||
{
|
||||
return $this->hasOne(RecoveryCode::class)->whereNotNull('code')->latestOfMany();
|
||||
}
|
||||
|
||||
public function recoveryCodes()
|
||||
{
|
||||
return $this->hasMany(RecoveryCode::class)->latest();
|
||||
}
|
||||
|
||||
public function phoneChangeCode()
|
||||
{
|
||||
return $this->hasOne(PhoneChangeCode::class);
|
||||
return $this->hasOne(phoneChangeCode::class)->whereNotNull('code')->latestOfMany();
|
||||
}
|
||||
|
||||
public function phoneChangeCodes()
|
||||
{
|
||||
return $this->hasMany(PhoneChangeCode::class)->latest();
|
||||
}
|
||||
|
||||
public function emailChangeCode()
|
||||
{
|
||||
return $this->hasOne(EmailChangeCode::class);
|
||||
return $this->hasOne(EmailChangeCode::class)->whereNotNull('code')->latestOfMany();
|
||||
}
|
||||
|
||||
public function emailChangeCodes()
|
||||
{
|
||||
return $this->hasMany(EmailChangeCode::class)->latest();
|
||||
}
|
||||
|
||||
public function currentProvisioningToken()
|
||||
{
|
||||
return $this->hasOne(ProvisioningToken::class)->where('used', false)->latestOfMany();
|
||||
}
|
||||
|
||||
public function provisioningTokens()
|
||||
{
|
||||
return $this->hasMany(ProvisioningToken::class)->latest();
|
||||
}
|
||||
|
||||
public function authTokens()
|
||||
|
|
@ -200,12 +235,30 @@ class Account extends Authenticatable
|
|||
/**
|
||||
* Attributes
|
||||
*/
|
||||
public function getIdentifierAttribute()
|
||||
public function getRecoveryCodeAttribute(): ?string
|
||||
{
|
||||
if ($this->currentRecoveryCode) {
|
||||
return $this->currentRecoveryCode->code;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getProvisioningTokenAttribute(): ?string
|
||||
{
|
||||
if ($this->currentProvisioningToken) {
|
||||
return $this->currentProvisioningToken->token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getIdentifierAttribute(): string
|
||||
{
|
||||
return $this->attributes['username'] . '@' . $this->attributes['domain'];
|
||||
}
|
||||
|
||||
public function getFullIdentifierAttribute()
|
||||
public function getFullIdentifierAttribute(): string
|
||||
{
|
||||
$displayName = $this->attributes['display_name']
|
||||
? '"' . $this->attributes['display_name'] . '" '
|
||||
|
|
@ -309,10 +362,24 @@ class Account extends Authenticatable
|
|||
return $authToken;
|
||||
}
|
||||
|
||||
public function provision(): string
|
||||
public function recover(?string $code = null): string
|
||||
{
|
||||
$this->provisioning_token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
return $this->provisioning_token;
|
||||
$recoveryCode = new RecoveryCode;
|
||||
$recoveryCode->code = $code ?? generatePin();
|
||||
$recoveryCode->account_id = $this->id;
|
||||
$recoveryCode->save();
|
||||
|
||||
return $recoveryCode->code;
|
||||
}
|
||||
|
||||
public function provision(?string $token = null): string
|
||||
{
|
||||
$provisioningToken = new ProvisioningToken;
|
||||
$provisioningToken->token = $token ?? Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$provisioningToken->account_id = $this->id;
|
||||
$provisioningToken->save();
|
||||
|
||||
return $provisioningToken->token;
|
||||
}
|
||||
|
||||
public function getAdminAttribute(): bool
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AccountCreationRequestToken extends Model
|
||||
class AccountCreationRequestToken extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
|
@ -40,4 +39,10 @@ class AccountCreationRequestToken extends Model
|
|||
? route('account.creation_request_token.check', $this->token)
|
||||
: null;
|
||||
}
|
||||
|
||||
public function consume()
|
||||
{
|
||||
$this->used = true;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AccountCreationToken extends Model
|
||||
class AccountCreationToken extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
|
@ -32,4 +31,10 @@ class AccountCreationToken extends Model
|
|||
{
|
||||
return $this->hasOne(AccountCreationRequestToken::class, 'acc_creation_token_id');
|
||||
}
|
||||
|
||||
public function consume()
|
||||
{
|
||||
$this->used = true;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
16
flexiapi/app/Consommable.php
Normal file
16
flexiapi/app/Consommable.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
abstract class Consommable extends Model
|
||||
{
|
||||
protected string $consommableAttribute = 'code';
|
||||
|
||||
public function consume()
|
||||
{
|
||||
$this->{$this->consommableAttribute} = null;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,9 +20,8 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class EmailChangeCode extends Model
|
||||
class EmailChangeCode extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,12 @@ class ProvisioningController extends Controller
|
|||
public function qrcode(Request $request, string $provisioningToken)
|
||||
{
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('provisioning_token', $provisioningToken)
|
||||
->where('id', function ($query) use ($provisioningToken) {
|
||||
$query->select('account_id')
|
||||
->from('provisioning_tokens')
|
||||
->where('used', false)
|
||||
->where('token', $provisioningToken);
|
||||
})
|
||||
->firstOrFail();
|
||||
|
||||
if ($account->activationExpired()) abort(404);
|
||||
|
|
@ -108,7 +113,12 @@ class ProvisioningController extends Controller
|
|||
public function provision(Request $request, string $provisioningToken)
|
||||
{
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('provisioning_token', $provisioningToken)
|
||||
->where('id', function ($query) use ($provisioningToken) {
|
||||
$query->select('account_id')
|
||||
->from('provisioning_tokens')
|
||||
->where('used', false)
|
||||
->where('token', $provisioningToken);
|
||||
})
|
||||
->firstOrFail();
|
||||
|
||||
if ($account->activationExpired() || ($provisioningToken != $account->provisioning_token)) {
|
||||
|
|
@ -116,7 +126,7 @@ class ProvisioningController extends Controller
|
|||
}
|
||||
|
||||
$account->activated = true;
|
||||
$account->provisioning_token = null;
|
||||
$account->currentProvisioningToken->consume();
|
||||
$account->save();
|
||||
|
||||
return $this->generateProvisioning($request, $account);
|
||||
|
|
|
|||
|
|
@ -135,13 +135,12 @@ class AccountController extends Controller
|
|||
$account->ip_address = $request->ip();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->user_agent = $request->header('User-Agent') ?? config('app.name');
|
||||
$account->provision();
|
||||
$account->save();
|
||||
|
||||
$account->updatePassword($request->get('password'), $request->get('algorithm'));
|
||||
|
||||
$token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first();
|
||||
$token->used = true;
|
||||
$token->consume();
|
||||
$token->account_id = $account->id;
|
||||
$token->save();
|
||||
|
||||
|
|
@ -208,7 +207,7 @@ class AccountController extends Controller
|
|||
$account->save();
|
||||
|
||||
$token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first();
|
||||
$token->used = true;
|
||||
$token->consume();
|
||||
$token->account_id = $account->id;
|
||||
$token->save();
|
||||
|
||||
|
|
@ -255,11 +254,6 @@ class AccountController extends Controller
|
|||
|
||||
public function activateEmail(Request $request, string $sip)
|
||||
{
|
||||
// For retro-compatibility
|
||||
if ($request->has('code')) {
|
||||
$request->merge(['confirmation_key' => $request->get('code')]);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'confirmation_key' => 'required|size:' . WebAuthenticateController::$emailCodeSize
|
||||
]);
|
||||
|
|
@ -281,11 +275,6 @@ class AccountController extends Controller
|
|||
|
||||
public function activatePhone(Request $request, string $sip)
|
||||
{
|
||||
// For retro-compatibility
|
||||
if ($request->has('code')) {
|
||||
$request->merge(['confirmation_key' => $request->get('code')]);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'confirmation_key' => 'required|digits:4'
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class CreationTokenController extends Controller
|
|||
$accountCreationToken->token = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$accountCreationToken->save();
|
||||
|
||||
$creationRequestToken->used = true;
|
||||
$creationRequestToken->consume();
|
||||
$creationRequestToken->acc_creation_token_id = $accountCreationToken->id;
|
||||
$creationRequestToken->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ class AccountController extends Controller
|
|||
|
||||
if (!$request->has('activated') || !(bool)$request->get('activated')) {
|
||||
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->provision();
|
||||
}
|
||||
|
||||
$account->save();
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PhoneChangeCode extends Model
|
||||
class PhoneChangeCode extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
|
|
|||
33
flexiapi/app/ProvisioningToken.php
Normal file
33
flexiapi/app/ProvisioningToken.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?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;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class ProvisioningToken extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public function consume()
|
||||
{
|
||||
$this->used = true;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
11
flexiapi/app/RecoveryCode.php
Normal file
11
flexiapi/app/RecoveryCode.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class RecoveryCode extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
|
|
@ -70,14 +70,13 @@ class AccountService
|
|||
$account->user_agent = config('app.name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->confirmation_key = generatePin();
|
||||
$account->provision();
|
||||
$account->save();
|
||||
|
||||
$account->updatePassword($request->get('password'), $request->has('algorithm') ? $request->get('algorithm') : 'SHA-256');
|
||||
|
||||
if ($this->api) {
|
||||
$token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first();
|
||||
$token->used = true;
|
||||
$token->consume();
|
||||
$token->account_id = $account->id;
|
||||
$token->save();
|
||||
}
|
||||
|
|
@ -109,7 +108,7 @@ class AccountService
|
|||
|
||||
$account = $request->user();
|
||||
|
||||
$phoneChangeCode = $account->phoneChangeCode ?? new PhoneChangeCode();
|
||||
$phoneChangeCode = $account->phoneChangeCode ?? new PhoneChangeCode;
|
||||
$phoneChangeCode->account_id = $account->id;
|
||||
$phoneChangeCode->phone = $request->get('phone');
|
||||
$phoneChangeCode->code = generatePin();
|
||||
|
|
@ -150,8 +149,6 @@ class AccountService
|
|||
|
||||
Log::channel('events')->info('Account Service: Account phone changed using SMS', ['id' => $account->identifier]);
|
||||
|
||||
$phoneChangeCode->delete();
|
||||
|
||||
$account->activated = true;
|
||||
$account->save();
|
||||
|
||||
|
|
@ -160,7 +157,7 @@ class AccountService
|
|||
return $account;
|
||||
}
|
||||
|
||||
$phoneChangeCode->delete();
|
||||
$phoneChangeCode->consume();
|
||||
|
||||
if ($this->api) {
|
||||
abort(403);
|
||||
|
|
@ -230,7 +227,7 @@ class AccountService
|
|||
return $account;
|
||||
}
|
||||
|
||||
$emailChangeCode->delete();
|
||||
$emailChangeCode->consume();
|
||||
|
||||
if ($this->api) {
|
||||
abort(403);
|
||||
|
|
@ -268,9 +265,10 @@ class AccountService
|
|||
|
||||
private function recoverAccount(Account $account): Account
|
||||
{
|
||||
$account->recovery_code = generatePin();
|
||||
$account->recover();
|
||||
$account->provision();
|
||||
$account->save();
|
||||
|
||||
$account->refresh();
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"endroid/qr-code": "^4.8",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/framework": "^9.52",
|
||||
"laravel/tinker": "^2.8",
|
||||
"namoshek/laravel-redis-sentinel": "^0.1",
|
||||
"ovh/ovh": "^3.2",
|
||||
"parsedown/laravel": "^1.2",
|
||||
|
|
|
|||
151
flexiapi/composer.lock
generated
151
flexiapi/composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c40b2725aff311036d760b67e577fdef",
|
||||
"content-hash": "920b287a3d53f86cce05f254b7e3cb7b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anhskohbo/no-captcha",
|
||||
|
|
@ -2189,6 +2189,75 @@
|
|||
},
|
||||
"time": "2023-11-08T14:08:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/tinker",
|
||||
"version": "v2.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/tinker.git",
|
||||
"reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/tinker/zipball/b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
|
||||
"reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||
"illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||
"php": "^7.2.5|^8.0",
|
||||
"psy/psysh": "^0.10.4|^0.11.1",
|
||||
"symfony/var-dumper": "^4.3.4|^5.0|^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.3.3|^1.4.2",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^8.5.8|^9.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Tinker\\TinkerServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Tinker\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Powerful REPL for the Laravel framework.",
|
||||
"keywords": [
|
||||
"REPL",
|
||||
"Tinker",
|
||||
"laravel",
|
||||
"psysh"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/tinker/issues",
|
||||
"source": "https://github.com/laravel/tinker/tree/v2.8.2"
|
||||
},
|
||||
"time": "2023-08-15T14:27:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "2.4.1",
|
||||
|
|
@ -4382,6 +4451,86 @@
|
|||
},
|
||||
"time": "2021-10-29T13:26:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.11.22",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "128fa1b608be651999ed9789c95e6e2a31b5802b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/128fa1b608be651999ed9789c95e6e2a31b5802b",
|
||||
"reference": "128fa1b608be651999ed9789c95e6e2a31b5802b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"nikic/php-parser": "^4.0 || ^3.1",
|
||||
"php": "^8.0 || ^7.0.8",
|
||||
"symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4",
|
||||
"symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
|
||||
"ext-pdo-sqlite": "The doc command requires SQLite to work.",
|
||||
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
|
||||
"ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history."
|
||||
},
|
||||
"bin": [
|
||||
"bin/psysh"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-0.11": "0.11.x-dev"
|
||||
},
|
||||
"bamarni-bin": {
|
||||
"bin-links": false,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Psy\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Justin Hileman",
|
||||
"email": "justin@justinhileman.info",
|
||||
"homepage": "http://justinhileman.com"
|
||||
}
|
||||
],
|
||||
"description": "An interactive shell for modern PHP.",
|
||||
"homepage": "http://psysh.org",
|
||||
"keywords": [
|
||||
"REPL",
|
||||
"console",
|
||||
"interactive",
|
||||
"shell"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.11.22"
|
||||
},
|
||||
"time": "2023-10-14T21:56:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "3.0.3",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ 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,
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 year'),
|
||||
'dtmf_protocol' => array_rand(Account::$dtmfProtocols),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
use App\Account;
|
||||
use App\ProvisioningToken;
|
||||
use App\RecoveryCode;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('phone_change_codes', function (Blueprint $table) {
|
||||
$table->string('code')->nullable(true)->change();
|
||||
});
|
||||
|
||||
Schema::table('email_change_codes', function (Blueprint $table) {
|
||||
$table->string('code')->nullable(true)->change();
|
||||
});
|
||||
|
||||
// Move the provisioning tokens and recovery code to a dedicated table
|
||||
Schema::create('provisioning_tokens', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('account_id')->unsigned();
|
||||
$table->string('token')->nullable();
|
||||
$table->boolean('used')->default(false);
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('account_id')->references('id')
|
||||
->on('accounts')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('recovery_codes', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('account_id')->unsigned();
|
||||
$table->string('code')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('account_id')->references('id')
|
||||
->on('accounts')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// Using a Query Builder as we don't want to use Eloquent magic there
|
||||
$accounts = DB::table('accounts')->whereNotNull('provisioning_token')->orWhereNotNull('recovery_code')->get();
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$progress = new ProgressBar(new ConsoleOutput, $accounts->count());
|
||||
$progress->start();
|
||||
}
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
if ($account->provisioning_token) {
|
||||
$provisioningToken = new ProvisioningToken;
|
||||
$provisioningToken->token = $account->provisioning_token;
|
||||
$provisioningToken->account_id = $account->id;
|
||||
$provisioningToken->save();
|
||||
}
|
||||
|
||||
if ($account->recovery_code) {
|
||||
$recoveryCode = new RecoveryCode;
|
||||
$recoveryCode->code = $account->recovery_code;
|
||||
$recoveryCode->account_id = $account->id;
|
||||
$recoveryCode->save();
|
||||
}
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->advance();
|
||||
}
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->finish();
|
||||
|
||||
// In two steps for SQLite
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropColumn('provisioning_token');
|
||||
});
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropColumn('recovery_code');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('phone_change_codes', function (Blueprint $table) {
|
||||
$table->string('code')->nullable(false)->change();
|
||||
});
|
||||
|
||||
Schema::table('email_change_codes', function (Blueprint $table) {
|
||||
$table->string('code')->nullable(false)->change();
|
||||
});
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->string('provisioning_token')->nullable();
|
||||
$table->string('recovery_code')->nullable();
|
||||
});
|
||||
|
||||
// Provisioning tokens
|
||||
$provisioningTokens = ProvisioningToken::all();
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$progress = new ProgressBar(new ConsoleOutput, $provisioningTokens->count());
|
||||
$progress->start();
|
||||
}
|
||||
|
||||
foreach ($provisioningTokens as $provisioningToken) {
|
||||
$account = Account::where('id', $provisioningToken->account_id)->first();
|
||||
$account->provisioning_token = $provisioningToken->token;
|
||||
$account->save();
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->advance();
|
||||
}
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->finish();
|
||||
|
||||
// Recovery codes
|
||||
$recoveryCodes = RecoveryCode::all();
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$progress = new ProgressBar(new ConsoleOutput, $recoveryCodes->count());
|
||||
$progress->start();
|
||||
}
|
||||
|
||||
foreach ($recoveryCodes as $recoveryCode) {
|
||||
$account = Account::where('id', $recoveryCode->account_id)->first();
|
||||
$account->recovery_code = $recoveryCode->code;
|
||||
$account->save();
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->advance();
|
||||
}
|
||||
|
||||
if (DB::getDriverName() !== 'sqlite') $progress->finish();
|
||||
|
||||
Schema::dropIfExists('provisioning_tokens');
|
||||
Schema::dropIfExists('recovery_codes');
|
||||
}
|
||||
};
|
||||
|
|
@ -370,7 +370,6 @@ class ApiAccountTest extends TestCase
|
|||
]);
|
||||
|
||||
$this->assertTrue(empty($response1['confirmation_key']));
|
||||
$this->assertTrue(empty($response1['provisioning_token']));
|
||||
}
|
||||
|
||||
public function testNotActivated()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue