diff --git a/frontend/src/pages/api/auth/forgot-password.ts b/frontend/src/pages/api/auth/forgot-password.ts index 5014de4..175f130 100644 --- a/frontend/src/pages/api/auth/forgot-password.ts +++ b/frontend/src/pages/api/auth/forgot-password.ts @@ -106,6 +106,13 @@ export const POST: APIRoute = async ({ request }) => { console.log('Reset email sent:', emailSent); + if (!emailSent) { + return new Response(JSON.stringify({ + success: false, + error: 'Не удалось отправить письмо. Попробуйте позже.' + }), { status: 500 }); + } + return new Response(JSON.stringify({ success: true, message: 'Ссылка для сброса пароля отправлена' @@ -115,8 +122,8 @@ export const POST: APIRoute = async ({ request }) => { console.error('Forgot password error:', error); return new Response(JSON.stringify({ - success: true, - message: 'Ссылка для сброса пароля отправлена' - }), { status: 200 }); + success: false, + error: 'Ошибка при обработке запроса' + }), { status: 500 }); } }; \ No newline at end of file diff --git a/frontend/src/pages/api/auth/request-password-reset.ts b/frontend/src/pages/api/auth/request-password-reset.ts index 2ba0b56..19edf33 100644 --- a/frontend/src/pages/api/auth/request-password-reset.ts +++ b/frontend/src/pages/api/auth/request-password-reset.ts @@ -1,6 +1,6 @@ import type { APIRoute } from 'astro'; - -const PB_POCKETBASE_URL = import.meta.env.PB_POCKETBASE_URL || 'http://localhost:8090'; +import { pb } from '../../../lib/pb'; +import { sendEmail, getSiteUrl } from '../../../lib/email'; const RATE_LIMIT_MAX_REQUESTS = 3; const RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000; @@ -38,6 +38,64 @@ function checkRateLimit(email: string): { allowed: boolean; remaining?: number; return { allowed: true, remaining: RATE_LIMIT_MAX_REQUESTS - timestamps.length }; } +function generateResetPasswordHtml(firstName: string, resetLink: string): string { + return ` + + + + + + Сброс пароля + + + + + + +
+ + + + + + + + + + +
+

Автоюрист Сургут

+

Юридические услуги для автовладельцев

+
+

Сброс пароля

+

+ Здравствуйте, ${firstName}! +

+

+ Вы запросили сброс пароля. Нажмите кнопку ниже для создания нового пароля: +

+ + + + +
+ + Сбросить пароль + +
+

+ Ссылка действительна 1 час. Если вы не запрашивали сброс пароля, просто проигнорируйте это письмо. +

+
+

+ © 2026 Автоюрист Сургут. Все права защищены. +

+
+
+ +`; +} + export const POST: APIRoute = async ({ request }) => { try { let body; @@ -77,39 +135,53 @@ export const POST: APIRoute = async ({ request }) => { ); } - const resetUrl = `${PB_POCKETBASE_URL}/api/collections/users/request-password-reset`; - - const response = await fetch(resetUrl, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email }), - }); - - if (response.status === 204) { + // Проверяем существует ли пользователь + let user = null; + try { + user = await pb.collection('users').getFirstListItem(`email="${email}"`); + } catch (e) { + console.log('User not found, still return success'); + } + + if (!user) { return new Response( JSON.stringify({ success: true, - message: 'Письмо для сброса пароля отправлено' + message: 'Ссылка для сброса пароля отправлена' }), { status: 200, headers: { 'Content-Type': 'application/json' } } ); } - let data; - try { - data = await response.json(); - } catch { + // Создаём свой токен сброса + const resetToken = Buffer.from(`${user.id}:${Date.now()}`).toString('base64').replace(/=/g, ''); + const resetLink = `${getSiteUrl()}/auth/reset-password?token=${resetToken}&userId=${user.id}`; + + // Отправляем письмо через SMTP.BZ + const firstName = user.firstName || 'Пользователь'; + const html = generateResetPasswordHtml(firstName, resetLink); + + const emailSent = await sendEmail({ + to: email, + subject: 'Сброс пароля — Автоюрист Сургут', + html + }); + + console.log('Password reset email sent:', emailSent); + + if (!emailSent) { return new Response( - JSON.stringify({ error: 'Ошибка обработки ответа' }), + JSON.stringify({ error: 'Не удалось отправить письмо. Попробуйте позже.' }), { status: 500, headers: { 'Content-Type': 'application/json' } } ); } return new Response( JSON.stringify({ - error: data.message || 'Ошибка при отправке письма для сброса пароля' + success: true, + message: 'Письмо для сброса пароля отправлено' }), - { status: response.status, headers: { 'Content-Type': 'application/json' } } + { status: 200, headers: { 'Content-Type': 'application/json' } } ); } catch (error) {