Skip to content

fix: answer a created public link with the hash that is its URL - #820

Merged
blaipr merged 1 commit into
mainfrom
fix/a-created-link-comes-back-with-its-url
Aug 18, 2026
Merged

fix: answer a created public link with the hash that is its URL#820
blaipr merged 1 commit into
mainfrom
fix/a-created-link-comes-back-with-its-url

Conversation

@blaipr

@blaipr blaipr commented Aug 18, 2026

Copy link
Copy Markdown
Member

account/viewLink/{hash} is the URL a public link hands out, and the service mints the hash — so an API caller creating a link got back only what they had sent, with hash: null, and could not hand out what they had just made.

The way round it was to fetch the link again with publicLink/view. That answers with data as well — the sealed vault — so working around the omission gave out more than reporting the hash does.

Account\CreateController and AuthToken\CreateController both already read the stored record back for this reason; the auth-token one carries a note about it, since a token a caller cannot read is a token that was not created. This is the same shape.

Cost

None. #812 already made this controller read the stored link back, for the expiry and the view limit it had been misreporting. This is one more field off an object already in hand.

What is deliberately still absent

data — the sealed vault — stays out of the response. Returning the whole stored model would have been the shorter change and would have handed the sealed payload to a token scoped only to PUBLICLINK_CREATE. The test asserts data is null as well as asserting the hash is present, so the response cannot quietly widen later.

Test

One test, asserting both directions: the hash comes back, it is the one the row is stored under, and data does not. Removing the field fails it with Failed asserting that a NULL is not empty.

3967 unit tests pass; PHPStan level 6 on src and PHPCS clean.

`account/viewLink/{hash}` is the URL a public link hands out, and the service
mints the hash — so an API caller creating a link got back only what they had
sent, with `hash: null`, and could not hand out what they had just made.

The way round it was to fetch the link again with `publicLink/view`, which
answers with `data` as well — the sealed vault — so working around the omission
gave out more than reporting the hash does.

It costs nothing: the controller already reads the stored link back for the
expiry and the view limit it had been misreporting, so this is one more field
off an object already in hand. `Account\CreateController` and
`AuthToken\CreateController` both read their record back for the same reason.

`data` stays out. Returning the whole stored model would have been the shorter
change and would have handed the sealed payload to a token scoped only to
PUBLICLINK_CREATE, so the test asserts `data` is null alongside asserting the
hash is present, and the response cannot quietly widen later.
@blaipr
blaipr merged commit 30810c3 into main Aug 18, 2026
13 of 16 checks passed
@blaipr
blaipr deleted the fix/a-created-link-comes-back-with-its-url branch August 18, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant