enhance: 二要素認証設定時のセキュリティを強化 (#11863)
* enhance: 二要素認証設定時のセキュリティを強化 パスワード入力が必要な操作を行う際、二要素認証が有効であれば確認コードの入力も必要にする * Update CoreModule.ts * Update 2fa.ts * wip * wip * Update 2fa.ts * tweak
This commit is contained in:
@@ -51,6 +51,7 @@ import { UserKeypairService } from './UserKeypairService.js';
|
||||
import { UserListService } from './UserListService.js';
|
||||
import { UserMutingService } from './UserMutingService.js';
|
||||
import { UserSuspendService } from './UserSuspendService.js';
|
||||
import { UserAuthService } from './UserAuthService.js';
|
||||
import { VideoProcessingService } from './VideoProcessingService.js';
|
||||
import { WebhookService } from './WebhookService.js';
|
||||
import { ProxyAccountService } from './ProxyAccountService.js';
|
||||
@@ -177,6 +178,7 @@ const $UserKeypairService: Provider = { provide: 'UserKeypairService', useExisti
|
||||
const $UserListService: Provider = { provide: 'UserListService', useExisting: UserListService };
|
||||
const $UserMutingService: Provider = { provide: 'UserMutingService', useExisting: UserMutingService };
|
||||
const $UserSuspendService: Provider = { provide: 'UserSuspendService', useExisting: UserSuspendService };
|
||||
const $UserAuthService: Provider = { provide: 'UserAuthService', useExisting: UserAuthService };
|
||||
const $VideoProcessingService: Provider = { provide: 'VideoProcessingService', useExisting: VideoProcessingService };
|
||||
const $WebhookService: Provider = { provide: 'WebhookService', useExisting: WebhookService };
|
||||
const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService };
|
||||
@@ -306,6 +308,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
UserListService,
|
||||
UserMutingService,
|
||||
UserSuspendService,
|
||||
UserAuthService,
|
||||
VideoProcessingService,
|
||||
WebhookService,
|
||||
UtilityService,
|
||||
@@ -428,6 +431,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$UserListService,
|
||||
$UserMutingService,
|
||||
$UserSuspendService,
|
||||
$UserAuthService,
|
||||
$VideoProcessingService,
|
||||
$WebhookService,
|
||||
$UtilityService,
|
||||
@@ -551,6 +555,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
UserListService,
|
||||
UserMutingService,
|
||||
UserSuspendService,
|
||||
UserAuthService,
|
||||
VideoProcessingService,
|
||||
WebhookService,
|
||||
UtilityService,
|
||||
@@ -672,6 +677,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$UserListService,
|
||||
$UserMutingService,
|
||||
$UserSuspendService,
|
||||
$UserAuthService,
|
||||
$VideoProcessingService,
|
||||
$WebhookService,
|
||||
$UtilityService,
|
||||
|
45
packages/backend/src/core/UserAuthService.ts
Normal file
45
packages/backend/src/core/UserAuthService.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { QueryFailedError } from 'typeorm';
|
||||
import * as OTPAuth from 'otpauth';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
import type { MiLocalUser } from '@/models/User.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserAuthService {
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@Inject(DI.userProfilesRepository)
|
||||
private userProfilesRepository: UserProfilesRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async twoFactorAuthenticate(profile: MiUserProfile, token: string): Promise<void> {
|
||||
if (profile.twoFactorBackupSecret?.includes(token)) {
|
||||
await this.userProfilesRepository.update({ userId: profile.userId }, {
|
||||
twoFactorBackupSecret: profile.twoFactorBackupSecret.filter((secret) => secret !== token),
|
||||
});
|
||||
} else {
|
||||
const delta = OTPAuth.TOTP.validate({
|
||||
secret: OTPAuth.Secret.fromBase32(profile.twoFactorSecret!),
|
||||
digits: 6,
|
||||
token,
|
||||
window: 5,
|
||||
});
|
||||
|
||||
if (delta === null) {
|
||||
throw new Error('authentication failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user