🎨 2FA設定のデザイン向上 / セキュリティキーの名前を変更できるように (#9985)

* wip

* fix

* wip

* wip

* ✌️

* rename key

* 🎨

* update CHANGELOG.md

* パスワードレスログインの判断はサーバーで

* 日本語

* 日本語

* 日本語

* 日本語

* ✌️

* fix

* refactor

* トークン→確認コード

* fix password-less / qr click

* use otpauth

* 日本語

* autocomplete

* パスワードレス設定は外に出す

* 🎨

* 🎨

---------

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
tamaina
2023-02-20 16:40:24 +09:00
committed by GitHub
parent ea92254b73
commit 980bf1306e
23 changed files with 640 additions and 267 deletions

View File

@@ -1,7 +1,10 @@
import * as speakeasy from 'speakeasy';
import * as OTPAuth from 'otpauth';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import type { UserProfilesRepository } from '@/models/index.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
export const meta = {
@@ -22,8 +25,14 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private userEntityService: UserEntityService,
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps, me) => {
const token = ps.token.replace(/\s/g, '');
@@ -34,13 +43,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new Error('二段階認証の設定が開始されていません');
}
const verified = (speakeasy as any).totp.verify({
secret: profile.twoFactorTempSecret,
encoding: 'base32',
token: token,
const delta = OTPAuth.TOTP.validate({
secret: OTPAuth.Secret.fromBase32(profile.twoFactorTempSecret),
digits: 6,
token,
window: 1,
});
if (!verified) {
if (delta === null) {
throw new Error('not verified');
}
@@ -48,6 +58,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
twoFactorSecret: profile.twoFactorTempSecret,
twoFactorEnabled: true,
});
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
detail: true,
includeSecrets: true,
}));
});
}
}