"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Crypto = exports.NumericCharacters = exports.UpperCaseAlphanumericCharacters = exports.AlphanumericCharacters = exports.PrintableCharacters = void 0;
exports.randomBytes = randomBytes;
exports.randomBytesSync = randomBytesSync;
exports.randomString = randomString;
exports.randomStringSync = randomStringSync;
const tslib_1 = require("tslib");
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
const crypto_1 = require("crypto");
const crypto = tslib_1.__importStar(require("crypto"));
const util_1 = require("util");
const resolver_1 = require("../../app/resolver");
const nativeAsyncRandomBytes = (0, util_1.promisify)(crypto_1.randomBytes);
randomBytes.__type = ['length', 'shouldReturnHex', 'randomBytes', 'P\'2!!2"8!`/#'];
randomBytes.__type = ['length', true, 'shouldReturnHex', 'randomBytes', 'P\'2!."2#&`/$'];
async function randomBytes(length, shouldReturnHex) {
    const bytes = await nativeAsyncRandomBytes(length);
    return shouldReturnHex ? bytes.toString('hex') : bytes;
}
randomBytes.__type = ['length', true, 'shouldReturnHex', 'randomBytes', 'P\'2!P."!J2#8P!&J`/$'];
randomBytesSync.__type = ['length', 'shouldReturnHex', 'randomBytesSync', 'P\'2!!2"8!/#'];
randomBytesSync.__type = ['length', true, 'shouldReturnHex', 'randomBytesSync', 'P\'2!."2#&/$'];
function randomBytesSync(length, shouldReturnHex) {
    const bytes = (0, crypto_1.randomBytes)(length);
    return shouldReturnHex ? bytes.toString('hex') : bytes;
}
randomBytesSync.__type = ['length', true, 'shouldReturnHex', 'randomBytesSync', 'P\'2!P."!J2#8P!&J/$'];
exports.PrintableCharacters = Array.from({ length: 127 - 32 }, __assignType((_, i) => String.fromCharCode(i + 32), ['_', 'i', '', 'P"2!"2""/#'])).join('');
exports.AlphanumericCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
exports.UpperCaseAlphanumericCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
exports.NumericCharacters = '0123456789';
async function randomString(length, source = exports.PrintableCharacters) {
    const reference = await randomBytes(length);
    const result = Array.from({ length });
    for (let i = 0; i < length; i++) {
        result[i] = source[reference[i] % source.length];
    }
    return result.join('');
}
randomString.__type = ['length', 'source', () => exports.PrintableCharacters, 'randomString', 'P\'2!&2">#&`/$'];
function randomStringSync(length, source = exports.PrintableCharacters) {
    const reference = randomBytesSync(length);
    const result = Array.from({ length });
    for (let i = 0; i < length; i++) {
        result[i] = source[reference[i] % source.length];
    }
    return result.join('');
}
randomStringSync.__type = ['length', 'source', () => exports.PrintableCharacters, 'randomStringSync', 'P\'2!&2">#&/$'];
class Crypto {
    static encrypt(data) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return this.getInstance().encrypt(data);
    }
    static decrypt(data) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return this.getInstance().decrypt(data);
    }
    static getInstance() {
        if (!this.instance) {
            this.instance = new Crypto();
        }
        return this.instance;
    }
    constructor() {
        const appConfig = (0, resolver_1.getAppConfig)();
        if (!appConfig.CRYPTO_SECRET) {
            throw new Error('CRYPTO_SECRET is not set in application configuration');
        }
        if (appConfig.CRYPTO_SECRET.length === 64 && /^[0-9a-f]+$/i.test(appConfig.CRYPTO_SECRET)) {
            this.key = Buffer.from(appConfig.CRYPTO_SECRET, 'hex');
        }
        else if (appConfig.CRYPTO_SECRET.length !== 32) {
            throw new Error('CRYPTO_SECRET must be 32 bytes (or 64 hex characters)');
        }
        else {
            this.key = Buffer.from(appConfig.CRYPTO_SECRET);
        }
        this.ivLength = appConfig.CRYPTO_IV_LENGTH;
    }
    encrypt(data) {
        // Check if the input is a Buffer
        const isBuffer = Buffer.isBuffer(data);
        // Convert to a buffer if it's a string
        if (!isBuffer) {
            data = Buffer.from(data);
        }
        // Generate a random initialization vector
        const iv = crypto.randomBytes(this.ivLength);
        const cipher = crypto.createCipheriv('aes-256-gcm', this.key, iv);
        // Encrypt the data
        const encryptedData = Buffer.concat([cipher.update(data), cipher.final()]);
        // Concatenate iv, encrypted data, and authentication tag into a single Buffer
        const outputData = Buffer.concat([iv, encryptedData, cipher.getAuthTag()]);
        // Return the data encoded as base64 if input was a string, else return as Buffer
        return isBuffer ? outputData : outputData.toString('base64');
    }
    decrypt(data) {
        // Check if the input is a Buffer
        const isBuffer = Buffer.isBuffer(data);
        // Convert to Buffer if it's a string
        const dataBuf = isBuffer ? data : Buffer.from(data, 'base64');
        // Split the input into iv, encrypted data, and authentication tag
        const iv = dataBuf.subarray(0, this.ivLength);
        const authTag = dataBuf.subarray(dataBuf.length - 16);
        const encryptedData = dataBuf.subarray(this.ivLength, dataBuf.length - 16);
        // Decrypt the data
        const decipher = crypto.createDecipheriv('aes-256-gcm', this.key, iv);
        decipher.setAuthTag(authTag);
        const decryptedData = Buffer.concat([decipher.update(encryptedData), decipher.final()]);
        // Return the decrypted data as a string if the input was a string, else return as Buffer
        return isBuffer ? decryptedData : decryptedData.toString('utf8');
    }
}
exports.Crypto = Crypto;
Crypto.__type = ['data', 'encrypt', 'decrypt', () => Crypto, 'instance', 'getInstance', 'key', 'ivLength', 'constructor', 'Crypto', 'P&2!&0"sP&2!&0#sP7$3%;sP"0&;s!3\';\'3(;P"0)5w*'];
//# sourceMappingURL=crypto.js.map