1
0
mirror of https://github.com/keeweb/keeweb.git synced 2024-06-25 07:37:46 +02:00
keeweb/desktop/main.js

109 lines
4.3 KiB
JavaScript
Raw Normal View History

2015-11-14 08:56:45 +01:00
// KeeWeb launcher script
// This script is distributed with the app and is its entry point
// 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
2019-08-18 08:12:11 +02:00
// (C) Antelle 2019, MIT license https://github.com/keeweb/keeweb
2015-11-14 08:56:45 +01:00
2020-03-29 10:59:40 +02:00
global.perfTimestamps = [{ name: 'pre-init', ts: process.hrtime() }];
2017-01-31 07:50:28 +01:00
const app = require('electron').app;
const path = require('path');
const fs = require('original-fs');
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({ name: 'loading main requires', ts: process.hrtime() });
2017-01-31 07:50:28 +01:00
const userDataDir = app.getPath('userData');
2017-12-02 20:38:13 +01:00
const userDataAppArchivePath = path.join(userDataDir, 'app.asar');
let entryPointDir = __dirname;
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({ name: 'getting data dir', ts: process.hrtime() });
try {
const appFilePath = entryPointDir.endsWith('app.asar') ? entryPointDir : __filename;
let userPackageStat;
try {
userPackageStat = fs.statSync(userDataAppArchivePath);
} catch (e) {}
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({ name: 'checking for new version', ts: process.hrtime() });
if (userPackageStat) {
const packageStat = fs.statSync(appFilePath);
2019-08-18 08:05:38 +02:00
const userPackageStatTime = Math.max(
userPackageStat.mtime.getTime(),
userPackageStat.ctime.getTime()
);
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({ name: 'getting asar file time', ts: process.hrtime() });
const packageStatTime = Math.max(packageStat.mtime.getTime(), packageStat.ctime.getTime());
if (userPackageStatTime > packageStatTime) {
let versionLocal = require('./package.json').version;
2019-08-18 08:05:38 +02:00
let versionUserData = require(path.join(userDataAppArchivePath, 'package.json'))
.version;
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({ name: 'getting package version', ts: process.hrtime() });
versionLocal = versionLocal.split('.');
versionUserData = versionUserData.split('.');
for (let i = 0; i < versionLocal.length; i++) {
if (+versionUserData[i] > +versionLocal[i]) {
entryPointDir = userDataAppArchivePath;
try {
validateSignature(userDataDir);
2020-03-29 10:59:40 +02:00
global.perfTimestamps.push({
name: 'validating signature',
ts: process.hrtime()
});
} catch (e) {
exitWithError('Error validating signatures: ' + e);
}
break;
}
if (+versionUserData[i] < +versionLocal[i]) {
break;
}
}
}
}
} catch (e) {
console.error('Error reading user file version', e); // eslint-disable-line no-console
}
const entryPointFile = path.join(entryPointDir, 'app.js');
require(entryPointFile);
function validateSignature(appPath) {
const signatures = JSON.parse(fs.readFileSync(path.join(appPath, 'signatures.json')));
2017-06-11 19:06:36 +02:00
const selfSignature = signatures.kwResSelf;
2017-12-02 20:38:13 +01:00
if (!selfSignature || !signatures['app.asar']) {
2017-06-13 22:43:22 +02:00
exitWithError('Invalid signature file');
}
2017-06-11 19:06:36 +02:00
delete signatures.kwResSelf;
const data = JSON.stringify(signatures);
validateDataSignature(Buffer.from(data), selfSignature, 'self');
2020-06-01 16:53:51 +02:00
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 verify = crypto.createVerify('RSA-SHA256');
let publicKey = '@@PUBLIC_KEY_CONTENT';
if (publicKey.startsWith('@@')) {
2019-08-16 23:05:39 +02:00
publicKey = fs.readFileSync('app/resources/public-key.pem', { encoding: 'utf8' }).trim();
}
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);
}