Browse Source

build: embed binary checksums in the npm package (#30611)

* build: embed binary checksums in the npm package

* Update docs/tutorial/installation.md

Co-authored-by: Jeremy Rose <[email protected]>

* refactor: replace reduce with loop

Co-authored-by: Jeremy Rose <[email protected]>
Samuel Attard 3 years ago
parent
commit
aab5ea5f9d
5 changed files with 48 additions and 4 deletions
  1. 1 0
      .gitignore
  2. 5 0
      docs/tutorial/installation.md
  3. 1 0
      npm/install.js
  4. 1 1
      npm/package.json
  5. 40 3
      script/release/publish-to-npm.js

+ 1 - 0
.gitignore

@@ -26,6 +26,7 @@ compile_commands.json
 # npm package
 /npm/dist
 /npm/path.txt
+/npm/checksums.json
 
 .npmrc
 

+ 5 - 0
docs/tutorial/installation.md

@@ -90,6 +90,11 @@ ELECTRON_CUSTOM_DIR="{{ version }}"
 The above configuration will download from URLs such as
 `https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
 
+If your mirror serves artifacts with different checksums to the official
+Electron release you may have to set `ELECTRON_USE_REMOTE_CHECKSUMS=1` to
+force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
+instead of the embedded checksums.
+
 #### Cache
 
 Alternatively, you can override the local cache. `@electron/get` will cache

+ 1 - 0
npm/install.js

@@ -41,6 +41,7 @@ downloadArtifact({
   artifactName: 'electron',
   force: process.env.force_no_cache === 'true',
   cacheRoot: process.env.electron_config_cache,
+  checksums: process.env.electron_use_remote_checksums ? undefined : require('./checksums.json'),
   platform,
   arch
 }).then(extractFile).catch(err => {

+ 1 - 1
npm/package.json

@@ -8,7 +8,7 @@
     "postinstall": "node install.js"
   },
   "dependencies": {
-    "@electron/get": "^1.0.1",
+    "@electron/get": "^1.13.0",
     "@types/node": "^14.6.2",
     "extract-zip": "^1.0.3"
   },

+ 40 - 3
script/release/publish-to-npm.js

@@ -103,6 +103,27 @@ new Promise((resolve, reject) => {
 
     return release;
   })
+  .then(async (release) => {
+    const checksumsAsset = release.assets.find((asset) => asset.name === 'SHASUMS256.txt');
+    if (!checksumsAsset) {
+      throw new Error(`cannot find SHASUMS256.txt from v${rootPackageJson.version} release assets`);
+    }
+
+    const checksumsContent = await getAssetContents(
+      rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron',
+      checksumsAsset.id
+    );
+
+    const checksumsObject = {};
+    for (const line of checksumsContent.trim().split('\n')) {
+      const [checksum, file] = line.split(' *');
+      checksumsObject[file] = checksum;
+    }
+
+    fs.writeFileSync(path.join(tempDir, 'checksums.json'), JSON.stringify(checksumsObject, null, 2));
+
+    return release;
+  })
   .then(async (release) => {
     const currentBranch = await getCurrentBranch();
 
@@ -145,10 +166,26 @@ new Promise((resolve, reject) => {
   // test that the package can install electron prebuilt from github release
     const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`);
     return new Promise((resolve, reject) => {
-      childProcess.execSync(`npm install ${tarballPath} --force --silent`, {
+      const result = childProcess.spawnSync('npm', ['install', tarballPath, '--force', '--silent'], {
         env: Object.assign({}, process.env, { electron_config_cache: tempDir }),
-        cwd: tempDir
+        cwd: tempDir,
+        stdio: 'inherit'
       });
+      if (result.status !== 0) {
+        return reject(new Error(`npm install failed with status ${result.status}`));
+      }
+      try {
+        const electronPath = require(path.resolve(tempDir, 'node_modules', rootPackageJson.name));
+        if (typeof electronPath !== 'string') {
+          return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module is not a string`));
+        }
+        if (!fs.existsSync(electronPath)) {
+          return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module does not exist on disk`));
+        }
+      } catch (e) {
+        console.error(e);
+        return reject(new Error(`loading the generated ${rootPackageJson.name} module failed with an error`));
+      }
       resolve(tarballPath);
     });
   })
@@ -181,6 +218,6 @@ new Promise((resolve, reject) => {
     }
   })
   .catch((err) => {
-    console.error(`Error: ${err}`);
+    console.error('Error:', err);
     process.exit(1);
   });