diff --git a/web-next/app/[locale]/log-in/LoginForm.tsx b/web-next/app/[locale]/log-in/LoginForm.tsx index c8885b3..e8dbd31 100644 --- a/web-next/app/[locale]/log-in/LoginForm.tsx +++ b/web-next/app/[locale]/log-in/LoginForm.tsx @@ -3,8 +3,9 @@ import { useState } from 'react' import { useTranslations, useLocale } from 'next-intl' import { Turnstile } from '@/components/Turnstile' +import { EMAIL_RE } from '@/lib/bnet' -const ERROR_KEYS = ['invalidCredentials', 'missingFields', 'invalidRequest', 'captchaFailed'] as const +const ERROR_KEYS = ['invalidCredentials', 'missingFields', 'invalidRequest', 'captchaFailed', 'notAnEmail'] as const export function LoginForm() { const t = useTranslations('Login') @@ -24,6 +25,13 @@ export function LoginForm() { setMessage({ ok: false, text: t('missingFields') }) return } + // El
lleva noValidate, así que el navegador no comprueba el + // type="email": si no se mira aquí, se entra con «15#1» y el servidor + // responde «credenciales incorrectas», que despista. + if (!EMAIL_RE.test(email.trim())) { + setMessage({ ok: false, text: t('notAnEmail') }) + return + } setBusy(true) setMessage(null) try { diff --git a/web-next/app/api/auth/login/route.ts b/web-next/app/api/auth/login/route.ts index fdc92bb..517d36f 100644 --- a/web-next/app/api/auth/login/route.ts +++ b/web-next/app/api/auth/login/route.ts @@ -2,6 +2,7 @@ import { authenticate, getGameAccounts } from '@/lib/auth' import { getSession } from '@/lib/session' import { setGameAccountSession } from '@/lib/account-session' import { verifyTurnstile } from '@/lib/turnstile' +import { EMAIL_RE } from '@/lib/bnet' export async function POST(request: Request) { let email = '' @@ -24,6 +25,10 @@ export async function POST(request: Request) { if (!email || !password) { return Response.json({ success: false, error: 'missingFields' }) } + // Con Battle.net se entra con el CORREO, no con la cuenta de juego («15#1»). + if (!EMAIL_RE.test(email)) { + return Response.json({ success: false, error: 'notAnEmail' }) + } const account = await authenticate(email, password) if (!account) { diff --git a/web-next/lib/bnet.ts b/web-next/lib/bnet.ts index 802e187..b273737 100644 --- a/web-next/lib/bnet.ts +++ b/web-next/lib/bnet.ts @@ -165,6 +165,19 @@ export function gameAccountDisplayName(username: string): string { */ export const GMAIL_RE = /^[a-zA-Z0-9._%+-]+@gmail\.com$/i +/** + * Forma de correo, para distinguirlo de un nombre de usuario. Con Battle.net se + * entra con el correo, pero la gente prueba con la cuenta de juego («15#1»), que + * no tiene @. + * + * A propósito NO exige punto en el dominio ni restringe a Gmail: el registro solo + * admite Gmail HOY, pero las cuentas ya creadas tienen correos de todo tipo + * (INNA@INNA.CL, e incluso Q@Q sin dominio), y validar de más al entrar las + * dejaría fuera. Solo hace falta separar «correo» de «usuario». Es el mismo + * criterio que aplica el navegador a un . + */ +export const EMAIL_RE = /^[^\s@]+@[^\s@]+$/ + /** * Cuentas de juego por cuenta Battle.net (WoW1…WoW8). Vive aquí, y no en la ruta * que la aplica, para que el correo de activación cite el límite REAL: el texto diff --git a/web-next/messages/en.json b/web-next/messages/en.json index 5afb703..f10a3c9 100644 --- a/web-next/messages/en.json +++ b/web-next/messages/en.json @@ -41,6 +41,7 @@ "connecting": "Signing in…", "success": "Signed in successfully. Redirecting…", "invalidCredentials": "Incorrect email or password", + "notAnEmail": "Enter your email address, not the account name.", "missingFields": "Please fill in all fields.", "invalidRequest": "Invalid request.", "genericError": "Something went wrong. Please try again later.", diff --git a/web-next/messages/es.json b/web-next/messages/es.json index 7cff32c..dbb4a38 100644 --- a/web-next/messages/es.json +++ b/web-next/messages/es.json @@ -41,6 +41,7 @@ "connecting": "Conectando…", "success": "Conexión exitosa. Redirigiendo…", "invalidCredentials": "Correo o contraseña incorrectos", + "notAnEmail": "Introduce tu correo electrónico, no el nombre de la cuenta.", "missingFields": "Por favor rellene todos los campos.", "invalidRequest": "Solicitud no válida.", "genericError": "Algo ha salido mal. Inténtalo más tarde.",