feat(policies): account removal policy

This commit is contained in:
무라쿠모 2024-05-11 21:55:40 +09:00
parent fdb49bc2e4
commit 0ec6a0fbfb
No known key found for this signature in database
GPG key ID: 139D6573F92DA9F7
9 changed files with 45 additions and 10 deletions

View file

@ -8,6 +8,7 @@ import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DeleteAccountService } from '@/core/DeleteAccountService.js';
import { RoleService } from '@/core/RoleService.js';
import { DI } from '@/di-symbols.js';
import { UserAuthService } from '@/core/UserAuthService.js';
import { ApiError } from '@/server/api/error.js';
@ -18,17 +19,21 @@ export const meta = {
secure: true,
errors: {
incorrectPassword: {
message: 'Incorrect password.',
code: 'INCORRECT_PASSWORD',
id: '44326b04-08ea-4525-b01c-98cc117bdd2a',
removalDisabled: {
message: 'Account removal is disabled by your role.',
code: 'REMOVAL_DISABLED',
id: '453d954b-3d8b-4df0-a261-b26ec6660ea3',
},
authenticationFailed: {
message: 'Authentication failed.',
message: 'Your password or 2FA token is invalid.',
code: 'AUTHENTICATION_FAILED',
id: 'ea791cff-63e7-4b2a-92fc-646ab641794e',
},
alreadyRemoved: {
message: 'Your account is already removed.',
code: 'ACCOUNT_REMOVED',
id: '59b8f0e6-6eb2-4dc1-a080-1de3108416d0',
},
},
} as const;
@ -52,18 +57,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private userAuthService: UserAuthService,
private deleteAccountService: DeleteAccountService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
const policies = await this.roleService.getUserPolicies(me.id);
if (!policies.canUseAccountRemoval) {
throw new ApiError(meta.errors.removalDisabled);
}
const userDetailed = await this.usersRepository.findOneByOrFail({ id: me.id });
if (userDetailed.isDeleted) {
return;
throw new ApiError(meta.errors.alreadyRemoved);
}
const passwordMatched = await bcrypt.compare(ps.password, profile.password!);
if (!passwordMatched) {
throw new ApiError(meta.errors.incorrectPassword);
throw new ApiError(meta.errors.authenticationFailed);
}
if (profile.twoFactorEnabled) {