"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setPrivateKey = setPrivateKey;
exports.writePrivateKey = writePrivateKey;
exports.configSigningKey = configSigningKey;
const tslib_1 = require("tslib");
const node_os_1 = tslib_1.__importDefault(require("node:os"));
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
const upath_1 = tslib_1.__importDefault(require("upath"));
const error_messages_1 = require("../../constants/error-messages");
const logger_1 = require("../../logger");
const exec_1 = require("../exec");
const regex_1 = require("../regex");
const sanitize_1 = require("../sanitize");
const sshKeyRegex = (0, regex_1.regEx)(/-----BEGIN ([A-Z ]+ )?PRIVATE KEY-----.*?-----END ([A-Z]+ )?PRIVATE KEY-----/, 's');
let gitPrivateKey;
class PrivateKey {
    key;
    keyId;
    constructor(key) {
        this.key = key.trim();
        (0, sanitize_1.addSecretForSanitizing)(this.key, 'global');
        logger_1.logger.debug('gitPrivateKey: successfully set (but not yet written/configured)');
    }
    async writeKey() {
        try {
            if (!this.keyId) {
                this.keyId = await this.importKey();
            }
            logger_1.logger.debug('gitPrivateKey: imported');
        }
        catch (err) {
            logger_1.logger.warn({ err }, 'gitPrivateKey: error importing');
            throw new Error(error_messages_1.PLATFORM_GPG_FAILED);
        }
    }
    async configSigningKey(cwd) {
        logger_1.logger.debug('gitPrivateKey: configuring commit signing');
        // TODO: types (#22198)
        await (0, exec_1.exec)(`git config user.signingkey ${this.keyId}`, { cwd });
        await (0, exec_1.exec)(`git config commit.gpgsign true`, { cwd });
        await (0, exec_1.exec)(`git config gpg.format ${this.gpgFormat}`, { cwd });
    }
}
class GPGKey extends PrivateKey {
    gpgFormat = 'openpgp';
    async importKey() {
        const keyFileName = upath_1.default.join(node_os_1.default.tmpdir() + '/git-private-gpg.key');
        await fs_extra_1.default.outputFile(keyFileName, this.key);
        const { stdout, stderr } = await (0, exec_1.exec)(`gpg --import ${keyFileName}`);
        logger_1.logger.debug({ stdout, stderr }, 'Private key import result');
        await fs_extra_1.default.remove(keyFileName);
        return `${stdout}${stderr}`
            .split(regex_1.newlineRegex)
            .find((line) => line.includes('secret key imported'))
            ?.replace('gpg: key ', '')
            .split(':')
            .shift();
    }
}
class SSHKey extends PrivateKey {
    gpgFormat = 'ssh';
    async importKey() {
        const keyFileName = upath_1.default.join(node_os_1.default.tmpdir() + '/git-private-ssh.key');
        if (await this.hasPassphrase(keyFileName)) {
            throw new Error('SSH key must have an empty passhprase');
        }
        await fs_extra_1.default.outputFile(keyFileName, this.key);
        process.on('exit', () => fs_extra_1.default.removeSync(keyFileName));
        await fs_extra_1.default.chmod(keyFileName, 0o600);
        // HACK: `git` calls `ssh-keygen -Y sign ...` internally for SSH-based
        // commit signing. Technically, only the private key is needed for signing,
        // but `ssh-keygen` has an implementation quirk which requires also the
        // public key file to exist. Therefore, we derive the public key from the
        // private key just to satisfy `ssh-keygen` until the problem has been
        // resolved.
        // https://github.com/renovatebot/renovate/issues/18197#issuecomment-2152333710
        const { stdout } = await (0, exec_1.exec)(`ssh-keygen -y -P "" -f ${keyFileName}`);
        const pubFileName = `${keyFileName}.pub`;
        await fs_extra_1.default.outputFile(pubFileName, stdout);
        process.on('exit', () => fs_extra_1.default.removeSync(pubFileName));
        return keyFileName;
    }
    async hasPassphrase(keyFileName) {
        try {
            await (0, exec_1.exec)(`ssh-keygen -y -P "" -f ${keyFileName}`);
        }
        catch (err) {
            return err.stderr.includes('incorrect passphrase supplied to decrypt private key');
        }
        return false;
    }
}
function getPrivateKeyFormat(key) {
    return sshKeyRegex.test(key) ? 'ssh' : 'gpg';
}
function createPrivateKey(key) {
    switch (getPrivateKeyFormat(key)) {
        case 'gpg':
            logger_1.logger.debug('gitPrivateKey: GPG key detected');
            return new GPGKey(key);
        case 'ssh':
            logger_1.logger.debug('gitPrivateKey: SSH key detected');
            return new SSHKey(key);
    }
}
function setPrivateKey(key) {
    if (!is_1.default.nonEmptyStringAndNotWhitespace(key)) {
        return;
    }
    gitPrivateKey = createPrivateKey(key);
}
async function writePrivateKey() {
    await gitPrivateKey?.writeKey();
}
async function configSigningKey(cwd) {
    await gitPrivateKey?.configSigningKey(cwd);
}
//# sourceMappingURL=private-key.js.map