From 1a59ec20e3a917b23d12663e49329ecce1ea8e88 Mon Sep 17 00:00:00 2001 From: chocolate-pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:34:46 +0900 Subject: [PATCH] Merge commit from fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Fix improper authorization in `admin/reset-password` * Apply suggestions from code review Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> * fix: improper authorization in `admin/unset-mfa` * fix --------- Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> --- .../server/api/endpoints/admin/reset-password.ts | 15 +++++++++------ .../src/server/api/endpoints/admin/unset-mfa.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index f19ffa173b..dc86768044 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -9,7 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { ApiError } from '@/server/api/error.js'; import type { UsersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; +import { RoleService } from '@/core/RoleService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { @@ -25,10 +27,10 @@ export const meta = { code: 'NO_SUCH_USER', id: 'ccafc7fe-5074-4edd-9dc0-8ef9ef6a701d', }, - cannotResetPasswordOfRootUser: { - message: 'Cannot reset password of the root user.', - code: 'CANNOT_RESET_PASSWORD_OF_ROOT_USER', - id: 'f28fc207-42ca-44c7-a577-44b4f0ec5999', + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: 'cda8f8ce-89a6-4f92-8055-33bbe0c1464d', }, }, @@ -66,6 +68,7 @@ export default class extends Endpoint { // eslint- @Inject(DI.userProfilesRepository) private userProfilesRepository: UserProfilesRepository, + private roleService: RoleService, private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { @@ -75,8 +78,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchUser); } - if (this.serverSettings.rootUserId === user.id) { - throw new ApiError(meta.errors.cannotResetPasswordOfRootUser); + if (await this.roleService.isAdministrator(user) && me.id !== user.id) { + throw new ApiError(meta.errors.accessDenied); } const passwd = secureRndstr(8); diff --git a/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts b/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts index 3d964825d3..75b3e3e2bf 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts @@ -11,6 +11,7 @@ import { MiUserProfile } from '@/models/UserProfile.js'; import { MiUserSecurityKey } from '@/models/UserSecurityKey.js'; import type { UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { RoleService } from '@/core/RoleService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { @@ -26,6 +27,11 @@ export const meta = { code: 'NO_SUCH_USER', id: 'ccafc7fe-5074-4edd-9dc0-8ef9ef6a701d', }, + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: 'cda8f8ce-89a6-4f92-8055-33bbe0c1464d', + }, }, } as const; @@ -46,6 +52,7 @@ export default class extends Endpoint { // eslint- @Inject(DI.usersRepository) private usersRepository: UsersRepository, + private roleService: RoleService, private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { @@ -55,6 +62,10 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchUser); } + if (await this.roleService.isAdministrator(user) && me.id !== user.id) { + throw new ApiError(meta.errors.accessDenied); + } + await this.db.transaction(async (transactionalEntityManager) => { // パスキーを全て削除 await transactionalEntityManager.delete(MiUserSecurityKey, { userId: user.id });