UNPKG

13.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.createMacApp = void 0;
4const bluebird_lst_1 = require("bluebird-lst");
5const builder_util_1 = require("builder-util");
6const fs_1 = require("builder-util/out/fs");
7const promises_1 = require("fs/promises");
8const path = require("path");
9const appInfo_1 = require("../appInfo");
10const platformPackager_1 = require("../platformPackager");
11const appBuilder_1 = require("../util/appBuilder");
12const ElectronFramework_1 = require("./ElectronFramework");
13function doRename(basePath, oldName, newName) {
14 return (0, promises_1.rename)(path.join(basePath, oldName), path.join(basePath, newName));
15}
16function moveHelpers(helperSuffixes, frameworksPath, appName, prefix) {
17 return bluebird_lst_1.default.map(helperSuffixes, suffix => {
18 const executableBasePath = path.join(frameworksPath, `${prefix}${suffix}.app`, "Contents", "MacOS");
19 return doRename(executableBasePath, `${prefix}${suffix}`, appName + suffix).then(() => doRename(frameworksPath, `${prefix}${suffix}.app`, `${appName}${suffix}.app`));
20 });
21}
22function getAvailableHelperSuffixes(helperEHPlist, helperNPPlist, helperRendererPlist, helperPluginPlist, helperGPUPlist) {
23 const result = [" Helper"];
24 if (helperEHPlist != null) {
25 result.push(" Helper EH");
26 }
27 if (helperNPPlist != null) {
28 result.push(" Helper NP");
29 }
30 if (helperRendererPlist != null) {
31 result.push(" Helper (Renderer)");
32 }
33 if (helperPluginPlist != null) {
34 result.push(" Helper (Plugin)");
35 }
36 if (helperGPUPlist != null) {
37 result.push(" Helper (GPU)");
38 }
39 return result;
40}
41/** @internal */
42async function createMacApp(packager, appOutDir, asarIntegrity, isMas) {
43 var _a, _b;
44 const appInfo = packager.appInfo;
45 // Electon uses the application name (CFBundleName) to resolve helper apps
46 // https://github.com/electron/electron/blob/main/shell/app/electron_main_delegate_mac.mm
47 // https://github.com/electron-userland/electron-builder/issues/6962
48 const appFilename = appInfo.sanitizedProductName;
49 const electronBranding = (0, ElectronFramework_1.createBrandingOpts)(packager.config);
50 const contentsPath = path.join(appOutDir, packager.info.framework.distMacOsAppName, "Contents");
51 const frameworksPath = path.join(contentsPath, "Frameworks");
52 const loginItemPath = path.join(contentsPath, "Library", "LoginItems");
53 const appPlistFilename = path.join(contentsPath, "Info.plist");
54 const helperPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper.app`, "Contents", "Info.plist");
55 const helperEHPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper EH.app`, "Contents", "Info.plist");
56 const helperNPPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper NP.app`, "Contents", "Info.plist");
57 const helperRendererPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Renderer).app`, "Contents", "Info.plist");
58 const helperPluginPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Plugin).app`, "Contents", "Info.plist");
59 const helperGPUPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (GPU).app`, "Contents", "Info.plist");
60 const helperLoginPlistFilename = path.join(loginItemPath, `${electronBranding.productName} Login Helper.app`, "Contents", "Info.plist");
61 const plistContent = await (0, appBuilder_1.executeAppBuilderAsJson)([
62 "decode-plist",
63 "-f",
64 appPlistFilename,
65 "-f",
66 helperPlistFilename,
67 "-f",
68 helperEHPlistFilename,
69 "-f",
70 helperNPPlistFilename,
71 "-f",
72 helperRendererPlistFilename,
73 "-f",
74 helperPluginPlistFilename,
75 "-f",
76 helperGPUPlistFilename,
77 "-f",
78 helperLoginPlistFilename,
79 ]);
80 if (plistContent[0] == null) {
81 throw new Error("corrupted Electron dist");
82 }
83 const appPlist = plistContent[0];
84 const helperPlist = plistContent[1];
85 const helperEHPlist = plistContent[2];
86 const helperNPPlist = plistContent[3];
87 const helperRendererPlist = plistContent[4];
88 const helperPluginPlist = plistContent[5];
89 const helperGPUPlist = plistContent[6];
90 const helperLoginPlist = plistContent[7];
91 // if an extend-info file was supplied, copy its contents in first
92 if (plistContent[8] != null) {
93 Object.assign(appPlist, plistContent[8]);
94 }
95 const buildMetadata = packager.config;
96 /**
97 * Configure bundleIdentifier for the generic Electron Helper process
98 *
99 * This was the only Helper in Electron 5 and before. Allow users to configure
100 * the bundleIdentifier for continuity.
101 */
102 const oldHelperBundleId = buildMetadata["helper-bundle-id"];
103 if (oldHelperBundleId != null) {
104 builder_util_1.log.warn("build.helper-bundle-id is deprecated, please set as build.mac.helperBundleId");
105 }
106 const defaultAppId = packager.platformSpecificBuildOptions.appId;
107 const cfBundleIdentifier = (0, appInfo_1.filterCFBundleIdentifier)((isMas ? (_a = packager.config.mas) === null || _a === void 0 ? void 0 : _a.appId : defaultAppId) || defaultAppId || appInfo.macBundleIdentifier);
108 const defaultHelperId = packager.platformSpecificBuildOptions.helperBundleId;
109 const helperBundleIdentifier = (0, appInfo_1.filterCFBundleIdentifier)((isMas ? (_b = packager.config.mas) === null || _b === void 0 ? void 0 : _b.helperBundleId : defaultHelperId) || defaultHelperId || oldHelperBundleId || `${cfBundleIdentifier}.helper`);
110 appPlist.CFBundleIdentifier = cfBundleIdentifier;
111 await packager.applyCommonInfo(appPlist, contentsPath);
112 // required for electron-updater proxy
113 if (!isMas) {
114 configureLocalhostAts(appPlist);
115 }
116 helperPlist.CFBundleExecutable = `${appFilename} Helper`;
117 helperPlist.CFBundleDisplayName = `${appInfo.productName} Helper`;
118 helperPlist.CFBundleIdentifier = helperBundleIdentifier;
119 helperPlist.CFBundleVersion = appPlist.CFBundleVersion;
120 /**
121 * Configure bundleIdentifier for Electron 5+ Helper processes
122 *
123 * In Electron 6, parts of the generic Electron Helper process were split into
124 * individual helper processes. Allow users to configure the bundleIdentifiers
125 * for continuity, specifically because macOS keychain access relies on
126 * bundleIdentifiers not changing (i.e. across versions of Electron).
127 */
128 function configureHelper(helper, postfix, userProvidedBundleIdentifier) {
129 helper.CFBundleExecutable = `${appFilename} Helper ${postfix}`;
130 helper.CFBundleDisplayName = `${appInfo.productName} Helper ${postfix}`;
131 helper.CFBundleIdentifier = userProvidedBundleIdentifier
132 ? (0, appInfo_1.filterCFBundleIdentifier)(userProvidedBundleIdentifier)
133 : (0, appInfo_1.filterCFBundleIdentifier)(`${helperBundleIdentifier}.${postfix}`);
134 helper.CFBundleVersion = appPlist.CFBundleVersion;
135 }
136 if (helperRendererPlist != null) {
137 configureHelper(helperRendererPlist, "(Renderer)", packager.platformSpecificBuildOptions.helperRendererBundleId);
138 }
139 if (helperPluginPlist != null) {
140 configureHelper(helperPluginPlist, "(Plugin)", packager.platformSpecificBuildOptions.helperPluginBundleId);
141 }
142 if (helperGPUPlist != null) {
143 configureHelper(helperGPUPlist, "(GPU)", packager.platformSpecificBuildOptions.helperGPUBundleId);
144 }
145 if (helperEHPlist != null) {
146 configureHelper(helperEHPlist, "EH", packager.platformSpecificBuildOptions.helperEHBundleId);
147 }
148 if (helperNPPlist != null) {
149 configureHelper(helperNPPlist, "NP", packager.platformSpecificBuildOptions.helperNPBundleId);
150 }
151 if (helperLoginPlist != null) {
152 helperLoginPlist.CFBundleExecutable = `${appFilename} Login Helper`;
153 helperLoginPlist.CFBundleDisplayName = `${appInfo.productName} Login Helper`;
154 // noinspection SpellCheckingInspection
155 helperLoginPlist.CFBundleIdentifier = `${cfBundleIdentifier}.loginhelper`;
156 helperLoginPlist.CFBundleVersion = appPlist.CFBundleVersion;
157 }
158 const protocols = (0, builder_util_1.asArray)(buildMetadata.protocols).concat((0, builder_util_1.asArray)(packager.platformSpecificBuildOptions.protocols));
159 if (protocols.length > 0) {
160 appPlist.CFBundleURLTypes = protocols.map(protocol => {
161 const schemes = (0, builder_util_1.asArray)(protocol.schemes);
162 if (schemes.length === 0) {
163 throw new builder_util_1.InvalidConfigurationError(`Protocol "${protocol.name}": must be at least one scheme specified`);
164 }
165 return {
166 CFBundleURLName: protocol.name,
167 CFBundleTypeRole: protocol.role || "Editor",
168 CFBundleURLSchemes: schemes.slice(),
169 };
170 });
171 }
172 const fileAssociations = packager.fileAssociations;
173 if (fileAssociations.length > 0) {
174 const documentTypes = await bluebird_lst_1.default.map(fileAssociations, async (fileAssociation) => {
175 const extensions = (0, builder_util_1.asArray)(fileAssociation.ext).map(platformPackager_1.normalizeExt);
176 const customIcon = await packager.getResource((0, builder_util_1.getPlatformIconFileName)(fileAssociation.icon, true), `${extensions[0]}.icns`);
177 let iconFile = appPlist.CFBundleIconFile;
178 if (customIcon != null) {
179 iconFile = path.basename(customIcon);
180 await (0, fs_1.copyOrLinkFile)(customIcon, path.join(path.join(contentsPath, "Resources"), iconFile));
181 }
182 const result = {
183 CFBundleTypeExtensions: extensions,
184 CFBundleTypeName: fileAssociation.name || extensions[0],
185 CFBundleTypeRole: fileAssociation.role || "Editor",
186 LSHandlerRank: fileAssociation.rank || "Default",
187 CFBundleTypeIconFile: iconFile,
188 };
189 if (fileAssociation.isPackage) {
190 result.LSTypeIsPackage = true;
191 }
192 return result;
193 });
194 // `CFBundleDocumentTypes` may be defined in `mac.extendInfo`, so we need to merge it in that case
195 appPlist.CFBundleDocumentTypes = [...(appPlist.CFBundleDocumentTypes || []), ...documentTypes];
196 }
197 if (asarIntegrity != null) {
198 appPlist.ElectronAsarIntegrity = asarIntegrity;
199 }
200 const plistDataToWrite = {
201 [appPlistFilename]: appPlist,
202 [helperPlistFilename]: helperPlist,
203 };
204 if (helperEHPlist != null) {
205 plistDataToWrite[helperEHPlistFilename] = helperEHPlist;
206 }
207 if (helperNPPlist != null) {
208 plistDataToWrite[helperNPPlistFilename] = helperNPPlist;
209 }
210 if (helperRendererPlist != null) {
211 plistDataToWrite[helperRendererPlistFilename] = helperRendererPlist;
212 }
213 if (helperPluginPlist != null) {
214 plistDataToWrite[helperPluginPlistFilename] = helperPluginPlist;
215 }
216 if (helperGPUPlist != null) {
217 plistDataToWrite[helperGPUPlistFilename] = helperGPUPlist;
218 }
219 if (helperLoginPlist != null) {
220 plistDataToWrite[helperLoginPlistFilename] = helperLoginPlist;
221 }
222 await Promise.all([
223 (0, appBuilder_1.executeAppBuilderAndWriteJson)(["encode-plist"], plistDataToWrite),
224 doRename(path.join(contentsPath, "MacOS"), electronBranding.productName, appPlist.CFBundleExecutable),
225 (0, fs_1.unlinkIfExists)(path.join(appOutDir, "LICENSE")),
226 (0, fs_1.unlinkIfExists)(path.join(appOutDir, "LICENSES.chromium.html")),
227 ]);
228 await moveHelpers(getAvailableHelperSuffixes(helperEHPlist, helperNPPlist, helperRendererPlist, helperPluginPlist, helperGPUPlist), frameworksPath, appFilename, electronBranding.productName);
229 if (helperLoginPlist != null) {
230 const prefix = electronBranding.productName;
231 const suffix = " Login Helper";
232 const executableBasePath = path.join(loginItemPath, `${prefix}${suffix}.app`, "Contents", "MacOS");
233 await doRename(executableBasePath, `${prefix}${suffix}`, appFilename + suffix).then(() => doRename(loginItemPath, `${prefix}${suffix}.app`, `${appFilename}${suffix}.app`));
234 }
235 const appPath = path.join(appOutDir, `${appInfo.productFilename}.app`);
236 await (0, promises_1.rename)(path.dirname(contentsPath), appPath);
237 // https://github.com/electron-userland/electron-builder/issues/840
238 const now = Date.now() / 1000;
239 await (0, promises_1.utimes)(appPath, now, now);
240}
241exports.createMacApp = createMacApp;
242function configureLocalhostAts(appPlist) {
243 // https://bencoding.com/2015/07/20/app-transport-security-and-localhost/
244 let ats = appPlist.NSAppTransportSecurity;
245 if (ats == null) {
246 ats = {};
247 appPlist.NSAppTransportSecurity = ats;
248 }
249 ats.NSAllowsLocalNetworking = true;
250 // https://github.com/electron-userland/electron-builder/issues/3377#issuecomment-446035814
251 ats.NSAllowsArbitraryLoads = true;
252 let exceptionDomains = ats.NSExceptionDomains;
253 if (exceptionDomains == null) {
254 exceptionDomains = {};
255 ats.NSExceptionDomains = exceptionDomains;
256 }
257 if (exceptionDomains.localhost == null) {
258 const allowHttp = {
259 NSTemporaryExceptionAllowsInsecureHTTPSLoads: false,
260 NSIncludesSubdomains: false,
261 NSTemporaryExceptionAllowsInsecureHTTPLoads: true,
262 NSTemporaryExceptionMinimumTLSVersion: "1.0",
263 NSTemporaryExceptionRequiresForwardSecrecy: false,
264 };
265 exceptionDomains.localhost = allowHttp;
266 exceptionDomains["127.0.0.1"] = allowHttp;
267 }
268}
269//# sourceMappingURL=electronMac.js.map
\No newline at end of file