Feature: Customer Account Services
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Caps brute-forcing a 6-digit OTP code (1M combinations, 10-minute
|
||||
* window, previously uncapped) — see Modules\Core\Auth\Services\
|
||||
* UserOtpService::validate(), which now invalidates the code entirely
|
||||
* (forcing a fresh generateAndSend()) once otp_attempts reaches its max,
|
||||
* rather than leaving a live code guessable indefinitely within its
|
||||
* expiry window.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->unsignedTinyInteger('otp_attempts')->default(0)->after('otp_expires_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('otp_attempts');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* A per-login session registry, independent of the actual session store
|
||||
* driver (SESSION_DRIVER=redis in this app — no "sessions" table to
|
||||
* purge by user_id the way the database driver would allow). Each
|
||||
* successful OTP login (Modules\Core\Auth\Services\UserOtpService::
|
||||
* validate()) records one row here and stamps the token into the
|
||||
* Laravel session payload; Modules\Core\Auth\Http\Middleware\
|
||||
* EnsureSessionNotRevoked checks it on every request. "Logout
|
||||
* everywhere" (Modules\Core\Auth\Services\UserSessionService::
|
||||
* revokeOtherSessions()) is then just marking every OTHER row
|
||||
* revoked_at, no session-store-specific logic anywhere.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_sessions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('token', 64)->unique();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamp('last_used_at');
|
||||
$table->timestamp('revoked_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'revoked_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_sessions');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user