feat: add support for auto-merging ElectronAsarIntegrity values

This commit is contained in:
Samuel Attard
2021-09-15 12:50:03 -07:00
parent fe8d99e31d
commit 36b58a84f3
5 changed files with 97 additions and 16 deletions

View File

@@ -30,6 +30,7 @@
"@types/debug": "^4.1.5",
"@types/fs-extra": "^9.0.4",
"@types/node": "^14.14.7",
"@types/plist": "^3.0.2",
"husky": "^4.3.0",
"lint-staged": "^10.5.1",
"prettier": "^2.1.2",
@@ -38,10 +39,11 @@
},
"dependencies": {
"@malept/cross-spawn-promise": "^1.1.0",
"asar": "^3.0.3",
"asar": "^3.1.0",
"debug": "^4.3.1",
"dir-compare": "^2.4.0",
"fs-extra": "^9.0.1"
"fs-extra": "^9.0.1",
"plist": "^3.0.4"
},
"husky": {
"hooks": {

View File

@@ -1,3 +1,5 @@
import * as asar from 'asar';
import * as crypto from 'crypto';
import * as fs from 'fs-extra';
import * as path from 'path';
import { d } from './debug';
@@ -19,3 +21,13 @@ export const detectAsarMode = async (appPath: string) => {
d('determined has asar');
return AsarMode.HAS_ASAR;
};
export const generateAsarIntegrity = (asarPath: string) => {
return {
algorithm: 'SHA256' as const,
hash: crypto
.createHash('SHA256')
.update(asar.getRawHeader(asarPath).headerString)
.digest('hex'),
};
};

View File

@@ -7,6 +7,7 @@ const MACHO_PREFIX = 'Mach-O ';
export enum AppFileType {
MACHO,
PLAIN,
INFO_PLIST,
SNAPSHOT,
APP_CODE,
}
@@ -50,6 +51,8 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
fileType = AppFileType.MACHO;
} else if (p.endsWith('.bin')) {
fileType = AppFileType.SNAPSHOT;
} else if (path.basename(p) === 'Info.plist') {
fileType = AppFileType.INFO_PLIST;
}
files.push({

View File

@@ -1,11 +1,14 @@
import { spawn } from '@malept/cross-spawn-promise';
import * as asar from 'asar';
import * as crypto from 'crypto';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as plist from 'plist';
import * as dircompare from 'dir-compare';
import { AppFile, AppFileType, getAllAppFiles } from './file-utils';
import { AsarMode, detectAsarMode } from './asar-utils';
import { AsarMode, detectAsarMode, generateAsarIntegrity } from './asar-utils';
import { sha } from './sha';
import { d } from './debug';
@@ -172,6 +175,9 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
}
}
const generatedIntegrity: Record<string, { algorithm: 'SHA256'; hash: string }> = {};
let didSplitAsar = false;
/**
* If we have an ASAR we just need to check if the two "app.asar" files have the same hash,
* if they are, same as above, we can leave one there and call it a day. If they're different
@@ -188,11 +194,10 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
);
if (x64AsarSha !== arm64AsarSha) {
didSplitAsar = true;
d('x64 and arm64 asars are different');
await fs.move(
path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'),
path.resolve(tmpApp, 'Contents', 'Resources', 'app-x64.asar'),
);
const x64AsarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app-x64.asar');
await fs.move(path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'), x64AsarPath);
const x64Unpacked = path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar.unpacked');
if (await fs.pathExists(x64Unpacked)) {
await fs.move(
@@ -201,9 +206,10 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
);
}
const arm64AsarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app-arm64.asar');
await fs.copy(
path.resolve(opts.arm64AppPath, 'Contents', 'Resources', 'app.asar'),
path.resolve(tmpApp, 'Contents', 'Resources', 'app-arm64.asar'),
arm64AsarPath,
);
const arm64Unpacked = path.resolve(
opts.arm64AppPath,
@@ -234,15 +240,42 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
);
pj.main = 'index.js';
await fs.writeJson(path.resolve(entryAsar, 'package.json'), pj);
await asar.createPackage(
entryAsar,
path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'),
);
const asarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar');
await asar.createPackage(entryAsar, asarPath);
generatedIntegrity['Resources/app.asar'] = generateAsarIntegrity(asarPath);
generatedIntegrity['Resources/app-x64.asar'] = generateAsarIntegrity(x64AsarPath);
generatedIntegrity['Resources/app-arm64.asar'] = generateAsarIntegrity(arm64AsarPath);
} else {
d('x64 and arm64 asars are the same');
generatedIntegrity['Resources/app.asar'] = generateAsarIntegrity(
path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'),
);
}
}
const plistFiles = x64Files.filter((f) => f.type === AppFileType.INFO_PLIST);
for (const plistFile of plistFiles) {
const x64PlistPath = path.resolve(opts.x64AppPath, plistFile.relativePath);
const arm64PlistPath = path.resolve(opts.arm64AppPath, plistFile.relativePath);
const { ElectronAsarIntegrity: x64Integrity, ...x64Plist } = plist.parse(
await fs.readFile(x64PlistPath, 'utf8'),
) as any;
const { ElectronAsarIntegrity: arm64Integrity, ...arm64Plist } = plist.parse(
await fs.readFile(arm64PlistPath, 'utf8'),
) as any;
if (JSON.stringify(x64Plist) !== JSON.stringify(arm64Plist)) {
throw new Error(
`Expected all Info.plist files to be identical when ignoring integrity when creating a universal build but "${plistFile.relativePath}" was not`,
);
}
const mergedPlist = { ...x64Plist, ElectronAsarIntegrity: generatedIntegrity };
await fs.writeFile(path.resolve(tmpApp, plistFile.relativePath), plist.build(mergedPlist));
}
for (const snapshotsFile of arm64Files.filter((f) => f.type === AppFileType.SNAPSHOT)) {
d('copying snapshot file', snapshotsFile.relativePath, 'to target application');
await fs.copy(

View File

@@ -314,6 +314,14 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/plist@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/plist/-/plist-3.0.2.tgz#61b3727bba0f5c462fe333542534a0c3e19ccb01"
integrity sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==
dependencies:
"@types/node" "*"
xmlbuilder ">=11.0.1"
"@types/retry@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
@@ -497,10 +505,10 @@ asap@^2.0.0:
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
asar@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/asar/-/asar-3.0.3.tgz#1fef03c2d6d2de0cbad138788e4f7ae03b129c7b"
integrity sha512-k7zd+KoR+n8pl71PvgElcoKHrVNiSXtw7odKbyNpmgKe7EGRF9Pnu3uLOukD37EvavKwVFxOUpqXTIZC5B5Pmw==
asar@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/asar/-/asar-3.1.0.tgz#70b0509449fe3daccc63beb4d3c7d2e24d3c6473"
integrity sha512-vyxPxP5arcAqN4F/ebHd/HhwnAiZtwhglvdmc7BR2f0ywbVNTOpSeyhLDbGXtE/y58hv1oC75TaNIXutnsOZsQ==
dependencies:
chromium-pickle-js "^0.2.0"
commander "^5.0.0"
@@ -559,6 +567,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
@@ -3711,6 +3724,14 @@ please-upgrade-node@^3.2.0:
dependencies:
semver-compare "^1.0.0"
plist@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe"
integrity sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==
dependencies:
base64-js "^1.5.1"
xmlbuilder "^9.0.7"
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -5037,6 +5058,16 @@ xdg-basedir@^3.0.0:
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
xmlbuilder@>=11.0.1:
version "15.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
xmlbuilder@^9.0.7:
version "9.0.7"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"