Files
router-lists-ui/backend/routes/ipsecPasswordsRoutes.js
T

316 lines
11 KiB
JavaScript

/**
* Роуты для управления IPSec паролями
* Пароли хранятся в S3 в зашифрованном виде
*/
const { sendError, sendOk } = require('../middleware/errorHandler');
const { readS3TextObject, writeS3JsonObject, deleteS3Object } = require('../services/s3Service');
const { encrypt, decrypt } = require('../utils/encryption');
const S3_KEY = 'network-config/ipsec-passwords.json';
/**
* GET /api/ipsec-passwords - получить список паролей (без расшифровки)
*/
async function getIpsecPasswords(req, res) {
try {
const data = await readS3TextObject(S3_KEY).catch(() => ({ body: '[]' }));
let passwords = [];
try {
passwords = JSON.parse(data.body || '[]');
if (!Array.isArray(passwords)) {
passwords = [];
}
} catch (parseError) {
passwords = [];
}
// Возвращаем список паролей БЕЗ расшифровки (только метаданные)
const result = passwords.map(p => ({
id: p.id,
name: p.name || '',
description: p.description || '',
createdAt: p.createdAt || null,
updatedAt: p.updatedAt || null,
// НЕ возвращаем зашифрованный пароль
}));
res.json(result);
} catch (error) {
console.error('Error reading IPSec passwords:', error);
return sendError(res, 500, 'Error reading IPSec passwords', 'E_S3');
}
}
/**
* GET /api/ipsec-passwords/:id - получить конкретный пароль (расшифрованный)
*/
async function getIpsecPassword(req, res) {
const { id } = req.params;
try {
const data = await readS3TextObject(S3_KEY).catch(() => ({ body: '[]' }));
let passwords = [];
try {
passwords = JSON.parse(data.body || '[]');
if (!Array.isArray(passwords)) {
passwords = [];
}
} catch (parseError) {
passwords = [];
}
const password = passwords.find(p => p.id === id);
if (!password) {
return sendError(res, 404, 'IPSec password not found', 'E_NOT_FOUND');
}
// Проверяем наличие зашифрованного пароля
if (!password.encryptedPassword) {
console.error(`IPSec password ${id} has no encryptedPassword field`);
console.error('Password object:', JSON.stringify(password, null, 2));
return sendError(res, 500, 'Password has no encrypted data', 'E_DECRYPT');
}
// Расшифровываем пароль для возврата
let decryptedPassword = '';
try {
if (typeof password.encryptedPassword !== 'string') {
console.error(`IPSec password ${id} encryptedPassword is not a string:`, typeof password.encryptedPassword);
return sendError(res, 500, 'Invalid encrypted password format', 'E_DECRYPT');
}
decryptedPassword = decrypt(password.encryptedPassword);
if (!decryptedPassword) {
console.error(`IPSec password ${id} decrypted to empty string`);
return sendError(res, 500, 'Password decrypted to empty string', 'E_DECRYPT');
}
} catch (decryptError) {
console.error('Error decrypting password:', decryptError);
console.error('Password ID:', id);
console.error('Encrypted password length:', password.encryptedPassword?.length);
console.error('Encrypted password preview:', password.encryptedPassword?.substring(0, 50));
console.error('Encrypted password format check:', password.encryptedPassword?.split(':').length, 'parts');
// Проверяем, возможно это старый формат или другой ключ
const errorMessage = decryptError.message || 'Unknown decryption error';
return sendError(res, 500, `Error decrypting password: ${errorMessage}. Check if ENCRYPTION_KEY is correct.`, 'E_DECRYPT');
}
res.json({
id: password.id,
name: password.name || '',
description: password.description || '',
password: decryptedPassword, // Расшифрованный пароль
createdAt: password.createdAt || null,
updatedAt: password.updatedAt || null,
});
} catch (error) {
console.error('Error reading IPSec password:', error);
return sendError(res, 500, 'Error reading IPSec password', 'E_S3');
}
}
/**
* POST /api/ipsec-passwords - создать новый пароль
*/
async function createIpsecPassword(req, res) {
const { name, password, description } = req.body;
if (!name || !password) {
return sendError(res, 400, 'Name and password are required', 'E_BAD_REQUEST');
}
try {
// Читаем текущие пароли
const data = await readS3TextObject(S3_KEY).catch(() => ({ body: '[]' }));
let passwords = [];
try {
passwords = JSON.parse(data.body || '[]');
if (!Array.isArray(passwords)) {
passwords = [];
}
} catch (parseError) {
passwords = [];
}
// Проверяем, нет ли уже пароля с таким именем
if (passwords.some(p => p.name === name)) {
return sendError(res, 400, 'Password with this name already exists', 'E_DUPLICATE');
}
// Шифруем пароль
let encryptedPassword;
try {
encryptedPassword = encrypt(password);
if (!encryptedPassword || encryptedPassword.trim() === '') {
console.error('Failed to encrypt password: result is empty');
return sendError(res, 500, 'Failed to encrypt password', 'E_ENCRYPT');
}
// Проверяем формат зашифрованного пароля
const parts = encryptedPassword.split(':');
if (parts.length !== 3) {
console.error('Invalid encrypted password format:', encryptedPassword.substring(0, 50));
return sendError(res, 500, 'Failed to encrypt password: invalid format', 'E_ENCRYPT');
}
} catch (encryptError) {
console.error('Error encrypting password:', encryptError);
return sendError(res, 500, `Failed to encrypt password: ${encryptError.message}`, 'E_ENCRYPT');
}
// Создаем новый пароль
const newPassword = {
id: `ipsec-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
name: String(name).trim(),
description: String(description || '').trim(),
encryptedPassword,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
passwords.push(newPassword);
// Сохраняем в S3
const meta = await writeS3JsonObject(S3_KEY, passwords);
// Возвращаем без расшифрованного пароля, но с ID
res.json({
id: newPassword.id,
name: newPassword.name,
description: newPassword.description,
createdAt: newPassword.createdAt,
updatedAt: newPassword.updatedAt,
});
} catch (error) {
console.error('Error creating IPSec password:', error);
return sendError(res, 500, 'Error creating IPSec password', 'E_S3');
}
}
/**
* PUT /api/ipsec-passwords/:id - обновить пароль
*/
async function updateIpsecPassword(req, res) {
const { id } = req.params;
const { name, password, description } = req.body;
try {
// Читаем текущие пароли
const data = await readS3TextObject(S3_KEY).catch(() => ({ body: '[]' }));
let passwords = [];
try {
passwords = JSON.parse(data.body || '[]');
if (!Array.isArray(passwords)) {
passwords = [];
}
} catch (parseError) {
passwords = [];
}
const index = passwords.findIndex(p => p.id === id);
if (index === -1) {
return sendError(res, 404, 'IPSec password not found', 'E_NOT_FOUND');
}
// Проверяем уникальность имени (если изменилось)
if (name && name !== passwords[index].name) {
if (passwords.some(p => p.id !== id && p.name === name)) {
return sendError(res, 400, 'Password with this name already exists', 'E_DUPLICATE');
}
}
// Обновляем пароль
if (name !== undefined) {
passwords[index].name = String(name).trim();
}
if (description !== undefined) {
passwords[index].description = String(description || '').trim();
}
if (password !== undefined) {
let encryptedPassword;
try {
encryptedPassword = encrypt(password);
if (!encryptedPassword || encryptedPassword.trim() === '') {
console.error('Failed to encrypt password: result is empty');
return sendError(res, 500, 'Failed to encrypt password', 'E_ENCRYPT');
}
// Проверяем формат зашифрованного пароля
const parts = encryptedPassword.split(':');
if (parts.length !== 3) {
console.error('Invalid encrypted password format:', encryptedPassword.substring(0, 50));
return sendError(res, 500, 'Failed to encrypt password: invalid format', 'E_ENCRYPT');
}
passwords[index].encryptedPassword = encryptedPassword;
} catch (encryptError) {
console.error('Error encrypting password:', encryptError);
return sendError(res, 500, `Failed to encrypt password: ${encryptError.message}`, 'E_ENCRYPT');
}
}
passwords[index].updatedAt = new Date().toISOString();
// Сохраняем в S3
const meta = await writeS3JsonObject(S3_KEY, passwords);
// Возвращаем без расшифрованного пароля
res.json({
id: passwords[index].id,
name: passwords[index].name,
description: passwords[index].description,
createdAt: passwords[index].createdAt,
updatedAt: passwords[index].updatedAt,
});
} catch (error) {
console.error('Error updating IPSec password:', error);
return sendError(res, 500, 'Error updating IPSec password', 'E_S3');
}
}
/**
* DELETE /api/ipsec-passwords/:id - удалить пароль
*/
async function deleteIpsecPassword(req, res) {
const { id } = req.params;
try {
// Читаем текущие пароли
const data = await readS3TextObject(S3_KEY).catch(() => ({ body: '[]' }));
let passwords = [];
try {
passwords = JSON.parse(data.body || '[]');
if (!Array.isArray(passwords)) {
passwords = [];
}
} catch (parseError) {
passwords = [];
}
const filtered = passwords.filter(p => p.id !== id);
if (filtered.length === passwords.length) {
return sendError(res, 404, 'IPSec password not found', 'E_NOT_FOUND');
}
// Сохраняем в S3
const meta = await writeS3JsonObject(S3_KEY, filtered);
res.json({ success: true });
} catch (error) {
console.error('Error deleting IPSec password:', error);
return sendError(res, 500, 'Error deleting IPSec password', 'E_S3');
}
}
module.exports = {
getIpsecPasswords,
getIpsecPassword,
createIpsecPassword,
updateIpsecPassword,
deleteIpsecPassword,
};