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."
}
}