mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
fix(security): harden jwt config and password rotation
This commit is contained in:
@@ -5,7 +5,7 @@ import StandalonePageFrame from '@/components/StandalonePageFrame';
|
||||
import { t } from '@/lib/i18n';
|
||||
|
||||
interface JwtWarningPageProps {
|
||||
reason: 'missing' | 'default' | 'too_short';
|
||||
reason: 'missing' | 'too_short';
|
||||
minLength: number;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,7 @@ export default function JwtWarningPage(props: JwtWarningPageProps) {
|
||||
const title =
|
||||
props.reason === 'missing'
|
||||
? t('txt_jwt_title_missing')
|
||||
: props.reason === 'default'
|
||||
? t('txt_jwt_title_default')
|
||||
: t('txt_jwt_title_too_short');
|
||||
: t('txt_jwt_title_too_short');
|
||||
|
||||
const isMissing = props.reason === 'missing';
|
||||
const fixTitle = isMissing ? t('txt_jwt_how_to_fix_add') : t('txt_jwt_how_to_fix_replace');
|
||||
|
||||
@@ -591,11 +591,14 @@ export async function changeMasterPassword(
|
||||
const oldEnc = await hkdfExpand(current.masterKey, 'enc', 32);
|
||||
const oldMac = await hkdfExpand(current.masterKey, 'mac', 32);
|
||||
const userSym = await decryptBw(args.profileKey, oldEnc, oldMac);
|
||||
if (userSym.length !== 64) {
|
||||
throw new Error('Invalid profile key');
|
||||
}
|
||||
const nextMasterKey = await pbkdf2(args.newPassword, args.email, current.kdfIterations, 32);
|
||||
const nextHash = await pbkdf2(nextMasterKey, args.newPassword, 1, 32);
|
||||
const nextEnc = await hkdfExpand(nextMasterKey, 'enc', 32);
|
||||
const nextMac = await hkdfExpand(nextMasterKey, 'mac', 32);
|
||||
const newKey = await encryptBw(userSym.slice(0, 64), nextEnc, nextMac);
|
||||
const newKey = await encryptBw(userSym, nextEnc, nextMac);
|
||||
const newMasterPasswordHash = bytesToBase64(nextHash);
|
||||
|
||||
const resp = await authedFetch('/api/accounts/password', {
|
||||
|
||||
@@ -42,7 +42,7 @@ export interface PendingPasskeyPassword {
|
||||
kdfIterations: number;
|
||||
}
|
||||
|
||||
export type JwtUnsafeReason = 'missing' | 'default' | 'too_short';
|
||||
export type JwtUnsafeReason = 'missing' | 'too_short';
|
||||
|
||||
export interface BootstrapAppResult {
|
||||
defaultKdfIterations: number;
|
||||
|
||||
@@ -669,7 +669,7 @@ const en: Record<string, string> = {
|
||||
"txt_jwt_secret_value_label": "Value:",
|
||||
"txt_jwt_secret_value_requirement": "Random string with at least {min} characters",
|
||||
"txt_jwt_what_is": "What is JWT?",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET is the server-side signing key used to issue and verify login tokens. If it is missing, too short, or still using the sample value, the instance is not safe to use normally.",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET is the server-side signing key used to issue and verify login tokens. If it is missing or too short, the instance is not safe to use normally.",
|
||||
"txt_how_to_fix": "How to fix",
|
||||
"txt_jwt_fix_step_1": "Open your deployment environment variables.",
|
||||
"txt_jwt_fix_step_2": "If your current key is not random enough, use the 32-character generator below.",
|
||||
|
||||
@@ -669,7 +669,7 @@ const es: Record<string, string> = {
|
||||
"txt_jwt_secret_value_label": "Valor:",
|
||||
"txt_jwt_secret_value_requirement": "Cadena aleatoria de al menos {min} caracteres",
|
||||
"txt_jwt_what_is": "Qué es JWT",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET es la clave de firma del lado del servidor utilizada para emitir y verificar tokens de inicio de sesión. Si no está presente, es demasiado corta o todavía usa el valor de ejemplo, la instancia no es segura para uso normal.",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET es la clave de firma del lado del servidor utilizada para emitir y verificar tokens de inicio de sesión. Si no está presente o es demasiado corta, la instancia no es segura para uso normal.",
|
||||
"txt_how_to_fix": "Cómo corregirlo",
|
||||
"txt_jwt_fix_step_1": "Abra las variables de entorno de su despliegue.",
|
||||
"txt_jwt_fix_step_2": "Si su clave actual no es lo suficientemente aleatoria, use el generador de 32 caracteres a continuación.",
|
||||
|
||||
@@ -669,7 +669,7 @@ const ru: Record<string, string> = {
|
||||
"txt_jwt_secret_value_label": "Значение:",
|
||||
"txt_jwt_secret_value_requirement": "Случайная строка, содержащая не менее {min} символов.",
|
||||
"txt_jwt_what_is": "Что такое JWT?",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET — это ключ подписи на стороне сервера, используемый для выдачи и проверки токенов входа. Если он отсутствует, слишком короткий или все еще использует образец значения, обычное использование экземпляра небезопасно.",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET — это ключ подписи на стороне сервера, используемый для выдачи и проверки токенов входа. Если он отсутствует или слишком короткий, обычное использование экземпляра небезопасно.",
|
||||
"txt_how_to_fix": "Как исправить",
|
||||
"txt_jwt_fix_step_1": "Откройте переменные среды развертывания.",
|
||||
"txt_jwt_fix_step_2": "Если ваш текущий ключ недостаточно случайный, используйте 32-значный генератор ниже.",
|
||||
|
||||
@@ -669,7 +669,7 @@ const zhCN: Record<string, string> = {
|
||||
"txt_jwt_secret_value_label": "值:",
|
||||
"txt_jwt_secret_value_requirement": "最低 {min} 位随机字符",
|
||||
"txt_jwt_what_is": "JWT 是什么",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET 是服务端用来签发和校验登录令牌的密钥。如果它缺失、过短,或者仍然使用示例值,实例就不能安全地正常使用。",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET 是服务端用来签发和校验登录令牌的密钥。如果它缺失或过短,实例就不能安全地正常使用。",
|
||||
"txt_how_to_fix": "处理步骤(添加 / 更换)",
|
||||
"txt_jwt_fix_step_1": "你可以继续下一步,不影响使用。",
|
||||
"txt_jwt_fix_step_2": "如果当前密钥不是强随机值,建议使用下方 32 位生成器。",
|
||||
|
||||
@@ -669,7 +669,7 @@ const zhTW: Record<string, string> = {
|
||||
"txt_jwt_secret_value_label": "值:",
|
||||
"txt_jwt_secret_value_requirement": "最低 {min} 位隨機字符",
|
||||
"txt_jwt_what_is": "JWT 是什麼",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET 是服務端用來簽發和校驗登錄令牌的密鑰。如果它缺失、過短,或者仍然使用示例值,實例就不能安全地正常使用。",
|
||||
"txt_jwt_what_is_body": "JWT_SECRET 是服務端用來簽發和校驗登錄令牌的密鑰。如果它缺失或過短,實例就不能安全地正常使用。",
|
||||
"txt_how_to_fix": "處理步驟(添加 / 更換)",
|
||||
"txt_jwt_fix_step_1": "你可以繼續下一步,不影響使用。",
|
||||
"txt_jwt_fix_step_2": "如果當前密鑰不是強隨機值,建議使用下方 32 位生成器。",
|
||||
|
||||
@@ -290,7 +290,7 @@ export interface ListResponse<T> {
|
||||
|
||||
export interface WebBootstrapResponse {
|
||||
defaultKdfIterations?: number;
|
||||
jwtUnsafeReason?: 'missing' | 'default' | 'too_short' | null;
|
||||
jwtUnsafeReason?: 'missing' | 'too_short' | null;
|
||||
jwtSecretMinLength?: number;
|
||||
registrationInviteRequired?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user