polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
207 lines • 8.32 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultAccountEncryption = exports.AccountEncryptionImpl = void 0;
exports.createAccountEncryption = createAccountEncryption;
const crypto = __importStar(require("crypto"));
const os = __importStar(require("os"));
const ENCRYPTION_CONFIG = {
algorithm: 'aes-256-gcm',
keyLength: 32,
ivLength: 16,
authTagLength: 16,
keyDerivationIterations: 100000,
saltString: 'polyv-cli-security-salt-v1.0'
};
class AccountEncryptionImpl {
constructor(masterKey) {
const keyInfo = this.resolveEncryptionKey(masterKey);
this.encryptionKey = keyInfo.key;
this.keySource = keyInfo.source;
}
resolveEncryptionKey(providedKey) {
let keyString;
let source;
if (providedKey) {
keyString = providedKey;
source = 'environment';
}
else if (process.env['POLYV_MASTER_KEY']) {
keyString = process.env['POLYV_MASTER_KEY'];
source = 'environment';
}
else {
keyString = this.generateDefaultKey();
source = 'generated';
}
if (!this.validateKey(keyString)) {
throw new Error('Invalid encryption key. Key must be at least 16 characters long and contain mixed case letters and numbers.');
}
return {
key: this.deriveEncryptionKey(keyString),
source
};
}
generateDefaultKey() {
let username = 'unknown';
try {
const userInfo = os.userInfo();
username = userInfo && userInfo.username ? userInfo.username : 'unknown';
}
catch {
username = 'unknown';
}
const machineInfo = {
hostname: os.hostname(),
platform: os.platform(),
arch: os.arch(),
homedir: os.homedir(),
username
};
const hash = crypto.createHash('sha256');
hash.update(JSON.stringify(machineInfo));
hash.update('polyv-cli-default-key-v1.0');
return hash.digest('hex');
}
deriveEncryptionKey(masterKey) {
const salt = Buffer.from(ENCRYPTION_CONFIG.saltString, 'utf8');
return crypto.pbkdf2Sync(masterKey, salt, ENCRYPTION_CONFIG.keyDerivationIterations, ENCRYPTION_CONFIG.keyLength, 'sha256');
}
encrypt(plaintext) {
try {
const iv = crypto.randomBytes(ENCRYPTION_CONFIG.ivLength);
const cipher = crypto.createCipheriv(ENCRYPTION_CONFIG.algorithm, this.encryptionKey, iv);
let encrypted = cipher.update(plaintext, 'utf8');
encrypted = Buffer.concat([encrypted, cipher.final()]);
const authTag = cipher.getAuthTag();
return {
algorithm: ENCRYPTION_CONFIG.algorithm,
iv: iv.toString('base64'),
authTag: authTag.toString('base64'),
encrypted: encrypted.toString('base64')
};
}
catch (error) {
throw new Error(`Failed to encrypt account secret. Please check your encryption key and try again. ` +
`Error: ${error instanceof Error ? error.message : 'Unknown encryption error'}`);
}
}
decrypt(encryptedData) {
try {
if (encryptedData.algorithm !== ENCRYPTION_CONFIG.algorithm) {
throw new Error(`Unsupported encryption algorithm: ${encryptedData.algorithm}. Expected: ${ENCRYPTION_CONFIG.algorithm}`);
}
const iv = Buffer.from(encryptedData.iv, 'base64');
const authTag = Buffer.from(encryptedData.authTag, 'base64');
const encrypted = Buffer.from(encryptedData.encrypted, 'base64');
const decipher = crypto.createDecipheriv(ENCRYPTION_CONFIG.algorithm, this.encryptionKey, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString('utf8');
}
catch (error) {
if (error instanceof Error) {
const errorMessage = error.message.toLowerCase();
if (errorMessage.includes('bad decrypt') ||
errorMessage.includes('unsupported state or unable to authenticate data') ||
errorMessage.includes('invalid authentication tag') ||
errorMessage.includes('authentication failed')) {
throw new Error('Failed to decrypt account secret. This may be due to:\n' +
'1. Incorrect encryption key (check POLYV_MASTER_KEY environment variable)\n' +
'2. Corrupted configuration file\n' +
'3. Configuration file created with different key\n\n' +
'Try: polyv-live-cli config recover');
}
}
throw new Error(`Failed to decrypt account secret: ${error instanceof Error ? error.message : 'Unknown decryption error'}\n\n` +
'Try: polyv-live-cli config recover');
}
}
generateKey() {
const randomBytes = crypto.randomBytes(32);
return randomBytes.toString('hex');
}
validateKey(key) {
if (!key || typeof key !== 'string') {
return false;
}
if (key.length < 16) {
return false;
}
const hasLowerCase = /[a-z]/.test(key);
const hasUpperOrNumber = /[A-Z0-9]/.test(key);
return hasLowerCase && hasUpperOrNumber;
}
testEncryption(testData = 'test-secret-data-2024') {
try {
const encrypted = this.encrypt(testData);
const decrypted = this.decrypt(encrypted);
return decrypted === testData;
}
catch {
return false;
}
}
getKeySource() {
return this.keySource;
}
validateEncryptedData(encryptedData) {
if (!encryptedData || typeof encryptedData !== 'object') {
return false;
}
const data = encryptedData;
return (data['algorithm'] === ENCRYPTION_CONFIG.algorithm &&
typeof data['iv'] === 'string' &&
typeof data['authTag'] === 'string' &&
typeof data['encrypted'] === 'string' &&
data['iv'].length > 0 &&
data['authTag'].length > 0 &&
data['encrypted'].length > 0);
}
getEncryptionMetadata() {
return {
algorithm: ENCRYPTION_CONFIG.algorithm,
keySource: this.keySource,
version: '1.0'
};
}
}
exports.AccountEncryptionImpl = AccountEncryptionImpl;
function createAccountEncryption(masterKey) {
return new AccountEncryptionImpl(masterKey);
}
exports.defaultAccountEncryption = createAccountEncryption();
//# sourceMappingURL=account-encryption.js.map