You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 67feb73
Browse filesBrowse the repository at this point in the historyBrowse files
refactor(speaker): scope a request by the tenant it declares, not by an id prefix
A speaker id was minted as `user_{tenant}_...` in three unrelated places, and
the WebUI treated that prefix as access control:
const userPrefix = `user_${user.id}_`
if (!speakerId.startsWith(userPrefix)) {
alert('You can only delete your own speakers.')
Deciding permission by string-matching a naming convention only holds while the
convention does. It already did not: moving the tenant to Chronicle's user id
left all 51 live speakers with ids reading `user_1_` and an owner of
`69b80e5894aa9ec334a421c9`, so the Speakers page filtered its own gallery down
to nothing and every delete was refused.
Ids are now opaque (`speaker_{uuid}`) and ownership is only ever
`speakers.user_id`. The three by-id endpoints plus `/enroll/append` take the
tenant the caller is acting for and 404 on a mismatch — 404 rather than 403 so
a refusal does not confirm the speaker exists. The service still has no caller
authentication, so this bounds mistakes, not attackers; the WebUI's alert
claimed a guarantee that was never enforced anywhere.
Existing ids keep their prefix. It is inert now, and renaming them would have
to move on-disk enrollment/quarantine directories, relative paths stored in
`speaker_audio_segments`, per-speaker manifests, and denormalized copies in
four Mongo collections plus `User.wakeword_allowed_speakers` — where a missed
rewrite silently disables the wake-word gate rather than failing.
The WebUI can no longer mint a tenant from a typed username: this service
cannot invent a Chronicle user id, so the selector only picks among tenants
that already have speaker data.
0 commit comments