mirror of https://github.com/keeweb/keeweb
webpack 4
parent
91a15c4b5e
commit
85f78257ed
151
Gruntfile.js
151
Gruntfile.js
|
@ -1,153 +1,26 @@
|
|||
/* eslint-env node */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const sass = require('node-sass');
|
||||
|
||||
const StringReplacePlugin = require('string-replace-webpack-plugin');
|
||||
const StatsPlugin = require('stats-webpack-plugin');
|
||||
const webpackConfig = require('./webpack.config');
|
||||
const postCssReplaceFont = require('./build/util/postcss-replace-font');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
require('time-grunt')(grunt);
|
||||
require('load-grunt-tasks')(grunt);
|
||||
grunt.loadTasks('grunt/tasks');
|
||||
|
||||
const webpack = require('webpack');
|
||||
const pkg = require('./package.json');
|
||||
const dt = new Date().toISOString().replace(/T.*/, '');
|
||||
grunt.loadTasks('build/tasks');
|
||||
|
||||
const date = new Date();
|
||||
const dt = date.toISOString().replace(/T.*/, '');
|
||||
const year = date.getFullYear();
|
||||
const minElectronVersionForUpdate = '1.7.0';
|
||||
const zipCommentPlaceholderPart = 'zip_comment_placeholder_that_will_be_replaced_with_hash';
|
||||
const zipCommentPlaceholder = zipCommentPlaceholderPart + '.'.repeat(512 - zipCommentPlaceholderPart.length);
|
||||
const electronVersion = pkg.devDependencies['electron'].replace(/^\D/, '');
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
function replaceFont(css) {
|
||||
css.walkAtRules('font-face', rule => {
|
||||
const fontFamily = rule.nodes.filter(n => n.prop === 'font-family')[0];
|
||||
if (!fontFamily) {
|
||||
throw 'Bad font rule: ' + rule.toString();
|
||||
}
|
||||
const value = fontFamily.value.replace(/["']/g, '');
|
||||
const fontFiles = {
|
||||
FontAwesome: 'fontawesome-webfont.woff'
|
||||
};
|
||||
const fontFile = fontFiles[value];
|
||||
if (!fontFile) {
|
||||
throw 'Unsupported font ' + value + ': ' + rule.toString();
|
||||
}
|
||||
const data = fs.readFileSync('tmp/fonts/' + fontFile, 'base64');
|
||||
const src = 'url(data:application/font-woff;charset=utf-8;base64,{data}) format(\'woff\')'
|
||||
.replace('{data}', data);
|
||||
rule.nodes = rule.nodes.filter(n => n.prop !== 'src');
|
||||
rule.append({ prop: 'src', value: src });
|
||||
});
|
||||
}
|
||||
|
||||
const webpackConfig = {
|
||||
entry: {
|
||||
app: 'app',
|
||||
vendor: ['jquery', 'underscore', 'backbone', 'kdbxweb', 'baron', 'pikaday', 'file-saver', 'jsqrcode',
|
||||
'argon2-wasm', 'argon2']
|
||||
},
|
||||
output: {
|
||||
path: path.resolve('.', 'tmp/js'),
|
||||
filename: 'app.js'
|
||||
},
|
||||
stats: {
|
||||
colors: false,
|
||||
modules: true,
|
||||
reasons: true
|
||||
},
|
||||
progress: false,
|
||||
failOnError: true,
|
||||
resolve: {
|
||||
modules: [path.join(__dirname, 'app/scripts'), path.join(__dirname, 'node_modules')],
|
||||
alias: {
|
||||
backbone: 'backbone/backbone-min.js',
|
||||
underscore: 'underscore/underscore-min.js',
|
||||
_: 'underscore/underscore-min.js',
|
||||
jquery: 'jquery/dist/jquery.min.js',
|
||||
kdbxweb: 'kdbxweb/dist/kdbxweb.js',
|
||||
baron: 'baron/baron.min.js',
|
||||
pikaday: 'pikaday/pikaday.js',
|
||||
filesaver: 'FileSaver.js/FileSaver.min.js',
|
||||
qrcode: 'jsqrcode/dist/qrcode.min.js',
|
||||
argon2: 'argon2-browser/dist/argon2.min.js',
|
||||
hbs: 'handlebars/runtime.js',
|
||||
'argon2-wasm': 'argon2-browser/dist/argon2.wasm',
|
||||
templates: path.join(__dirname, 'app/templates')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.hbs$/, loader: StringReplacePlugin.replace('handlebars-loader', { replacements: [{
|
||||
pattern: /\r?\n\s*/g,
|
||||
replacement: function() { return '\n'; }
|
||||
}]})},
|
||||
{ test: /runtime-info\.js$/, loader: StringReplacePlugin.replace({ replacements: [
|
||||
{
|
||||
pattern: /@@VERSION/g,
|
||||
replacement: function () { return pkg.version + (grunt.option('beta') ? '-beta' : ''); }
|
||||
},
|
||||
{ pattern: /@@BETA/g, replacement: function() { return grunt.option('beta') ? '1' : ''; } },
|
||||
{ pattern: /@@DATE/g, replacement: function() { return dt; } },
|
||||
{ pattern: /@@COMMIT/g, replacement: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); } }
|
||||
]})},
|
||||
{ test: /baron(\.min)?\.js$/, loader: 'exports-loader?baron; delete window.baron;' },
|
||||
{ test: /pikaday\.js$/, loader: 'uglify-loader' },
|
||||
{ test: /handlebars/, loader: 'strip-sourcemap-loader' },
|
||||
{ test: /\.js$/, exclude: /(node_modules)/, loader: 'babel-loader',
|
||||
query: { presets: ['es2015'], cacheDirectory: true }
|
||||
},
|
||||
{ test: /\.json$/, loader: 'json-loader' },
|
||||
{ test: /argon2\.wasm$/, loader: 'base64-loader' },
|
||||
{ test: /argon2(\.min)?\.js/, loader: 'raw-loader' },
|
||||
{ test: /\.scss$/, loader: 'raw-loader' }
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity, filename: 'vendor.js' }),
|
||||
new webpack.BannerPlugin('keeweb v' + pkg.version + ', (c) ' + year + ' ' + pkg.author.name +
|
||||
', opensource.org/licenses/' + pkg.license),
|
||||
new webpack.ProvidePlugin({ _: 'underscore', $: 'jquery' }),
|
||||
new webpack.IgnorePlugin(/^(moment)$/),
|
||||
new StringReplacePlugin(),
|
||||
new StatsPlugin('stats.json', { chunkModules: true })
|
||||
],
|
||||
node: {
|
||||
console: false,
|
||||
process: false,
|
||||
crypto: false,
|
||||
Buffer: false,
|
||||
__filename: false,
|
||||
__dirname: false,
|
||||
fs: false,
|
||||
setImmediate: false,
|
||||
path: false
|
||||
},
|
||||
externals: {
|
||||
xmldom: 'null',
|
||||
crypto: 'null',
|
||||
fs: 'null',
|
||||
path: 'null'
|
||||
}
|
||||
};
|
||||
|
||||
const webpackDevConfig = Object.assign({}, webpackConfig, {
|
||||
resolve: Object.assign({}, webpackConfig.resolve, {
|
||||
alias: Object.assign({}, webpackConfig.resolve.alias, {
|
||||
backbone: 'backbone/backbone.js',
|
||||
underscore: 'underscore/underscore.js',
|
||||
_: 'underscore/underscore.js',
|
||||
jquery: 'jquery/dist/jquery.js',
|
||||
baron: 'baron/baron.js',
|
||||
filesaver: 'FileSaver.js/FileSaver.js',
|
||||
qrcode: 'jsqrcode/dist/qrcode.js',
|
||||
argon2: 'argon2-browser/dist/argon2.js'
|
||||
})
|
||||
})
|
||||
});
|
||||
const electronVersion = pkg.dependencies.electron.replace(/^\D/, '');
|
||||
|
||||
grunt.initConfig({
|
||||
gitinfo: {
|
||||
|
@ -285,7 +158,7 @@ module.exports = function(grunt) {
|
|||
postcss: {
|
||||
options: {
|
||||
processors: [
|
||||
replaceFont,
|
||||
postCssReplaceFont,
|
||||
require('cssnano')({discardComments: {removeAll: true}})
|
||||
]
|
||||
},
|
||||
|
@ -340,11 +213,11 @@ module.exports = function(grunt) {
|
|||
}
|
||||
},
|
||||
webpack: {
|
||||
js: webpackConfig
|
||||
js: webpackConfig.config(grunt, date)
|
||||
},
|
||||
'webpack-dev-server': {
|
||||
options: {
|
||||
webpack: webpackDevConfig,
|
||||
webpack: webpackConfig.devServerConfig(grunt, date),
|
||||
publicPath: '/tmp/js',
|
||||
progress: false
|
||||
},
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<link rel="stylesheet" href="css/main.css?__inline=true" />
|
||||
<script src="js/vendor.js?__inline=true"></script>
|
||||
<script src="js/app.js?__inline=true"></script>
|
||||
<script src="js/runtime.js?__inline=true"></script>
|
||||
</head>
|
||||
<body class="th-d">
|
||||
<noscript>
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
const fs = require('fs');
|
||||
const signer = require('pkcs15-smartcard-sign');
|
||||
const keytar = require('keytar');
|
||||
|
||||
const verifyKey = fs.readFileSync('app/resources/public-key.pem');
|
||||
const key = '02';
|
||||
|
||||
function getPin() {
|
||||
if (getPin.pin) {
|
||||
return Promise.resolve(getPin.pin);
|
||||
}
|
||||
return keytar.getPassword('keeweb.pin', 'keeweb').then(pass => {
|
||||
if (pass) {
|
||||
getPin.pin = pass;
|
||||
return pass;
|
||||
} else {
|
||||
throw 'Cannot find PIN';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function sign(grunt, data) {
|
||||
return getPin()
|
||||
.then(pin => signer.sign({ data, verifyKey, pin, key }))
|
||||
.catch(err => {
|
||||
if (grunt) {
|
||||
grunt.warn(`Error signing data: ${err}`);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.getPin = getPin;
|
|
@ -1,31 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('codesign', 'Launches Apple codesign', function () {
|
||||
const done = this.async();
|
||||
const opt = this.options();
|
||||
const config = require('../../keys/codesign.json');
|
||||
for (const file of this.files) {
|
||||
const args = [
|
||||
'-s',
|
||||
config.identities[opt.identity]
|
||||
];
|
||||
if (opt.deep) {
|
||||
args.push('--deep');
|
||||
}
|
||||
args.push(file.src);
|
||||
grunt.log.writeln('codesign:', args.join(' '));
|
||||
grunt.util.spawn({
|
||||
cmd: 'codesign',
|
||||
args: args,
|
||||
opts: {stdio: 'inherit'}
|
||||
}, (error, result, code) => {
|
||||
if (error) {
|
||||
return grunt.warn('codesign: ' + error);
|
||||
}
|
||||
if (code) {
|
||||
return grunt.warn('codesign exit code ' + code);
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('nsis', 'Launches NSIS installer', function () {
|
||||
const done = this.async();
|
||||
const opt = this.options();
|
||||
const args = [];
|
||||
const win = process.platform === 'win32';
|
||||
const prefix = win ? '/' : '-';
|
||||
Object.keys(opt.vars).forEach(key => {
|
||||
let value = opt.vars[key];
|
||||
if (typeof value === 'function') {
|
||||
value = value();
|
||||
}
|
||||
if (value) {
|
||||
args.push(`${prefix}D${key}=${value}`);
|
||||
}
|
||||
});
|
||||
args.push(`${prefix}Darch=${opt.arch}`);
|
||||
args.push(`${prefix}Doutput=${opt.output}`);
|
||||
args.push(`${prefix}NOCD`);
|
||||
args.push(`${prefix}V2`);
|
||||
args.push(opt.installScript);
|
||||
const executable = win ? 'C:\\Program Files (x86)\\NSIS\\makensis.exe' : 'makensis';
|
||||
grunt.log.writeln('Running NSIS:', args.join(' '));
|
||||
grunt.util.spawn({
|
||||
cmd: executable,
|
||||
args: args,
|
||||
opts: {stdio: 'inherit'}
|
||||
}, (error, result, code) => {
|
||||
if (error) {
|
||||
return grunt.warn('NSIS error: ' + error);
|
||||
}
|
||||
if (code) {
|
||||
return grunt.warn('NSIS exit code ' + code);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('sign-archive', 'Signs archive with a private key', function () {
|
||||
const done = this.async();
|
||||
const fs = require('fs');
|
||||
const sign = require('../lib/sign');
|
||||
const file = fs.readFileSync(this.options().file);
|
||||
const ix = file.toString('binary').lastIndexOf(this.options().signature);
|
||||
if (ix < 0) {
|
||||
grunt.warn('Signature placeholder not found');
|
||||
return;
|
||||
}
|
||||
const data = file.slice(0, ix);
|
||||
sign(grunt, data).then(signature => {
|
||||
signature = Buffer.from(signature.toString('hex'), 'binary');
|
||||
if (signature.byteLength !== Buffer.from(this.options().signature, 'binary').byteLength) {
|
||||
grunt.warn('Bad signature length');
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < signature.byteLength; i++) {
|
||||
file[ix + i] = signature[i];
|
||||
}
|
||||
fs.writeFileSync(this.options().file, file);
|
||||
done();
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,42 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('sign-desktop-files', 'Signs desktop files', async function () {
|
||||
const done = this.async();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sign = require('../lib/sign');
|
||||
const appPath = this.options().path;
|
||||
|
||||
const signatures = {};
|
||||
const signedFiles = [];
|
||||
await walk(appPath);
|
||||
|
||||
const data = JSON.stringify(signatures);
|
||||
signatures.kwResSelf = await getSignature(Buffer.from(data));
|
||||
grunt.file.write(path.join(appPath, 'signatures.json'), JSON.stringify(signatures));
|
||||
|
||||
grunt.log.writeln(`\nSigned ${signedFiles.length} files: ${signedFiles.join(', ')}`);
|
||||
done();
|
||||
|
||||
async function walk(dir) {
|
||||
const list = fs.readdirSync(dir);
|
||||
for (const fileName of list) {
|
||||
const file = dir + '/' + fileName;
|
||||
const stat = fs.statSync(file);
|
||||
if (stat && stat.isDirectory()) {
|
||||
await walk(file);
|
||||
} else {
|
||||
const relFile = file.substr(appPath.length + 1);
|
||||
const fileData = grunt.file.read(file, { encoding: null });
|
||||
signatures[relFile] = await getSignature(fileData);
|
||||
signedFiles.push(relFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getSignature(data) {
|
||||
const signature = await sign(grunt, data);
|
||||
grunt.log.write('.');
|
||||
return signature.toString('base64');
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('sign-dist', 'Creates files signatures', async function () {
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const sign = require('../lib/sign');
|
||||
|
||||
const done = this.async();
|
||||
const opt = this.options();
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const file of this.files) {
|
||||
grunt.log.writeln(`Calculating sha256 for ${file.src.length} files...`);
|
||||
for (const src of file.src) {
|
||||
const basename = path.basename(src);
|
||||
const file = grunt.file.read(src, { encoding: null });
|
||||
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(file);
|
||||
const digest = hash.digest('hex');
|
||||
|
||||
const rawSignature = await sign(grunt, file);
|
||||
const signature = rawSignature.toString('hex');
|
||||
|
||||
results.push({ basename, digest, signature });
|
||||
|
||||
grunt.log.writeln(basename);
|
||||
}
|
||||
|
||||
grunt.file.write(file.dest, results.map(line => `${line.digest} *${line.basename}`).join('\n'));
|
||||
grunt.file.write(opt.sign, results.map(line => `${line.signature} *${line.basename}`).join('\n'));
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
};
|
|
@ -1,101 +0,0 @@
|
|||
/**
|
||||
* This will require the latest (unreleased) version of `osslsigncode` with pkcs11 patch
|
||||
* Build it like this:
|
||||
*
|
||||
* curl -L http://sourceforge.net/projects/osslsigncode/files/osslsigncode/osslsigncode-1.7.1.tar.gz/download -o osslsigncode.tar.gz
|
||||
* tar -zxvf osslsigncode.tar.gz
|
||||
* git clone https://git.code.sf.net/p/osslsigncode/osslsigncode osslsigncode-master
|
||||
* cp osslsigncode-master/osslsigncode.c osslsigncode-1.7.1/osslsigncode.c
|
||||
* rm osslsigncode.tar.gz
|
||||
* rm -rf osslsigncode-master
|
||||
* cd osslsigncode-1.7.1/
|
||||
* export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
|
||||
* ./configure
|
||||
* make
|
||||
* sudo cp osslsigncode /usr/local/bin/osslsigncode
|
||||
*
|
||||
* Install this:
|
||||
* brew install opensc
|
||||
* brew install engine_pkcs11
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', async function () {
|
||||
const opt = this.options();
|
||||
const done = this.async();
|
||||
if (opt.pvk) {
|
||||
const keytar = require('keytar');
|
||||
keytar.getPassword(opt.keytarPasswordService, opt.keytarPasswordAccount).then(password => {
|
||||
if (!password) {
|
||||
return grunt.warn('Code sign password not found');
|
||||
}
|
||||
const promises = Object.keys(opt.files).map(file => signFile(file, opt.files[file], opt, password));
|
||||
Promise.all(promises).then(done);
|
||||
}).catch(e => {
|
||||
grunt.warn('Code sign error: ' + e);
|
||||
});
|
||||
} else {
|
||||
const sign = require('../lib/sign');
|
||||
const pin = await sign.getPin();
|
||||
for (const file of Object.keys(opt.files)) {
|
||||
await signFile(file, opt.files[file], opt, pin);
|
||||
}
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
function signFile(file, name, opt, password) {
|
||||
const signedFile = file + '.sign';
|
||||
return new Promise((resolve, reject) => {
|
||||
const pkcsArgs = opt.pvk ? [] : [
|
||||
'-pkcs11engine', '/usr/local/lib/engines/engine_pkcs11.so',
|
||||
'-pkcs11module', '/usr/local/lib/opensc-pkcs11.so'
|
||||
];
|
||||
const args = [
|
||||
'-spc', opt.spc,
|
||||
'-key', opt.pvk ? require('path').resolve(opt.pvk) : opt.key,
|
||||
'-pass', password,
|
||||
'-h', opt.algo,
|
||||
'-n', name,
|
||||
'-i', opt.url,
|
||||
'-t', 'http://timestamp.verisign.com/scripts/timstamp.dll',
|
||||
...pkcsArgs,
|
||||
'-in', file,
|
||||
'-out', signedFile
|
||||
];
|
||||
const spawned = grunt.util.spawn({
|
||||
cmd: 'osslsigncode',
|
||||
args: args
|
||||
}, (error, result, code) => {
|
||||
if (error || code) {
|
||||
spawned.kill();
|
||||
grunt.warn(`Cannot sign file ${file}, signtool error ${code}: ${error}`);
|
||||
return reject();
|
||||
}
|
||||
grunt.util.spawn({
|
||||
cmd: 'osslsigncode',
|
||||
args: ['verify', signedFile]
|
||||
}, (ex, result, code) => {
|
||||
if (code) {
|
||||
grunt.warn(`Verify error ${file}: \n${result.stdout.toString()}`);
|
||||
return;
|
||||
}
|
||||
if (fs.existsSync(file)) {
|
||||
fs.renameSync(signedFile, file);
|
||||
}
|
||||
grunt.log.writeln(`Signed ${file}: ${name}`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
// spawned.stdout.pipe(process.stdout);
|
||||
spawned.stderr.pipe(process.stderr);
|
||||
// spawned.stdin.setEncoding('utf-8');
|
||||
// spawned.stdin.write(password);
|
||||
// spawned.stdin.write('\n');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,32 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('sign-html', 'Signs html page with a private key', function () {
|
||||
if (this.options().skip) {
|
||||
grunt.log.writeln('Skipped app html signing');
|
||||
return;
|
||||
}
|
||||
const done = this.async();
|
||||
const fs = require('fs');
|
||||
const sign = require('../lib/sign');
|
||||
const data = fs.readFileSync(this.options().file);
|
||||
let fileStr = data.toString();
|
||||
const marker = '<meta name="kw-signature" content="';
|
||||
const ix = fileStr.indexOf(marker);
|
||||
if (ix < 0) {
|
||||
grunt.warn('Signature placeholder not found');
|
||||
return;
|
||||
}
|
||||
sign(null, data).then(signature => {
|
||||
signature = signature.toString('base64');
|
||||
fileStr = fileStr.replace(marker, marker + signature);
|
||||
fs.writeFileSync(this.options().file, fileStr, 'utf8');
|
||||
done();
|
||||
}).catch(e => {
|
||||
if (e === 'Cannot find PIN') {
|
||||
grunt.warn('Error signing app html. To build without sign, please launch grunt with --skip-sign.');
|
||||
} else {
|
||||
grunt.warn('Sign error: ' + e);
|
||||
}
|
||||
done(false);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,54 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask('validate-desktop-update', 'Validates desktop update package', function () {
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const done = this.async();
|
||||
const StreamZip = require(path.resolve(__dirname, '../../desktop/node_modules/node-stream-zip'));
|
||||
const zip = new StreamZip({ file: this.options().file, storeEntries: true });
|
||||
const expFiles = this.options().expected;
|
||||
const expFilesCount = this.options().expectedCount;
|
||||
const publicKey = fs.readFileSync(this.options().publicKey, 'binary');
|
||||
const zipFileData = fs.readFileSync(this.options().file);
|
||||
zip.on('error', err => {
|
||||
grunt.warn(err);
|
||||
});
|
||||
zip.on('ready', () => {
|
||||
let valid = true;
|
||||
if (!zip.comment) {
|
||||
grunt.warn('No comment in ZIP');
|
||||
return;
|
||||
}
|
||||
if (zip.comment.length !== 512) {
|
||||
grunt.warn('Bad comment length in ZIP');
|
||||
return;
|
||||
}
|
||||
const verify = crypto.createVerify('RSA-SHA256');
|
||||
verify.write(zipFileData.slice(0, zip.centralDirectory.headerOffset + 22));
|
||||
verify.end();
|
||||
const signature = Buffer.from(zip.comment, 'hex');
|
||||
if (!verify.verify(publicKey, signature)) {
|
||||
grunt.warn('Invalid ZIP signature');
|
||||
return;
|
||||
}
|
||||
if (zip.entriesCount !== expFilesCount) {
|
||||
grunt.warn(`ZIP contains ${zip.entriesCount} entries, expected ${expFilesCount}`);
|
||||
valid = false;
|
||||
}
|
||||
expFiles.forEach(entry => {
|
||||
try {
|
||||
if (!zip.entryDataSync(entry)) {
|
||||
grunt.warn('Corrupted entry in desktop update archive: ' + entry);
|
||||
valid = false;
|
||||
}
|
||||
} catch (e) {
|
||||
grunt.warn('Entry not found in desktop update archive: ' + entry);
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
if (valid) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
|
@ -9,17 +9,16 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/keeweb/keeweb"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.2.2",
|
||||
"@babel/preset-env": "^7.2.3",
|
||||
"argon2-browser": "1.5.2",
|
||||
"babel-core": "6.26.3",
|
||||
"babel-loader": "7.0.0",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-loader": "8.0.5",
|
||||
"backbone": "1.3.3",
|
||||
"baron": "2.2.2",
|
||||
"base64-loader": "1.0.0",
|
||||
"bourbon": "4.2.7",
|
||||
"cssnano": "3.10.0",
|
||||
"cssnano": "4.1.8",
|
||||
"electron": "^1.7.9",
|
||||
"eslint": "^5.12.0",
|
||||
"eslint-config-standard": "12.0.0",
|
||||
|
@ -27,10 +26,9 @@
|
|||
"eslint-plugin-node": "^8.0.1",
|
||||
"eslint-plugin-promise": "4.0.1",
|
||||
"eslint-plugin-standard": "4.0.0",
|
||||
"exports-loader": "0.6.4",
|
||||
"exports-loader": "0.7.0",
|
||||
"file-saver": "1.3.3",
|
||||
"font-awesome": "4.7.0",
|
||||
"get-folder-size": "1.0.0",
|
||||
"grunt": "1.0.3",
|
||||
"grunt-concurrent": "2.3.1",
|
||||
"grunt-contrib-clean": "2.0.0",
|
||||
|
@ -50,7 +48,7 @@
|
|||
"grunt-webpack": "3.1.3",
|
||||
"handlebars": "4.0.12",
|
||||
"handlebars-loader": "1.7.1",
|
||||
"html-minifier": "3.5.2",
|
||||
"html-minifier": "3.5.21",
|
||||
"jquery": "3.3.1",
|
||||
"json-loader": "^0.5.4",
|
||||
"jsqrcode": "github:antelle/jsqrcode#0.1.3",
|
||||
|
@ -61,15 +59,17 @@
|
|||
"normalize.css": "5.0.0",
|
||||
"pikaday": "1.5.1",
|
||||
"pkcs15-smartcard-sign": "^1.0.0",
|
||||
"raw-loader": "0.5.1",
|
||||
"raw-loader": "1.0.0",
|
||||
"stats-webpack-plugin": "0.7.0",
|
||||
"string-replace-webpack-plugin": "0.1.3",
|
||||
"strip-sourcemap-loader": "0.0.1",
|
||||
"sumchecker": "^2.0.2",
|
||||
"time-grunt": "2.0.0",
|
||||
"uglify-loader": "3.0.0",
|
||||
"webpack": "^2.6.1",
|
||||
"webpack-dev-server": "^2.4.5"
|
||||
"uglifyjs-webpack-plugin": "^2.1.1",
|
||||
"webpack": "^4.28.3",
|
||||
"webpack-bundle-analyzer": "^3.0.3",
|
||||
"webpack-dev-server": "^3.1.14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"grunt-appdmg": "1.0.0",
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
const path = require('path');
|
||||
|
||||
const webpack = require('webpack');
|
||||
|
||||
const StringReplacePlugin = require('string-replace-webpack-plugin');
|
||||
const StatsPlugin = require('stats-webpack-plugin');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const pkg = require('./package.json');
|
||||
|
||||
function config(grunt, date) {
|
||||
const dt = date.toISOString().replace(/T.*/, '');
|
||||
const year = date.getFullYear();
|
||||
return {
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: 'app',
|
||||
vendor: ['jquery', 'underscore', 'backbone', 'kdbxweb', 'baron',
|
||||
'pikaday', 'file-saver', 'jsqrcode', 'argon2-wasm', 'argon2']
|
||||
},
|
||||
output: {
|
||||
path: path.resolve('.', 'tmp/js'),
|
||||
filename: '[name].js'
|
||||
},
|
||||
target: 'web',
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
stats: {
|
||||
colors: false,
|
||||
modules: true,
|
||||
reasons: true
|
||||
},
|
||||
progress: false,
|
||||
failOnError: true,
|
||||
resolve: {
|
||||
modules: [path.join(__dirname, 'app/scripts'), path.join(__dirname, 'node_modules')],
|
||||
alias: {
|
||||
backbone: 'backbone/backbone-min.js',
|
||||
underscore: 'underscore/underscore-min.js',
|
||||
_: 'underscore/underscore-min.js',
|
||||
jquery: 'jquery/dist/jquery.min.js',
|
||||
kdbxweb: 'kdbxweb/dist/kdbxweb.js',
|
||||
baron: 'baron/baron.min.js',
|
||||
pikaday: 'pikaday/pikaday.js',
|
||||
filesaver: 'FileSaver.js/FileSaver.min.js',
|
||||
qrcode: 'jsqrcode/dist/qrcode.min.js',
|
||||
argon2: 'argon2-browser/dist/argon2.min.js',
|
||||
hbs: 'handlebars/runtime.js',
|
||||
'argon2-wasm': 'argon2-browser/dist/argon2.wasm',
|
||||
templates: path.join(__dirname, 'app/templates')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.hbs$/, loader: StringReplacePlugin.replace('handlebars-loader', {
|
||||
replacements: [{ pattern: /\r?\n\s*/g, replacement: () => '\n' }]
|
||||
})
|
||||
},
|
||||
{
|
||||
test: /runtime-info\.js$/, loader: StringReplacePlugin.replace({
|
||||
replacements: [
|
||||
{ pattern: /@@VERSION/g, replacement: () => pkg.version + (grunt.option('beta') ? '-beta' : '') },
|
||||
{ pattern: /@@BETA/g, replacement: () => grunt.option('beta') ? '1' : '' },
|
||||
{ pattern: /@@DATE/g, replacement: () => dt },
|
||||
{ pattern: /@@COMMIT/g, replacement: () => grunt.config.get('gitinfo.local.branch.current.shortSHA') }
|
||||
]
|
||||
})
|
||||
},
|
||||
{test: /baron(\.min)?\.js$/, loader: 'exports-loader?baron; delete window.baron;'},
|
||||
{test: /pikaday\.js$/, loader: 'uglify-loader'},
|
||||
{test: /handlebars/, loader: 'strip-sourcemap-loader'},
|
||||
{
|
||||
test: /\.js$/, exclude: /(node_modules)/, loader: 'babel-loader',
|
||||
query: {presets: ['@babel/preset-env'], cacheDirectory: true}
|
||||
},
|
||||
{test: /argon2\.wasm/, type: 'javascript/auto', loader: 'base64-loader'},
|
||||
{test: /argon2(\.min)?\.js/, loader: 'raw-loader'},
|
||||
{test: /\.scss$/, loader: 'raw-loader'}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendor',
|
||||
chunks: 'all'
|
||||
}
|
||||
}
|
||||
},
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
cache: true,
|
||||
parallel: true
|
||||
}),
|
||||
new BundleAnalyzerPlugin({
|
||||
openAnalyzer: false,
|
||||
analyzerMode: 'static',
|
||||
reportFilename: '../stats/analyzer_report.html',
|
||||
generateStatsFile: true,
|
||||
statsFilename: '../stats/stats.json'
|
||||
})
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin('keeweb v' + pkg.version + ', (c) ' + year + ' ' + pkg.author.name +
|
||||
', opensource.org/licenses/' + pkg.license),
|
||||
new webpack.ProvidePlugin({_: 'underscore', $: 'jquery'}),
|
||||
new webpack.IgnorePlugin(/^(moment)$/),
|
||||
new StringReplacePlugin()
|
||||
// new StatsPlugin('stats.json', {chunkModules: true})
|
||||
],
|
||||
node: {
|
||||
console: false,
|
||||
process: false,
|
||||
crypto: false,
|
||||
Buffer: false,
|
||||
__filename: false,
|
||||
__dirname: false,
|
||||
fs: false,
|
||||
setImmediate: false,
|
||||
path: false
|
||||
},
|
||||
externals: {
|
||||
xmldom: 'null',
|
||||
crypto: 'null',
|
||||
fs: 'null',
|
||||
path: 'null'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function devServerConfig(grunt, date) {
|
||||
const devServerConfig = config(grunt, date);
|
||||
Object.assign(devServerConfig, {
|
||||
mode: 'development'
|
||||
});
|
||||
Object.assign(devServerConfig.resolve.alias, {
|
||||
backbone: 'backbone/backbone.js',
|
||||
underscore: 'underscore/underscore.js',
|
||||
_: 'underscore/underscore.js',
|
||||
jquery: 'jquery/dist/jquery.js',
|
||||
baron: 'baron/baron.js',
|
||||
filesaver: 'FileSaver.js/FileSaver.js',
|
||||
qrcode: 'jsqrcode/dist/qrcode.js',
|
||||
argon2: 'argon2-browser/dist/argon2.js'
|
||||
});
|
||||
return devServerConfig;
|
||||
}
|
||||
|
||||
module.exports.config = config;
|
||||
module.exports.devServerConfig = devServerConfig;
|
Loading…
Reference in New Issue