mirror of https://github.com/keeweb/keeweb.git
Merge branch 'release-1.5'
This commit is contained in:
commit
daba40e51a
|
@ -666,12 +666,12 @@ module.exports = function(grunt) {
|
|||
|
||||
grunt.registerTask('build-desktop-executables', [
|
||||
'electron',
|
||||
'codesign:app',
|
||||
'sign-exe:win32-build-x64',
|
||||
'sign-exe:win32-build-ia32',
|
||||
'copy:desktop-darwin-helper-x64',
|
||||
'copy:desktop-windows-helper-ia32',
|
||||
'copy:desktop-windows-helper-x64'
|
||||
'copy:desktop-windows-helper-x64',
|
||||
'codesign:app'
|
||||
]);
|
||||
|
||||
grunt.registerTask('build-desktop-archives', [
|
||||
|
|
|
@ -3,7 +3,8 @@ const AppSettingsModel = require('../models/app-settings-model');
|
|||
const ExportApi = {
|
||||
settings: {
|
||||
get: function(key) { return key ? AppSettingsModel.instance.get(key) : AppSettingsModel.instance.toJSON(); },
|
||||
set: function(key, value) { AppSettingsModel.instance.set(key, value); }
|
||||
set: function(key, value) { AppSettingsModel.instance.set(key, value); },
|
||||
del: function(key) { AppSettingsModel.instance.unset(key); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ const AppSettingsModel = require('../models/app-settings-model');
|
|||
const UpdateModel = require('../models/update-model');
|
||||
const Transport = require('../comp/transport');
|
||||
const Logger = require('../util/logger');
|
||||
const SemVer = require('../util/semver');
|
||||
const publicKey = require('raw-loader!../../resources/public-key.pem');
|
||||
|
||||
const logger = new Logger('updater');
|
||||
|
@ -113,7 +114,7 @@ const Updater = {
|
|||
}
|
||||
if (!startedByUser && this.getAutoUpdateType() === 'install') {
|
||||
this.update(startedByUser);
|
||||
} else if (this.compareVersions(UpdateModel.instance.get('lastVersion'), RuntimeInfo.version) > 0) {
|
||||
} else if (SemVer.compareVersions(UpdateModel.instance.get('lastVersion'), RuntimeInfo.version) > 0) {
|
||||
UpdateModel.instance.set('updateStatus', 'found');
|
||||
}
|
||||
},
|
||||
|
@ -133,7 +134,7 @@ const Updater = {
|
|||
canAutoUpdate: function() {
|
||||
const minLauncherVersion = UpdateModel.instance.get('lastCheckUpdMin');
|
||||
if (minLauncherVersion) {
|
||||
const cmp = this.compareVersions(Launcher.version, minLauncherVersion);
|
||||
const cmp = SemVer.compareVersions(Launcher.version, minLauncherVersion);
|
||||
if (cmp < 0) {
|
||||
UpdateModel.instance.set({ updateStatus: 'ready', updateManual: true });
|
||||
return false;
|
||||
|
@ -142,29 +143,13 @@ const Updater = {
|
|||
return true;
|
||||
},
|
||||
|
||||
compareVersions: function(left, right) {
|
||||
left = left.split('.');
|
||||
right = right.split('.');
|
||||
for (let num = 0; num < left.length; num++) {
|
||||
const partLeft = left[num] | 0;
|
||||
const partRight = right[num] | 0;
|
||||
if (partLeft < partRight) {
|
||||
return -1;
|
||||
}
|
||||
if (partLeft > partRight) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
update: function(startedByUser, successCallback) {
|
||||
const ver = UpdateModel.instance.get('lastVersion');
|
||||
if (!this.enabled) {
|
||||
logger.info('Updater is disabled');
|
||||
return;
|
||||
}
|
||||
if (this.compareVersions(RuntimeInfo.version, ver) >= 0) {
|
||||
if (SemVer.compareVersions(RuntimeInfo.version, ver) >= 0) {
|
||||
logger.info('You are using the latest version');
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -496,6 +496,7 @@
|
|||
"setPlDevelopStart": "Hier entlang",
|
||||
"setPlTranslate": "Oder {}",
|
||||
"setPlTranslateLink": "übersetzen Sie die App in Ihre Sprache",
|
||||
"setPlAutoUpdate": "Automatisch aktualisieren",
|
||||
"setAboutTitle": "Über",
|
||||
"setAboutBuilt": "Diese App wurde mit den folgenden Werkzeugen erstellt",
|
||||
"setAboutLic": "Lizenz",
|
||||
|
|
|
@ -43,6 +43,8 @@ const AppModel = Backbone.Model.extend({
|
|||
this.listenTo(Backbone, 'select-entry', this.selectEntry);
|
||||
|
||||
this.appLogger = new Logger('app');
|
||||
|
||||
AppModel.instance = this;
|
||||
},
|
||||
|
||||
prepare: function() {
|
||||
|
|
|
@ -8,6 +8,8 @@ const IoCache = require('../storage/io-cache');
|
|||
const AppSettingsModel = require('../models/app-settings-model');
|
||||
const BaseLocale = require('../locales/base.json');
|
||||
const SignatureVerifier = require('../util/signature-verifier');
|
||||
const SemVer = require('../util/semver');
|
||||
const RuntimeInfo = require('../comp/runtime-info');
|
||||
|
||||
const commonLogger = new Logger('plugin');
|
||||
const io = new IoCache({
|
||||
|
@ -111,6 +113,25 @@ const Plugin = Backbone.Model.extend(_.extend({}, PluginStatus, {
|
|||
(!manifest.locale || !manifest.locale.title || !/^[a-z]{2}(-[A-Z]{2})?$/.test(manifest.locale.name))) {
|
||||
return 'Bad plugin locale';
|
||||
}
|
||||
if (manifest.desktop && !RuntimeInfo.launcher) {
|
||||
return 'Desktop plugin';
|
||||
}
|
||||
if (manifest.versionMin) {
|
||||
if (!/^\d+\.\d+\.\d+$/.test(manifest.versionMin)) {
|
||||
return 'Invalid versionMin';
|
||||
}
|
||||
if (SemVer.compareVersions(manifest.versionMin, RuntimeInfo.version) > 0) {
|
||||
return `Required min app version is ${manifest.versionMin}, actual ${RuntimeInfo.version}`;
|
||||
}
|
||||
}
|
||||
if (manifest.versionMax) {
|
||||
if (!/^\d+\.\d+\.\d+$/.test(manifest.versionMax)) {
|
||||
return 'Invalid versionMin';
|
||||
}
|
||||
if (SemVer.compareVersions(manifest.versionMax, RuntimeInfo.version) < 0) {
|
||||
return `Required max app version is ${manifest.versionMax}, actual ${RuntimeInfo.version}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
validateUpdatedManifest(newManifest) {
|
||||
|
|
|
@ -168,6 +168,10 @@ const StorageDropbox = StorageBase.extend({
|
|||
return '/' + fileName + '.kdbx';
|
||||
},
|
||||
|
||||
_encodeJsonHttpHeader(json) {
|
||||
return json.replace(/[\u007f-\uffff]/g, c => '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4));
|
||||
},
|
||||
|
||||
_apiCall: function(args) {
|
||||
this._oauthAuthorize(err => {
|
||||
if (err) {
|
||||
|
@ -177,7 +181,7 @@ const StorageDropbox = StorageBase.extend({
|
|||
let headers;
|
||||
let data = args.data;
|
||||
if (args.apiArg) {
|
||||
headers = { 'Dropbox-API-Arg': JSON.stringify(args.apiArg) };
|
||||
headers = { 'Dropbox-API-Arg': this._encodeJsonHttpHeader(JSON.stringify(args.apiArg)) };
|
||||
if (args.data) {
|
||||
headers['Content-Type'] = 'application/octet-stream';
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ const FeatureDetector = {
|
|||
return this.isMac;
|
||||
},
|
||||
ensureCanRun: function() {
|
||||
if (/MSIE |Trident/.test(navigator.userAgent)) {
|
||||
throw 'IE detected';
|
||||
if (!window.crypto) {
|
||||
throw 'WebCrypto not available';
|
||||
}
|
||||
if (!localStorage.length) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
const SemVer = {
|
||||
compareVersions(left, right) {
|
||||
left = left.split('.');
|
||||
right = right.split('.');
|
||||
for (let num = 0; num < left.length; num++) {
|
||||
const partLeft = left[num] | 0;
|
||||
const partRight = right[num] | 0;
|
||||
if (partLeft < partRight) {
|
||||
return -1;
|
||||
}
|
||||
if (partLeft > partRight) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = SemVer;
|
|
@ -57,13 +57,13 @@ const SettingsFileView = Backbone.View.extend({
|
|||
let canBackup = false;
|
||||
Object.keys(Storage).forEach(name => {
|
||||
const prv = Storage[name];
|
||||
if (!canBackup && prv.backup && prv.enabled) {
|
||||
canBackup = true;
|
||||
}
|
||||
if (!prv.system && prv.enabled) {
|
||||
storageProviders.push({
|
||||
name: prv.name, icon: prv.icon, iconSvg: prv.iconSvg, own: name === fileStorage, backup: prv.backup
|
||||
});
|
||||
if (!canBackup && prv.backup) {
|
||||
canBackup = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
|
||||
|
|
|
@ -12,6 +12,7 @@ const SettingsManager = require('../../comp/settings-manager');
|
|||
const Storage = require('../../storage');
|
||||
const FeatureDetector = require('../../util/feature-detector');
|
||||
const Locale = require('../../util/locale');
|
||||
const SemVer = require('../../util/semver');
|
||||
const Links = require('../../const/links');
|
||||
const AutoType = require('../../auto-type');
|
||||
|
||||
|
@ -131,7 +132,7 @@ const SettingsGeneralView = Backbone.View.extend({
|
|||
return errMsg;
|
||||
case 'ok':
|
||||
let msg = Locale.setGenCheckedAt + ' ' + Format.dtStr(UpdateModel.instance.get('lastCheckDate')) + ': ';
|
||||
const cmp = Updater.compareVersions(RuntimeInfo.version, UpdateModel.instance.get('lastVersion'));
|
||||
const cmp = SemVer.compareVersions(RuntimeInfo.version, UpdateModel.instance.get('lastVersion'));
|
||||
if (cmp >= 0) {
|
||||
msg += Locale.setGenLatestVer;
|
||||
} else {
|
||||
|
|
|
@ -8,6 +8,8 @@ const Format = require('../../util/format');
|
|||
const SettingsManager = require('../../comp/settings-manager');
|
||||
const SignatureVerifier = require('../../util/signature-verifier');
|
||||
const FeatureDetector = require('../../util/feature-detector');
|
||||
const SemVer = require('../../util/semver');
|
||||
const RuntimeInfo = require('../../comp/runtime-info');
|
||||
const Links = require('../../const/links');
|
||||
|
||||
const SettingsPluginsView = Backbone.View.extend({
|
||||
|
@ -86,11 +88,26 @@ const SettingsPluginsView = Backbone.View.extend({
|
|||
installError: this.installErrors[pl.url],
|
||||
official: pl.manifest.publicKey === publicKey
|
||||
}))
|
||||
.filter(pl => !plugins.get(pl.manifest.name) &&
|
||||
(!pl.manifest.locale || !SettingsManager.allLocales[pl.manifest.locale.name]))
|
||||
.filter(pl => !plugins.get(pl.manifest.name) && this.canInstallPlugin(pl))
|
||||
.sort((x, y) => x.manifest.name.localeCompare(y.manifest.name));
|
||||
},
|
||||
|
||||
canInstallPlugin(plugin) {
|
||||
if (plugin.manifest.locale && SettingsManager.allLocales[plugin.manifest.locale.name]) {
|
||||
return false;
|
||||
}
|
||||
if (plugin.manifest.desktop && !RuntimeInfo.launcher) {
|
||||
return false;
|
||||
}
|
||||
if (plugin.manifest.versionMin && SemVer.compareVersions(plugin.manufest.versionMin, RuntimeInfo.version) > 0) {
|
||||
return false;
|
||||
}
|
||||
if (plugin.manifest.versionMax && SemVer.compareVersions(plugin.manufest.versionMax, RuntimeInfo.version) > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
installClick() {
|
||||
const installBtn = this.$el.find('.settings_plugins-install-btn');
|
||||
const urlTextBox = this.$el.find('#settings__plugins-install-url');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "KeeWeb",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"description": "Free cross-platform password manager compatible with KeePass",
|
||||
"main": "main.js",
|
||||
"homepage": "https://keeweb.info",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "keeweb",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"description": "Free cross-platform password manager compatible with KeePass",
|
||||
"main": "Gruntfile.js",
|
||||
"private": true,
|
||||
"homepage": "https://keeweb.info",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -44,7 +44,7 @@ RUN wget https://github.com/keeweb/keeweb-plugins/archive/master.zip; \
|
|||
unzip master.zip; \
|
||||
rm master.zip; \
|
||||
mv keeweb-plugins-master/docs keeweb/plugins; \
|
||||
rm -rf keeweb-plugins-master
|
||||
rm -rf keeweb-plugins-master \
|
||||
rm keeweb/plugins/CNAME
|
||||
|
||||
ENTRYPOINT ["/opt/entrypoint.sh"]
|
||||
|
|
|
@ -16,6 +16,8 @@ const pkg = require('./package.json');
|
|||
|
||||
const op = args.shift();
|
||||
|
||||
const bumpVersion = args.some(arg => arg === '--bump-version');
|
||||
|
||||
showBanner();
|
||||
|
||||
switch (op) {
|
||||
|
@ -47,6 +49,7 @@ function signPlugin(packageName) {
|
|||
}
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(packageName, 'manifest.json')));
|
||||
const privateKey = fs.readFileSync(path.join(packageName, 'private_key.pem'), 'binary');
|
||||
let changed = false;
|
||||
for (const res of Object.keys(manifest.resources)) {
|
||||
console.log(`Signing ${res}...`);
|
||||
let fileName;
|
||||
|
@ -65,10 +68,21 @@ function signPlugin(packageName) {
|
|||
const sign = crypto.createSign('RSA-SHA256');
|
||||
sign.write(fs.readFileSync(fileName));
|
||||
sign.end();
|
||||
manifest.resources[res] = sign.sign(privateKey).toString('base64');
|
||||
const signature = sign.sign(privateKey).toString('base64');
|
||||
if (manifest.resources[res] !== signature) {
|
||||
manifest.resources[res] = signature;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
if (bumpVersion) {
|
||||
manifest.version = manifest.version.replace(/\d+$/, v => +v + 1);
|
||||
}
|
||||
fs.writeFileSync(path.join(packageName, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
||||
console.log('Done, package manifest updated');
|
||||
} else {
|
||||
console.log('No changes');
|
||||
}
|
||||
fs.writeFileSync(path.join(packageName, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
||||
console.log('Done, package manifest updated');
|
||||
}
|
||||
|
||||
function watchSignPlugin() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "keeweb-plugin",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"description": "KeeWeb plugin utils",
|
||||
"main": "keeweb-plugin.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
Release notes
|
||||
-------------
|
||||
##### v1.5.1 (2017-05-23)
|
||||
`-` fix #631: unicode characters in Dropbox files
|
||||
`-` fix backups in desktop
|
||||
`+` plugin API improvements
|
||||
|
||||
##### v1.5.0 (2017-05-20)
|
||||
`+` plugins
|
||||
`*` translations are available only as plugins
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const ps = require('child_process');
|
||||
|
||||
const cwd = path.resolve(__dirname, 'keeweb');
|
||||
|
||||
if (!fs.existsSync(cwd)) {
|
||||
console.log('Cloning...');
|
||||
ps.spawnSync('git', ['clone', 'git@github.com:keeweb/keeweb.git', '-b', 'gh-pages'], {cwd: __dirname});
|
||||
}
|
||||
|
||||
console.log('Getting log...');
|
||||
|
||||
ps.spawnSync('git', ['reset', '--hard'], {cwd});
|
||||
ps.spawnSync('git', ['checkout', 'gh-pages'], {cwd});
|
||||
const gitLog = ps.spawnSync('git', ['log'], {cwd}).stdout.toString();
|
||||
|
||||
console.log('Gettings tags...');
|
||||
|
||||
const tags = ps.spawnSync('git', ['tag', '-l'], {cwd})
|
||||
.stdout.toString()
|
||||
.split('\n')
|
||||
.filter(tag => tag);
|
||||
|
||||
console.log(`Found ${tags.length} tags`);
|
||||
|
||||
const stats = [];
|
||||
for (const tag of tags) {
|
||||
console.log(`Tag: ${tag}`);
|
||||
const match = new RegExp(`commit (\\w+)\\nAuthor[^\\n]+\\nDate:\\s*([^\\n]+)\\n\\n\\s*${tag}`).exec(gitLog);
|
||||
const [, rev, date] = match;
|
||||
const dt = new Date(date).getTime();
|
||||
const checkoutRes = ps.spawnSync('git', ['checkout', rev], {cwd});
|
||||
if (checkoutRes.error) {
|
||||
console.error('Checkout error', checkoutRes.error);
|
||||
throw 'Checkout error';
|
||||
}
|
||||
|
||||
const size = {};
|
||||
|
||||
const data = fs.readFileSync(path.join(cwd, 'index.html'));
|
||||
const html = data.toString();
|
||||
|
||||
size.total = data.byteLength;
|
||||
size.favicons = /<link rel="shortcut icon"[^>]+>/.exec(html)[0].length +
|
||||
(/<link rel="apple-touch-icon"[^>]+>/.exec(html) || [''])[0].length;
|
||||
size.css = /<style>.*?<\/style>/.exec(html)[0].length;
|
||||
size.jsVendor = /<\/style><script>[\s\S]*?<\/script>/.exec(html)[0].length;
|
||||
size.jsApp = /<\/script><script>[\s\S]*?<\/script>/.exec(html)[0].length;
|
||||
|
||||
stats.push({ tag, rev, dt, size });
|
||||
}
|
||||
|
||||
// https://api.github.com/repos/keeweb/keeweb/issues?state=all&sort=created&direction=asc
|
||||
|
||||
console.log('Saving stats...');
|
||||
|
||||
fs.writeFileSync(path.resolve(__dirname, 'release-stats.json'), JSON.stringify(stats, null, 2));
|
||||
|
||||
console.log('Done');
|
Loading…
Reference in New Issue