jonnybarnes.uk/app/Services/Micropub/Handlers/EntryHandler.php
Jonny Barnes faf8e5c1ec
Fix CSRF exemption and array-input crash on revocation/introspection
An Opus code review of the branch caught two real bugs the test suite
structurally couldn't see:

- /revocation and /introspect were never added to bootstrap/app.php's
  CSRF except list, so both were fully broken (403) for any real
  external client, despite every feature test passing — CSRF
  verification is short-circuited entirely while running tests.
  Verified live against the running app before and after the fix, and
  added a regression test that asserts against the actual configured
  exemptions rather than relying on request-time behavior that tests
  can't exercise.

- An array-shaped `token` param (e.g. token[]=a&token[]=b) crashed
  both endpoints with a 500, since this app promotes PHP warnings
  ("Array to string conversion") to exceptions. Fixed at the shared
  root, MicropubToken::findActive(), which also closes the same latent
  hole in VerifyMicropubToken's access_token param that predates this
  branch. Verified live and covered with regression tests.

Also applied the review's lower-severity findings: added the missing
introspection_endpoint Link header and metadata test assertions,
removed the now-dead is_string($scopes) array branch in the Micropub
handlers and media controller (scope is unconditionally a string from
the DB now, this guarded against a JWT-array-claim shape that can no
longer occur), dropped a redundant #[Table] model attribute, sized
token_hash to its actual 64-char length, and removed a one-off inline
style in the admin view.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014625MfkGZ7GVdbqKme4a8L
2026-08-13 17:03:43 +01:00

49 lines
1.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Micropub\Handlers;
use App\Exceptions\InvalidTokenScopeException;
use App\Services\ArticleService;
use App\Services\BookmarkService;
use App\Services\LikeService;
use App\Services\Micropub\Data\EntryData;
use App\Services\Micropub\Data\MicropubData;
use App\Services\NoteService;
class EntryHandler implements MicropubHandlerInterface
{
public function dataClass(): string
{
return EntryData::class;
}
/**
* @throws InvalidTokenScopeException
*/
public function handle(MicropubData $data): array
{
assert($data instanceof EntryData);
$scopes = $data->tokenData['scope'];
$scopes = explode(' ', $scopes);
if (! in_array('create', $scopes, true)) {
throw new InvalidTokenScopeException;
}
$dataArray = $data->toArray();
$location = match (true) {
isset($dataArray['like-of']) => resolve(LikeService::class)->create($dataArray)->url,
isset($dataArray['bookmark-of']) => resolve(BookmarkService::class)->create($dataArray)->uri,
isset($dataArray['name']) => resolve(ArticleService::class)->create($dataArray)->link,
default => resolve(NoteService::class)->create($dataArray)->uri,
};
return [
'response' => 'created',
'url' => $location,
];
}
}