validate desktop updates before running

pull/438/merge
antelle 2017-06-05 12:00:30 +02:00
parent 41656b76b6
commit 69257b82ad
2 changed files with 45 additions and 1 deletions

View File

@ -290,6 +290,11 @@ module.exports = function(grunt) {
options: { replacements: [{ pattern: ' manifest="manifest.appcache"', replacement: '' }] },
files: { 'tmp/desktop/app/index.html': 'dist/index.html' }
},
'desktop-public-key': {
options: { replacements: [{ pattern: '\'PUBLIC_KEY_CONTENT\'', replacement:
'`' + fs.readFileSync('keys/public-key.pem', {encoding: 'utf8'}).trim() + '`' }] },
files: { 'tmp/desktop/app/main.js': 'desktop/main.js' }
},
'cordova-html': {
options: { replacements: [{ pattern: '<script', replacement: '<script src="cordova.js"></script><script' }] },
files: { 'tmp/cordova/app/index.html': 'dist/index.html' }
@ -678,6 +683,7 @@ module.exports = function(grunt) {
grunt.registerTask('build-desktop-app-content', [
'copy:desktop-app-content',
'string-replace:desktop-public-key',
'string-replace:desktop-html'
]);

View File

@ -4,7 +4,7 @@
// It checks whether the app is available in userData folder and if its version is higher than local, launches it
// This script is the only part which will be updated only with the app itself, auto-update will not change it
// (C) Antelle 2015, MIT license https://github.com/keeweb/keeweb
// (C) Antelle 2017, MIT license https://github.com/keeweb/keeweb
const app = require('electron').app;
const path = require('path');
@ -23,6 +23,11 @@ if (fs.existsSync(appPathUserData)) {
for (let i = 0; i < versionLocal.length; i++) {
if (+versionUserData[i] > +versionLocal[i]) {
appPath = appPathUserData;
try {
validateSignature(path);
} catch (e) {
exitWithError('Error validating signatures: ' + e);
}
break;
}
if (+versionUserData[i] < +versionLocal[i]) {
@ -34,4 +39,37 @@ if (fs.existsSync(appPathUserData)) {
}
}
function validateSignature(appPath) {
const signatures = JSON.parse(fs.readFileSync(path.join(appPath, 'signatures.json')));
const selfSignature = signatures.self;
if (!selfSignature) {
exitWithError('No self signature');
}
delete signatures.self;
const data = JSON.stringify(signatures);
validateDataSignature(Buffer.from(data), selfSignature, 'self');
Object.keys(signatures).forEach(signedFilePath => {
const resourcePath = path.join(appPath, signedFilePath);
const fileData = fs.readFileSync(resourcePath);
validateDataSignature(fileData, signatures[signedFilePath], signedFilePath);
});
}
function validateDataSignature(data, signature, name) {
const crypto = require('crypto');
const publicKey = 'PUBLIC_KEY_CONTENT';
const verify = crypto.createVerify('RSA-SHA256');
verify.write(data);
verify.end();
signature = Buffer.from(signature, 'base64');
if (!verify.verify(publicKey, signature)) {
exitWithError('Resource corrupted: ' + name);
}
}
function exitWithError(err) {
console.error(err); // eslint-disable-line no-console
process.exit(1);
}
require(appPath);