Token de seguridad y cambio de contraseña (páginas protegidas)

- lib/security-token.ts: requestSecurityToken (token de 6 chars, cooldown 7 días,
  guarda en home_securitytoken, email) + checkSecurityToken.
- lib/change-password.ts: changePassword (valida token + contraseña actual con
  authenticate, re-deriva verifier SRP6 v2, actualiza battlenet_accounts).
- Routes /api/account/security-token y /change-password (guard; el cambio hace
  logout de la sesión). Páginas /security-token y /change-password (protegidas) con
  sus forms cliente e i18n (SecurityToken, ChangePassword).

Verificado: páginas redirigen a login sin sesión, APIs 401. Reutiliza
home_securitytoken de Django y la crypto validada.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 23:36:05 +00:00
parent 548fca16e6
commit 1da7349373
10 changed files with 383 additions and 0 deletions
+30
View File
@@ -176,5 +176,35 @@
"destination": "Destination account",
"success": "Character {name} has been transferred to the destination account."
}
},
"SecurityToken": {
"title": "Security token",
"info": "The security token is a 6-character (case-sensitive) code required for important account actions. You can request a new one every 7 days.",
"lastRequest": "Request date",
"never": "Not requested",
"request": "Request token",
"requesting": "Requesting…",
"success": "The security token has been sent to your email.",
"cooldown": "You can only request a token every 7 days.",
"noEmail": "Add an email to your account before requesting a token.",
"genericError": "Something went wrong. Please try again later."
},
"ChangePassword": {
"title": "Change password",
"info": "The new password must be alphanumeric and up to 16 characters. You need a security token.",
"currentPassword": "Current password",
"newPassword": "New password",
"confPassword": "Confirm new password",
"token": "Security token",
"submit": "Change password",
"changing": "Changing…",
"success": "Password changed. You have been logged out for security.",
"missingFields": "Please fill in all fields.",
"passwordMismatch": "Passwords do not match.",
"passwordTooLong": "The password must not exceed 16 characters.",
"invalidToken": "The security token is incorrect.",
"wrongCurrentPassword": "The current password is incorrect.",
"accountNotFound": "Account not found.",
"genericError": "Something went wrong. Please try again later."
}
}
+30
View File
@@ -176,5 +176,35 @@
"destination": "Cuenta de destino",
"success": "El personaje {name} ha sido transferido a la cuenta de destino."
}
},
"SecurityToken": {
"title": "Token de seguridad",
"info": "El token de seguridad es un código de 6 caracteres (sensible a mayúsculas) que se solicita para acciones importantes de tu cuenta. Puedes solicitar uno nuevo cada 7 días.",
"lastRequest": "Fecha de solicitud",
"never": "Sin solicitar",
"request": "Solicitar token",
"requesting": "Solicitando…",
"success": "Se ha enviado el token de seguridad a tu correo.",
"cooldown": "Solo puedes solicitar un token cada 7 días.",
"noEmail": "Añade un correo a tu cuenta antes de solicitar un token.",
"genericError": "Algo ha salido mal. Inténtalo más tarde."
},
"ChangePassword": {
"title": "Cambiar contraseña",
"info": "La nueva contraseña debe ser alfanumérica y de hasta 16 caracteres. Necesitas un token de seguridad.",
"currentPassword": "Contraseña actual",
"newPassword": "Contraseña nueva",
"confPassword": "Confirmar contraseña nueva",
"token": "Token de seguridad",
"submit": "Cambiar contraseña",
"changing": "Cambiando…",
"success": "Contraseña cambiada. Has sido desconectado por seguridad.",
"missingFields": "Por favor, complete todos los campos.",
"passwordMismatch": "Las contraseñas no coinciden.",
"passwordTooLong": "La contraseña no debe exceder los 16 caracteres.",
"invalidToken": "El token de seguridad es incorrecto.",
"wrongCurrentPassword": "La contraseña actual es incorrecta.",
"accountNotFound": "No se ha encontrado la cuenta.",
"genericError": "Algo ha salido mal. Inténtalo más tarde."
}
}