remote code signing

This commit is contained in:
antelle 2020-04-05 21:43:32 +02:00
parent 52045ad2a6
commit 79ca627e7c
No known key found for this signature in database
GPG Key ID: 094A2F2D6136A4EE
4 changed files with 74 additions and 43 deletions

View File

@ -579,8 +579,8 @@ module.exports = function(grunt) {
'sign-exe': {
options: {
url: pkg.homepage,
get vm() {
return getCodeSingConfig().windowsVM;
get windows() {
return getCodeSingConfig().windows;
},
get certHash() {
return getCodeSingConfig().microsoftCertHash;

View File

@ -1,51 +1,60 @@
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const AdmZip = require('adm-zip');
const { runRemoteTask } = require('run-remote-task');
module.exports = function(grunt) {
grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', function() {
const opt = this.options();
for (const [file, name] of Object.entries(opt.files)) {
signFile(file, name, opt);
}
});
grunt.registerMultiTask(
'sign-exe',
'Signs exe file with authenticode certificate',
async function() {
const done = this.async();
const opt = this.options();
function signFile(file, name, opt) {
const fileNameWithoutFolder = path.basename(file);
const sharePath = `${process.env.HOME}/VMShare/${fileNameWithoutFolder}`;
fs.copyFileSync(file, sharePath);
const timeServer = 'http://timestamp.verisign.com/scripts/timstamp.dll';
const cmd = 'VBoxManage';
const args = [
'guestcontrol',
opt.vm.name,
'--username',
opt.vm.user,
'--password',
opt.vm.pass,
'run',
opt.vm.exec,
`sign /t ${timeServer} /d "${name}" /du ${opt.url} ${opt.vm.share}${fileNameWithoutFolder}`
];
// the algo is not working: "/fd ${opt.algo}"
let res = spawnSync(cmd, args);
if (res.status) {
args[5] = '*';
const cmdStr = cmd + ' ' + args.join(' ');
grunt.warn(`Sign error ${file}: exit code ${res.status}.\nCommand: ${cmdStr}`);
}
res = spawnSync('osslsigncode', ['verify', sharePath]);
if (res.status) {
const hasCertHash = res.stdout.includes(`Serial : ${opt.certHash}`);
if (!hasCertHash) {
grunt.warn(
`Verify error ${file}: exit code ${res.status}.\n${res.stdout.toString()}`
);
for (const [file, name] of Object.entries(opt.files)) {
await signFile(file, name, opt);
}
done();
}
);
async function signFile(file, name, opt) {
grunt.log.writeln(`Signing ${file}...`);
const fileNameWithoutFolder = path.basename(file);
const actionConfig = {
exe: fileNameWithoutFolder,
name: name || fileNameWithoutFolder,
url: opt.url
};
const zip = new AdmZip();
zip.addFile('action.json', Buffer.from(JSON.stringify(actionConfig)));
zip.addLocalFile(file);
const zipContents = zip.toBuffer();
fs.writeFileSync('data.zip', zipContents);
try {
const taskResult = await runRemoteTask(opt.windows, zipContents);
const signedFile = taskResult.file;
const res = spawnSync('osslsigncode', ['verify', signedFile]);
if (res.status) {
const hasCertHash = res.stdout.includes(`Serial : ${opt.certHash}`);
if (!hasCertHash) {
grunt.warn(
`Verify error ${file}: exit code ${res.status}.\n${res.stdout.toString()}`
);
}
}
fs.renameSync(signedFile, file);
grunt.log.writeln(`Signed ${file}: ${name}`);
} catch (e) {
grunt.warn(`Sign error ${file}: ${e}`);
}
fs.renameSync(sharePath, file);
grunt.log.writeln(`Signed ${file}: ${name}`);
}
};

20
package-lock.json generated
View File

@ -1555,6 +1555,11 @@
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz",
"integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ=="
},
"adm-zip": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz",
"integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g=="
},
"agent-base": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
@ -12380,6 +12385,21 @@
"aproba": "^1.1.1"
}
},
"run-remote-task": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/run-remote-task/-/run-remote-task-0.1.0.tgz",
"integrity": "sha512-FiEaJDoRxCaPnYh73niWlFq96poLBQzR8gRkfWzKr1MoChwiGMe1+JBoY3xojxzjA4ESGwrsaxSfzvJ339rxjg==",
"requires": {
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
"rxjs": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",

View File

@ -14,6 +14,7 @@
"@babel/plugin-external-helpers": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/preset-env": "^7.9.0",
"adm-zip": "^0.4.14",
"argon2-browser": "1.13.0",
"autoprefixer": "^9.7.5",
"babel-cli": "^6.26.0",
@ -77,6 +78,7 @@
"prettier": "^1.19.1",
"puppeteer": "^2.1.1",
"raw-loader": "^4.0.0",
"run-remote-task": "^0.1.0",
"sass-loader": "^8.0.2",
"stats-webpack-plugin": "0.7.0",
"string-replace-webpack-plugin": "0.1.3",