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) {