diff --git a/packages/plugin/integrity-digest/README.md b/packages/plugin/integrity-digest/README.md new file mode 100644 index 0000000000..04ab27f8b7 --- /dev/null +++ b/packages/plugin/integrity-digest/README.md @@ -0,0 +1,35 @@ +## @electron-forge/plugin-integrity-digest + +This plugin provides a `packageAfterCopy` hook for calculating and storing integrity digests when packaging with Electron Forge. + +### Usage + +Install `@electron-forge/plugin-integrity-digest` and add this plugin to the `plugins` array in your Forge configuration: + +```shell +# Yarn +yarn add --dev @electron-forge/plugin-integrity-digest + +# npm +npm i -D @electron-forge/plugin-integrity-digest +``` + +```js +// forge.config.js + +const { IntegrityDigestPlugin } = require('@electron-forge/plugin-integrity-digest'); + +const forgeConfig = { + plugins: [new IntegrityDigestPlugin()], +}; + +module.exports = forgeConfig; +``` + +If desired, you can pass a specific version of integrity digest to calculate and store. Currently, the only version is `1`. + +```js +const forgeConfig = { + plugins: [new IntegrityDigestPlugin({version: 1})], +}; +``` \ No newline at end of file diff --git a/packages/plugin/integrity-digest/package.json b/packages/plugin/integrity-digest/package.json new file mode 100644 index 0000000000..048d2af44b --- /dev/null +++ b/packages/plugin/integrity-digest/package.json @@ -0,0 +1,27 @@ +{ + "name": "@electron-forge/plugin-integrity-digest", + "version": "8.0.0-alpha.4", + "description": "A plugin for generating integrity digests in Electron Forge", + "repository": "https://github.com/electron/forge", + "author": "Noah Gregory ", + "license": "MIT", + "main": "dist/IntegrityDigestPlugin.js", + "files": [ + "dist", + "src", + "package.json", + "README.md" + ], + "typings": "dist/IntegrityDigestPlugin.d.ts", + "engines": { + "node": ">= 22.12.0" + }, + "dependencies": { + "@electron-forge/plugin-base": "workspace:*", + "@electron-forge/shared-types": "workspace:*", + "@electron/asar": "^4.1.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/plugin/integrity-digest/src/IntegrityDigestPlugin.ts b/packages/plugin/integrity-digest/src/IntegrityDigestPlugin.ts new file mode 100644 index 0000000000..0d31dbf68d --- /dev/null +++ b/packages/plugin/integrity-digest/src/IntegrityDigestPlugin.ts @@ -0,0 +1,54 @@ +import path from 'node:path'; + +import { + calculateIntegrityDigestForApp, + setStoredIntegrityDigestForApp, + // eslint-disable-next-line import/no-unresolved -- @electron/asar is ESM; ESLint can't resolve it. +} from '@electron/asar'; +import { namedHookWithTaskFn, PluginBase } from '@electron-forge/plugin-base'; +import { + ForgeMultiHookMap, + type ForgePlatform, +} from '@electron-forge/shared-types'; + +type IntegrityDigestVersion = 1; // TODO: Export this from @electron/asar + +export type IntegrityDigestConfig = { + version: IntegrityDigestVersion; +}; + +export default class IntegrityDigestPlugin extends PluginBase { + name = 'integrity-digest'; + + constructor(config: IntegrityDigestConfig = { version: 1 }) { + super(config); + } + + getHooks(): ForgeMultiHookMap { + return { + packageAfterCopy: namedHookWithTaskFn<'packageAfterCopy'>( + async ( + listrTask, + resolvedForgeConfig, + resourcesPath, + electronVersion, + platform, + ) => { + const { version } = this.config; + const applePlatforms: ForgePlatform[] = ['darwin', 'mas']; + if (!applePlatforms.includes(platform)) return; + // `resourcesPath` points to `.app/Contents/Resources/app`, so go up 3 levels to reach `.app`. + const appPath = path.resolve(resourcesPath, '../../..'); + const integrityDigest = calculateIntegrityDigestForApp( + appPath, + version, + ); + setStoredIntegrityDigestForApp(appPath, integrityDigest); + }, + 'Calculating and Storing Integrity Digest', + ), + }; + } +} + +export { IntegrityDigestPlugin }; diff --git a/yarn.lock b/yarn.lock index 13f4878766..fc8b91af9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1111,6 +1111,16 @@ __metadata: languageName: unknown linkType: soft +"@electron-forge/plugin-integrity-digest@workspace:packages/plugin/integrity-digest": + version: 0.0.0-use.local + resolution: "@electron-forge/plugin-integrity-digest@workspace:packages/plugin/integrity-digest" + dependencies: + "@electron-forge/plugin-base": "workspace:*" + "@electron-forge/shared-types": "workspace:*" + "@electron/asar": "npm:4.1.0" + languageName: unknown + linkType: soft + "@electron-forge/plugin-local-electron@workspace:packages/plugin/local-electron": version: 0.0.0-use.local resolution: "@electron-forge/plugin-local-electron@workspace:packages/plugin/local-electron" @@ -1405,6 +1415,23 @@ __metadata: languageName: unknown linkType: soft +"@electron/asar@npm:4.1.0": + version: 4.1.0 + resolution: "@electron/asar@npm:4.1.0" + dependencies: + commander: "npm:^13.1.0" + glob: "npm:^13.0.2" + minimatch: "npm:^10.0.1" + plist: "npm:^3.1.0" + dependenciesMeta: + electron: + built: true + bin: + asar: bin/asar.mjs + checksum: 10c0/f75565faeae0e54170ec625ceb5339d0f5c3fec79ff6d6794b0172aa2c5d96a2a9d189943c78004875b53d0010f39925dc6d6fcc76b324571986e68f82d87b0a + languageName: node + linkType: hard + "@electron/asar@npm:^3.2.1": version: 3.4.1 resolution: "@electron/asar@npm:3.4.1" @@ -6747,6 +6774,13 @@ __metadata: languageName: node linkType: hard +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + "bare-events@npm:^2.7.0": version: 2.8.2 resolution: "bare-events@npm:2.8.2" @@ -6938,6 +6972,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^5.0.2": + version: 5.0.3 + resolution: "brace-expansion@npm:5.0.3" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/e474d300e581ec56851b3863ff1cf18573170c6d06deb199ccbd03b2119c36975f6ce2abc7b770f5bebddc1ab022661a9fea9b4d56f33315d7bef54d8793869e + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -11411,6 +11454,17 @@ __metadata: languageName: node linkType: hard +"glob@npm:^13.0.2": + version: 13.0.6 + resolution: "glob@npm:13.0.6" + dependencies: + minimatch: "npm:^10.2.2" + minipass: "npm:^7.1.3" + path-scurry: "npm:^2.0.2" + checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a + languageName: node + linkType: hard + "glob@npm:^7.1.3, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -14816,12 +14870,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.0.1, minimatch@npm:^10.1.1": - version: 10.1.1 - resolution: "minimatch@npm:10.1.1" +"minimatch@npm:^10.0.1, minimatch@npm:^10.2.2": + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902 + brace-expansion: "npm:^5.0.2" + checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945 languageName: node linkType: hard @@ -14834,6 +14888,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.1.1": + version: 10.1.1 + resolution: "minimatch@npm:10.1.1" + dependencies: + "@isaacs/brace-expansion": "npm:^5.0.0" + checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902 + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -14990,6 +15053,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb + languageName: node + linkType: hard + "minizlib@npm:^2.1.1": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -16432,6 +16502,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482 + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.12": version: 0.1.12 resolution: "path-to-regexp@npm:0.1.12"