From 71881cea908cfed8a41d9db0d61ff61b19a5f70f Mon Sep 17 00:00:00 2001 From: Youri Wijnands Date: Thu, 28 Jul 2022 22:01:26 +0200 Subject: [PATCH 1/5] Prune expires_at tokens --- src/Console/Commands/PruneExpired.php | 6 +++- tests/PruneExpiredTest.php | 45 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Console/Commands/PruneExpired.php b/src/Console/Commands/PruneExpired.php index b6ede50..db68d46 100644 --- a/src/Console/Commands/PruneExpired.php +++ b/src/Console/Commands/PruneExpired.php @@ -33,7 +33,11 @@ public function handle() $hours = $this->option('hours'); - $model::where('created_at', '<', now()->subMinutes($expiration + ($hours * 60)))->delete(); + $threshold = now()->subMinutes($expiration + ($hours * 60)); + + $model::where('created_at', '<', $threshold) + ->orWhere('expires_at', '<', $threshold) + ->delete(); $this->components->info("Tokens expired for more than [$hours hours] pruned successfully."); diff --git a/tests/PruneExpiredTest.php b/tests/PruneExpiredTest.php index e0e09e3..6c5f05f 100644 --- a/tests/PruneExpiredTest.php +++ b/tests/PruneExpiredTest.php @@ -94,6 +94,51 @@ public function test_cant_delete_expired_tokens_with_null_expiration() $this->assertDatabaseHas('personal_access_tokens', ['name' => 'Test']); } + public function test_can_delete_expired_tokens_with_expires_at_expiration() + { + $this->loadLaravelMigrations(['--database' => 'testbench']); + $this->artisan('migrate', ['--database' => 'testbench'])->run(); + + config(['sanctum.expiration' => 60]); + + $user = UserForPruneExpiredTest::forceCreate([ + 'name' => 'Taylor Otwell', + 'email' => 'taylor@laravel.com', + 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', + ]); + + $token_1 = PersonalAccessToken::forceCreate([ + 'tokenable_id' => $user->id, + 'tokenable_type' => get_class($user), + 'name' => 'Test_1', + 'token' => hash('sha256', 'test_1'), + 'expires_at' => now()->subMinutes(181), + ]); + + $token_2 = PersonalAccessToken::forceCreate([ + 'tokenable_id' => $user->id, + 'tokenable_type' => get_class($user), + 'name' => 'Test_2', + 'token' => hash('sha256', 'test_2'), + 'expires_at' => now()->subMinutes(179), + ]); + + $token_3 = PersonalAccessToken::forceCreate([ + 'tokenable_id' => $user->id, + 'tokenable_type' => get_class($user), + 'name' => 'Test_3', + 'token' => hash('sha256', 'test_3'), + 'expires_at' => now()->subMinutes(121), + ]); + + $this->artisan('sanctum:prune-expired --hours=2') + ->expectsOutputToContain('Tokens expired for more than [2 hours] pruned successfully.'); + + $this->assertDatabaseMissing('personal_access_tokens', ['name' => 'Test_1']); + $this->assertDatabaseHas('personal_access_tokens', ['name' => 'Test_2']); + $this->assertDatabaseHas('personal_access_tokens', ['name' => 'Test_3']); + } + protected function getPackageProviders($app) { return [SanctumServiceProvider::class]; From 8d6ca8a3e50cd05047e6a3c63743dce91268f661 Mon Sep 17 00:00:00 2001 From: Youri Wijnands Date: Thu, 28 Jul 2022 22:11:38 +0200 Subject: [PATCH 2/5] Fix missing test for when expires_at is null --- tests/PruneExpiredTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PruneExpiredTest.php b/tests/PruneExpiredTest.php index 6c5f05f..2101d17 100644 --- a/tests/PruneExpiredTest.php +++ b/tests/PruneExpiredTest.php @@ -128,7 +128,7 @@ public function test_can_delete_expired_tokens_with_expires_at_expiration() 'tokenable_type' => get_class($user), 'name' => 'Test_3', 'token' => hash('sha256', 'test_3'), - 'expires_at' => now()->subMinutes(121), + 'expires_at' => null, ]); $this->artisan('sanctum:prune-expired --hours=2') From 7f386c4517d349388bc2d36a8d994f2271bdc33f Mon Sep 17 00:00:00 2001 From: Youri Wijnands Date: Fri, 29 Jul 2022 15:01:21 +0200 Subject: [PATCH 3/5] Always prune by expires_at --- src/Console/Commands/PruneExpired.php | 28 ++++++++++++++------------- tests/PruneExpiredTest.php | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Console/Commands/PruneExpired.php b/src/Console/Commands/PruneExpired.php index db68d46..eeea752 100644 --- a/src/Console/Commands/PruneExpired.php +++ b/src/Console/Commands/PruneExpired.php @@ -28,24 +28,26 @@ class PruneExpired extends Command */ public function handle() { - if ($expiration = config('sanctum.expiration')) { - $model = Sanctum::$personalAccessTokenModel; - - $hours = $this->option('hours'); + $model = Sanctum::$personalAccessTokenModel; - $threshold = now()->subMinutes($expiration + ($hours * 60)); + $hours = $this->option('hours'); - $model::where('created_at', '<', $threshold) - ->orWhere('expires_at', '<', $threshold) - ->delete(); + $this->components->task( + 'Pruning tokens with expired expires_at timestamps', + fn() => $model::where('expires_at', '<', now()->subHours($hours))->delete() + ); - $this->components->info("Tokens expired for more than [$hours hours] pruned successfully."); - - return 0; + if ($expiration = config('sanctum.expiration')) { + $this->components->task( + 'Pruning tokens with expired expiration value', + fn() => $model::where('created_at', '<', now()->subMinutes($expiration + ($hours * 60)))->delete() + ); + } else { + $this->components->warn('Expiration value not specified in configuration file.'); } - $this->components->warn('Expiration value not specified in configuration file.'); + $this->components->info("Tokens expired for more than [$hours hours] pruned successfully."); - return 1; + return 0; } } diff --git a/tests/PruneExpiredTest.php b/tests/PruneExpiredTest.php index 2101d17..2c751c6 100644 --- a/tests/PruneExpiredTest.php +++ b/tests/PruneExpiredTest.php @@ -112,7 +112,7 @@ public function test_can_delete_expired_tokens_with_expires_at_expiration() 'tokenable_type' => get_class($user), 'name' => 'Test_1', 'token' => hash('sha256', 'test_1'), - 'expires_at' => now()->subMinutes(181), + 'expires_at' => now()->subMinutes(121), ]); $token_2 = PersonalAccessToken::forceCreate([ @@ -120,7 +120,7 @@ public function test_can_delete_expired_tokens_with_expires_at_expiration() 'tokenable_type' => get_class($user), 'name' => 'Test_2', 'token' => hash('sha256', 'test_2'), - 'expires_at' => now()->subMinutes(179), + 'expires_at' => now()->subMinutes(119), ]); $token_3 = PersonalAccessToken::forceCreate([ From f99ee78b8cdd368d9de59354eaff54f3aa823ff9 Mon Sep 17 00:00:00 2001 From: Youri Wijnands Date: Fri, 29 Jul 2022 15:23:52 +0200 Subject: [PATCH 4/5] StyleCI fixes --- src/Console/Commands/PruneExpired.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/Commands/PruneExpired.php b/src/Console/Commands/PruneExpired.php index eeea752..55c99f2 100644 --- a/src/Console/Commands/PruneExpired.php +++ b/src/Console/Commands/PruneExpired.php @@ -34,13 +34,13 @@ public function handle() $this->components->task( 'Pruning tokens with expired expires_at timestamps', - fn() => $model::where('expires_at', '<', now()->subHours($hours))->delete() + fn () => $model::where('expires_at', '<', now()->subHours($hours))->delete() ); if ($expiration = config('sanctum.expiration')) { $this->components->task( 'Pruning tokens with expired expiration value', - fn() => $model::where('created_at', '<', now()->subMinutes($expiration + ($hours * 60)))->delete() + fn () => $model::where('created_at', '<', now()->subMinutes($expiration + ($hours * 60)))->delete() ); } else { $this->components->warn('Expiration value not specified in configuration file.'); From 67211a2e13277d966f270c03567845372754909c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Jul 2022 10:41:38 -0500 Subject: [PATCH 5/5] formatting --- src/Console/Commands/PruneExpired.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Commands/PruneExpired.php b/src/Console/Commands/PruneExpired.php index 55c99f2..d358b45 100644 --- a/src/Console/Commands/PruneExpired.php +++ b/src/Console/Commands/PruneExpired.php @@ -39,7 +39,7 @@ public function handle() if ($expiration = config('sanctum.expiration')) { $this->components->task( - 'Pruning tokens with expired expiration value', + 'Pruning tokens with expired expiration value based on configuration file', fn () => $model::where('created_at', '<', now()->subMinutes($expiration + ($hours * 60)))->delete() ); } else {