"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMacApp = void 0;
const bluebird_lst_1 = require("bluebird-lst");
const builder_util_1 = require("builder-util");
const fs_1 = require("builder-util/out/fs");
const promises_1 = require("fs/promises");
const path = require("path");
const appInfo_1 = require("../appInfo");
const platformPackager_1 = require("../platformPackager");
const appBuilder_1 = require("../util/appBuilder");
const ElectronFramework_1 = require("./ElectronFramework");
function doRename(basePath, oldName, newName) {
    return promises_1.rename(path.join(basePath, oldName), path.join(basePath, newName));
}
function moveHelpers(helperSuffixes, frameworksPath, appName, prefix) {
    return bluebird_lst_1.default.map(helperSuffixes, suffix => {
        const executableBasePath = path.join(frameworksPath, `${prefix}${suffix}.app`, "Contents", "MacOS");
        return doRename(executableBasePath, `${prefix}${suffix}`, appName + suffix).then(() => doRename(frameworksPath, `${prefix}${suffix}.app`, `${appName}${suffix}.app`));
    });
}
function getAvailableHelperSuffixes(helperEHPlist, helperNPPlist, helperRendererPlist, helperPluginPlist, helperGPUPlist) {
    const result = [" Helper"];
    if (helperEHPlist != null) {
        result.push(" Helper EH");
    }
    if (helperNPPlist != null) {
        result.push(" Helper NP");
    }
    if (helperRendererPlist != null) {
        result.push(" Helper (Renderer)");
    }
    if (helperPluginPlist != null) {
        result.push(" Helper (Plugin)");
    }
    if (helperGPUPlist != null) {
        result.push(" Helper (GPU)");
    }
    return result;
}
/** @internal */
async function createMacApp(packager, appOutDir, asarIntegrity, isMas) {
    const appInfo = packager.appInfo;
    const appFilename = appInfo.productFilename;
    const electronBranding = ElectronFramework_1.createBrandingOpts(packager.config);
    const contentsPath = path.join(appOutDir, packager.info.framework.distMacOsAppName, "Contents");
    const frameworksPath = path.join(contentsPath, "Frameworks");
    const loginItemPath = path.join(contentsPath, "Library", "LoginItems");
    const appPlistFilename = path.join(contentsPath, "Info.plist");
    const helperPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper.app`, "Contents", "Info.plist");
    const helperEHPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper EH.app`, "Contents", "Info.plist");
    const helperNPPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper NP.app`, "Contents", "Info.plist");
    const helperRendererPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Renderer).app`, "Contents", "Info.plist");
    const helperPluginPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Plugin).app`, "Contents", "Info.plist");
    const helperGPUPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (GPU).app`, "Contents", "Info.plist");
    const helperLoginPlistFilename = path.join(loginItemPath, `${electronBranding.productName} Login Helper.app`, "Contents", "Info.plist");
    const plistContent = await appBuilder_1.executeAppBuilderAsJson([
        "decode-plist",
        "-f",
        appPlistFilename,
        "-f",
        helperPlistFilename,
        "-f",
        helperEHPlistFilename,
        "-f",
        helperNPPlistFilename,
        "-f",
        helperRendererPlistFilename,
        "-f",
        helperPluginPlistFilename,
        "-f",
        helperGPUPlistFilename,
        "-f",
        helperLoginPlistFilename,
    ]);
    if (plistContent[0] == null) {
        throw new Error("corrupted Electron dist");
    }
    const appPlist = plistContent[0];
    const helperPlist = plistContent[1];
    const helperEHPlist = plistContent[2];
    const helperNPPlist = plistContent[3];
    const helperRendererPlist = plistContent[4];
    const helperPluginPlist = plistContent[5];
    const helperGPUPlist = plistContent[6];
    const helperLoginPlist = plistContent[7];
    // if an extend-info file was supplied, copy its contents in first
    if (plistContent[8] != null) {
        Object.assign(appPlist, plistContent[8]);
    }
    const buildMetadata = packager.config;
    /**
     * Configure bundleIdentifier for the generic Electron Helper process
     *
     * This was the only Helper in Electron 5 and before. Allow users to configure
     * the bundleIdentifier for continuity.
     */
    const oldHelperBundleId = buildMetadata["helper-bundle-id"];
    if (oldHelperBundleId != null) {
        builder_util_1.log.warn("build.helper-bundle-id is deprecated, please set as build.mac.helperBundleId");
    }
    const helperBundleIdentifier = appInfo_1.filterCFBundleIdentifier(packager.platformSpecificBuildOptions.helperBundleId || oldHelperBundleId || `${appInfo.macBundleIdentifier}.helper`);
    await packager.applyCommonInfo(appPlist, contentsPath);
    // required for electron-updater proxy
    if (!isMas) {
        configureLocalhostAts(appPlist);
    }
    helperPlist.CFBundleExecutable = `${appFilename} Helper`;
    helperPlist.CFBundleDisplayName = `${appInfo.productName} Helper`;
    helperPlist.CFBundleIdentifier = helperBundleIdentifier;
    helperPlist.CFBundleVersion = appPlist.CFBundleVersion;
    /**
     * Configure bundleIdentifier for Electron 5+ Helper processes
     *
     * In Electron 6, parts of the generic Electron Helper process were split into
     * individual helper processes. Allow users to configure the bundleIdentifiers
     * for continuity, specifically because macOS keychain access relies on
     * bundleIdentifiers not changing (i.e. across versions of Electron).
     */
    function configureHelper(helper, postfix, userProvidedBundleIdentifier) {
        helper.CFBundleExecutable = `${appFilename} Helper ${postfix}`;
        helper.CFBundleDisplayName = `${appInfo.productName} Helper ${postfix}`;
        helper.CFBundleIdentifier = userProvidedBundleIdentifier
            ? appInfo_1.filterCFBundleIdentifier(userProvidedBundleIdentifier)
            : appInfo_1.filterCFBundleIdentifier(`${helperBundleIdentifier}.${postfix}`);
        helper.CFBundleVersion = appPlist.CFBundleVersion;
    }
    if (helperRendererPlist != null) {
        configureHelper(helperRendererPlist, "(Renderer)", packager.platformSpecificBuildOptions.helperRendererBundleId);
    }
    if (helperPluginPlist != null) {
        configureHelper(helperPluginPlist, "(Plugin)", packager.platformSpecificBuildOptions.helperPluginBundleId);
    }
    if (helperGPUPlist != null) {
        configureHelper(helperGPUPlist, "(GPU)", packager.platformSpecificBuildOptions.helperGPUBundleId);
    }
    if (helperEHPlist != null) {
        configureHelper(helperEHPlist, "EH", packager.platformSpecificBuildOptions.helperEHBundleId);
    }
    if (helperNPPlist != null) {
        configureHelper(helperNPPlist, "NP", packager.platformSpecificBuildOptions.helperNPBundleId);
    }
    if (helperLoginPlist != null) {
        helperLoginPlist.CFBundleExecutable = `${appFilename} Login Helper`;
        helperLoginPlist.CFBundleDisplayName = `${appInfo.productName} Login Helper`;
        // noinspection SpellCheckingInspection
        helperLoginPlist.CFBundleIdentifier = `${appInfo.macBundleIdentifier}.loginhelper`;
        helperLoginPlist.CFBundleVersion = appPlist.CFBundleVersion;
    }
    const protocols = builder_util_1.asArray(buildMetadata.protocols).concat(builder_util_1.asArray(packager.platformSpecificBuildOptions.protocols));
    if (protocols.length > 0) {
        appPlist.CFBundleURLTypes = protocols.map(protocol => {
            const schemes = builder_util_1.asArray(protocol.schemes);
            if (schemes.length === 0) {
                throw new builder_util_1.InvalidConfigurationError(`Protocol "${protocol.name}": must be at least one scheme specified`);
            }
            return {
                CFBundleURLName: protocol.name,
                CFBundleTypeRole: protocol.role || "Editor",
                CFBundleURLSchemes: schemes.slice(),
            };
        });
    }
    const fileAssociations = packager.fileAssociations;
    if (fileAssociations.length > 0) {
        appPlist.CFBundleDocumentTypes = await bluebird_lst_1.default.map(fileAssociations, async (fileAssociation) => {
            const extensions = builder_util_1.asArray(fileAssociation.ext).map(platformPackager_1.normalizeExt);
            const customIcon = await packager.getResource(builder_util_1.getPlatformIconFileName(fileAssociation.icon, true), `${extensions[0]}.icns`);
            let iconFile = appPlist.CFBundleIconFile;
            if (customIcon != null) {
                iconFile = path.basename(customIcon);
                await fs_1.copyOrLinkFile(customIcon, path.join(path.join(contentsPath, "Resources"), iconFile));
            }
            const result = {
                CFBundleTypeExtensions: extensions,
                CFBundleTypeName: fileAssociation.name || extensions[0],
                CFBundleTypeRole: fileAssociation.role || "Editor",
                LSHandlerRank: fileAssociation.rank || "Default",
                CFBundleTypeIconFile: iconFile,
            };
            if (fileAssociation.isPackage) {
                result.LSTypeIsPackage = true;
            }
            return result;
        });
    }
    if (asarIntegrity != null) {
        appPlist.AsarIntegrity = JSON.stringify(asarIntegrity);
    }
    const plistDataToWrite = {
        [appPlistFilename]: appPlist,
        [helperPlistFilename]: helperPlist,
    };
    if (helperEHPlist != null) {
        plistDataToWrite[helperEHPlistFilename] = helperEHPlist;
    }
    if (helperNPPlist != null) {
        plistDataToWrite[helperNPPlistFilename] = helperNPPlist;
    }
    if (helperRendererPlist != null) {
        plistDataToWrite[helperRendererPlistFilename] = helperRendererPlist;
    }
    if (helperPluginPlist != null) {
        plistDataToWrite[helperPluginPlistFilename] = helperPluginPlist;
    }
    if (helperGPUPlist != null) {
        plistDataToWrite[helperGPUPlistFilename] = helperGPUPlist;
    }
    if (helperLoginPlist != null) {
        plistDataToWrite[helperLoginPlistFilename] = helperLoginPlist;
    }
    await Promise.all([
        appBuilder_1.executeAppBuilderAndWriteJson(["encode-plist"], plistDataToWrite),
        doRename(path.join(contentsPath, "MacOS"), electronBranding.productName, appPlist.CFBundleExecutable),
        fs_1.unlinkIfExists(path.join(appOutDir, "LICENSE")),
        fs_1.unlinkIfExists(path.join(appOutDir, "LICENSES.chromium.html")),
    ]);
    await moveHelpers(getAvailableHelperSuffixes(helperEHPlist, helperNPPlist, helperRendererPlist, helperPluginPlist, helperGPUPlist), frameworksPath, appFilename, electronBranding.productName);
    if (helperLoginPlist != null) {
        const prefix = electronBranding.productName;
        const suffix = " Login Helper";
        const executableBasePath = path.join(loginItemPath, `${prefix}${suffix}.app`, "Contents", "MacOS");
        await doRename(executableBasePath, `${prefix}${suffix}`, appFilename + suffix).then(() => doRename(loginItemPath, `${prefix}${suffix}.app`, `${appFilename}${suffix}.app`));
    }
    const appPath = path.join(appOutDir, `${appFilename}.app`);
    await promises_1.rename(path.dirname(contentsPath), appPath);
    // https://github.com/electron-userland/electron-builder/issues/840
    const now = Date.now() / 1000;
    await promises_1.utimes(appPath, now, now);
}
exports.createMacApp = createMacApp;
function configureLocalhostAts(appPlist) {
    // https://bencoding.com/2015/07/20/app-transport-security-and-localhost/
    let ats = appPlist.NSAppTransportSecurity;
    if (ats == null) {
        ats = {};
        appPlist.NSAppTransportSecurity = ats;
    }
    ats.NSAllowsLocalNetworking = true;
    // https://github.com/electron-userland/electron-builder/issues/3377#issuecomment-446035814
    ats.NSAllowsArbitraryLoads = true;
    let exceptionDomains = ats.NSExceptionDomains;
    if (exceptionDomains == null) {
        exceptionDomains = {};
        ats.NSExceptionDomains = exceptionDomains;
    }
    if (exceptionDomains.localhost == null) {
        const allowHttp = {
            NSTemporaryExceptionAllowsInsecureHTTPSLoads: false,
            NSIncludesSubdomains: false,
            NSTemporaryExceptionAllowsInsecureHTTPLoads: true,
            NSTemporaryExceptionMinimumTLSVersion: "1.0",
            NSTemporaryExceptionRequiresForwardSecrecy: false,
        };
        exceptionDomains.localhost = allowHttp;
        exceptionDomains["127.0.0.1"] = allowHttp;
    }
}
//# sourceMappingURL=electronMac.js.map