feat(mikrotikBackupRoutes): add encryption and decryption for backup content to enhance security
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s
This commit is contained in:
@@ -16,9 +16,24 @@ const { sendError, sendOk } = require('../middleware/errorHandler');
|
||||
const { writeS3TextObject, readS3TextObject, listS3Objects } = require('../services/s3Service');
|
||||
const { readServersFromS3 } = require('./serversRoutes');
|
||||
const { createRosClient, fetchExportViaFile } = require('../services/mikrotikApplyService');
|
||||
const { decrypt } = require('../utils/encryption');
|
||||
const { encrypt, decrypt } = require('../utils/encryption');
|
||||
|
||||
const BACKUP_PREFIX = 'backups/mikrotik';
|
||||
const ENCRYPTED_PREFIX = 'ENC:';
|
||||
|
||||
/** Расшифровать содержимое бэкапа (поддерживает старые незашифрованные) */
|
||||
function decryptBackupContent(raw) {
|
||||
if (!raw || typeof raw !== 'string') return '';
|
||||
if (raw.startsWith(ENCRYPTED_PREFIX)) {
|
||||
try {
|
||||
return decrypt(raw.slice(ENCRYPTED_PREFIX.length));
|
||||
} catch (e) {
|
||||
console.error('Backup decryption failed:', e?.message);
|
||||
throw new Error(`Failed to decrypt backup: ${e?.message || 'decryption error'}`);
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function buildBackupKey(serverId, createdAt, suffix) {
|
||||
const safeId = String(serverId || 'unknown').replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
@@ -44,7 +59,17 @@ async function saveBackupForServer(serverId, config, { source, comment } = {}) {
|
||||
'',
|
||||
].filter(Boolean);
|
||||
|
||||
const content = `${headerLines.join('\n')}\n${String(config || '').replace(/^\uFEFF/, '')}`;
|
||||
let content = `${headerLines.join('\n')}\n${String(config || '').replace(/^\uFEFF/, '')}`;
|
||||
|
||||
// Шифруем содержимое на S3, если задан ENCRYPTION_KEY
|
||||
if (process.env.ENCRYPTION_KEY) {
|
||||
try {
|
||||
content = ENCRYPTED_PREFIX + encrypt(content);
|
||||
} catch (e) {
|
||||
console.error('Backup encryption failed:', e?.message);
|
||||
throw new Error(`Failed to encrypt backup: ${e?.message || 'encryption error'}`);
|
||||
}
|
||||
}
|
||||
|
||||
const meta = await writeS3TextObject(key, content, 'text/plain');
|
||||
return { key, createdAt: now.toISOString(), s3: meta };
|
||||
@@ -132,11 +157,12 @@ async function getBackup(req, res) {
|
||||
}
|
||||
|
||||
const data = await readS3TextObject(key);
|
||||
const config = decryptBackupContent(data.body || '');
|
||||
|
||||
return res.json({
|
||||
ok: true,
|
||||
key,
|
||||
config: data.body || '',
|
||||
config,
|
||||
etag: data.etag,
|
||||
lastModified: data.lastModified,
|
||||
contentLength: data.contentLength,
|
||||
@@ -169,8 +195,8 @@ async function diffBackups(req, res) {
|
||||
readS3TextObject(keyB),
|
||||
]);
|
||||
|
||||
const bodyA = a.body || '';
|
||||
const bodyB = b.body || '';
|
||||
const bodyA = decryptBackupContent(a.body || '');
|
||||
const bodyB = decryptBackupContent(b.body || '');
|
||||
|
||||
return res.json({
|
||||
ok: true,
|
||||
|
||||
Reference in New Issue
Block a user