D3V-Server/backend/migrations/20260319000000_wireguard_encrypt_keys.js

62 lines
2.2 KiB
JavaScript
Raw Permalink Normal View History

/**
* Data migration: encrypts existing plaintext WireGuard private keys
* and pre-shared keys in the database.
*
* This migration is safe to run multiple times (idempotent):
* already-encrypted values (prefix "enc:") are skipped.
*
* Requires DB_ENCRYPTION_KEY to be set in the environment.
* If not set, migration logs a warning and exits without modifying data.
*/
import { encrypt } from "../lib/crypto.js";
const migrate_name = "wireguard_encrypt_keys";
export async function up(knex) {
const key = process.env.DB_ENCRYPTION_KEY;
if (!key) {
console.warn(`[${migrate_name}] DB_ENCRYPTION_KEY not set — skipping encryption migration. Keys remain as plaintext.`);
return;
}
console.log(`[${migrate_name}] Encrypting existing WireGuard keys...`);
// --- wg_interface: encrypt private_key ---
const ifaces = await knex("wg_interface").select("id", "private_key");
let ifaceCount = 0;
for (const iface of ifaces) {
if (!iface.private_key || iface.private_key.startsWith("enc:")) continue;
await knex("wg_interface").where("id", iface.id).update({
private_key: encrypt(iface.private_key),
});
ifaceCount++;
}
console.log(`[${migrate_name}] wg_interface: ${ifaceCount} rows encrypted.`);
// --- wg_client: encrypt private_key + pre_shared_key ---
const clients = await knex("wg_client").select("id", "private_key", "pre_shared_key");
let clientCount = 0;
for (const client of clients) {
const updates = {};
if (client.private_key && !client.private_key.startsWith("enc:")) {
updates.private_key = encrypt(client.private_key);
}
if (client.pre_shared_key && !client.pre_shared_key.startsWith("enc:")) {
updates.pre_shared_key = encrypt(client.pre_shared_key);
}
if (Object.keys(updates).length > 0) {
await knex("wg_client").where("id", client.id).update(updates);
clientCount++;
}
}
console.log(`[${migrate_name}] wg_client: ${clientCount} rows encrypted.`);
console.log(`[${migrate_name}] Done.`);
}
export async function down(knex) {
// Intentionally a no-op: decrypting back to plaintext would require the key,
// and rolling back encryption is a security risk.
console.warn(`[${migrate_name}] down() is a no-op. Keys remain encrypted.`);
}