#21: Add signature validation during installations [partial]

This commit is contained in:
Scott E. Graves
2019-04-17 21:16:57 -05:00
parent 77094630b2
commit 946b54f2e6
6 changed files with 92 additions and 68 deletions

View File

@@ -65,7 +65,8 @@
"build/**/*", "build/**/*",
"node_modules/**/*", "node_modules/**/*",
"src/helpers.js", "src/helpers.js",
"public/detect_linux.sh" "public/detect_linux.sh",
"public/install_linux.sh"
], ],
"linux": { "linux": {
"category": "Utility", "category": "Utility",

View File

@@ -16,6 +16,7 @@ require.extensions['.sh'] = function (module, filename) {
module.exports = fs.readFileSync(filename, 'utf8'); module.exports = fs.readFileSync(filename, 'utf8');
}; };
const detectScript = require('./detect_linux.sh'); const detectScript = require('./detect_linux.sh');
const installScript = require('./update_linux.sh');
const publicKey = const publicKey =
'-----BEGIN PUBLIC KEY-----\n' + '-----BEGIN PUBLIC KEY-----\n' +
'MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEKfZmq5mMAtD4kSt2Gc/5J\n' + 'MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEKfZmq5mMAtD4kSt2Gc/5J\n' +
@@ -718,53 +719,63 @@ ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
} }
}; };
if (os.platform() === 'win32') { let command;
const executeInstall = () => { let args;
helpers const platform = os.platform();
.executeAsync(data.Source) if (platform === 'win32') {
.then(() => { command = data.Source;
cleanupFiles(); } else if (platform === 'darwin') {
closeApplication(); command = 'open';
}) args = ['-a', 'Finder', data.Source];
.catch(error => { } else if (platform === 'linux') {
cleanupFiles(); try {
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, { const execPath = path.join(os.tmpdir(), 'install_linux.sh');
Source: data.Source, fs.writeFileSync(execPath, installScript);
}, error); fs.chmodSync(execPath, '750');
}); command = execPath;
}; args = [data.Source];
if (hasSignature) { } catch (e) {
helpers cleanupFiles();
.verifySignature(data.Source, tempSig, tempPub) standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
.then(() => { Source: data.Source,
executeInstall(); }, e);
})
.catch(() => {
cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source,
}, 'Failed to verify installation package signature');
});
} else { // TODO Check Sha256
executeInstall();
} }
} else if (data.Source.toLocaleLowerCase().endsWith('.dmg')) { } else {
cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source,
}, Error('Platform not supported: ' + os.platform()));
}
if (command) {
const executeInstall = () => { const executeInstall = () => {
helpers helpers
.executeAsync('open', ['-a', 'Finder', data.Source]) .executeAsync(command, args)
.then(() => { .then(() => {
cleanupFiles(); cleanupFiles();
closeApplication(); closeApplication();
}) })
.catch(error => { .catch(error => {
cleanupFiles(); cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, { standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source, Source: data.Source,
}, error); }, error);
}); });
}; };
if (hasHash) { if (hasSignature) {
helpers
.verifySignature(data.Source, tempSig, tempPub)
.then(() => {
executeInstall();
})
.catch(() => {
cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source,
}, 'Failed to verify installation package signature');
});
} else if (hasHash) {
helpers helpers
.verifyHash(data.Source, data.Sha256) .verifyHash(data.Source, data.Sha256)
.then(()=> { .then(()=> {
@@ -779,22 +790,6 @@ ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
} else { } else {
executeInstall(); executeInstall();
} }
} else if (data.Source.toLocaleLowerCase().endsWith('.appimage')) {
cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source,
}, Error('Not implemented upgrade: ' + data.Source));
// TODO Generate and execute script with delay
/*helpers
.executeAsync(data.Source)
.then(() => {
closeApplication();
})
.catch(error => {
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
Source: data.Source,
}, error);
});*/
} else { } else {
cleanupFiles(); cleanupFiles();
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, { standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {

8
public/update_linux.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
sleep 5
chmod +x "$1"
"$1"&
sleep 1
rm -f "$0"

View File

@@ -3,6 +3,7 @@ const path = require('path');
const os = require('os'); const os = require('os');
const axios = require('axios/index'); const axios = require('axios/index');
const exec = require('child_process').exec; const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const spawn = require('child_process').spawn; const spawn = require('child_process').spawn;
const Constants = require('./constants'); const Constants = require('./constants');
const RandomString = require('randomstring'); const RandomString = require('randomstring');
@@ -547,8 +548,7 @@ module.exports.verifySignature = (file, signatureFile, publicKeyFile) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const executeVerify = openssl => { const executeVerify = openssl => {
//openssl dgst -sha256 -verify $pubkeyfile -signature signature.sig file //openssl dgst -sha256 -verify $pubkeyfile -signature signature.sig file
const command = '"' + openssl + '" dgst -sha256 -verify "' + publicKeyFile + '" -signature "' + signatureFile + '"'; execFile(openssl, ['dgst', '-sha256', '-verify', publicKeyFile, '-signature', signatureFile], res => {
exec(command, res => {
if (res.code !== 0) { if (res.code !== 0) {
reject(res); reject(res);
} else { } else {
@@ -571,14 +571,15 @@ module.exports.verifySignature = (file, signatureFile, publicKeyFile) => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
const openssl = path.join(item.value(), 'bin', 'openssl.exe'); executeVerify(path.join(item.value(), 'bin', 'openssl.exe'));
executeVerify(openssl);
} }
}); });
} else { } else {
reject('Failed to locate \'openssl.exe\''); reject('Failed to locate \'openssl.exe\'');
} }
}); });
} else if (os.platform() === 'linux') {
executeVerify('openssl');
} else { } else {
reject('Platform not supported: ' + os.platform()) reject('Platform not supported: ' + os.platform())
} }
@@ -587,13 +588,32 @@ module.exports.verifySignature = (file, signatureFile, publicKeyFile) => {
module.exports.verifyHash = (file, hash) => { module.exports.verifyHash = (file, hash) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (os.platform() === 'darwin') { const platform = os.platform();
reject('Not implemented'); let command;
} else if (os.platform() === 'linux') { let args;
reject('Not implemented'); if (platform === 'darwin') {
command = 'shasum';
args = ['-b', '-a', '256', file];
} else if (platform === 'linux') {
command = 'sha256sum';
args = ['-b', file, '-z'];
} }
else { else {
reject('Platform not supported: ' + os.platform()) reject('Platform not supported: ' + os.platform())
} }
if (command) {
execFile(command, args, (err, stdout) => {
if (err) {
reject(err);
} else {
const hash2 = stdout.split(' ')[0].trim().toLowerCase();
if (hash2 === hash.toLowerCase()) {
resolve();
} else {
reject('Checksum failed for file');
}
}
});
}
}); });
}; };

View File

@@ -15,7 +15,7 @@
--heading_other_text_color: var(--heading_text_color); --heading_other_text_color: var(--heading_text_color);
--text_color_transition: color 0.3s; --text_color_transition: color 0.3s;
--default_font_size: 4vmin --default_font_size: 4.8vmin
} }
* { * {