diff --git a/web-next/lib/recover.ts b/web-next/lib/recover.ts
index edc3401..3bd7a09 100644
--- a/web-next/lib/recover.ts
+++ b/web-next/lib/recover.ts
@@ -144,6 +144,26 @@ export async function requestRecovery(type: string, value: string): Promise {
+ if (!token) return false
+ try {
+ const [rows] = await db(DB.default).query(
+ 'SELECT created_at FROM passwordreset WHERE token = ? AND used = 0',
+ [token],
+ )
+ const pr = rows[0]
+ if (!pr) return false
+ return Date.now() - new Date(pr.created_at).getTime() <= 3600_000
+ } catch {
+ return false
+ }
+}
+
export async function resetPassword(token: string, newPassword: string, confPassword: string): Promise {
const [rows] = await db(DB.default).query(
'SELECT id, email, created_at FROM passwordreset WHERE token = ? AND used = 0',
diff --git a/web-next/messages/en.json b/web-next/messages/en.json
index 9f7c051..f43323c 100644
--- a/web-next/messages/en.json
+++ b/web-next/messages/en.json
@@ -276,8 +276,9 @@
"saving": "Saving…",
"success": "Password reset. You can now sign in.",
"goLogin": "Go to sign in",
- "invalidLink": "The link is invalid or has already been used.",
- "expiredLink": "The link has expired. Please request a new one.",
+ "invalidLink": "The password reset link is invalid",
+ "expiredLink": "The password reset link has expired",
+ "needHelp": "If you need help creating an account, you can contact the {realm} team.",
"passwordMismatch": "Passwords do not match.",
"passwordTooLong": "The password must not exceed 16 characters.",
"accountNotFound": "Account not found.",
diff --git a/web-next/messages/es.json b/web-next/messages/es.json
index 08d7f47..d37faf1 100644
--- a/web-next/messages/es.json
+++ b/web-next/messages/es.json
@@ -276,8 +276,9 @@
"saving": "Guardando…",
"success": "Contraseña restablecida. Ya puedes iniciar sesión.",
"goLogin": "Ir a iniciar sesión",
- "invalidLink": "El enlace no es válido o ya se ha usado.",
- "expiredLink": "El enlace ha caducado. Solicita uno nuevo.",
+ "invalidLink": "El enlace de restablecer la contraseña es inválido",
+ "expiredLink": "El enlace de restablecer la contraseña ha caducado",
+ "needHelp": "Si necesitas ayuda para crear una cuenta, puedes contactar con el equipo de {realm}.",
"passwordMismatch": "Las contraseñas no coinciden.",
"passwordTooLong": "La contraseña no debe exceder los 16 caracteres.",
"accountNotFound": "No se ha encontrado la cuenta.",