OverviewFilesCommitsIssuesDocsReleasesPeers

mirall-cli / node_modules / electron-windows-msix / lib / utils.js

315 lines · javascript ref:
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLayout = exports.makeProgramOptions = exports.locateMSIXTooling = exports.setLogLevel = exports.verifyOptions = exports.ensureFolders = exports.ensurePublisherPrefix = exports.removePublisherPrefix = exports.removeFileExtension = exports.getBinaries = void 0;
const crypto_1 = __importDefault(require("crypto"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const logger_1 = require("./logger");
const manifestation_1 = require("./manifestation");
const bin_1 = require("./bin");
const win_version_1 = require("./win-version");
const DEFAULT_WIN_KIT_VERSION = '10.0.26100.0';
const MIN_ARM_WIN_KIT_VERSION = '10.0.22621.0';
const WIN_KIT_BIN_PATH = 'C:\\Program Files (x86)\\Windows Kits\\10\\bin';
const MAKE_PRI_EXE = 'makepri.exe';
const MAKE_APPX_EXE = 'makeappx.exe';
const SIGN_TOOL = 'SignTool.exe';
const MAKE_CERT_EXE = 'makecert.exe';
const getBinaries = async (windowsKitPath) => {
    const binaries = {
        makeAppx: path_1.default.join(windowsKitPath, MAKE_APPX_EXE),
        makePri: path_1.default.join(windowsKitPath, MAKE_PRI_EXE),
        signTool: path_1.default.join(windowsKitPath, SIGN_TOOL),
        makeCert: path_1.default.join(windowsKitPath, MAKE_CERT_EXE),
    };
    if (!(await fs_extra_1.default.exists(binaries.makeAppx)))
        logger_1.log.error(`MakeAppx binary ${MAKE_APPX_EXE} not found in:`, true, { windowsKitPath });
    if (!(await fs_extra_1.default.exists(binaries.makePri)))
        logger_1.log.error(`MakePri binary ${MAKE_PRI_EXE} not found in:`, true, { windowsKitPath });
    if (!(await fs_extra_1.default.exists(binaries.signTool)))
        logger_1.log.error(`SignTool binary ${SIGN_TOOL} not found in:`, true, { windowsKitPath });
    if (!(await fs_extra_1.default.exists(binaries.makeCert)))
        logger_1.log.error(`MakeCert binary ${MAKE_CERT_EXE} not found in:`, true, { windowsKitPath });
    return binaries;
};
exports.getBinaries = getBinaries;
const removeFileExtension = (executablePath) => {
    if (!executablePath)
        return undefined;
    const executable = path_1.default.basename(executablePath);
    return executable.replace(/\.[^\/.]+$/, "");
};
exports.removeFileExtension = removeFileExtension;
const removePublisherPrefix = (publisher) => {
    return publisher.replace(/^CN=/, "");
};
exports.removePublisherPrefix = removePublisherPrefix;
const ensurePublisherPrefix = (publisher) => {
    return !publisher || publisher.startsWith('CN=') ? publisher : `CN=${publisher}`;
};
exports.ensurePublisherPrefix = ensurePublisherPrefix;
const ensureFolders = async (options) => {
    const outputDir = options.outputDir;
    const layoutDir = path_1.default.join(options.outputDir, 'msix_layout');
    if (await fs_extra_1.default.exists(outputDir)) {
        logger_1.log.debug('Output dir already exists. Making sure its empty.', { outputDir });
        await fs_extra_1.default.emptyDir(outputDir);
    }
    else {
        logger_1.log.debug('Output dir does not exists. Creating it.');
        await fs_extra_1.default.ensureDir(outputDir);
    }
    logger_1.log.debug('Creating layout dir', { layoutDir });
    await fs_extra_1.default.ensureDir(layoutDir);
    return { outputDir, layoutDir };
};
exports.ensureFolders = ensureFolders;
const verifyOptions = async (options, manifestVars) => {
    const { manifestIsSparsePackage, manifestPublisher } = manifestVars || {};
    const publisher = manifestPublisher || (0, exports.ensurePublisherPrefix)(options.manifestVariables?.publisher);
    const windowsSignOptions = options.windowsSignOptions;
    const sign = options.sign !== undefined ? options.sign : true;
    let hasManifestParams = false;
    logger_1.log.debug('You are calling with following packaging options', options);
    if (!options.appManifest && options.manifestVariables) {
        if (!options.manifestVariables.packageVersion)
            logger_1.log.error('Neither package version <packageVersion> nor app manifest <appManifest> provided.', true);
        if (!(0, win_version_1.isValidVersion)(options.manifestVariables.packageVersion))
            logger_1.log.error('Package version <packageVersion> is not a semantic version.', true, { packageVersion: options.manifestVariables.packageVersion });
        if (!options.manifestVariables.publisher)
            logger_1.log.error('Neither publisher <publisher> nor app manifest <appManifest> provided.', true);
        if (!options.manifestVariables.publisherDisplayName)
            logger_1.log.warn('Neither publisher display name <publisherDisplayName> nor app manifest <appManifest> provided. Using publisher as display name.');
        if (!options.manifestVariables.packageDisplayName)
            logger_1.log.warn('Neither package display name <packageDisplayName> nor app manifest <appManifest> provided. Using app executable as display name.');
        if (!options.manifestVariables.appExecutable)
            logger_1.log.error('Neither app executable <appExecutable> nor app manifest <appManifest> provided.', true);
        if (!options.manifestVariables.targetArch)
            logger_1.log.error('Neither target architecture <targetArch> nor app manifest <appManifest> provided.', true);
        if (!options.manifestVariables.packageMinOSVersion)
            logger_1.log.warn('Neither package min OS version <packageMinOSVersion> nor app manifest <appManifest> provided. Using default OS version 10.0.14393.0.');
        if (!options.manifestVariables.packageMaxOSVersionTested)
            logger_1.log.warn('Neither package max OS version tested <packageMaxOSVersionTested> nor app manifest <appManifest> provided. Using default OS version 10.0.14393.0.');
        if (!options.manifestVariables.packageIdentity)
            logger_1.log.error('Neither package identity <packageIdentity> nor app manifest <appManifest> provided.', true);
        if (!options.manifestVariables.appDisplayName)
            logger_1.log.warn('Neither app display name <appDisplayName> nor app manifest <appManifest> provided. Using app executable as display name.');
        if (!options.manifestVariables.packageDescription)
            logger_1.log.warn('Neither package description <packageDescription> nor app manifest <appManifest> provided. Using app executable as description.');
        if (!options.manifestVariables.packageBackgroundColor)
            logger_1.log.warn('Neither package background color <packageBackgroundColor> nor app manifest <appManifest> provided. Using default background color transparent.');
        hasManifestParams = true;
    }
    if (!hasManifestParams && !options.appManifest)
        logger_1.log.error('Neither app manifest <appManifest> nor manifest variables <manifestVariables> provided.', true);
    if (options.appManifest && !(await fs_extra_1.default.exists(options.appManifest)))
        logger_1.log.error('Path to application manifest <appManifest> does not exist.', true, { appManifest: options.appManifest });
    if (!options.appDir && !manifestIsSparsePackage)
        logger_1.log.error('Path to application <appDir> not provided.', true);
    if (!(await fs_extra_1.default.exists(options.appDir)) && !manifestIsSparsePackage)
        logger_1.log.error('Path to application <appDir> does not exist.', true, { appDir: options.appDir });
    if (!options.packageAssets)
        logger_1.log.warn('Path to packages assets <packageAssets> not provided, using default assets.');
    if (options.packageAssets && !(await fs_extra_1.default.exists(options.packageAssets)))
        logger_1.log.error('Path to packages assets provided but <packageAssets> does not exist.', true, { packageAssets: options.packageAssets });
    if (sign) {
        if (!windowsSignOptions || (!windowsSignOptions['appDirectory'] && (!windowsSignOptions['files'] || windowsSignOptions['files'].length === 0))) {
            logger_1.log.warn('Neither path to application <appDir> nor files <files> provided in windows sign options. Will add MSIX package to files.');
        }
        if ((!windowsSignOptions?.certificateFile && !process.env.WINDOWS_CERTIFICATE_FILE) && (windowsSignOptions?.certificatePassword || process.env.WINDOWS_CERTIFICATE_PASSWORD))
            logger_1.log.warn('Path to cert <certificateFile> or environment variable WINDOWS_CERTIFICATE_FILE not provided. A dev cert will be created with the provided password and the package will be signed with it!');
        if (!windowsSignOptions?.certificateFile && (!windowsSignOptions?.certificatePassword && !process.env.WINDOWS_CERTIFICATE_PASSWORD))
            logger_1.log.warn('Path to cert <certificateFile> and cert password <certificatePassword> or environment variable WINDOWS_CERTIFICATE_PASSWORD not provided. A dev cert will be created with a random password and the package will be signed with it!');
        if (windowsSignOptions?.certificateFile && !(await fs_extra_1.default.exists(windowsSignOptions?.certificateFile)))
            logger_1.log.error('Path to cert <certificateFile> does not exist.', true, { certificateFile: windowsSignOptions?.certificateFile });
        if (windowsSignOptions?.certificateFile && !windowsSignOptions?.certificatePassword && !process.env.WINDOWS_CERTIFICATE_PASSWORD)
            logger_1.log.warn('Cert password <certificatePassword> not provided.');
        if (windowsSignOptions?.certificateFile && windowsSignOptions?.certificatePassword) {
            const certPublisher = await (0, bin_1.getCertPublisher)(windowsSignOptions?.certificateFile, windowsSignOptions?.certificatePassword);
            if (publisher != certPublisher)
                logger_1.log.error('The publisher in the manifest must match the publisher of the cert', false, { manifest_publisher: publisher, cert_publisher: certPublisher });
        }
    }
};
exports.verifyOptions = verifyOptions;
const setLogLevel = (options) => {
    const { logLevel } = options;
    globalThis.SHOW_WARNINGS = logLevel === 'warn';
    globalThis.DEBUG = logLevel === 'debug';
};
exports.setLogLevel = setLogLevel;
const locateMSIXTooling = async (options, manifestVars) => {
    const { appManifest, windowsKitVersion, windowsKitPath } = options;
    let arch = process.env.PROCESSOR_ARCHITECTURE === 'ARM64' ? 'arm64' : 'x64';
    if (windowsKitPath) {
        logger_1.log.debug('WindowsKitPath was provided and takes priority over WindowsKitVersion. Checking if it exists....', { windowsKitPath });
        if (await fs_extra_1.default.pathExists(windowsKitPath)) {
            const binaries = await (0, exports.getBinaries)(windowsKitPath);
            logger_1.log.debug('WindowsKitPath exists. Getting binary paths.', binaries);
            return binaries;
        }
        else {
            logger_1.log.error('The WindowsKitPath was provided but does not exist.', true, windowsKitPath);
        }
    }
    else {
        logger_1.log.debug('No WindowsKitPath provided. Will try WindowsKitVersion next.');
    }
    if (windowsKitVersion) {
        // Older versions than WinKit 10.0.22621.0 for ARM are missing the makeAppx.exe and we will fall back to x64 in that case.
        if (win_version_1.WindowsOSVersion.IsOlder(windowsKitVersion, MIN_ARM_WIN_KIT_VERSION) && arch === 'arm64') {
            arch = 'x64';
        }
        logger_1.log.debug('WindowsKitVersion was provided and takes priority over AppxManifest. Checking if it exists....', { windowsKitVersion });
        const windowsKitPathExec = path_1.default.join(WIN_KIT_BIN_PATH, windowsKitVersion, arch);
        if (await fs_extra_1.default.pathExists(windowsKitPathExec)) {
            const binaries = await (0, exports.getBinaries)(windowsKitPathExec);
            logger_1.log.debug(`WindowsKit version ${windowsKitVersion} exists. Getting binary paths.`, binaries);
            return binaries;
        }
        else {
            logger_1.log.error('WindowsKitVersion was provided but does not exist.', true, windowsKitPathExec);
        }
    }
    else {
        logger_1.log.debug('No WindowsKitVersion provided. Will try AppxManifest.xml min OS version next.');
    }
    if (appManifest || options.manifestVariables?.packageMinOSVersion) {
        let { manifestOsMinVersion } = manifestVars || {};
        manifestOsMinVersion = manifestOsMinVersion || options.manifestVariables?.packageMinOSVersion;
        logger_1.log.debug('WindowsKitVersion was derived from OSMinVersion of the AppxManifest. Checking if it exists....', { manifestOsMinVersion });
        if (manifestOsMinVersion) {
            // Older versions than WinKit 10.0.22621.0 for ARM are missing the makeAppx.exe and we will fall back to x64 in that case.
            if (win_version_1.WindowsOSVersion.IsOlder(manifestOsMinVersion, MIN_ARM_WIN_KIT_VERSION) && arch === 'arm64') {
                arch = 'x64';
            }
            logger_1.log.debug('WindowsKitVersion was derived from OSMinVersion of the AppxManifest. Checking if it exists....', { windowsKitVersion });
            const windowsKitPathExec = path_1.default.join(WIN_KIT_BIN_PATH, manifestOsMinVersion, arch);
            if (await fs_extra_1.default.pathExists(windowsKitPathExec)) {
                const binaries = await (0, exports.getBinaries)(windowsKitPathExec);
                logger_1.log.debug(`WindowsKit version ${windowsKitVersion} from AppxManifest exists. Getting binary paths.`, binaries);
                return binaries;
            }
            else {
                logger_1.log.error('WindowsKitVersion read from AppManifest but WindowsKit does not exist.', true, windowsKitPathExec);
            }
        }
        else {
            logger_1.log.error("Couldn't find Windows Kit version in AppManifest.");
        }
    }
    logger_1.log.debug('No information on WindowsKitVersion was provided, using default binaries. Checking if it exists....', { windowsKitVersion });
    const windowsKitPathExec = path_1.default.join(WIN_KIT_BIN_PATH, DEFAULT_WIN_KIT_VERSION, arch);
    if (await fs_extra_1.default.pathExists(windowsKitPathExec)) {
        const binaries = await (0, exports.getBinaries)(windowsKitPathExec);
        logger_1.log.debug(`Getting binary paths from default WindowsKit path.`, binaries);
        return binaries;
    }
    else {
        logger_1.log.error('No information on WindowsKitVersion was provided and default WindowsKit path does not exist.', true, windowsKitPathExec);
    }
    logger_1.log.error('Unable to locate MSIX Tooling. Giving up!', true);
};
exports.locateMSIXTooling = locateMSIXTooling;
/**
 * Generates a secure random password.
 * @returns {string} - Generated password.
 */
function generatePassword() {
    const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    const symbols = '!@#%^&*()-_=+[]{}<>?,.';
    const fullCharset = charset + symbols;
    const length = 16;
    let password = '';
    const bytes = crypto_1.default.randomBytes(length);
    for (let i = 0; i < length; i++) {
        password += fullCharset[bytes[i] % fullCharset.length];
    }
    return password;
}
const makeProgramOptions = async (options, manifestVars) => {
    const { makeAppx, makePri, signTool, makeCert } = await (0, exports.locateMSIXTooling)(options, manifestVars);
    const { outputDir, layoutDir } = await (0, exports.ensureFolders)(options);
    const { manifestAppName, manifestPackageArch, manifestIsSparsePackage, manifestPublisher } = manifestVars || {};
    const appName = manifestAppName || (0, exports.removeFileExtension)(options.manifestVariables?.appExecutable) || 'app';
    const packageArch = manifestPackageArch || options.manifestVariables?.targetArch;
    const isSparsePackage = manifestIsSparsePackage || false;
    const msixPackageName = options.packageName || (packageArch ? `${appName}_${packageArch}.msix` : `${appName}.msix`);
    const msix = path_1.default.join(outputDir, msixPackageName);
    const appManifestLayout = path_1.default.join(layoutDir, `AppxManifest.xml`);
    const assetsLayout = path_1.default.join(layoutDir, `assets`);
    const appLayout = path_1.default.join(layoutDir, `app`);
    const priConfig = path_1.default.join(layoutDir, 'priconfig.xml');
    const priFile = path_1.default.join(layoutDir, 'resources.pri');
    const createPri = options.createPri !== undefined ? options.createPri : true;
    const publisher = options.manifestVariables?.publisher || manifestPublisher || '';
    const sign = options.sign !== undefined ? options.sign : true;
    let windowsSignOptions;
    let cert_pfx = windowsSignOptions?.certificateFile || '';
    let cert_cer = '';
    let cert_pass = '';
    const createDevCert = sign && !options.windowsSignOptions?.certificateFile && !process.env.WINDOWS_CERTIFICATE_FILE;
    if (sign) {
        windowsSignOptions = options.windowsSignOptions || { files: [msix], certificateFile: '', certificatePassword: '', hashes: ["sha256"] };
        cert_pass = windowsSignOptions?.certificatePassword || process.env.WINDOWS_CERTIFICATE_PASSWORD || generatePassword();
        if (!windowsSignOptions.hashes || windowsSignOptions.hashes.length === 0) {
            windowsSignOptions.hashes = ['sha256'];
        }
        if (createDevCert) {
            cert_pfx = path_1.default.join(outputDir, 'dev_cert.pfx');
            cert_cer = path_1.default.join(outputDir, 'dev_cert.cer');
            windowsSignOptions[`certificateFile`] = cert_pfx;
            windowsSignOptions[`certificatePassword`] = cert_pass;
        }
        if (options.logLevel === 'debug') {
            windowsSignOptions[`debug`] = true;
        }
        const hasAppDirectorySet = 'appDirectory' in windowsSignOptions && windowsSignOptions.appDirectory;
        const hasFilesSet = 'files' in windowsSignOptions && windowsSignOptions.files && windowsSignOptions.files.length > 0;
        if (!hasAppDirectorySet && !hasFilesSet) {
            windowsSignOptions[`files`] = [msix];
        }
    }
    const appManifestIn = await (0, manifestation_1.manifest)(options);
    const program = {
        makeMsix: makeAppx,
        makePri,
        makeCert,
        signTool,
        outputDir,
        layoutDir,
        msix,
        appDir: options.appDir,
        appLayout,
        appManifestIn,
        appManifestLayout,
        assetsIn: options.packageAssets || path_1.default.join(__dirname, '..', 'static', 'assets'),
        assetsLayout,
        cert_pfx,
        cert_cer,
        cert_pass: cert_pass || '',
        priConfig,
        priFile,
        createPri,
        isSparsePackage,
        sign,
        windowsSignOptions,
        createDevCert,
        publisher,
    };
    logger_1.log.debug('Program options', program);
    return program;
};
exports.makeProgramOptions = makeProgramOptions;
const createLayout = async (program) => {
    await fs_extra_1.default.writeFile(program.appManifestLayout, program.appManifestIn);
    await fs_extra_1.default.copy(program.assetsIn, program.assetsLayout);
    if (!program.isSparsePackage) {
        await fs_extra_1.default.copy(program.appDir, program.appLayout);
    }
};
exports.createLayout = createLayout;
//# sourceMappingURL=utils.js.map