mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 03:46:37 +01:00 
			
		
		
		
	refactor: 💡 refact recovery code
This commit is contained in:
		@@ -126,9 +126,9 @@ interface TOTPStatus {
 | 
			
		||||
 | 
			
		||||
interface RecoveryKeysResponse {
 | 
			
		||||
    success: boolean;
 | 
			
		||||
    recoveryCodes?: string;
 | 
			
		||||
    recoveryCodes?: string[];
 | 
			
		||||
    keysExist?: boolean;
 | 
			
		||||
    usedRecoveryCodes?: string;
 | 
			
		||||
    usedRecoveryCodes?: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class MultiFactorAuthenticationOptions extends OptionsWidget {
 | 
			
		||||
@@ -231,6 +231,7 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const usedResult = await server.get<RecoveryKeysResponse>("totp_recovery/used");
 | 
			
		||||
 | 
			
		||||
        if (usedResult.usedRecoveryCodes) {
 | 
			
		||||
            this.keyFiller(usedResult.usedRecoveryCodes);
 | 
			
		||||
            this.$generateRecoveryCodeButton.text(t("multi_factor_authentication.recovery_keys_regenerate"));
 | 
			
		||||
@@ -239,14 +240,19 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private keyFiller(values: string) {
 | 
			
		||||
        const keys = values.split(',').slice(0, 8);
 | 
			
		||||
 | 
			
		||||
    private keyFiller(values: string[]) {
 | 
			
		||||
        this.fillKeys("");
 | 
			
		||||
 | 
			
		||||
        keys.forEach((key, index) => {
 | 
			
		||||
            if (index < 8 && key && typeof key === 'string') {
 | 
			
		||||
                this.$recoveryKeys[index].text(key.trim());
 | 
			
		||||
        values.forEach((key, index) => {
 | 
			
		||||
            if (typeof key === 'string') {
 | 
			
		||||
                const date = new Date(key.replace(/\//g, '-'));
 | 
			
		||||
                if (isNaN(date.getTime())) {
 | 
			
		||||
                    this.$recoveryKeys[index].text(key);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$recoveryKeys[index].text(t("multi_factor_authentication.recovery_keys_used", { date: key.replace(/\//g, '-') }));
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this.$recoveryKeys[index].text(t("multi_factor_authentication.recovery_keys_unused", { index: key }));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1322,6 +1322,8 @@
 | 
			
		||||
    "recovery_keys_no_key_set": "未设置恢复代码",
 | 
			
		||||
    "recovery_keys_generate": "生成恢复代码",
 | 
			
		||||
    "recovery_keys_regenerate": "重新生成恢复代码",
 | 
			
		||||
    "recovery_keys_used": "已使用: {{date}}",
 | 
			
		||||
    "recovery_keys_unused": "恢复代码 {{index}} 未使用",
 | 
			
		||||
    "oauth_title": "OAuth/OpenID 认证",
 | 
			
		||||
    "oauth_description": "OpenID 是一种标准化方式,允许您使用其他服务(如 Google)的账户登录网站,以验证您的身份。请参阅这些 <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">指南</a> 通过 Google 设置 OpenID 服务。",
 | 
			
		||||
    "oauth_description_warning": "要启用 OAuth/OpenID,您需要设置 config.ini 文件中的 OAuth/OpenID 基础 URL、客户端 ID 和客户端密钥,并重新启动应用程序。",
 | 
			
		||||
 
 | 
			
		||||
@@ -1333,6 +1333,8 @@
 | 
			
		||||
    "recovery_keys_no_key_set": "No recovery codes set",
 | 
			
		||||
    "recovery_keys_generate": "Generate Recovery Codes",
 | 
			
		||||
    "recovery_keys_regenerate": "Regenerate Recovery Codes",
 | 
			
		||||
    "recovery_keys_used": "Used: {{date}}",
 | 
			
		||||
    "recovery_keys_unused": "Recovery code {{index}} is unused",
 | 
			
		||||
    "oauth_title": "OAuth/OpenID",
 | 
			
		||||
    "oauth_description": "OpenID is a standardized way to let you log into websites using an account from another service, like Google, to verify your identity. Follow these <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">instructions</a> to setup an OpenID service through Google.",
 | 
			
		||||
    "oauth_description_warning": "To enable OAuth/OpenID, you need to set the OAuth/OpenID base URL, client ID and client secret in the config.ini file and restart the application.",
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import type { Request } from 'express';
 | 
			
		||||
import { randomBytes } from 'crypto';
 | 
			
		||||
 | 
			
		||||
function setRecoveryCodes(req: Request) {
 | 
			
		||||
    const success = recovery_codes.setRecoveryCodes(req.body.recoveryCodes);
 | 
			
		||||
    const success = recovery_codes.setRecoveryCodes(req.body.recoveryCodes.join(','));
 | 
			
		||||
    return { success: success, message: 'Recovery codes set!' };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -31,15 +31,28 @@ function generateRecoveryCodes() {
 | 
			
		||||
        randomBytes(16).toString('base64')
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    recovery_codes.setRecoveryCodes(recoveryKeys.toString());
 | 
			
		||||
    recovery_codes.setRecoveryCodes(recoveryKeys.join(','));
 | 
			
		||||
 | 
			
		||||
    return { success: true, recoveryCodes: recoveryKeys.toString() };
 | 
			
		||||
    return { success: true, recoveryCodes: recoveryKeys };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getUsedRecoveryCodes() {
 | 
			
		||||
    if (!recovery_codes.isRecoveryCodeSet()) {
 | 
			
		||||
        return []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const dateRegex = RegExp(/^\d{4}\/\d{2}\/\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/gm);
 | 
			
		||||
    const recoveryCodes = recovery_codes.getRecoveryCodes();
 | 
			
		||||
    const usedStatus: string[] = [];
 | 
			
		||||
 | 
			
		||||
    recoveryCodes.forEach((recoveryKey: string) => {
 | 
			
		||||
        if (dateRegex.test(recoveryKey)) usedStatus.push(recoveryKey);
 | 
			
		||||
        else usedStatus.push(recoveryCodes.indexOf(recoveryKey));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        success: true,
 | 
			
		||||
        usedRecoveryCodes: recovery_codes.getUsedRecoveryCodes().toString()
 | 
			
		||||
        usedRecoveryCodes: usedStatus
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
import sql from '../sql.js';
 | 
			
		||||
import optionService from '../options.js';
 | 
			
		||||
import crypto from 'crypto';
 | 
			
		||||
@@ -26,7 +24,7 @@ function setRecoveryCodes(recoveryCodes: string) {
 | 
			
		||||
 | 
			
		||||
function getRecoveryCodes() {
 | 
			
		||||
    if (!isRecoveryCodeSet()) {
 | 
			
		||||
        return Array(8).fill("Keys not set")
 | 
			
		||||
        return []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return sql.transactional(() => {
 | 
			
		||||
@@ -67,25 +65,9 @@ function verifyRecoveryCode(recoveryCodeGuess: string) {
 | 
			
		||||
    return loginSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getUsedRecoveryCodes() {
 | 
			
		||||
    if (!isRecoveryCodeSet()) {
 | 
			
		||||
        return Array(8).fill("Recovery code not set")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const dateRegex = RegExp(/^\d{4}\/\d{2}\/\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/gm);
 | 
			
		||||
    const recoveryCodes = getRecoveryCodes();
 | 
			
		||||
    const usedStatus: string[] = [];
 | 
			
		||||
 | 
			
		||||
    recoveryCodes.forEach((recoveryKey: string) => {
 | 
			
		||||
        if (dateRegex.test(recoveryKey)) usedStatus.push('Used: ' + recoveryKey);
 | 
			
		||||
        else usedStatus.push('Recovery code ' + recoveryCodes.indexOf(recoveryKey) + ' is unused');
 | 
			
		||||
    });
 | 
			
		||||
    return usedStatus;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    setRecoveryCodes,
 | 
			
		||||
    getRecoveryCodes,
 | 
			
		||||
    verifyRecoveryCode,
 | 
			
		||||
    getUsedRecoveryCodes,
 | 
			
		||||
    isRecoveryCodeSet
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user