fix(NetworkConfigManager, server): enhance IPSec password encryption and decryption error handling; add validation for encrypted password format and improve logging for better debugging
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m21s

This commit is contained in:
2026-01-22 19:54:32 +07:00
parent 999285801d
commit 86e8b5fece
2 changed files with 100 additions and 12 deletions
+61 -4
View File
@@ -67,13 +67,37 @@ async function getIpsecPassword(req, res) {
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 {
decryptedPassword = decrypt(password.encryptedPassword || '');
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);
return sendError(res, 500, 'Error decrypting password', 'E_DECRYPT');
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({
@@ -120,7 +144,23 @@ async function createIpsecPassword(req, res) {
}
// Шифруем пароль
const encryptedPassword = encrypt(password);
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 = {
@@ -192,7 +232,24 @@ async function updateIpsecPassword(req, res) {
passwords[index].description = String(description || '').trim();
}
if (password !== undefined) {
passwords[index].encryptedPassword = encrypt(password);
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();
+39 -8
View File
@@ -53,30 +53,61 @@ function encrypt(text) {
* @returns {string} - Расшифрованный текст
*/
function decrypt(encryptedText) {
if (!encryptedText) return '';
if (!encryptedText) {
throw new Error('Encrypted text is empty');
}
if (typeof encryptedText !== 'string') {
throw new Error('Encrypted text must be a string');
}
try {
const parts = encryptedText.split(':');
if (parts.length !== 3) {
throw new Error('Invalid encrypted format');
throw new Error(`Invalid encrypted format: expected 3 parts separated by ':', got ${parts.length}`);
}
const [ivBase64, authTagBase64, encryptedBase64] = parts;
const iv = Buffer.from(ivBase64, 'base64');
const authTag = Buffer.from(authTagBase64, 'base64');
const encrypted = encryptedBase64;
if (!ivBase64 || !authTagBase64 || !encryptedBase64) {
throw new Error('Invalid encrypted format: one or more parts are empty');
}
let iv, authTag;
try {
iv = Buffer.from(ivBase64, 'base64');
authTag = Buffer.from(authTagBase64, 'base64');
} catch (bufferError) {
throw new Error(`Failed to decode base64: ${bufferError.message}`);
}
if (iv.length !== 16) {
throw new Error(`Invalid IV length: expected 16 bytes, got ${iv.length}`);
}
if (authTag.length !== 16) {
throw new Error(`Invalid auth tag length: expected 16 bytes, got ${authTag.length}`);
}
const key = getEncryptionKey();
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
let decrypted = decipher.update(encryptedBase64, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
} catch (error) {
console.error('Decryption error:', error);
throw new Error('Failed to decrypt data');
if (error.message.includes('Unsupported state') || error.message.includes('bad decrypt')) {
throw new Error(`Decryption failed: possibly wrong encryption key or corrupted data. Original error: ${error.message}`);
}
console.error('Decryption error details:', {
error: error.message,
stack: error.stack,
encryptedTextLength: encryptedText.length,
encryptedTextPreview: encryptedText.substring(0, 100)
});
throw error;
}
}