File size: 1,762 Bytes
9b8d6f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | const crypto = require('crypto');
const PREFIX = 'enc:v1';
function getSecretKey() {
const source =
process.env.PAYMENT_CREDENTIAL_SECRET ||
process.env.JWT_SECRET ||
process.env.SNIPPE_API_KEY ||
'development-only-payment-credential-secret';
return crypto.createHash('sha256').update(String(source)).digest();
}
function encryptSecret(value) {
if (!value) return null;
const text = String(value);
if (text.startsWith(`${PREFIX}:`)) return text;
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', getSecretKey(), iv);
const ciphertext = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
return [
PREFIX,
iv.toString('base64url'),
tag.toString('base64url'),
ciphertext.toString('base64url'),
].join(':');
}
function decryptSecret(value) {
if (!value) return null;
const text = String(value);
if (!text.startsWith(`${PREFIX}:`)) return text;
const parts = text.split(':');
if (parts.length !== 5) {
throw new Error('Invalid encrypted secret format');
}
const [, , ivValue, tagValue, ciphertextValue] = parts;
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
getSecretKey(),
Buffer.from(ivValue, 'base64url')
);
decipher.setAuthTag(Buffer.from(tagValue, 'base64url'));
return Buffer.concat([
decipher.update(Buffer.from(ciphertextValue, 'base64url')),
decipher.final(),
]).toString('utf8');
}
function maskSecret(value) {
const secret = decryptSecret(value);
if (!secret) return null;
if (secret.length <= 8) return '********';
return `${secret.slice(0, 4)}...${secret.slice(-4)}`;
}
module.exports = {
decryptSecret,
encryptSecret,
maskSecret,
};
|