"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