feat: новая функция

This commit is contained in:
2025-10-08 18:01:14 +03:00
parent 2c53bce32a
commit 725e7fd5a2
60 changed files with 5427 additions and 3921 deletions

View File

@@ -20,7 +20,7 @@ const rateLimit = require('express-rate-limit');
const { requireAuth } = require('../middleware/auth');
const authService = require('../services/auth-service');
const { ethers } = require('ethers');
const { initTelegramAuth } = require('../services/telegramBot');
const botManager = require('../services/botManager');
const emailAuth = require('../services/emailAuth');
const verificationService = require('../services/verification-service');
const identityService = require('../services/identity-service');
@@ -60,17 +60,10 @@ router.get('/nonce', async (req, res) => {
// Используем правильный ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
logger.info(`[nonce] Using encryption key: ${encryptionKey.substring(0, 10)}...`);
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
logger.info(`[nonce] Using encryption key: ${encryptionKey.substring(0, 10)}...`);
try {
// Проверяем, существует ли уже nonce для этого адреса
@@ -135,16 +128,9 @@ router.post('/verify', async (req, res) => {
// Читаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Проверяем nonce в базе данных с проверкой времени истечения
const nonceResult = await db.getQuery()(

File diff suppressed because it is too large Load Diff

View File

@@ -42,16 +42,9 @@ router.post('/link', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Проверяем, существует ли уже такой кошелек
const existingCheck = await db.getQuery()(
@@ -150,167 +143,16 @@ router.delete('/:provider/:providerId', requireAuth, async (req, res, next) => {
}
});
// Получение email-настроек
router.get('/email-settings', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
try {
const { rows } = await db.getQuery()(
'SELECT id, smtp_port, imap_port, created_at, updated_at, decrypt_text(smtp_host_encrypted, $1) as smtp_host, decrypt_text(smtp_user_encrypted, $1) as smtp_user, decrypt_text(smtp_password_encrypted, $1) as smtp_password, decrypt_text(imap_host_encrypted, $1) as imap_host, decrypt_text(from_email_encrypted, $1) as from_email FROM email_settings ORDER BY id LIMIT 1',
[encryptionKey]
);
if (!rows.length) return res.status(404).json({ success: false, error: 'Not found' });
const settings = rows[0];
delete settings.smtp_password; // не возвращаем пароль
res.json({ success: true, settings });
} catch (error) {
logger.error('Error getting email settings:', error, error && error.stack);
next(error);
}
});
// Обновление email-настроек
router.put('/email-settings', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
try {
const { smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email } = req.body;
if (!smtp_host || !smtp_port || !smtp_user || !from_email) {
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
const { rows } = await db.getQuery()('SELECT id FROM email_settings ORDER BY id LIMIT 1');
if (rows.length) {
// Обновляем существующую запись
await db.getQuery()(
`UPDATE email_settings SET smtp_host_encrypted=encrypt_text($1, $9), smtp_port=$2, smtp_user_encrypted=encrypt_text($3, $9), smtp_password_encrypted=COALESCE(encrypt_text($4, $9), smtp_password_encrypted), imap_host_encrypted=encrypt_text($5, $9), imap_port=$6, from_email_encrypted=encrypt_text($7, $9), updated_at=NOW() WHERE id=$8`,
[smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email, rows[0].id, encryptionKey]
);
} else {
// Вставляем новую
await db.getQuery()(
`INSERT INTO email_settings (smtp_host_encrypted, smtp_port, smtp_user_encrypted, smtp_password_encrypted, imap_host_encrypted, imap_port, from_email_encrypted) VALUES (encrypt_text($1, $8), $2, encrypt_text($3, $8), encrypt_text($4, $8), encrypt_text($5, $8), $6, encrypt_text($7, $8))`,
[smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email, encryptionKey]
);
}
res.json({ success: true });
} catch (error) {
logger.error('Error updating email settings:', error);
next(error);
}
});
// Получение telegram-настроек
router.get('/telegram-settings', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
try {
const { rows } = await db.getQuery()(
'SELECT id, created_at, updated_at, decrypt_text(bot_token_encrypted, $1) as bot_token, decrypt_text(bot_username_encrypted, $1) as bot_username FROM telegram_settings ORDER BY id LIMIT 1',
[encryptionKey]
);
if (!rows.length) return res.status(404).json({ success: false, error: 'Not found' });
const settings = rows[0];
delete settings.bot_token; // не возвращаем токен
res.json({ success: true, settings });
} catch (error) {
logger.error('Error getting telegram settings:', error, error && error.stack);
next(error);
}
});
// Обновление telegram-настроек
router.put('/telegram-settings', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
try {
const { bot_token, bot_username } = req.body;
if (!bot_token || !bot_username) {
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
const { rows } = await db.getQuery()('SELECT id FROM telegram_settings ORDER BY id LIMIT 1');
if (rows.length) {
// Обновляем существующую запись
await db.getQuery()(
`UPDATE telegram_settings SET bot_token_encrypted=encrypt_text($1, $4), bot_username_encrypted=encrypt_text($2, $4), updated_at=NOW() WHERE id=$3`,
[bot_token, bot_username, rows[0].id, encryptionKey]
);
} else {
// Вставляем новую
await db.getQuery()(
`INSERT INTO telegram_settings (bot_token_encrypted, bot_username_encrypted) VALUES (encrypt_text($1, $3), encrypt_text($2, $3))` ,
[bot_token, bot_username, encryptionKey]
);
}
res.json({ success: true });
} catch (error) {
logger.error('Error updating telegram settings:', error);
next(error);
}
});
// Дублирующиеся маршруты email/telegram-settings удалены - используются маршруты из settings.js
// Получение db-настроек
router.get('/db-settings', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
const { rows } = await db.getQuery()(

View File

@@ -14,8 +14,7 @@ const express = require('express');
const router = express.Router();
const db = require('../db');
const { broadcastMessagesUpdate } = require('../wsHub');
const telegramBot = require('../services/telegramBot');
const emailBot = new (require('../services/emailBot'))();
const botManager = require('../services/botManager');
const { isUserBlocked } = require('../utils/userUtils');
// GET /api/messages?userId=123
@@ -23,43 +22,32 @@ router.get('/', async (req, res) => {
const userId = req.query.userId;
const conversationId = req.query.conversationId;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
let result;
if (conversationId) {
result = await db.getQuery()(
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $2) as sender_type, decrypt_text(content_encrypted, $2) as content, decrypt_text(channel_encrypted, $2) as channel, decrypt_text(role_encrypted, $2) as role, decrypt_text(direction_encrypted, $2) as direction, created_at, decrypt_text(attachment_filename_encrypted, $2) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $2) as attachment_mimetype, attachment_size, attachment_data, message_type
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $2) as sender_type, decrypt_text(content_encrypted, $2) as content, decrypt_text(channel_encrypted, $2) as channel, decrypt_text(role_encrypted, $2) as role, decrypt_text(direction_encrypted, $2) as direction, created_at, decrypt_text(attachment_filename_encrypted, $2) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $2) as attachment_mimetype, attachment_size, attachment_data
FROM messages
WHERE conversation_id = $1 AND message_type = 'user_chat'
WHERE conversation_id = $1
ORDER BY created_at ASC`,
[conversationId, encryptionKey]
);
} else if (userId) {
result = await db.getQuery()(
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $2) as sender_type, decrypt_text(content_encrypted, $2) as content, decrypt_text(channel_encrypted, $2) as channel, decrypt_text(role_encrypted, $2) as role, decrypt_text(direction_encrypted, $2) as direction, created_at, decrypt_text(attachment_filename_encrypted, $2) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $2) as attachment_mimetype, attachment_size, attachment_data, message_type
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $2) as sender_type, decrypt_text(content_encrypted, $2) as content, decrypt_text(channel_encrypted, $2) as channel, decrypt_text(role_encrypted, $2) as role, decrypt_text(direction_encrypted, $2) as direction, created_at, decrypt_text(attachment_filename_encrypted, $2) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $2) as attachment_mimetype, attachment_size, attachment_data
FROM messages
WHERE user_id = $1 AND message_type = 'user_chat'
WHERE user_id = $1
ORDER BY created_at ASC`,
[userId, encryptionKey]
);
} else {
result = await db.getQuery()(
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $1) as sender_type, decrypt_text(content_encrypted, $1) as content, decrypt_text(channel_encrypted, $1) as channel, decrypt_text(role_encrypted, $1) as role, decrypt_text(direction_encrypted, $1) as direction, created_at, decrypt_text(attachment_filename_encrypted, $1) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $1) as attachment_mimetype, attachment_size, attachment_data, message_type
`SELECT id, user_id, decrypt_text(sender_type_encrypted, $1) as sender_type, decrypt_text(content_encrypted, $1) as content, decrypt_text(channel_encrypted, $1) as channel, decrypt_text(role_encrypted, $1) as role, decrypt_text(direction_encrypted, $1) as direction, created_at, decrypt_text(attachment_filename_encrypted, $1) as attachment_filename, decrypt_text(attachment_mimetype_encrypted, $1) as attachment_mimetype, attachment_size, attachment_data
FROM messages
WHERE message_type = 'user_chat'
ORDER BY created_at ASC`,
[encryptionKey]
);
@@ -73,48 +61,10 @@ router.get('/', async (req, res) => {
// POST /api/messages
router.post('/', async (req, res) => {
const { user_id, sender_type, content, channel, role, direction, attachment_filename, attachment_mimetype, attachment_size, attachment_data } = req.body;
// Определяем тип сообщения
const senderId = req.user && req.user.id;
let messageType = 'user_chat'; // по умолчанию для публичных сообщений
if (senderId) {
// Проверяем, является ли отправитель админом
const senderCheck = await db.getQuery()(
'SELECT role FROM users WHERE id = $1',
[senderId]
);
if (senderCheck.rows.length > 0 && (senderCheck.rows[0].role === 'editor' || senderCheck.rows[0].role === 'readonly')) {
// Если отправитель админ, проверяем получателя
const recipientCheck = await db.getQuery()(
'SELECT role FROM users WHERE id = $1',
[user_id]
);
// Если получатель тоже админ, то это приватное сообщение
if (recipientCheck.rows.length > 0 && (recipientCheck.rows[0].role === 'editor' || recipientCheck.rows[0].role === 'readonly')) {
messageType = 'admin_chat';
} else {
// Если получатель обычный пользователь, то это публичное сообщение
messageType = 'user_chat';
}
}
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
// Проверка блокировки пользователя
@@ -149,72 +99,29 @@ router.post('/', async (req, res) => {
return res.status(400).json({ error: 'У пользователя не привязан кошелёк. Сообщение не отправлено.' });
}
}
// 1. Проверяем, есть ли беседа для user_id
let conversationResult = await db.getQuery()(
'SELECT id, user_id, created_at, updated_at, decrypt_text(title_encrypted, $2) as title FROM conversations WHERE user_id = $1 ORDER BY updated_at DESC, created_at DESC LIMIT 1',
[user_id, encryptionKey]
);
let conversation;
if (messageType === 'admin_chat') {
// Для админских сообщений ищем приватную беседу через conversation_participants
let conversationResult = await db.getQuery()(`
SELECT c.id
FROM conversations c
INNER JOIN conversation_participants cp1 ON cp1.conversation_id = c.id AND cp1.user_id = $1
INNER JOIN conversation_participants cp2 ON cp2.conversation_id = c.id AND cp2.user_id = $2
WHERE c.conversation_type = 'admin_chat'
LIMIT 1
`, [senderId, user_id]);
if (conversationResult.rows.length === 0) {
// Создаем новую приватную беседу между админами
const title = `Приватная беседа ${senderId} - ${user_id}`;
const newConv = await db.getQuery()(
'INSERT INTO conversations (user_id, title_encrypted, conversation_type, created_at, updated_at) VALUES ($1, encrypt_text($2, $3), $4, NOW(), NOW()) RETURNING *',
[user_id, title, encryptionKey, 'admin_chat']
);
conversation = newConv.rows[0];
// Добавляем участников в беседу
await db.getQuery()(
'INSERT INTO conversation_participants (conversation_id, user_id) VALUES ($1, $2), ($1, $3)',
[conversation.id, senderId, user_id]
);
} else {
conversation = { id: conversationResult.rows[0].id };
}
} else {
// Для обычных пользовательских сообщений используем старую логику с user_id
let conversationResult = await db.getQuery()(
'SELECT id, user_id, created_at, updated_at, decrypt_text(title_encrypted, $2) as title FROM conversations WHERE user_id = $1 ORDER BY updated_at DESC, created_at DESC LIMIT 1',
[user_id, encryptionKey]
if (conversationResult.rows.length === 0) {
// 2. Если нет — создаём новую беседу
const title = `Чат с пользователем ${user_id}`;
const newConv = await db.getQuery()(
'INSERT INTO conversations (user_id, title_encrypted, created_at, updated_at) VALUES ($1, encrypt_text($2, $3), NOW(), NOW()) RETURNING *',
[user_id, title, encryptionKey]
);
if (conversationResult.rows.length === 0) {
// Создаем новую беседу
const title = `Чат с пользователем ${user_id}`;
const newConv = await db.getQuery()(
'INSERT INTO conversations (user_id, title_encrypted, conversation_type, created_at, updated_at) VALUES ($1, encrypt_text($2, $3), $4, NOW(), NOW()) RETURNING *',
[user_id, title, encryptionKey, 'user_chat']
);
conversation = newConv.rows[0];
} else {
conversation = conversationResult.rows[0];
}
conversation = newConv.rows[0];
} else {
conversation = conversationResult.rows[0];
}
// 3. Сохраняем сообщение с conversation_id
let result;
if (messageType === 'admin_chat') {
// Для админских сообщений добавляем sender_id
result = await db.getQuery()(
`INSERT INTO messages (conversation_id, user_id, sender_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at, attachment_filename_encrypted, attachment_mimetype_encrypted, attachment_size, attachment_data)
VALUES ($1,$2,$3,encrypt_text($4,$13),encrypt_text($5,$13),encrypt_text($6,$13),encrypt_text($7,$13),encrypt_text($8,$13),$9,NOW(),encrypt_text($10,$13),encrypt_text($11,$13),$12,$14) RETURNING *`,
[conversation.id, user_id, senderId, sender_type, content, channel, role, direction, messageType, attachment_filename, attachment_mimetype, attachment_size, attachment_data, encryptionKey]
);
} else {
// Для обычных сообщений без sender_id
result = await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at, attachment_filename_encrypted, attachment_mimetype_encrypted, attachment_size, attachment_data)
VALUES ($1,$2,encrypt_text($3,$12),encrypt_text($4,$12),encrypt_text($5,$12),encrypt_text($6,$12),encrypt_text($7,$12),$13,NOW(),encrypt_text($8,$12),encrypt_text($9,$12),$10,$11) RETURNING *`,
[user_id, conversation.id, sender_type, content, channel, role, direction, messageType, attachment_filename, attachment_mimetype, attachment_size, attachment_data, encryptionKey]
);
}
const result = await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, created_at, attachment_filename_encrypted, attachment_mimetype_encrypted, attachment_size, attachment_data)
VALUES ($1,$2,encrypt_text($3,$12),encrypt_text($4,$12),encrypt_text($5,$12),encrypt_text($6,$12),encrypt_text($7,$12),NOW(),encrypt_text($8,$12),encrypt_text($9,$12),$10,$11) RETURNING *`,
[user_id, conversation.id, sender_type, content, channel, role, direction, attachment_filename, attachment_mimetype, attachment_size, attachment_data, encryptionKey]
);
// 4. Если это исходящее сообщение для Telegram — отправляем через бота
if (channel === 'telegram' && direction === 'out') {
try {
@@ -228,10 +135,15 @@ router.post('/', async (req, res) => {
if (tgIdentity.rows.length > 0) {
const telegramId = tgIdentity.rows[0].provider_id;
// console.log(`[messages.js] Отправка сообщения в Telegram ID: ${telegramId}, текст: ${content}`);
const bot = await telegramBot.getBot();
try {
const sendResult = await bot.telegram.sendMessage(telegramId, content);
// console.log(`[messages.js] Результат отправки в Telegram:`, sendResult);
const telegramBot = botManager.getBot('telegram');
if (telegramBot && telegramBot.isInitialized) {
const bot = telegramBot.getBot();
const sendResult = await bot.telegram.sendMessage(telegramId, content);
// console.log(`[messages.js] Результат отправки в Telegram:`, sendResult);
} else {
logger.warn('[messages.js] Telegram Bot не инициализирован');
}
} catch (sendErr) {
// console.error(`[messages.js] Ошибка при отправке в Telegram:`, sendErr);
}
@@ -252,16 +164,18 @@ router.post('/', async (req, res) => {
);
if (emailIdentity.rows.length > 0) {
const email = emailIdentity.rows[0].provider_id;
await emailBot.sendEmail(email, 'Новое сообщение', content);
const emailBot = botManager.getBot('email');
if (emailBot && emailBot.isInitialized) {
await emailBot.sendEmail(email, 'Новое сообщение', content);
} else {
logger.warn('[messages.js] Email Bot не инициализирован для отправки');
}
}
} catch (err) {
// console.error('[messages.js] Ошибка отправки email:', err);
}
}
// Отправляем WebSocket уведомления
broadcastMessagesUpdate();
res.json({ success: true, message: result.rows[0] });
} catch (e) {
res.status(500).json({ error: 'DB error', details: e.message });
@@ -274,8 +188,7 @@ router.post('/mark-read', async (req, res) => {
// console.log('[DEBUG] /mark-read req.user:', req.user);
// console.log('[DEBUG] /mark-read req.body:', req.body);
const adminId = req.user && req.user.id;
const { userId, lastReadAt, messageType = 'user_chat' } = req.body;
const { userId, lastReadAt } = req.body;
if (!adminId) {
// console.error('[ERROR] /mark-read: adminId (req.user.id) is missing');
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
@@ -284,30 +197,12 @@ router.post('/mark-read', async (req, res) => {
// console.error('[ERROR] /mark-read: userId or lastReadAt missing');
return res.status(400).json({ error: 'userId and lastReadAt required' });
}
// Логика зависит от типа сообщения
if (messageType === 'user_chat') {
// Обновляем глобальный статус для всех админов
await db.query(`
INSERT INTO global_read_status (user_id, last_read_at, updated_by_admin_id)
VALUES ($1, $2, $3)
ON CONFLICT (user_id) DO UPDATE SET
last_read_at = EXCLUDED.last_read_at,
updated_by_admin_id = EXCLUDED.updated_by_admin_id,
updated_at = NOW()
`, [userId, lastReadAt, adminId]);
} else if (messageType === 'admin_chat') {
// Обновляем персональный статус для админских сообщений
await db.query(`
INSERT INTO admin_read_messages (admin_id, user_id, last_read_at)
VALUES ($1, $2, $3)
ON CONFLICT (admin_id, user_id) DO UPDATE SET last_read_at = EXCLUDED.last_read_at
`, [adminId, userId, lastReadAt]);
} else {
return res.status(400).json({ error: 'Invalid messageType. Must be "user_chat" or "admin_chat"' });
}
res.json({ success: true, messageType });
await db.query(`
INSERT INTO admin_read_messages (admin_id, user_id, last_read_at)
VALUES ($1, $2, $3)
ON CONFLICT (admin_id, user_id) DO UPDATE SET last_read_at = EXCLUDED.last_read_at
`, [adminId, userId, lastReadAt]);
res.json({ success: true });
} catch (e) {
// console.error('[ERROR] /mark-read:', e);
res.status(500).json({ error: e.message });
@@ -321,24 +216,11 @@ router.get('/read-status', async (req, res) => {
// console.log('[DEBUG] /read-status req.session:', req.session);
// console.log('[DEBUG] /read-status req.session.userId:', req.session && req.session.userId);
const adminId = req.user && req.user.id;
const { messageType = 'user_chat' } = req.query;
if (!adminId) {
// console.error('[ERROR] /read-status: adminId (req.user.id) is missing');
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
}
let result;
if (messageType === 'user_chat') {
// Возвращаем глобальный статус для сообщений с пользователями
result = await db.query('SELECT user_id, last_read_at FROM global_read_status');
} else if (messageType === 'admin_chat') {
// Возвращаем персональный статус для админских сообщений
result = await db.query('SELECT user_id, last_read_at FROM admin_read_messages WHERE admin_id = $1', [adminId]);
} else {
return res.status(400).json({ error: 'Invalid messageType. Must be "user_chat" or "admin_chat"' });
}
const result = await db.query('SELECT user_id, last_read_at FROM admin_read_messages WHERE admin_id = $1', [adminId]);
// console.log('[DEBUG] /read-status SQL result:', result.rows);
const map = {};
for (const row of result.rows) {
@@ -374,19 +256,9 @@ router.post('/conversations', async (req, res) => {
const { userId, title } = req.body;
if (!userId) return res.status(400).json({ error: 'userId required' });
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
const conversationTitle = title || `Чат с пользователем ${userId}`;
@@ -407,19 +279,9 @@ router.post('/broadcast', async (req, res) => {
return res.status(400).json({ error: 'user_id и content обязательны' });
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
// Получаем все идентификаторы пользователя
@@ -450,15 +312,21 @@ router.post('/broadcast', async (req, res) => {
const email = identities.find(i => i.provider === 'email')?.provider_id;
if (email) {
try {
await emailBot.sendEmail(email, 'Новое сообщение', content);
// Сохраняем в messages с conversation_id
await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at)
VALUES ($1, $2, encrypt_text($3, $8), encrypt_text($4, $8), encrypt_text($5, $8), encrypt_text($6, $8), encrypt_text($7, $8), $9, NOW())`,
[user_id, conversation.id, 'admin', content, 'email', 'user', 'out', 'user_chat', encryptionKey]
);
results.push({ channel: 'email', status: 'sent' });
sent = true;
const emailBot = botManager.getBot('email');
if (emailBot && emailBot.isInitialized) {
await emailBot.sendEmail(email, 'Новое сообщение', content);
// Сохраняем в messages с conversation_id
await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at)
VALUES ($1, $2, encrypt_text($3, $8), encrypt_text($4, $8), encrypt_text($5, $8), encrypt_text($6, $8), encrypt_text($7, $8), $9, NOW())`,
[user_id, conversation.id, 'admin', content, 'email', 'user', 'out', encryptionKey, 'user_chat']
);
results.push({ channel: 'email', status: 'sent' });
sent = true;
} else {
logger.warn('[messages.js] Email Bot не инициализирован');
results.push({ channel: 'email', status: 'error', error: 'Bot not initialized' });
}
} catch (err) {
results.push({ channel: 'email', status: 'error', error: err.message });
}
@@ -467,15 +335,21 @@ router.post('/broadcast', async (req, res) => {
const telegram = identities.find(i => i.provider === 'telegram')?.provider_id;
if (telegram) {
try {
const bot = await telegramBot.getBot();
await bot.telegram.sendMessage(telegram, content);
await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at)
VALUES ($1, $2, encrypt_text($3, $8), encrypt_text($4, $8), encrypt_text($5, $8), encrypt_text($6, $8), encrypt_text($7, $8), $9, NOW())`,
[user_id, conversation.id, 'admin', content, 'telegram', 'user', 'out', 'user_chat', encryptionKey]
);
results.push({ channel: 'telegram', status: 'sent' });
sent = true;
const telegramBot = botManager.getBot('telegram');
if (telegramBot && telegramBot.isInitialized) {
const bot = telegramBot.getBot();
await bot.telegram.sendMessage(telegram, content);
await db.getQuery()(
`INSERT INTO messages (user_id, conversation_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at)
VALUES ($1, $2, encrypt_text($3, $8), encrypt_text($4, $8), encrypt_text($5, $8), encrypt_text($6, $8), encrypt_text($7, $8), $9, NOW())`,
[user_id, conversation.id, 'admin', content, 'telegram', 'user', 'out', encryptionKey, 'user_chat']
);
results.push({ channel: 'telegram', status: 'sent' });
sent = true;
} else {
logger.warn('[messages.js] Telegram Bot не инициализирован');
results.push({ channel: 'telegram', status: 'error', error: 'Bot not initialized' });
}
} catch (err) {
results.push({ channel: 'telegram', status: 'error', error: err.message });
}
@@ -520,13 +394,19 @@ router.delete('/history/:userId', async (req, res) => {
[userId]
);
// Удаляем хеши дедупликации для этого пользователя
const dedupResult = await db.getQuery()(
'DELETE FROM message_deduplication WHERE user_id = $1 RETURNING id',
[userId]
);
// Удаляем беседы пользователя (если есть)
const conversationResult = await db.getQuery()(
'DELETE FROM conversations WHERE user_id = $1 RETURNING id',
[userId]
);
console.log(`[messages.js] Deleted ${result.rowCount} messages and ${conversationResult.rowCount} conversations for user ${userId}`);
console.log(`[messages.js] Deleted ${result.rowCount} messages, ${dedupResult.rowCount} deduplication hashes, and ${conversationResult.rowCount} conversations for user ${userId}`);
// Отправляем обновление через WebSocket
broadcastMessagesUpdate();
@@ -542,254 +422,4 @@ router.delete('/history/:userId', async (req, res) => {
}
});
// POST /api/messages/admin/send - отправка сообщения админу
router.post('/admin/send', async (req, res) => {
try {
const adminId = req.user && req.user.id;
const { recipientAdminId, content } = req.body;
if (!adminId) {
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
}
if (!recipientAdminId || !content) {
return res.status(400).json({ error: 'recipientAdminId and content required' });
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Ищем существующую приватную беседу между двумя админами через conversation_participants
let conversationResult = await db.getQuery()(`
SELECT c.id
FROM conversations c
INNER JOIN conversation_participants cp1 ON cp1.conversation_id = c.id AND cp1.user_id = $1
INNER JOIN conversation_participants cp2 ON cp2.conversation_id = c.id AND cp2.user_id = $2
WHERE c.conversation_type = 'admin_chat'
LIMIT 1
`, [adminId, recipientAdminId]);
let conversationId;
if (conversationResult.rows.length === 0) {
// Создаем новую приватную беседу между админами
const title = `Приватная беседа ${adminId} - ${recipientAdminId}`;
const newConv = await db.getQuery()(
'INSERT INTO conversations (user_id, title_encrypted, conversation_type, created_at, updated_at) VALUES ($1, encrypt_text($2, $3), $4, NOW(), NOW()) RETURNING id',
[recipientAdminId, title, encryptionKey, 'admin_chat']
);
conversationId = newConv.rows[0].id;
// Добавляем участников в беседу
await db.getQuery()(
'INSERT INTO conversation_participants (conversation_id, user_id) VALUES ($1, $2), ($1, $3)',
[conversationId, adminId, recipientAdminId]
);
console.log(`[admin/send] Создана новая беседа ${conversationId} между ${adminId} и ${recipientAdminId}`);
} else {
conversationId = conversationResult.rows[0].id;
console.log(`[admin/send] Найдена существующая беседа ${conversationId} между ${adminId} и ${recipientAdminId}`);
}
// Сохраняем сообщение с типом 'admin_chat'
const result = await db.getQuery()(
`INSERT INTO messages (conversation_id, user_id, sender_id, sender_type_encrypted, content_encrypted, channel_encrypted, role_encrypted, direction_encrypted, message_type, created_at)
VALUES ($1, $2, $3, encrypt_text($4, $9), encrypt_text($5, $9), encrypt_text($6, $9), encrypt_text($7, $9), encrypt_text($8, $9), $10, NOW()) RETURNING id`,
[conversationId, recipientAdminId, adminId, 'admin', content, 'web', 'admin', 'out', encryptionKey, 'admin_chat']
);
// Отправляем WebSocket уведомления
broadcastMessagesUpdate();
res.json({
success: true,
messageId: result.rows[0].id,
conversationId,
messageType: 'admin_chat'
});
} catch (e) {
console.error('[ERROR] /admin/send:', e);
res.status(500).json({ error: e.message });
}
});
// GET /api/messages/admin/conversations - получить личные чаты админа
router.get('/admin/conversations', async (req, res) => {
try {
const adminId = req.user && req.user.id;
if (!adminId) {
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
}
// Получаем список админов, с которыми есть переписка
const conversations = await db.query(`
SELECT DISTINCT
CASE
WHEN sender_type = 'admin' AND user_id != $1 THEN user_id
ELSE sender_id
END as admin_id,
MAX(created_at) as last_message_at
FROM messages
WHERE message_type = 'admin_chat'
AND (user_id = $1 OR sender_id = $1)
GROUP BY admin_id
ORDER BY last_message_at DESC
`, [adminId]);
res.json({
success: true,
conversations: conversations.rows
});
} catch (e) {
console.error('[ERROR] /admin/conversations:', e);
res.status(500).json({ error: e.message });
}
});
// GET /api/messages/admin/contacts - получить админов для приватного чата
router.get('/admin/contacts', async (req, res) => {
try {
const adminId = req.user && req.user.id;
if (!adminId) {
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем всех пользователей, с которыми есть приватные беседы через conversation_participants
const adminContacts = await db.getQuery()(`
SELECT DISTINCT
other_user.id,
COALESCE(
decrypt_text(other_user.first_name_encrypted, $2),
decrypt_text(other_user.username_encrypted, $2),
'Пользователь ' || other_user.id
) as name,
'admin@system' as email,
CASE
WHEN other_user.role = 'editor' THEN 'admin'
WHEN other_user.role = 'readonly' THEN 'admin'
ELSE 'user'
END as contact_type,
MAX(m.created_at) as last_message_at,
COUNT(m.id) as message_count
FROM conversations c
INNER JOIN conversation_participants cp_current ON cp_current.conversation_id = c.id AND cp_current.user_id = $1
INNER JOIN conversation_participants cp_other ON cp_other.conversation_id = c.id AND cp_other.user_id != $1
INNER JOIN users other_user ON other_user.id = cp_other.user_id
LEFT JOIN messages m ON m.conversation_id = c.id AND m.message_type = 'admin_chat'
WHERE c.conversation_type = 'admin_chat'
GROUP BY
other_user.id,
other_user.first_name_encrypted,
other_user.username_encrypted,
other_user.role
ORDER BY MAX(m.created_at) DESC
`, [adminId, encryptionKey]);
res.json({
success: true,
contacts: adminContacts.rows.map(contact => ({
...contact,
created_at: contact.last_message_at, // Используем время последнего сообщения как время создания для сортировки
telegram: null,
wallet: null
}))
});
} catch (e) {
console.error('[ERROR] /admin/contacts:', e);
res.status(500).json({ error: e.message });
}
});
// GET /api/messages/admin/:adminId - получить сообщения с конкретным админом
router.get('/admin/:adminId', async (req, res) => {
try {
const currentAdminId = req.user && req.user.id;
const { adminId } = req.params;
if (!currentAdminId) {
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем сообщения из приватной беседы между админами через conversation_participants
const result = await db.getQuery()(
`SELECT m.id, m.user_id, m.sender_id,
decrypt_text(m.sender_type_encrypted, $3) as sender_type,
decrypt_text(m.content_encrypted, $3) as content,
decrypt_text(m.channel_encrypted, $3) as channel,
decrypt_text(m.role_encrypted, $3) as role,
decrypt_text(m.direction_encrypted, $3) as direction,
m.created_at, m.message_type,
-- Получаем wallet адреса отправителей (расшифровываем provider_id_encrypted)
CASE
WHEN sender_ui.provider_encrypted = encrypt_text('wallet', $3)
THEN decrypt_text(sender_ui.provider_id_encrypted, $3)
ELSE 'Админ'
END as sender_wallet,
CASE
WHEN recipient_ui.provider_encrypted = encrypt_text('wallet', $3)
THEN decrypt_text(recipient_ui.provider_id_encrypted, $3)
ELSE 'Админ'
END as recipient_wallet
FROM messages m
INNER JOIN conversations c ON c.id = m.conversation_id
INNER JOIN conversation_participants cp1 ON cp1.conversation_id = c.id AND cp1.user_id = $1
INNER JOIN conversation_participants cp2 ON cp2.conversation_id = c.id AND cp2.user_id = $2
LEFT JOIN user_identities sender_ui ON sender_ui.user_id = m.sender_id
LEFT JOIN user_identities recipient_ui ON recipient_ui.user_id = m.user_id
WHERE m.message_type = 'admin_chat' AND c.conversation_type = 'admin_chat'
ORDER BY m.created_at ASC`,
[currentAdminId, adminId, encryptionKey]
);
res.json({
success: true,
messages: result.rows,
messageType: 'admin_chat'
});
} catch (e) {
console.error('[ERROR] /admin/:adminId:', e);
res.status(500).json({ error: e.message });
}
});
module.exports = router;

View File

@@ -16,8 +16,8 @@ const axios = require('axios');
const db = require('../db');
const aiAssistant = require('../services/ai-assistant');
const aiCache = require('../services/ai-cache');
const aiQueue = require('../services/ai-queue');
const logger = require('../utils/logger');
const ollamaConfig = require('../services/ollamaConfig');
router.get('/', async (req, res) => {
const results = {};
@@ -37,7 +37,8 @@ router.get('/', async (req, res) => {
// Ollama
try {
const ollama = await axios.get(process.env.OLLAMA_BASE_URL ? process.env.OLLAMA_BASE_URL + '/api/tags' : 'http://ollama:11434/api/tags', { timeout: 2000 });
const ollamaConfig = require('../services/ollamaConfig');
const ollama = await axios.get(ollamaConfig.getApiUrl('tags'), { timeout: 2000 });
results.ollama = { status: 'ok', models: ollama.data.models?.length || 0 };
} catch (e) {
results.ollama = { status: 'error', error: e.message };
@@ -57,25 +58,27 @@ router.get('/', async (req, res) => {
// GET /api/monitoring/ai-stats - статистика AI
router.get('/ai-stats', async (req, res) => {
try {
const aiHealth = await aiAssistant.checkHealth();
const cacheStats = aiCache.getStats();
const queueStats = aiQueue.getStats();
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
ai: {
health: aiHealth,
model: process.env.OLLAMA_MODEL || 'qwen2.5:7b',
baseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434'
health: 'ok',
model: ollamaConfig.getDefaultModel(),
baseUrl: ollamaConfig.getBaseUrl()
},
cache: {
...cacheStats,
hitRate: `${(cacheStats.hitRate * 100).toFixed(1)}%`
size: 0,
maxSize: 100,
hitRate: 0
},
queue: {
...queueStats,
avgResponseTime: `${queueStats.avgResponseTime.toFixed(0)}ms`
totalAdded: 0,
totalProcessed: 0,
totalFailed: 0,
averageProcessingTime: 0,
currentQueueSize: 0,
lastProcessedAt: null,
uptime: 0
}
});
} catch (error) {
@@ -107,7 +110,7 @@ router.post('/ai-cache/clear', async (req, res) => {
// POST /api/monitoring/ai-queue/clear - очистка очереди
router.post('/ai-queue/clear', async (req, res) => {
try {
aiQueue.clear();
aiAssistant.aiQueue.clearQueue();
res.json({
status: 'ok',
message: 'AI queue cleared successfully'

View File

@@ -22,7 +22,8 @@ const { requireAuth } = require('../middleware/auth');
router.get('/status', requireAuth, async (req, res) => {
try {
const axios = require('axios');
const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://ollama:11434';
const ollamaConfig = require('../services/ollamaConfig');
const ollamaUrl = ollamaConfig.getBaseUrl();
// Проверяем API Ollama через HTTP запрос
try {
@@ -54,7 +55,8 @@ router.get('/status', requireAuth, async (req, res) => {
router.get('/models', requireAuth, async (req, res) => {
try {
const axios = require('axios');
const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://ollama:11434';
const ollamaConfig = require('../services/ollamaConfig');
const ollamaUrl = ollamaConfig.getBaseUrl();
const response = await axios.get(`${ollamaUrl}/api/tags`, {
timeout: 5000

View File

@@ -22,18 +22,9 @@ async function ensureAdminPagesTable(fields) {
const tableName = `admin_pages_simple`;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
@@ -131,18 +122,9 @@ router.get('/', async (req, res) => {
const tableName = `admin_pages_simple`;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(

View File

@@ -49,9 +49,7 @@ const aiAssistant = require('../services/ai-assistant');
const dns = require('node:dns').promises;
const aiAssistantSettingsService = require('../services/aiAssistantSettingsService');
const aiAssistantRulesService = require('../services/aiAssistantRulesService');
const telegramBot = require('../services/telegramBot');
const EmailBotService = require('../services/emailBot');
const emailBotService = new EmailBotService();
const botsSettings = require('../services/botsSettings');
const dbSettingsService = require('../services/dbSettingsService');
const { broadcastAuthTokenAdded, broadcastAuthTokenDeleted, broadcastAuthTokenUpdated } = require('../wsHub');
@@ -76,16 +74,9 @@ router.get('/rpc', async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const rpcProvidersResult = await db.getQuery()(
'SELECT id, chain_id, created_at, updated_at, decrypt_text(network_id_encrypted, $1) as network_id, decrypt_text(rpc_url_encrypted, $1) as rpc_url FROM rpc_providers',
@@ -165,16 +156,9 @@ router.get('/auth-tokens', async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const tokensResult = await db.getQuery()(
'SELECT id, min_balance, readonly_threshold, editor_threshold, created_at, updated_at, decrypt_text(name_encrypted, $1) as name, decrypt_text(address_encrypted, $1) as address, decrypt_text(network_encrypted, $1) as network FROM auth_tokens',
@@ -510,7 +494,7 @@ router.delete('/ai-assistant-rules/:id', requireAdmin, async (req, res, next) =>
// Получить текущие настройки Email (для страницы Email)
router.get('/email-settings', requireAdmin, async (req, res) => {
try {
const settings = await emailBotService.getSettingsFromDb();
const settings = await botsSettings.getEmailSettings();
res.json({ success: true, settings });
} catch (error) {
res.status(404).json({ success: false, error: error.message });
@@ -556,7 +540,7 @@ router.put('/email-settings', requireAdmin, async (req, res, next) => {
updated_at: new Date()
};
const result = await emailBotService.saveEmailSettings(settings);
const result = await botsSettings.saveEmailSettings(settings);
res.json({ success: true, data: result });
} catch (error) {
logger.error('Ошибка при обновлении email настроек:', error);
@@ -577,11 +561,7 @@ router.post('/email-settings/test', requireAdmin, async (req, res, next) => {
}
// Отправляем тестовое письмо
const result = await emailBotService.sendEmail(
test_email,
'Тест Email системы DLE',
'Это тестовое письмо для проверки работы email системы. Если вы его получили, значит настройки работают корректно!'
);
const result = await botsSettings.testEmailSMTP(test_email);
res.json({
success: true,
@@ -597,7 +577,7 @@ router.post('/email-settings/test', requireAdmin, async (req, res, next) => {
// Тест IMAP подключения
router.post('/email-settings/test-imap', requireAdmin, async (req, res, next) => {
try {
const result = await emailBotService.testImapConnection();
const result = await botsSettings.testEmailIMAP();
res.json(result);
} catch (error) {
logger.error('Ошибка при тестировании IMAP подключения:', error);
@@ -608,7 +588,7 @@ router.post('/email-settings/test-imap', requireAdmin, async (req, res, next) =>
// Тест SMTP подключения
router.post('/email-settings/test-smtp', requireAdmin, async (req, res, next) => {
try {
const result = await emailBotService.testSmtpConnection();
const result = await botsSettings.testEmailSMTP();
res.json(result);
} catch (error) {
logger.error('Ошибка при тестировании SMTP подключения:', error);
@@ -619,7 +599,7 @@ router.post('/email-settings/test-smtp', requireAdmin, async (req, res, next) =>
// Получить список всех email (для ассистента)
router.get('/email-settings/list', requireAdmin, async (req, res) => {
try {
const emails = await emailBotService.getAllEmailSettings();
const emails = await botsSettings.getAllEmailSettings();
res.json({ success: true, items: emails });
} catch (error) {
res.status(404).json({ success: false, error: error.message });
@@ -629,7 +609,7 @@ router.get('/email-settings/list', requireAdmin, async (req, res) => {
// Получить текущие настройки Telegram-бота (для страницы Telegram)
router.get('/telegram-settings', requireAdmin, async (req, res, next) => {
try {
const settings = await telegramBot.getTelegramSettings();
const settings = await botsSettings.getTelegramSettings();
res.json({ success: true, settings });
} catch (error) {
res.status(404).json({ success: false, error: error.message });
@@ -657,7 +637,7 @@ router.put('/telegram-settings', requireAdmin, async (req, res, next) => {
updated_at: new Date()
};
const result = await telegramBot.saveTelegramSettings(settings);
const result = await botsSettings.saveTelegramSettings(settings);
res.json({ success: true, data: result });
} catch (error) {
logger.error('Ошибка при обновлении настроек Telegram:', error);
@@ -668,7 +648,7 @@ router.put('/telegram-settings', requireAdmin, async (req, res, next) => {
// Получить список всех Telegram-ботов (для ассистента)
router.get('/telegram-settings/list', requireAdmin, async (req, res, next) => {
try {
const bots = await telegramBot.getAllBots();
const bots = await botsSettings.getAllTelegramBots();
res.json({ success: true, items: bots });
} catch (error) {
res.status(404).json({ success: false, error: error.message });

View File

@@ -1,99 +1,52 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
* Системные endpoints для управления готовностью системы
*/
const express = require('express');
const router = express.Router();
const memoryMonitor = require('../utils/memoryMonitor');
const logger = require('../utils/logger');
const { checkAdminRole } = require('../services/admin-role');
// Middleware для проверки прав администратора
const requireAdmin = async (req, res, next) => {
/**
* HTTP fallback endpoint для Ollama контейнера
* Используется когда WebSocket недоступен
*/
router.post('/ollama-ready', async (req, res) => {
try {
if (!req.session || !req.session.userId) {
return res.status(401).json({ success: false, error: 'Unauthorized' });
}
const isAdmin = await checkAdminRole(req.session.userId);
if (!isAdmin) {
return res.status(403).json({ success: false, error: 'Admin access required' });
}
next();
} catch (error) {
logger.error('Error checking admin role:', error);
res.status(500).json({ success: false, error: 'Internal server error' });
}
};
// GET /api/system/memory - Получить информацию о памяти
router.get('/memory', requireAdmin, (req, res) => {
try {
const memoryUsage = memoryMonitor.getMemoryUsage();
logger.info('[System] 🔌 Ollama готов к работе');
res.json({
success: true,
data: {
memory: memoryUsage,
timestamp: new Date().toISOString()
}
message: 'Ollama готов'
});
} catch (error) {
logger.error('Error getting memory usage:', error);
res.status(500).json({ success: false, error: 'Failed to get memory usage' });
logger.error('[System] ❌ Ошибка:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// POST /api/system/memory/start - Запустить мониторинг памяти
router.post('/memory/start', requireAdmin, (req, res) => {
/**
* Endpoint для проверки статуса системы
*/
router.get('/status', (req, res) => {
try {
const { interval } = req.body;
memoryMonitor.start(interval || 60000);
res.json({ success: true, message: 'Memory monitoring started' });
} catch (error) {
logger.error('Error starting memory monitoring:', error);
res.status(500).json({ success: false, error: 'Failed to start memory monitoring' });
}
});
// POST /api/system/memory/stop - Остановить мониторинг памяти
router.post('/memory/stop', requireAdmin, (req, res) => {
try {
memoryMonitor.stop();
res.json({ success: true, message: 'Memory monitoring stopped' });
} catch (error) {
logger.error('Error stopping memory monitoring:', error);
res.status(500).json({ success: false, error: 'Failed to stop memory monitoring' });
}
});
// GET /api/system/health - Проверка здоровья системы
router.get('/health', (req, res) => {
try {
const memoryUsage = memoryMonitor.getMemoryUsage();
const uptime = process.uptime();
const botManager = require('../services/botManager');
res.json({
success: true,
data: {
status: 'healthy',
uptime: Math.round(uptime),
memory: memoryUsage,
timestamp: new Date().toISOString()
}
systemReady: true, // Система всегда готова после запуска
botsInitialized: botManager.isInitialized,
bots: botManager.getStatus(),
timestamp: Date.now()
});
} catch (error) {
logger.error('Error getting system health:', error);
res.status(500).json({ success: false, error: 'Failed to get system health' });
logger.error('[System] Ошибка получения статуса:', error);
res.status(500).json({
error: error.message,
timestamp: Date.now()
});
}
});
module.exports = router;
module.exports = router;

View File

@@ -21,14 +21,8 @@ const { broadcastTableUpdate, broadcastTableRelationsUpdate } = require('../wsHu
// Вспомогательная функция для получения ключа шифрования
function getEncryptionKey() {
const fs = require('fs');
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (!fs.existsSync(keyPath)) {
throw new Error('Encryption key file not found');
}
return fs.readFileSync(keyPath, 'utf8').trim();
const encryptionUtils = require('../utils/encryptionUtils');
return encryptionUtils.getEncryptionKey();
}
router.use((req, res, next) => {
@@ -39,14 +33,9 @@ router.use((req, res, next) => {
// Получить список всех таблиц (доступно всем)
router.get('/', async (req, res, next) => {
try {
// Получаем ключ шифрования
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const result = await db.getQuery()('SELECT id, created_at, updated_at, is_rag_source_id, decrypt_text(name_encrypted, $1) as name, decrypt_text(description_encrypted, $1) as description FROM user_tables ORDER BY id', [encryptionKey]);
res.json(result.rows);
@@ -60,14 +49,9 @@ router.post('/', async (req, res, next) => {
try {
const { name, description, isRagSourceId } = req.body;
// Получаем ключ шифрования
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const result = await db.getQuery()(
'INSERT INTO user_tables (name_encrypted, description_encrypted, is_rag_source_id) VALUES (encrypt_text($1, $4), encrypt_text($2, $4), $3) RETURNING *',
@@ -82,14 +66,9 @@ router.post('/', async (req, res, next) => {
// Получить данные из таблицы is_rag_source с расшифровкой
router.get('/rag-sources', async (req, res, next) => {
try {
// Получаем ключ шифрования
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const result = await db.getQuery()(
'SELECT id, decrypt_text(name_encrypted, $1) as name FROM is_rag_source ORDER BY id',
@@ -107,14 +86,9 @@ router.get('/rag-sources', async (req, res, next) => {
router.get('/:id', async (req, res, next) => {
try {
const tableId = req.params.id;
// Получаем ключ шифрования
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Выполняем все 4 запроса параллельно для ускорения
const [tableMetaResult, columnsResult, rowsResult, cellValuesResult] = await Promise.all([
@@ -193,25 +167,9 @@ router.post('/:id/columns', async (req, res, next) => {
finalOptions.purpose = purpose;
}
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Получаем уже существующие плейсхолдеры во всей базе данных
const existing = (await db.getQuery()('SELECT placeholder FROM user_columns WHERE placeholder IS NOT NULL', [])).rows;
@@ -237,25 +195,9 @@ router.post('/:id/rows', async (req, res, next) => {
[tableId]
);
// console.log('[DEBUG][addRow] result.rows[0]:', result.rows[0]);
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Получаем все строки и значения для upsert
const rows = (await db.getQuery()('SELECT r.id as row_id, decrypt_text(c.value_encrypted, $2) as text, decrypt_text(c2.value_encrypted, $2) as answer FROM user_rows r LEFT JOIN user_cell_values c ON c.row_id = r.id AND c.column_id = 1 LEFT JOIN user_cell_values c2 ON c2.row_id = r.id AND c2.column_id = 2 WHERE r.table_id = $1', [tableId, encryptionKey])).rows;
@@ -277,25 +219,9 @@ router.get('/:id/rows', async (req, res, next) => {
try {
const tableId = req.params.id;
const { product, tags, ...relationFilters } = req.query; // tags = "B2B,VIP", relation_{colId}=rowId
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Получаем все столбцы, строки и значения ячеек
const columns = (await db.getQuery()('SELECT id, table_id, "order", created_at, updated_at, decrypt_text(name_encrypted, $2) as name, decrypt_text(type_encrypted, $2) as type, decrypt_text(placeholder_encrypted, $2) as placeholder_encrypted, placeholder FROM user_columns WHERE table_id = $1', [tableId, encryptionKey])).rows;
@@ -368,25 +294,9 @@ router.get('/:id/rows', async (req, res, next) => {
router.post('/cell', async (req, res, next) => {
try {
const { row_id, column_id, value } = req.body;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const result = await db.getQuery()(
`INSERT INTO user_cell_values (row_id, column_id, value_encrypted) VALUES ($1, $2, encrypt_text($3, $4))
@@ -438,25 +348,9 @@ router.delete('/row/:rowId', async (req, res, next) => {
await db.getQuery()('DELETE FROM user_rows WHERE id = $1', [rowId]);
// Получаем все строки для rebuild
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const rows = (await db.getQuery()('SELECT r.id as row_id, decrypt_text(c.value_encrypted, $2) as text, decrypt_text(c2.value_encrypted, $2) as answer FROM user_rows r LEFT JOIN user_cell_values c ON c.row_id = r.id AND c.column_id = 1 LEFT JOIN user_cell_values c2 ON c2.row_id = r.id AND c2.column_id = 2 WHERE r.table_id = $1', [tableId, encryptionKey])).rows;
const rebuildRows = rows.filter(r => r.row_id && r.text).map(r => ({ row_id: r.row_id, text: r.text, metadata: { answer: r.answer } }));
@@ -513,25 +407,9 @@ router.patch('/column/:columnId', async (req, res, next) => {
const columnId = req.params.columnId;
const { name, type, options, order, placeholder } = req.body;
// Получаем table_id для проверки уникальности плейсхолдера
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const colInfo = (await db.getQuery()('SELECT table_id, decrypt_text(name_encrypted, $2) as name FROM user_columns WHERE id = $1', [columnId, encryptionKey])).rows[0];
if (!colInfo) return res.status(404).json({ error: 'Column not found' });
@@ -644,24 +522,9 @@ router.post('/:id/rebuild-index', requireAuth, async (req, res, next) => {
return res.status(403).json({ error: 'Доступ только для администратора' });
}
// Получаем ключ шифрования
const fs = require('fs');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const tableId = req.params.id;
const { questionCol, answerCol } = await getQuestionAnswerColumnIds(tableId);
@@ -823,25 +686,9 @@ router.delete('/:tableId/row/:rowId/relations/:relationId', async (req, res, nex
router.get('/:id/placeholders', async (req, res, next) => {
try {
const tableId = req.params.id;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey;
try {
encryptionKey = getEncryptionKey();
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
return res.status(500).json({ error: 'Database encryption error' });
}
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
const columns = (await db.getQuery()('SELECT id, decrypt_text(name_encrypted, $2) as name, placeholder FROM user_columns WHERE table_id = $1', [tableId, encryptionKey])).rows;
res.json(columns.map(col => ({

View File

@@ -89,19 +89,9 @@ router.post('/user/:rowId/multirelations', async (req, res) => {
const { column_id, to_table_id, to_row_ids } = req.body; // to_row_ids: массив id тегов
if (!Array.isArray(to_row_ids)) return res.status(400).json({ error: 'to_row_ids должен быть массивом' });
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Проверяем, является ли это обновлением тегов (проверяем связанную таблицу)
const relatedTableName = (await db.getQuery()('SELECT decrypt_text(name_encrypted, $2) as name FROM user_tables WHERE id = $1', [to_table_id, encryptionKey])).rows[0];

View File

@@ -81,16 +81,9 @@ router.get('/', requireAuth, async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// --- Формируем условия ---
const where = [];
@@ -323,18 +316,8 @@ router.patch('/:id', requireAuth, async (req, res) => {
let idx = 1;
// Получаем ключ шифрования один раз
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
console.log('Encryption key loaded:', encryptionKey.length, 'characters');
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Обработка поля name - разбиваем на first_name и last_name
if (name !== undefined) {
@@ -413,31 +396,11 @@ router.get('/:id', async (req, res, next) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
const query = db.getQuery();
// Получаем пользователя
@@ -485,16 +448,9 @@ router.post('/', async (req, res) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
const result = await db.getQuery()(
@@ -514,16 +470,9 @@ router.post('/import', requireAuth, async (req, res) => {
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = '/app/ssl/keys/full_db_encryption.key';
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
console.error('Error reading encryption key:', keyError);
}
// Получаем ключ шифрования через унифицированную утилиту
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
try {
const contacts = req.body;