From 5717994ab8c80f468de3b9b0523efbe8593ea45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Thu, 14 Dec 2023 14:13:41 +0000 Subject: [PATCH] Fix #132 Move the provisioning_tokens and recovery_codes to dedicated table --- flexiapi/app/Account.php | 97 +++++++++-- flexiapi/app/AccountCreationRequestToken.php | 9 +- flexiapi/app/AccountCreationToken.php | 9 +- flexiapi/app/Consommable.php | 16 ++ flexiapi/app/EmailChangeCode.php | 3 +- .../Account/ProvisioningController.php | 16 +- .../Api/Account/AccountController.php | 15 +- .../Api/Account/CreationTokenController.php | 2 +- .../Api/Admin/AccountController.php | 1 - flexiapi/app/PhoneChangeCode.php | 3 +- flexiapi/app/ProvisioningToken.php | 33 ++++ flexiapi/app/RecoveryCode.php | 11 ++ flexiapi/app/Services/AccountService.php | 16 +- flexiapi/composer.json | 1 + flexiapi/composer.lock | 151 +++++++++++++++++- .../database/factories/AccountFactory.php | 1 - ...3_move_tokens_and_codes_to_consommable.php | 140 ++++++++++++++++ flexiapi/tests/Feature/ApiAccountTest.php | 1 - 18 files changed, 472 insertions(+), 53 deletions(-) create mode 100644 flexiapi/app/Consommable.php create mode 100644 flexiapi/app/ProvisioningToken.php create mode 100644 flexiapi/app/RecoveryCode.php create mode 100644 flexiapi/database/migrations/2023_12_11_155543_move_tokens_and_codes_to_consommable.php diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index 9d6a111..d06a7bf 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -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 diff --git a/flexiapi/app/AccountCreationRequestToken.php b/flexiapi/app/AccountCreationRequestToken.php index aedb61e..c210f72 100644 --- a/flexiapi/app/AccountCreationRequestToken.php +++ b/flexiapi/app/AccountCreationRequestToken.php @@ -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(); + } } diff --git a/flexiapi/app/AccountCreationToken.php b/flexiapi/app/AccountCreationToken.php index 754224a..840c410 100644 --- a/flexiapi/app/AccountCreationToken.php +++ b/flexiapi/app/AccountCreationToken.php @@ -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(); + } } diff --git a/flexiapi/app/Consommable.php b/flexiapi/app/Consommable.php new file mode 100644 index 0000000..a276595 --- /dev/null +++ b/flexiapi/app/Consommable.php @@ -0,0 +1,16 @@ +{$this->consommableAttribute} = null; + $this->save(); + } +} diff --git a/flexiapi/app/EmailChangeCode.php b/flexiapi/app/EmailChangeCode.php index c59927c..21be5bc 100644 --- a/flexiapi/app/EmailChangeCode.php +++ b/flexiapi/app/EmailChangeCode.php @@ -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; diff --git a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php index 28e6a24..7272ccc 100644 --- a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php +++ b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php @@ -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); diff --git a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php index 4b22978..17e7732 100644 --- a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php @@ -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' ]); diff --git a/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php b/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php index cee3f22..396ac7e 100644 --- a/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/CreationTokenController.php @@ -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(); diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php index 2f86d2e..975ba0e 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php @@ -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(); diff --git a/flexiapi/app/PhoneChangeCode.php b/flexiapi/app/PhoneChangeCode.php index a5c2e93..5914c0b 100644 --- a/flexiapi/app/PhoneChangeCode.php +++ b/flexiapi/app/PhoneChangeCode.php @@ -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; diff --git a/flexiapi/app/ProvisioningToken.php b/flexiapi/app/ProvisioningToken.php new file mode 100644 index 0000000..cb5ce34 --- /dev/null +++ b/flexiapi/app/ProvisioningToken.php @@ -0,0 +1,33 @@ +. +*/ + +namespace App; + +use Illuminate\Database\Eloquent\Factories\HasFactory; + +class ProvisioningToken extends Consommable +{ + use HasFactory; + + public function consume() + { + $this->used = true; + $this->save(); + } +} diff --git a/flexiapi/app/RecoveryCode.php b/flexiapi/app/RecoveryCode.php new file mode 100644 index 0000000..01935a9 --- /dev/null +++ b/flexiapi/app/RecoveryCode.php @@ -0,0 +1,11 @@ +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; } diff --git a/flexiapi/composer.json b/flexiapi/composer.json index d0c9348..e480571 100644 --- a/flexiapi/composer.json +++ b/flexiapi/composer.json @@ -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", diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index 4753109..9baf25b 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -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", diff --git a/flexiapi/database/factories/AccountFactory.php b/flexiapi/database/factories/AccountFactory.php index d2c6eac..3695e5f 100644 --- a/flexiapi/database/factories/AccountFactory.php +++ b/flexiapi/database/factories/AccountFactory.php @@ -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), diff --git a/flexiapi/database/migrations/2023_12_11_155543_move_tokens_and_codes_to_consommable.php b/flexiapi/database/migrations/2023_12_11_155543_move_tokens_and_codes_to_consommable.php new file mode 100644 index 0000000..a1701cd --- /dev/null +++ b/flexiapi/database/migrations/2023_12_11_155543_move_tokens_and_codes_to_consommable.php @@ -0,0 +1,140 @@ +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'); + } +}; diff --git a/flexiapi/tests/Feature/ApiAccountTest.php b/flexiapi/tests/Feature/ApiAccountTest.php index 8ad4bd7..f9e4d25 100644 --- a/flexiapi/tests/Feature/ApiAccountTest.php +++ b/flexiapi/tests/Feature/ApiAccountTest.php @@ -370,7 +370,6 @@ class ApiAccountTest extends TestCase ]); $this->assertTrue(empty($response1['confirmation_key'])); - $this->assertTrue(empty($response1['provisioning_token'])); } public function testNotActivated()