/ jenkins / lib.js
lib.js
  1  const path = require('path');
  2  const { createHash } = require('crypto');
  3  const { readFileSync } = require('fs');
  4  const { spawn } = require('child_process');
  5  
  6  const { hashPersonalMessage, ecsign, toBuffer, addHexPrefix } = require('ethereumjs-util');
  7  
  8  const genCommitFilename = (name, version, commit, buildId, isCodeSigning) => {
  9    const winRegex = /exe$/;
 10    const macRegex = /dmg$/;
 11    const split = name.split(version);
 12    const signed = winRegex.test(name) || macRegex.test(name)
 13      ? isCodeSigning ? '-signed' : '-unsigned'
 14      : '';
 15  
 16    return `${split[0]}${version}-${commit}-${buildId}${signed}${split[1]}`;
 17  };
 18  
 19  const genFileList = (linux, windows, osx) => {
 20    const { platform } = process;
 21    if (platform === 'linux') {
 22      return [...linux, ...windows];
 23    } else if (platform === 'darwin') {
 24      return [...osx];
 25    } else {
 26      throw new Error('Unrecognized host platform.');
 27    }
 28  };
 29  
 30  const genSha512 = filePath => {
 31    const hash = createHash('sha512');
 32    const data = readFileSync(filePath);
 33    hash.update(data);
 34    return hash.digest('hex');
 35  };
 36  
 37  const runChildProcess = cmd =>
 38    new Promise((resolve, reject) => {
 39      const child = spawn('sh', ['-c', cmd]);
 40  
 41      child.stdout.on('data', data => {
 42        process.stdout.write(data);
 43      });
 44  
 45      child.stderr.on('data', data => {
 46        process.stderr.write(data);
 47      });
 48  
 49      child.on('close', code => {
 50        if (code !== 0) {
 51          return reject(`Child process exited with code: ${code}`);
 52        }
 53        resolve();
 54      });
 55    });
 56  
 57  const uploadToS3 = (localFilePath, s3FilePath) =>
 58    runChildProcess(`aws s3 cp "${localFilePath}" "${s3FilePath}"`);
 59  
 60  const genS3Url = (filename, commit, bucket) => `s3://${bucket}/${commit}/${filename}`;
 61  
 62  const genManifestFile = manifest =>
 63    manifest.map(info => ({
 64      Filename: info.commitFilename,
 65      SHA512: info.fileHash
 66    }));
 67  
 68  const genManifestFilename = (flavor, version, commit, buildId) =>
 69    `manifest.${flavor}.v${version}.${commit}.${buildId}.json`;
 70  
 71  const genSignatureFile = (manifestHash, pKeyString) => {
 72    const pKeyBuffer = Buffer.from(pKeyString, 'hex');
 73    return signMessageWithPrivKeyV2(pKeyBuffer, manifestHash);
 74  };
 75  
 76  const genSignatureFilename = (flavor, version, commit, buildId) =>
 77    `manifest.${flavor}.v${version}.${commit}.${buildId}.signature`;
 78  
 79  const genManifest = (fileList, version, jenkinsBuildId, gitCommit, gitCommitShort, s3Bucket, isCodeSigning) =>
 80    fileList.map(filename => {
 81      const fullPath = path.resolve('dist/electron-builds/', filename);
 82      const commitFilename = genCommitFilename(filename, version, gitCommitShort, jenkinsBuildId, isCodeSigning);
 83  
 84      return {
 85        fullPath,
 86        filename,
 87        commitFilename,
 88        fileHash: genSha512(fullPath),
 89        s3Url: genS3Url(commitFilename, gitCommit, s3Bucket)
 90      };
 91    });
 92  
 93  function signMessageWithPrivKeyV2(privKey, msg) {
 94    const hash = hashPersonalMessage(toBuffer(msg));
 95    const signed = ecsign(hash, privKey);
 96    const combined = Buffer.concat([
 97      Buffer.from(signed.r),
 98      Buffer.from(signed.s),
 99      Buffer.from([signed.v])
100    ]);
101    const combinedHex = combined.toString('hex');
102  
103    return addHexPrefix(combinedHex);
104  }
105  
106  module.exports = {
107    genCommitFilename,
108    genManifestFile,
109    genFileList,
110    genSha512,
111    genS3Url,
112    uploadToS3,
113    signMessageWithPrivKeyV2,
114    genManifestFilename,
115    genManifest,
116    genSignatureFile,
117    genSignatureFilename
118  };