import { createCipheriv, createDecipheriv, createHash, randomBytes, } from "crypto"; import { env } from "@/lib/env"; const ALGO = "aes-256-gcm"; function deriveKey(secret: string) { return createHash("sha256").update(secret).digest(); } export function encryptSecret(value: string) { if (!env.encryptionKey) { throw new Error("ENCRYPTION_KEY is not configured"); } const iv = randomBytes(12); const key = deriveKey(env.encryptionKey); const cipher = createCipheriv(ALGO, key, iv); const encrypted = Buffer.concat([ cipher.update(value, "utf8"), cipher.final(), ]); const tag = cipher.getAuthTag(); return `${iv.toString("base64")}:${tag.toString("base64")}:${encrypted.toString("base64")}`; } export function decryptSecret(payload: string) { if (!env.encryptionKey) { throw new Error("ENCRYPTION_KEY is not configured"); } const [ivEncoded, tagEncoded, valueEncoded] = payload.split(":"); if (!ivEncoded || !tagEncoded || !valueEncoded) { throw new Error("Invalid encrypted payload"); } const key = deriveKey(env.encryptionKey); const decipher = createDecipheriv( ALGO, key, Buffer.from(ivEncoded, "base64"), ); decipher.setAuthTag(Buffer.from(tagEncoded, "base64")); const decrypted = Buffer.concat([ decipher.update(Buffer.from(valueEncoded, "base64")), decipher.final(), ]); return decrypted.toString("utf8"); } function derivePleskKey() { if (!env.pleskCredEncKey) { throw new Error("PLESK_CRED_ENC_KEY is not configured"); } const raw = env.pleskCredEncKey.trim(); if (/^[0-9a-fA-F]{64}$/.test(raw)) { return Buffer.from(raw, "hex"); } const b64 = Buffer.from(raw, "base64"); if (b64.length === 32) { return b64; } throw new Error("PLESK_CRED_ENC_KEY must be 32-byte base64 or 64-char hex"); } export function encryptPleskSecret(value: string, keyId = "v1") { const iv = randomBytes(12); const key = derivePleskKey(); const cipher = createCipheriv(ALGO, key, iv); const encrypted = Buffer.concat([ cipher.update(value, "utf8"), cipher.final(), ]); const tag = cipher.getAuthTag(); return { encryptedSecret: `${iv.toString("base64")}:${tag.toString("base64")}:${encrypted.toString("base64")}`, secretKid: keyId, }; } export function decryptPleskSecret(payload: string) { const [ivEncoded, tagEncoded, valueEncoded] = payload.split(":"); if (!ivEncoded || !tagEncoded || !valueEncoded) { throw new Error("Invalid encrypted payload"); } const key = derivePleskKey(); const decipher = createDecipheriv( ALGO, key, Buffer.from(ivEncoded, "base64"), ); decipher.setAuthTag(Buffer.from(tagEncoded, "base64")); const decrypted = Buffer.concat([ decipher.update(Buffer.from(valueEncoded, "base64")), decipher.final(), ]); return decrypted.toString("utf8"); }