admin: bypass the reserved-username blocklist at write time too

UpdateUsernameAdmin already skipped the reserved-word check in the
availability lookup, but UserStore.UpdateUsername's own write path
(replacePeerUsernameTx / CollectibleUsernameStore.SetEditableUsername)
enforces the same operator blocklist a second time, independently and
unconditionally. That second check is what was still rejecting an admin
handing out a word they'd deliberately reserved, with "username occupied".

Add UpdateUsernameAdmin/SetEditableUsernameAdmin bypass variants down the
write path (postgres and memory) and route users.Service's actual write
through them when the availability check was already bypassed.
This commit is contained in:
Astra 2026-09-15 16:22:00 +01:00
parent 53872f8fc9
commit ea17d7da0d
6 changed files with 180 additions and 15 deletions

View file

@ -105,7 +105,18 @@ func NewCollectibleUsernameStore() *CollectibleUsernameStore {
// usernames on the user and channel rows, so tests need this hook to give a peer
// the editable registry row the projection expects. An empty username clears the
// slot.
func (s *CollectibleUsernameStore) SetEditableUsername(_ context.Context, peer domain.Peer, username string) (bool, error) {
func (s *CollectibleUsernameStore) SetEditableUsername(ctx context.Context, peer domain.Peer, username string) (bool, error) {
return s.setEditableUsernameChecked(ctx, peer, username, true)
}
// SetEditableUsernameAdmin is SetEditableUsername without the operator
// reserved-username blocklist check, for the admin console deliberately
// assigning a reserved word to a specific account.
func (s *CollectibleUsernameStore) SetEditableUsernameAdmin(ctx context.Context, peer domain.Peer, username string) (bool, error) {
return s.setEditableUsernameChecked(ctx, peer, username, false)
}
func (s *CollectibleUsernameStore) setEditableUsernameChecked(_ context.Context, peer domain.Peer, username string, checkReserved bool) (bool, error) {
if !validCollectibleUsernamePeer(peer) {
return false, domain.ErrUsernameInvalid
}
@ -121,7 +132,7 @@ func (s *CollectibleUsernameStore) SetEditableUsername(_ context.Context, peer d
return false, domain.ErrUsernameInvalid
}
key := strings.ToLower(username)
if s.nameReserved(key) {
if checkReserved && s.nameReserved(key) {
return false, domain.ErrUsernameOccupied
}
if existing, ok := s.registry[key]; ok {