Add Micropub q=source and reject malformed requests

Servers supporting updates must support the source content query. It
was falling through to the token response, so clients got a 200 with no
post in it. Return the raw note as microformats2 JSON, honouring
properties[].

Malformed requests could cause a 500 or worse. A replace value sent as a
string overwrote the note with its first character, because $value[0]
indexes the string. Validate update operations before applying any of
them, and return invalid_request for wrongly shaped properties, unknown
or malformed q values, and missing update URLs.

Share URL resolution between updates and q=source in NoteResolver, which
also rejects URLs on other hosts and invalid note IDs. Those IDs used to
decode to a real note because invalid characters were skipped.

Allow photo objects without alt text, and parse the published date
before saving so that an invalid date doesn't leave a stray note behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jonny Barnes 2026-11-02 18:59:23 +00:00
commit 3dce7d3a60
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8

View file

@ -30,6 +30,9 @@ class NoteService
$content = null;
}
// an invalid date throws, so parse it before anything is saved
$published = $this->getPublished($data);
$note = Note::create(
[
'note' => $content,
@ -38,7 +41,7 @@ class NoteService
]
);
if ($published = $this->getPublished($data)) {
if ($published !== null) {
$note->created_at = $note->updated_at = $published;
}
@ -205,11 +208,11 @@ class NoteService
if (is_string($photo)) {
$photoUrl = $photo;
} elseif (is_array($photo)) {
$photoUrl = $photo['value'];
$photoAlt = $photo['alt'];
$photoUrl = $photo['value'] ?? null;
$photoAlt = is_string($photo['alt'] ?? null) ? $photo['alt'] : null;
}
if (empty($photoUrl)) {
if (! is_string($photoUrl) || $photoUrl === '') {
continue;
}