diff --git a/app/Http/Controllers/Admin/TokensController.php b/app/Http/Controllers/Admin/TokensController.php new file mode 100644 index 00000000..1b5348f9 --- /dev/null +++ b/app/Http/Controllers/Admin/TokensController.php @@ -0,0 +1,33 @@ +get(); + + return view('admin.tokens.index', compact('tokens')); + } + + /** + * Revoke a Micropub token. + */ + public function revoke(MicropubToken $token): RedirectResponse + { + $token->revoke(); + + return redirect('/admin/tokens'); + } +} diff --git a/resources/views/admin/tokens/index.blade.php b/resources/views/admin/tokens/index.blade.php new file mode 100644 index 00000000..cb7edda9 --- /dev/null +++ b/resources/views/admin/tokens/index.blade.php @@ -0,0 +1,27 @@ +@extends('master') + +@section('title')List Tokens « Admin CP « @stop + +@section('content') +
No tokens have been issued.
+ @else ++ View and revoke issued Micropub tokens. +
+Edit your bio. diff --git a/routes/web.php b/routes/web.php index fbba6329..e8924f32 100644 --- a/routes/web.php +++ b/routes/web.php @@ -10,6 +10,7 @@ use App\Http\Controllers\Admin\NotesController as AdminNotesController; use App\Http\Controllers\Admin\PasskeysController; use App\Http\Controllers\Admin\PlacesController as AdminPlacesController; use App\Http\Controllers\Admin\SyndicationTargetsController; +use App\Http\Controllers\Admin\TokensController; use App\Http\Controllers\ArticlesController; use App\Http\Controllers\AuthController; use App\Http\Controllers\BookmarksController; @@ -147,6 +148,12 @@ Route::middleware(MyAuthMiddleware::class)->prefix('admin')->group(function () { Route::delete('/{clientId}', [ClientsController::class, 'destroy']); }); + // Micropub Tokens + Route::prefix('tokens')->group(function () { + Route::get('/', [TokensController::class, 'index']); + Route::put('/{token}/revoke', [TokensController::class, 'revoke']); + }); + // Bio Route::prefix('bio')->group(function () { Route::get('/', [BioController::class, 'show'])->name('admin.bio.show'); diff --git a/tests/Feature/Admin/TokensTest.php b/tests/Feature/Admin/TokensTest.php new file mode 100644 index 00000000..0c415296 --- /dev/null +++ b/tests/Feature/Admin/TokensTest.php @@ -0,0 +1,87 @@ +get('/admin/tokens'); + $response->assertRedirect(); + } + + #[Test] + public function index_lists_issued_tokens(): void + { + $user = User::factory()->make(); + $token = MicropubToken::create([ + 'token_hash' => hash('sha256', 'a-token'), + 'client_id' => 'https://quill.p3k.io', + 'me' => 'https://jonnybarnes.uk', + 'scope' => 'create update', + ]); + + $response = $this->actingAs($user)->get('/admin/tokens'); + $response->assertOk(); + $response->assertSeeText($token->client_id); + } + + #[Test] + public function revoke_requires_authentication(): void + { + $token = MicropubToken::create([ + 'token_hash' => hash('sha256', 'a-token'), + 'client_id' => 'https://quill.p3k.io', + 'me' => 'https://jonnybarnes.uk', + 'scope' => 'create', + ]); + + $response = $this->put("/admin/tokens/{$token->id}/revoke"); + $response->assertRedirect(); + + $this->assertFalse($token->fresh()->isRevoked); + } + + #[Test] + public function revoke_marks_the_token_as_revoked(): void + { + $user = User::factory()->make(); + $token = MicropubToken::create([ + 'token_hash' => hash('sha256', 'a-token'), + 'client_id' => 'https://quill.p3k.io', + 'me' => 'https://jonnybarnes.uk', + 'scope' => 'create', + ]); + + $this->actingAs($user)->put("/admin/tokens/{$token->id}/revoke"); + + $this->assertTrue($token->fresh()->isRevoked); + } + + #[Test] + public function revoke_redirects_to_index(): void + { + $user = User::factory()->make(); + $token = MicropubToken::create([ + 'token_hash' => hash('sha256', 'a-token'), + 'client_id' => 'https://quill.p3k.io', + 'me' => 'https://jonnybarnes.uk', + 'scope' => 'create', + ]); + + $response = $this->actingAs($user)->put("/admin/tokens/{$token->id}/revoke"); + + $response->assertRedirect('/admin/tokens'); + } +}