fix(auth): allow admins to change any username including their own
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / ts / ts (packages + web) (push) Successful in 2m59s
ci / api / api (push) Successful in 49s
ci / db / db (push) Successful in 1m17s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m25s

This commit is contained in:
mrleo1nid committed 2026-10-21 17:33:19 +03:00
1 parent b0cbd0f149
commit c34272d508
16 files changed
+431 -266

No files matched your search

+3
View File
@@ -2298,6 +2298,9 @@ components:
UpdateUserRequest: UpdateUserRequest:
type: object type: object
properties: properties:
username:
type: string
description: Новый логин. Может менять только администратор, в том числе у себя
display_name: display_name:
type: string type: string
maxLength: 64 maxLength: 64
+33
View File
@@ -154,6 +154,39 @@ describe('users admin', () => {
expect(await within(table).findByText('@ilya')).toBeInTheDocument(); expect(await within(table).findByText('@ilya')).toBeInTheDocument();
}); });
it.each(['root', 'anna'])('lets admins change the username of %s', async (target) => {
const root = makeUser('root', 'admin');
const anna = makeUser('anna', 'user');
const { user, api, session } = await renderApp([root, anna], '/admin/users', { signedInAs: root });
await user.click(await screen.findByRole('button', { name: `Действия с ${target}` }));
await user.click(screen.getByRole('menuitem', { name: 'Изменить логин' }));
const dialog = screen.getByRole('dialog', { name: 'Изменить логин' });
const input = within(dialog).getByLabelText('Логин');
await user.clear(input);
await user.type(input, `new.${target}`);
await user.click(within(dialog).getByRole('button', { name: 'Сохранить' }));
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
expect(await screen.findByText(`@new.${target}`)).toBeInTheDocument();
expect(api.users.get(target === 'root' ? root.id : anna.id)?.username).toBe(`new.${target}`);
if (target === 'root') expect(session.state).toMatchObject({ status: 'signed_in', user: { username: 'new.root' } });
});
it('keeps the username dialog open when the new username is taken', async () => {
const root = makeUser('root', 'admin');
const anna = makeUser('anna', 'user');
const { user, api } = await renderApp([root, anna], '/admin/users', { signedInAs: root });
await user.click(await screen.findByRole('button', { name: 'Действия с anna' }));
await user.click(screen.getByRole('menuitem', { name: 'Изменить логин' }));
const dialog = screen.getByRole('dialog', { name: 'Изменить логин' });
const input = within(dialog).getByLabelText('Логин');
await user.clear(input);
await user.type(input, 'ROOT');
await user.click(within(dialog).getByRole('button', { name: 'Сохранить' }));
await waitFor(() => expect(input).toHaveAttribute('aria-invalid', 'true'));
expect(api.users.get(anna.id)?.username).toBe('anna');
expect(dialog).toBeInTheDocument();
});
it('offers moderators only what they may do', async () => { it('offers moderators only what they may do', async () => {
const mod = makeUser('mod', 'moderator'); const mod = makeUser('mod', 'moderator');
const anna = makeUser('anna', 'user'); const anna = makeUser('anna', 'user');
+1
View File
@@ -15,6 +15,7 @@ type Entry = components['schemas']['AuditEntry'];
function details(e: Entry, roleName: (r: string) => string): string { function details(e: Entry, roleName: (r: string) => string): string {
const p = e.payload ?? {}; const p = e.payload ?? {};
if (e.action === 'user.role_change') return `${roleName(String(p.from))} → ${roleName(String(p.to))}`; if (e.action === 'user.role_change') return `${roleName(String(p.from))} → ${roleName(String(p.to))}`;
if (e.action === 'user.username_change') return `${String(p.from)} → ${String(p.to)}`;
const parts = [p.username, p.role && roleName(String(p.role)), p.display_name].filter( const parts = [p.username, p.role && roleName(String(p.role)), p.display_name].filter(
(v): v is string => typeof v === 'string' && v !== '', (v): v is string => typeof v === 'string' && v !== '',
); );
+49
View File
@@ -46,6 +46,7 @@ export function UsersPage() {
const [role, setRole] = useState<Role | null>(null); const [role, setRole] = useState<Role | null>(null);
const query = useDebounced(q.trim(), 200); const query = useDebounced(q.trim(), 200);
const [creating, setCreating] = useState(false); const [creating, setCreating] = useState(false);
const [renaming, setRenaming] = useState<AdminUser | null>(null);
const [confirm, setConfirm] = useState<Confirm | null>(null); const [confirm, setConfirm] = useState<Confirm | null>(null);
const [secret, setSecret] = useState<{ username: string; password: string } | null>(null); const [secret, setSecret] = useState<{ username: string; password: string } | null>(null);
const [actionError, setActionError] = useState<unknown>(null); const [actionError, setActionError] = useState<unknown>(null);
@@ -112,6 +113,8 @@ export function UsersPage() {
const actionsFor = (u: AdminUser): MenuItem[] => { const actionsFor = (u: AdminUser): MenuItem[] => {
const items: MenuItem[] = []; const items: MenuItem[] = [];
const can = (a: Parameters<typeof canManageUser>[2]) => canManageUser(me, u, a); const can = (a: Parameters<typeof canManageUser>[2]) => canManageUser(me, u, a);
if (me.role === 'admin')
items.push({ label: t('users.change_username'), onSelect: () => setRenaming(u) });
if (can('reset_password')) if (can('reset_password'))
items.push({ label: t('users.reset_password'), icon: lockResetIcon, onSelect: () => setConfirm({ kind: 'reset', user: u }) }); items.push({ label: t('users.reset_password'), icon: lockResetIcon, onSelect: () => setConfirm({ kind: 'reset', user: u }) });
if (can('reset_recommendations')) if (can('reset_recommendations'))
@@ -250,6 +253,18 @@ export function UsersPage() {
/> />
)} )}
{renaming && (
<ChangeUsernameDialog
user={renaming}
onClose={() => setRenaming(null)}
onSaved={async (updated) => {
if (updated.id === me.id) session.setUser({ ...me, username: updated.username });
setRenaming(null);
await refresh();
}}
/>
)}
{confirm && ( {confirm && (
<Dialog <Dialog
title={t(`users.${TITLES[confirm.kind]}`)} title={t(`users.${TITLES[confirm.kind]}`)}
@@ -368,6 +383,40 @@ function CreateUserDialog({
); );
} }
function ChangeUsernameDialog({ user, onClose, onSaved }: {
user: AdminUser;
onClose: () => void;
onSaved: (user: AdminUser) => Promise<void>;
}) {
const { t } = useTranslation(['admin', 'common']);
const session = useSession();
const errorText = useErrorText();
const fieldError = useFieldError();
const [username, setUsername] = useState(user.username);
const save = useMutation({
mutationFn: async () => unwrap(await session.client.PATCH('/api/v1/admin/users/{id}', {
params: { path: { id: user.id } }, body: { username: username.trim() },
})),
onSuccess: onSaved,
});
const error = fieldError(save.error, 'username');
return (
<Dialog title={t('users.change_username')} onClose={onClose} footer={
<>
<Button variant="ghost" onClick={onClose}>{t('common:form.cancel')}</Button>
<Button type="submit" form="change-username" variant="primary" busy={save.isPending}
disabled={!username.trim() || username.trim() === user.username}>{t('common:settings.save')}</Button>
</>
}>
<form id="change-username" className={s.sessions} noValidate onSubmit={(e) => { e.preventDefault(); save.mutate(); }}>
<Field label={t('create.username')} value={username} onChange={setUsername} autoCapitalize="none"
spellCheck={false} hint={t('create.username_hint')} error={error} mono />
<FormError>{save.error && !error ? errorText(save.error) : null}</FormError>
</form>
</Dialog>
);
}
function TemporaryPasswordDialog({ username, password, onClose }: { username: string; password: string; onClose: () => void }) { function TemporaryPasswordDialog({ username, password, onClose }: { username: string; password: string; onClose: () => void }) {
const { t } = useTranslation(['admin', 'common']); const { t } = useTranslation(['admin', 'common']);
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
+7
View File
@@ -243,6 +243,13 @@ export function fakeApi(initial: FakeUser[]) {
if (!user || user.role === 'user') return problem(403, 'auth.forbidden'); if (!user || user.role === 'user') return problem(403, 'auth.forbidden');
const target = users.get(userPath[1]!); const target = users.get(userPath[1]!);
if (!target) return problem(404, 'common.not_found'); if (!target) return problem(404, 'common.not_found');
if (typeof body?.username === 'string') {
if (user.role !== 'admin') return problem(403, 'auth.forbidden');
const username = body.username.trim().toLowerCase();
if ([...users.values()].some((u) => u.id !== target.id && u.username.toLowerCase() === username))
return problem(422, 'auth.username_taken', { errors: [{ field: 'username', code: 'auth.username_taken' }] });
target.username = username;
}
if (typeof body?.reviews_uploads === 'boolean') { if (typeof body?.reviews_uploads === 'boolean') {
if (user.role !== 'admin') return problem(403, 'auth.forbidden'); if (user.role !== 'admin') return problem(403, 'auth.forbidden');
target.reviews_uploads = body.reviews_uploads; target.reviews_uploads = body.reviews_uploads;
+1
View File
@@ -19,6 +19,7 @@
| Создать пользователя с ролью `user` | — | ✅ | ✅ | | Создать пользователя с ролью `user` | — | ✅ | ✅ |
| Сбросить пароль / рекомендации, заблокировать `user` | — | ✅ | ✅ | | Сбросить пароль / рекомендации, заблокировать `user` | — | ✅ | ✅ |
| Создать `moderator` / `admin`, менять роли | — | — | ✅ | | Создать `moderator` / `admin`, менять роли | — | — | ✅ |
| Менять логин любого пользователя, включая себя | — | — | ✅ |
| Сбросить пароль / рекомендации, заблокировать `moderator` | — | — | ✅ | | Сбросить пароль / рекомендации, заблокировать `moderator` | — | — | ✅ |
| Удалить пользователя | — | — | ✅ | | Удалить пользователя | — | — | ✅ |
| Хранилища, сканирование, переиндексация | — | — | ✅ | | Хранилища, сканирование, переиндексация | — | — | ✅ |
@@ -1705,6 +1705,8 @@ export interface components {
temporary_password: string; temporary_password: string;
}; };
UpdateUserRequest: { UpdateUserRequest: {
/** @description Новый логин. Может менять только администратор, в том числе у себя */
username?: string;
/** @description Пустая строка — сбросить имя */ /** @description Пустая строка — сбросить имя */
display_name?: string; display_name?: string;
role?: components["schemas"]["Role"]; role?: components["schemas"]["Role"];
+2
View File
@@ -1,5 +1,6 @@
{ {
"users": { "users": {
"change_username": "Change username",
"title": "Users", "title": "Users",
"subtitle": "Create users and moderators, manage roles, upload review, reset passwords, block accounts", "subtitle": "Create users and moderators, manage roles, upload review, reset passwords, block accounts",
"create": "Create user", "create": "Create user",
@@ -60,6 +61,7 @@
"empty": "No entries yet", "empty": "No entries yet",
"more": "Show more", "more": "Show more",
"actions": { "actions": {
"user.username_change": "Username changed",
"user.bootstrap_create": "Initial administrator created", "user.bootstrap_create": "Initial administrator created",
"user.bootstrap_credentials": "Administrator credentials set", "user.bootstrap_credentials": "Administrator credentials set",
"user.create": "User created", "user.create": "User created",
+2
View File
@@ -1,5 +1,6 @@
{ {
"users": { "users": {
"change_username": "Изменить логин",
"title": "Пользователи", "title": "Пользователи",
"subtitle": "Создание пользователей и модераторов, роли, аудит загрузок, сброс пароля, блокировка", "subtitle": "Создание пользователей и модераторов, роли, аудит загрузок, сброс пароля, блокировка",
"create": "Создать пользователя", "create": "Создать пользователя",
@@ -60,6 +61,7 @@
"empty": "Записей пока нет", "empty": "Записей пока нет",
"more": "Показать ещё", "more": "Показать ещё",
"actions": { "actions": {
"user.username_change": "Изменён логин",
"user.bootstrap_create": "Создан стартовый администратор", "user.bootstrap_create": "Создан стартовый администратор",
"user.bootstrap_credentials": "Заданы учётные данные администратора", "user.bootstrap_credentials": "Заданы учётные данные администратора",
"user.create": "Создан пользователь", "user.create": "Создан пользователь",
+265 -262
View File
@@ -975,6 +975,9 @@ type UpdateUserRequest struct {
// ReviewsUploads Выдать или забрать аудит загрузок. Может менять только админ, в том числе у себя // ReviewsUploads Выдать или забрать аудит загрузок. Может менять только админ, в том числе у себя
ReviewsUploads *bool `json:"reviews_uploads,omitempty"` ReviewsUploads *bool `json:"reviews_uploads,omitempty"`
Role *Role `json:"role,omitempty"` Role *Role `json:"role,omitempty"`
// Username Новый логин. Может менять только администратор, в том числе у себя
Username *string `json:"username,omitempty"`
} }
// UploadBatchCreated defines model for UploadBatchCreated. // UploadBatchCreated defines model for UploadBatchCreated.
@@ -9801,268 +9804,268 @@ func (sh *strictHandler) GetReadyz(w http.ResponseWriter, r *http.Request) {
// Base64 encoded, gzipped, json marshaled Swagger object // Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{ var swaggerSpec = []string{
"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",
"AQA=", "+/8/AAD//8MLYPW0UQEA",
} }
// GetSwagger returns the content of the embedded swagger specification file // GetSwagger returns the content of the embedded swagger specification file
+18 -1
View File
@@ -150,13 +150,14 @@ func displayName(s string) (*string, error) {
// UserPatch — изменения пользователя из админки. nil — не менять. // UserPatch — изменения пользователя из админки. nil — не менять.
type UserPatch struct { type UserPatch struct {
Username *string
DisplayName *string DisplayName *string
Role *Role Role *Role
IsBlocked *bool IsBlocked *bool
ReviewsUploads *bool ReviewsUploads *bool
} }
// UpdateUser меняет имя, роль и блокировку с проверкой прав по каждому изменению. // UpdateUser меняет логин, имя, роль и блокировку с проверкой прав по каждому изменению.
func (s *Service) UpdateUser(ctx context.Context, p Principal, id uuid.UUID, patch UserPatch) (User, error) { func (s *Service) UpdateUser(ctx context.Context, p Principal, id uuid.UUID, patch UserPatch) (User, error) {
if patch.Role != nil && !patch.Role.Valid() { if patch.Role != nil && !patch.Role.Valid() {
return User{}, apperr.Validation("role", CodeRoleInvalid, "unknown role", nil) return User{}, apperr.Validation("role", CodeRoleInvalid, "unknown role", nil)
@@ -178,6 +179,19 @@ func (s *Service) UpdateUser(ctx context.Context, p Principal, id uuid.UUID, pat
}) })
} }
if patch.Username != nil {
if p.Role != RoleAdmin {
return forbidden()
}
username := NormalizeUsername(*patch.Username)
if err := ValidateUsername("username", username); err != nil {
return err
}
if username != target.Username {
upd.Username = &username
audit("user.username_change", map[string]any{"from": target.Username, "to": username})
}
}
if patch.DisplayName != nil { if patch.DisplayName != nil {
if !CanManageUser(actor, tgt, UserEdit) { if !CanManageUser(actor, tgt, UserEdit) {
return forbidden() return forbidden()
@@ -247,6 +261,9 @@ func (s *Service) UpdateUser(ctx context.Context, p Principal, id uuid.UUID, pat
} }
return nil return nil
}) })
if errors.Is(err, ErrUsernameTaken) {
return User{}, apperr.Validation("username", CodeUsernameTaken, "username is taken", nil)
}
return out, err return out, err
} }
+1 -1
View File
@@ -63,7 +63,7 @@ func (h *Handler) UpdateUser(ctx context.Context, req gen.UpdateUserRequestObjec
if err != nil { if err != nil {
return nil, err return nil, err
} }
patch := UserPatch{DisplayName: req.Body.DisplayName, IsBlocked: req.Body.IsBlocked, ReviewsUploads: req.Body.ReviewsUploads} patch := UserPatch{Username: req.Body.Username, DisplayName: req.Body.DisplayName, IsBlocked: req.Body.IsBlocked, ReviewsUploads: req.Body.ReviewsUploads}
if req.Body.Role != nil { if req.Body.Role != nil {
r := Role(*req.Body.Role) r := Role(*req.Body.Role)
patch.Role = &r patch.Role = &r
+28
View File
@@ -76,6 +76,34 @@ func TestAdminCreatesModeratorWhoCreatesUser(t *testing.T) {
assert.Equal(t, auth.CodeForbidden, e.createUser(listener, "another", "user").code()) assert.Equal(t, auth.CodeForbidden, e.createUser(listener, "another", "user").code())
} }
func TestAdminChangesUsername(t *testing.T) {
e := newEnv(t)
root := e.addUser("root", "root-password-1", auth.RoleAdmin)
listener := e.addUser("listener", "listener-password-1", auth.RoleUser)
mod := e.addUser("mod", "mod-password-1", auth.RoleModerator)
tok := e.signIn("root", "root-password-1")
patch := func(token string, id uuid.UUID, username string) resp {
return e.do(http.MethodPatch, "/api/v1/admin/users/"+id.String(), map[string]any{"username": username}, bearer(token))
}
for _, target := range []auth.User{listener, mod, root} {
r := patch(tok, target.ID, " NEW."+target.Username+" ")
require.Equal(t, http.StatusOK, r.Code, r.Body.String())
assert.Equal(t, "new."+target.Username, r.body["username"])
assert.Equal(t, "user.username_change", e.store.Audit[len(e.store.Audit)-1].Action)
assert.Equal(t, http.StatusOK, e.login("new."+target.Username, map[uuid.UUID]string{
root.ID: "root-password-1", listener.ID: "listener-password-1", mod.ID: "mod-password-1",
}[target.ID], "web").Code)
}
assert.Equal(t, http.StatusOK, e.do(http.MethodGet, "/api/v1/me", nil, bearer(tok)).Code, "own rename preserves session")
assert.Equal(t, auth.CodeUsernameTaken, patch(tok, listener.ID, "NEW.ROOT").code())
assert.Equal(t, auth.CodeUsernameInvalid, patch(tok, listener.ID, "invalid space").code())
assert.Equal(t, auth.CodeUsernameInvalid, patch(tok, listener.ID, "").code())
assert.Equal(t, "new.listener", e.store.Users[listener.ID].Username)
modTok := e.signIn("new.mod", "mod-password-1")
assert.Equal(t, auth.CodeForbidden, patch(modTok, listener.ID, "forbidden").code())
assert.Equal(t, auth.CodeForbidden, patch(modTok, mod.ID, "forbidden").code())
}
func TestCreateUserValidation(t *testing.T) { func TestCreateUserValidation(t *testing.T) {
e := newEnv(t) e := newEnv(t)
e.addUser("root", "root-password-1", auth.RoleAdmin) e.addUser("root", "root-password-1", auth.RoleAdmin)
@@ -293,7 +293,18 @@ func (s *MemStore) LockActiveAdmins(ctx context.Context) (int, error) { return s
// UpdateUser реализует auth.Store. // UpdateUser реализует auth.Store.
func (s *MemStore) UpdateUser(ctx context.Context, id uuid.UUID, upd auth.UserUpdate) (auth.User, error) { func (s *MemStore) UpdateUser(ctx context.Context, id uuid.UUID, upd auth.UserUpdate) (auth.User, error) {
if upd.Username != nil {
unlock := s.lock()
taken := s.usernameTaken(*upd.Username, id)
unlock()
if taken {
return auth.User{}, auth.ErrUsernameTaken
}
}
err := s.update(id, func(u *auth.User) { err := s.update(id, func(u *auth.User) {
if upd.Username != nil {
u.Username = *upd.Username
}
if upd.DisplayName != nil { if upd.DisplayName != nil {
u.DisplayName = *upd.DisplayName u.DisplayName = *upd.DisplayName
} }
+7 -2
View File
@@ -340,8 +340,9 @@ func (s *PgStore) UpdateUser(ctx context.Context, id uuid.UUID, upd UserUpdate)
r := string(*upd.Role) r := string(*upd.Role)
role = &r role = &r
} }
return scanUser(s.q.QueryRow(ctx, ` u, err := scanUser(s.q.QueryRow(ctx, `
UPDATE users SET UPDATE users SET
username = COALESCE($8, username),
display_name = CASE WHEN $2 THEN $3 ELSE display_name END, display_name = CASE WHEN $2 THEN $3 ELSE display_name END,
role = COALESCE($4::user_role, role), role = COALESCE($4::user_role, role),
is_blocked = COALESCE($5, is_blocked), is_blocked = COALESCE($5, is_blocked),
@@ -349,7 +350,11 @@ func (s *PgStore) UpdateUser(ctx context.Context, id uuid.UUID, upd UserUpdate)
token_version = token_version + CASE WHEN $6 THEN 1 ELSE 0 END, token_version = token_version + CASE WHEN $6 THEN 1 ELSE 0 END,
updated_at = now() updated_at = now()
WHERE id = $1 WHERE id = $1
RETURNING `+userColumns, id, setName, name, role, upd.IsBlocked, upd.RevokeTokens, upd.ReviewsUploads)) RETURNING `+userColumns, id, setName, name, role, upd.IsBlocked, upd.RevokeTokens, upd.ReviewsUploads, upd.Username))
if isUniqueViolation(err) {
return User{}, ErrUsernameTaken
}
return u, err
} }
// ResetPassword реализует Store. // ResetPassword реализует Store.
+1
View File
@@ -31,6 +31,7 @@ type UserFilter struct {
// UserUpdate — изменения из админки. nil — не менять. // UserUpdate — изменения из админки. nil — не менять.
type UserUpdate struct { type UserUpdate struct {
Username *string
DisplayName **string DisplayName **string
Role *Role Role *Role
IsBlocked *bool IsBlocked *bool