Files
ldap-auth-service/lib/registerApi.js
2026-08-20 17:31:17 +05:00

97 lines
3.5 KiB
JavaScript

'use strict';
const express = require('express');
const ldapClient = require('./ldapClient');
const requests = require('./requests');
const mailer = require('./mailer');
const router = express.Router();
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const { NAME_RE } = requests;
const lastSendAt = new Map();
function errorResponse(res, err) {
const status = err.status || 500;
res.status(status).json({ success: false, error: err.message || 'Внутренняя ошибка сервера' });
}
async function getTakenLogins() {
const users = await ldapClient.listUsers();
const taken = users.map((u) => u.login).filter(Boolean);
const all = requests.listRequests();
for (const r of [...all.pending, ...all.history]) {
if (r.login) taken.push(r.login);
}
return taken;
}
async function getUsedEmails(excludePhase) {
const users = await ldapClient.listUsers();
const emails = users.map((u) => u.email).filter(Boolean).map((e) => e.toLowerCase());
const all = requests.listRequests();
for (const r of [...all.pending, ...all.history]) {
if (excludePhase && r.phase === excludePhase) continue;
if (r.email) emails.push(r.email.toLowerCase());
}
return new Set(emails);
}
router.post('/send-code', async (req, res) => {
const { email } = req.body || {};
if (!email || !EMAIL_RE.test(String(email))) {
return res.status(400).json({ success: false, error: 'Некорректный email' });
}
const now = Date.now();
const last = lastSendAt.get(String(email).toLowerCase());
if (last && now - last < 30000) {
return res.status(429).json({ success: false, error: 'Код уже отправлен, подождите 30 секунд' });
}
try {
const used = await getUsedEmails('denied');
if (used.has(String(email).toLowerCase())) {
return res.status(409).json({ success: false, error: 'Эта почта уже используется' });
}
const { code } = requests.issueCode(email);
await mailer.sendVerificationCode(email, code);
lastSendAt.set(String(email).toLowerCase(), Date.now());
res.json({ success: true, message: 'Код отправлен на указанную почту' });
} catch (err) {
errorResponse(res, err);
}
});
router.post('/verify-code', (req, res) => {
const { email, code } = req.body || {};
try {
const record = requests.verifyCode(email, code);
res.json({ success: true, emailVerified: !!record.emailVerified });
} catch (err) {
errorResponse(res, err);
}
});
router.post('/submit', async (req, res) => {
const surname = String(req.body.surname || '').trim();
const name = String(req.body.name || '').trim();
const patronymic = String(req.body.patronymic || '').trim();
const { email, password } = req.body || {};
if (!surname || !name) {
return res.status(400).json({ success: false, error: 'Фамилия и имя обязательны' });
}
if (!NAME_RE.test(surname) || !NAME_RE.test(name) || (patronymic && !NAME_RE.test(patronymic))) {
return res.status(400).json({ success: false, error: 'ФИО должно содержать только русские буквы' });
}
try {
const taken = await getTakenLogins();
const record = requests.submitRequest(
{ surname, name, patronymic, email, password },
taken
);
res.json({ success: true, login: record.login, message: 'Заявка отправлена на рассмотрение администратором' });
} catch (err) {
errorResponse(res, err);
}
});
module.exports = router;