"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.signAndNotarizeMacOS = signAndNotarizeMacOS;
exports.signBinary = signBinary;
const osx_sign_1 = require("@electron/osx-sign");
const notarize_1 = require("@electron/notarize");
const path_1 = require("path");
const path_2 = require("../../utils/path");
const fs_1 = require("fs");
const logger_1 = require("../../utils/logger");
const fs_extra_1 = __importDefault(require("fs-extra"));
const config_service_1 = require("../config/config.service");
const logger = logger_1.Logger.getInstance("installer.macOS.helper");
// Turn on all osx-sign logs
// import debug from "debug";
// debug.enable("electron-osx-sign*");
async function signAndNotarizeMacOS() {
    const path = path_2.PathUtils.getIOCDAppBundlePath();
    await signBinary(path);
    await notarizeOnMacOS(path);
}
// readme - https://github.com/electron/osx-sign
async function signBinary(pathToSign) {
    logger.info('Starting code signing process on macOS...');
    const codeSignConfig = config_service_1.ConfigManager.config.mac.codeSign;
    switch (codeSignConfig.type) {
        case 'off':
            logger.info('Code signing is disabled (type: off)');
            return;
        case 'keychain':
            await signWithKeychain(pathToSign);
            break;
        case 'custom':
            await signWithCustomScript(pathToSign);
            break;
        default:
            throw new Error(`Unsupported code signing type: ${codeSignConfig.type}`);
    }
    logger.info('Code signing completed successfully!');
}
async function signWithKeychain(pathToSign) {
    logger.debug('Signing with keychain...');
    const codeSignConfig = config_service_1.ConfigManager.config.mac.codeSign;
    logger.debug(`Removing _CodeSignature directory if it exists...`);
    const codeSignaturePath = (0, path_1.join)(path_2.PathUtils.getIOCDDir(), '_CodeSignature');
    if ((0, fs_1.existsSync)(codeSignaturePath)) {
        fs_extra_1.default.removeSync(codeSignaturePath);
        logger.debug(`Removed existing _CodeSignature directory`);
    }
    else {
        logger.debug(`No existing _CodeSignature directory found`);
    }
    // things we don't need to sign
    const IGNORE_EXT = [
        ".png", ".jpg", ".jpeg", ".gif", ".icns", ".ico", ".svg",
        ".js", ".css", "._js", "._css",
        ".ttf", ".otf", ".woff", ".woff2",
        ".pak", ".bin", ".dat", ".json", ".plist", ".md", ".txt", ".rtf",
        ".html", ".css", ".map",
        ".mp3", ".mp4", ".wav", ".webm", ".mov", ".ttf",
        ".asar",
        ".DS_Store" // do not sign app.asar
    ];
    // remove embedded.provisionprofile file if it is in the app bundle - it gets added by code-signing during dev builds
    const embeddedProvisionProfilePath = (0, path_1.join)(path_2.PathUtils.getIOCDDir(), 'embedded.provisionprofile');
    if ((0, fs_1.existsSync)(embeddedProvisionProfilePath)) {
        logger.debug('Removing embedded.provisionprofile from app bundle...');
        fs_extra_1.default.removeSync(embeddedProvisionProfilePath);
        logger.debug('embedded.provisionprofile removed');
    }
    const configPath = path_2.PathUtils.getConfigDir();
    const entitlementsPath = (0, path_1.join)(configPath, "mac-build", "entitlements.mac.plist");
    if (!(0, fs_1.existsSync)(entitlementsPath)) {
        logger.error(`Entitlements file not found at path: ${entitlementsPath}`);
        throw new Error(`Entitlements file not found at path: ${entitlementsPath}`);
    }
    let config = {
        app: pathToSign,
        entitlements: entitlementsPath,
        entitlementsInherit: entitlementsPath,
        "entitlements-inherit": entitlementsPath,
        "hardened-runtime": true,
        hardenedRuntime: true,
        preAutoEntitlements: false,
        "pre-auto-entitlements": false,
        gatekeeperAssess: false, // skip assessment during sign
        "gatekeeper-assess": false,
        force: true, // re-sign even if already signed
        strictVerify: true,
        "strict-verify": true,
    }; // Add identity if specified
    if (codeSignConfig.identity) {
        config.identity = codeSignConfig.identity;
        logger.debug(`Using code signing identity: ${codeSignConfig.identity}`);
    } // Add keychain if specified
    if (codeSignConfig.keychain) {
        config.keychain = codeSignConfig.keychain;
        logger.debug(`Using keychain: ${codeSignConfig.keychain}`);
    }
    config.ignore = (filePath) => {
        // skip obvious non-executables by extension
        const lower = filePath.toLowerCase();
        if (IGNORE_EXT.some(ext => lower.endsWith(ext)))
            return true;
        // never sign signature metadata
        if (lower.includes("/contents/_codesignature/"))
            return true;
        if (lower.endsWith("/contents/coderesources"))
            return true;
        if (lower.includes("/contents/components/"))
            return true; // skip components folder in contents entirely
        // otherwise let it sign
        logger.debug(`Signing file: ${filePath}`);
        return false;
    };
    config.optionsForFile = () => {
        return config;
    };
    const provisionProfilePath = (0, path_1.join)(process.cwd(), 'config', 'mac-build', 'io.cd.provisionprofile');
    logger.debug('Checking for provisioning profile at:', provisionProfilePath);
    if ((0, fs_1.existsSync)(provisionProfilePath)) {
        logger.debug('Using provisioning profile:', provisionProfilePath);
        config.provisioningProfile = provisionProfilePath;
    }
    else {
        logger.debug('No provisioning profile found at:', provisionProfilePath);
    }
    logger.debug(`Signing with config`, config);
    await (0, osx_sign_1.sign)(config);
}
async function signWithCustomScript(pathToSign) {
    logger.debug('Signing with custom script...');
    const codeSignConfig = config_service_1.ConfigManager.config.mac.codeSign;
    if (!codeSignConfig.customCodeSignScriptPath) {
        throw new Error('Custom code signing requires customCodeSignScriptPath to be configured');
    }
    if (!(0, fs_1.existsSync)(codeSignConfig.customCodeSignScriptPath)) {
        throw new Error(`Custom code signing script not found: ${codeSignConfig.customCodeSignScriptPath}`);
    }
    try {
        logger.debug(`Loading custom code signing script: ${codeSignConfig.customCodeSignScriptPath}`);
        // Clear require cache to ensure fresh script load
        const scriptPath = (0, path_1.resolve)(codeSignConfig.customCodeSignScriptPath);
        delete require.cache[scriptPath];
        const customScript = require(scriptPath);
        let signFunction;
        // Support multiple export formats
        if (typeof customScript === 'function') {
            signFunction = customScript;
        }
        else if (typeof customScript.default === 'function') {
            signFunction = customScript.default;
        }
        else if (typeof customScript.sign === 'function') {
            signFunction = customScript.sign;
        }
        else {
            throw new Error('Custom code signing script must export a function (either as default export, named "sign" export, or direct export)');
        }
        // Execute the signing function with the app bundle path and full config
        await signFunction(pathToSign, codeSignConfig);
        logger.debug('Custom code signing script executed successfully');
    }
    catch (error) {
        if (error instanceof Error) {
            throw new Error(`Custom code signing script failed: ${error.message}`);
        }
        else {
            throw new Error(`Custom code signing script failed: ${String(error)}`);
        }
    }
}
// readme - https://github.com/electron/notarize
async function notarizeOnMacOS(pathToNotarize) {
    logger.info('Starting notarization process on macOS...');
    const notarizationConfig = config_service_1.ConfigManager.config.mac.notarization;
    switch (notarizationConfig.type) {
        case 'off':
            logger.info('Notarization is disabled (type: off)');
            return;
        case 'notarytool':
            await notarizeWithNotarytool(pathToNotarize);
            break;
        case 'custom':
            await notarizeWithCustomScript(pathToNotarize);
            break;
        default:
            throw new Error(`Unsupported notarization type: ${notarizationConfig.type}`);
    }
    logger.info('Notarization completed successfully!');
}
async function notarizeWithNotarytool(pathToNotarize) {
    logger.debug(`Notarizing with notarytool, path is ${pathToNotarize}...`);
    const notarizationConfig = config_service_1.ConfigManager.config.mac.notarization;
    logger.debug('Notarization config:', notarizationConfig);
    if (!notarizationConfig.appleId || !notarizationConfig.appleIdPassword || !notarizationConfig.appleTeamId) {
        throw new Error('Notarization with notarytool requires appleId, appleIdPassword, and appleTeamId to be configured');
    }
    let config = {
        appPath: pathToNotarize,
        appleId: notarizationConfig.appleId ?? "",
        appleIdPassword: notarizationConfig.appleIdPassword ?? "",
        teamId: notarizationConfig.appleTeamId ?? "",
    };
    await (0, notarize_1.notarize)(config);
}
async function notarizeWithCustomScript(pathToNotarize) {
    logger.debug('Notarizing with custom script...');
    const notarizationConfig = config_service_1.ConfigManager.config.mac.notarization;
    if (!notarizationConfig.customNotarizationScriptPath) {
        throw new Error('Custom notarization requires customNotarizationScriptPath to be configured');
    }
    if (!(0, fs_1.existsSync)(notarizationConfig.customNotarizationScriptPath)) {
        throw new Error(`Custom notarization script not found: ${notarizationConfig.customNotarizationScriptPath}`);
    }
    try {
        logger.debug(`Loading custom notarization script: ${notarizationConfig.customNotarizationScriptPath}`);
        // Clear require cache to ensure fresh script load
        const scriptPath = (0, path_1.resolve)(notarizationConfig.customNotarizationScriptPath);
        delete require.cache[scriptPath];
        const customScript = require(scriptPath);
        let notarizeFunction;
        // Support multiple export formats
        if (typeof customScript === 'function') {
            notarizeFunction = customScript;
        }
        else if (typeof customScript.default === 'function') {
            notarizeFunction = customScript.default;
        }
        else if (typeof customScript.notarize === 'function') {
            notarizeFunction = customScript.notarize;
        }
        else {
            throw new Error('Custom notarization script must export a function (either as default export, named "notarize" export, or direct export)');
        }
        // Execute the notarization function with the app bundle path and full config
        await notarizeFunction(pathToNotarize, notarizationConfig);
        logger.debug('Custom notarization script executed successfully');
    }
    catch (error) {
        if (error instanceof Error) {
            throw new Error(`Custom notarization script failed: ${error.message}`);
        }
        else {
            throw new Error(`Custom notarization script failed: ${String(error)}`);
        }
    }
}
//# sourceMappingURL=macOS.helper.js.map