Merge branch 'develop'

This commit is contained in:
antelle 2019-03-31 15:52:38 +02:00
commit 8215d608b7
54 changed files with 470 additions and 253 deletions

View File

@ -1,13 +0,0 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 14
# Label requiring a response
responseRequiredLabel: need info
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ obj/
xcuserdata/
*.suo
.idea/
.vscode

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

View File

@ -7,15 +7,25 @@
<meta name="kw-signature" content="">
<meta name="kw-config" content="(no-config)">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!--<link rel="manifest" href="manifest.json">-->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="KeeWeb">
<meta name="theme-color" content="#6386ec">
<meta name="msapplication-config" content="browserconfig.xml">
<meta name="msapplication-TileColor" content="#6386ec">
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="#6386ec">
<meta name="msapplication-config" content="browserconfig.xml">
<meta name="msapplication-TileColor" content="#6386ec">
<meta name="theme-color" content="#6386ec">
<link rel="apple-touch-startup-image" href="icons/splash-640x1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-750x1294.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1242x2148.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1125x2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1536x2048.png" media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1668x2224.png" media="(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-2048x2732.png" media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="manifest" href="manifest.json">
<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>

View File

@ -27,7 +27,7 @@ const Locale = require('./util/locale');
const ready = Launcher && Launcher.ready || $;
ready(() => {
if (FeatureDetector.isPopup && AuthReceiver.receive() || FeatureDetector.isFrame) {
if (AuthReceiver.receive() || FeatureDetector.isFrame) {
return;
}
loadMixins();

View File

@ -1,4 +1,5 @@
const EntryCollection = require('../collections/entry-collection');
const Ranking = require('../util/ranking');
const urlPartsRegex = /^(\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(.*)/;
@ -39,7 +40,10 @@ AutoTypeFilter.prototype.prepareFilter = function() {
AutoTypeFilter.prototype.getEntryRank = function(entry) {
let rank = 0;
if (this.titleLower && entry.title) {
rank += this.getStringRank(entry.title.toLowerCase(), this.titleLower);
rank += Ranking.getStringRank(
entry.title.toLowerCase(),
this.titleLower
);
}
if (this.urlParts && entry.url) {
const entryUrlParts = urlPartsRegex.exec(entry.url.toLowerCase());
@ -78,22 +82,4 @@ AutoTypeFilter.prototype.getEntryRank = function(entry) {
return rank;
};
AutoTypeFilter.prototype.getStringRank = function(s1, s2) {
let ix = s1.indexOf(s2);
if (ix === 0 && s1.length === s2.length) {
return 10;
} else if (ix === 0) {
return 5;
} else if (ix > 0) {
return 3;
}
ix = s2.indexOf(s1);
if (ix === 0) {
return 5;
} else if (ix > 0) {
return 3;
}
return 0;
};
module.exports = AutoTypeFilter;

View File

@ -199,7 +199,7 @@ const AutoType = {
processEventWithFilter(evt) {
const entries = evt.filter.getEntries();
if (entries.length === 1) {
if (entries.length === 1 && AppSettingsModel.instance.get('directAutotype')) {
this.hideWindow(() => {
this.runAndHandleResult({ entry: entries.at(0) });
});
@ -221,6 +221,14 @@ const AutoType = {
}
});
});
this.selectEntryView.on('show-open-files', () => {
this.selectEntryView.hide();
Backbone.trigger('open-file');
Backbone.once('closed-open-view', () => {
this.selectEntryView.show();
this.selectEntryView.setupKeys();
}, this);
});
},
resetPendingEvent() {

View File

@ -19,17 +19,21 @@ const EntryCollection = Backbone.Collection.extend({
'-created': Comparators.dateComparator('created', false),
'updated': Comparators.dateComparator('updated', true),
'-updated': Comparators.dateComparator('updated', false),
'-attachments': function(x, y) { return this.attachmentSortVal(x).localeCompare(this.attachmentSortVal(y)); }
'-attachments': function(x, y) { return this.attachmentSortVal(x).localeCompare(this.attachmentSortVal(y)); },
'-rank': Comparators.rankComparator()
},
defaultComparator: 'title',
filter: null,
initialize: function(models, options) {
const comparatorName = options && options.comparator || this.defaultComparator;
this.comparator = this.comparators[comparatorName];
},
sortEntries: function(comparator) {
sortEntries: function(comparator, filter) {
this.filter = filter;
this.comparator = this.comparators[comparator] || this.comparators[this.defaultComparator];
this.sort();
},

View File

@ -3,6 +3,9 @@ const Storage = require('../storage');
const AuthReceiver = {
receive: function() {
if (!FeatureDetector.isPopup && !FeatureDetector.isStandalone) {
return false;
}
const opener = window.opener || window.parent;
const message = this.urlArgsToMessage(window.location.href);
const hasKeys = Object.keys(message).filter(key => key !== 'config').length > 0;
@ -10,7 +13,9 @@ const AuthReceiver = {
return false;
}
if (FeatureDetector.isStandalone) {
Storage[sessionStorage.authStorage].handleOAuthReturnMessage(message);
if (sessionStorage.authStorage) {
Storage[sessionStorage.authStorage].handleOAuthReturnMessage(message);
}
return false;
} else {
opener.postMessage(message, window.location.origin);

View File

@ -3,10 +3,10 @@ const Launcher = require('./launcher');
const AppSettingsModel = require('../models/app-settings-model');
const CopyPaste = {
simpleCopy: !!Launcher,
simpleCopy: !!(Launcher && Launcher.clipboardSupported),
copy: function(text) {
if (Launcher) {
if (this.simpleCopy) {
Launcher.setClipboardText(text);
const clipboardSeconds = AppSettingsModel.instance.get('clipboardSeconds');
if (clipboardSeconds > 0) {

View File

@ -1,12 +1,18 @@
/* global FingerprintAuth */
const Backbone = require('backbone');
const Launcher = {
name: 'cordova',
version: '6.0.0',
autoTypeSupported: false,
thirdPartyStoragesSupported: false,
clipboardSupported: false,
ready: function(callback) {
document.addEventListener('deviceready', callback, false);
document.addEventListener('pause', () => {
Backbone.trigger('app-minimized');
}, false);
},
platform: function() {
return 'cordova';
@ -40,6 +46,12 @@ const Launcher = {
return [...parts].join('/');
},
writeFile: function(path, data, callback) {
const createFile = filePath => {
window.resolveLocalFileSystemURL(filePath.dir, dir => {
dir.getFile(filePath.file, {create: true}, writeFile);
}, callback, callback);
};
const writeFile = fileEntry => {
fileEntry.createWriter(fileWriter => {
fileWriter.onerror = callback;
@ -48,7 +60,14 @@ const Launcher = {
}, callback);
};
window.resolveLocalFileSystemURL(path, writeFile, callback, callback);
if (path.startsWith('cdvfile://')) { // then file exists
window.resolveLocalFileSystemURL(path, writeFile, callback, callback);
} else { // create file on sd card
const filePath = this.parsePath(path);
this.mkdir(filePath.dir, () => {
createFile(filePath);
});
}
},
readFile: function(path, encoding, callback) {
window.resolveLocalFileSystemURL(path, fileEntry => {
@ -109,14 +128,15 @@ const Launcher = {
return {
path: fileName,
dir: parts.pop(),
file: parts.join('/')
file: parts.pop(),
dir: parts.join('/')
};
},
createFsWatcher: function(path) {
return null; // not in android with content provider
},
// ensureRunnable: function(path) { },
preventExit: function(e) {
e.returnValue = false;
return false;
@ -124,29 +144,30 @@ const Launcher = {
exit: function() {
this.hideApp();
},
requestExit: function() { /* skip in cordova */ },
requestRestart: function() {
window.location.reload();
},
cancelRestart: function() { /* skip in cordova */ },
setClipboardText: function(text) {
// TODO
},
getClipboardText: function() {
// TODO
},
clearClipboardText: function() {
// TODO
},
setClipboardText: function(text) {},
getClipboardText: function() {},
clearClipboardText: function() {},
minimizeApp: function() {
this.hideApp();
},
canMinimize: function() {
return false;
},
canDetectOsSleep: function() {
return false;
},
updaterEnabled: function() {
return false;
},
// getMainWindow: function() { },
resolveProxy: function(url, callback) { /* skip in cordova */ },
openWindow: function(opts) { /* skip in cordova */ },
@ -169,6 +190,12 @@ const Launcher = {
window.cordova.exec(onFileSelected, callback, 'FileChooser', 'choose');
},
getCookies(callback) {
// TODO
},
setCookies(cookies) {
// TODO
},
fingerprints: {
config: {
@ -184,7 +211,7 @@ const Launcher = {
const encryptConfig = _.extend({}, this.config, {
username: fileId,
password: password
password: password.getText()
});
FingerprintAuth.encrypt(encryptConfig, result => {

View File

@ -9,6 +9,7 @@ const Launcher = {
version: window.process.versions.electron,
autoTypeSupported: true,
thirdPartyStoragesSupported: true,
clipboardSupported: true,
req: window.require,
platform: function() {
return process.platform;
@ -27,7 +28,7 @@ const Launcher = {
},
devTools: true,
openDevTools: function() {
this.electron().remote.getCurrentWindow().openDevTools();
this.electron().remote.getCurrentWindow().openDevTools({ mode: 'bottom' });
},
getSaveFileName: function(defaultPath, callback) {
if (defaultPath) {
@ -211,6 +212,7 @@ const Launcher = {
showMainWindow: function() {
const win = this.getMainWindow();
win.show();
win.focus();
win.restore();
},
spawn: function(config) {

View File

@ -1,5 +1,6 @@
const Backbone = require('backbone');
const Locale = require('./../util/locale');
const FeatureDetector = require('../util/feature-detector');
const SettingsManager = {
neutralLocale: null,
@ -28,9 +29,7 @@ const SettingsManager = {
if (settings.get('theme')) {
this.setTheme(settings.get('theme'));
}
if (settings.get('fontSize')) {
this.setFontSize(settings.get('fontSize'));
}
this.setFontSize(settings.get('fontSize'));
const locale = settings.get('locale');
try {
if (locale) {
@ -59,7 +58,8 @@ const SettingsManager = {
},
setFontSize: function(fontSize) {
document.documentElement.style.fontSize = fontSize ? (12 + fontSize * 2) + 'px' : '';
const defaultFontSize = FeatureDetector.isMobile ? 14 : 12;
document.documentElement.style.fontSize = (defaultFontSize + (fontSize || 0) * 2) + 'px';
},
setLocale(loc) {

View File

@ -27,6 +27,7 @@
"help": "Help",
"settings": "Settings",
"plugins": "Plugins",
"rank": "rank",
"cache": "cache",
"file": "file",
@ -146,6 +147,7 @@
"searchOptions": "Options",
"searchCase": "Match case",
"searchRegex": "RegEx",
"searchRank": "Rank",
"openOpen": "Open",
"openNew": "New",
@ -355,6 +357,7 @@
"setGenShowSubgroups": "Show entries from all subgroups",
"setGenTableView": "Entries list table view",
"setGenColorfulIcons": "Colorful custom icons in list",
"setGenDirectAutotype": "If only one matching entry is found, select that one automatically for Autotype",
"setGenFunction": "Function",
"setGenAutoSyncOnClose": "Automatically save and sync on close",
"setGenAutoSyncTimer": "Automatically save and sync periodically",
@ -387,6 +390,7 @@
"setGenTryBetaWarning": "Unsaved files",
"setGenTryBetaWarningBody": "Please save all files and click this button again",
"setGenShowAppLogs": "Show app logs",
"setGenReloadApp": "Reload the app",
"setFilePath": "File path",
"setFileStorage": "This file is loaded from {}.",

View File

@ -562,6 +562,6 @@
"webdavSavePut": "Ecraser le fichier kdbx avec PUT",
"launcherSave": "Sauvegarder base des mots de passe",
"launcherFileFilter": "Fichiers Keepass",
"authPopupRequired": "Les pop-up sont blockés",
"authPopupRequired": "Les pop-up sont bloquées",
"authPopupRequiredBody": "Merci d'autoriser les popups pour cette appli dans votre navigateur ou essayez à nouveau."
}

View File

@ -240,7 +240,7 @@ const AppModel = Backbone.Model.extend({
},
setFilter: function(filter) {
this.filter = filter;
this.filter = this.prepareFilter(filter);
this.filter.subGroups = this.settings.get('expandGroups');
if (!this.filter.advanced && this.advancedSearch) {
this.filter.advanced = this.advancedSearch;
@ -274,7 +274,7 @@ const AppModel = Backbone.Model.extend({
getEntries: function() {
const entries = this.getEntriesByFilter(this.filter);
entries.sortEntries(this.sort);
entries.sortEntries(this.sort, this.filter);
if (this.filter.trash) {
this.addTrashGroups(entries);
}
@ -282,7 +282,6 @@ const AppModel = Backbone.Model.extend({
},
getEntriesByFilter: function(filter) {
filter = this.prepareFilter(filter);
const entries = new EntryCollection();
this.files.forEach(file => {
file.forEachEntry(filter, entry => entries.push(entry));
@ -303,12 +302,8 @@ const AppModel = Backbone.Model.extend({
prepareFilter: function(filter) {
filter = _.clone(filter);
if (filter.text) {
filter.textLower = filter.text.toLowerCase();
}
if (filter.tag) {
filter.tagLower = filter.tag.toLowerCase();
}
filter.textLower = filter.text ? filter.text.toLowerCase() : '';
filter.tagLower = filter.tag ? filter.tag.toLowerCase() : '';
return filter;
},
@ -1021,12 +1016,12 @@ const AppModel = Backbone.Model.extend({
},
saveFileFingerprint: function(file, password) {
if (Launcher && Launcher.fingerprints && password) {
if (Launcher && Launcher.fingerprints && !file.has('fingerprint')) {
const fileInfo = this.fileInfos.get(file.id);
Launcher.fingerprints.register(file.id, this.params.password, token => {
Launcher.fingerprints.register(file.id, password, token => {
if (token) {
fileInfo.set('fingerprint', token);
this.model.fileInfos.save();
fileInfo.set({ fingerprint: token });
this.fileInfos.save();
}
});
}

View File

@ -18,6 +18,7 @@ const AppSettingsModel = Backbone.Model.extend({
minimizeOnClose: false,
tableView: false,
colorfulIcons: false,
directAutotype: true,
titlebarStyle: 'default',
lockOnMinimize: true,
lockOnCopy: false,

View File

@ -5,6 +5,7 @@ const Color = require('../util/color');
const IconUrl = require('../util/icon-url');
const Otp = require('../util/otp');
const kdbxweb = require('kdbxweb');
const Ranking = require('../util/ranking');
const EntryModel = Backbone.Model.extend({
defaults: {},
@ -16,9 +17,6 @@ const EntryModel = Backbone.Model.extend({
fieldRefFields: ['title', 'password', 'user', 'url', 'notes'],
fieldRefIds: { T: 'Title', U: 'UserName', P: 'Password', A: 'URL', N: 'Notes' },
initialize: function() {
},
setEntry: function(entry, group, file) {
this.entry = entry;
this.group = group;
@ -392,6 +390,7 @@ const EntryModel = Backbone.Model.extend({
const hasValue = val && (typeof val === 'string' || val.isProtected && val.byteLength);
if (hasValue || allowEmpty || this.builtInFields.indexOf(field) >= 0) {
this._entryModified();
val = this.sanitizeFieldValue(val);
this.entry.fields[field] = val;
} else if (this.entry.fields.hasOwnProperty(field)) {
this._entryModified();
@ -400,6 +399,15 @@ const EntryModel = Backbone.Model.extend({
this._fillByEntry();
},
sanitizeFieldValue: function(val) {
if (val && !val.isProtected && val.indexOf('\x1A') >= 0) {
// https://github.com/keeweb/keeweb/issues/910
// eslint-disable-next-line no-control-regex
val = val.replace(/\x1A/g, '');
}
return val;
},
hasField: function(field) {
return this.entry.fields.hasOwnProperty(field);
},
@ -635,6 +643,56 @@ const EntryModel = Backbone.Model.extend({
this.entry.times.creationTime = this.entry.times.lastModTime;
this.entry.fields.Title = '';
this._fillByEntry();
},
getRank: function(searchString) {
if (!searchString) {
// no search string given, so rank all items the same
return 0;
}
let rank = 0;
const ranking = [
{
field: 'Title',
multiplicator: 10
},
{
field: 'URL',
multiplicator: 8
},
{
field: 'UserName',
multiplicator: 5
},
{
field: 'Notes',
multiplicator: 2
}
];
const fieldNames = Object.keys(this.fields);
_.forEach(fieldNames, field => {
ranking.push(
{
field: field,
multiplicator: 2
}
);
});
_.forEach(ranking, rankingEntry => {
if (this._getFieldString(rankingEntry.field).toLowerCase() !== '') {
const calculatedRank = Ranking.getStringRank(
searchString,
this._getFieldString(rankingEntry.field).toLowerCase()
) * rankingEntry.multiplicator;
rank += calculatedRank;
}
});
return rank;
}
});

View File

@ -421,11 +421,17 @@ const FileModel = Backbone.Model.extend({
syncing: false,
syncError: error
});
const shouldResetFingerprint = this.get('passwordChanged') && this.has('fingerprint');
if (shouldResetFingerprint && !error) {
this.set({ fingerprint: null });
}
if (!this.get('open')) {
return;
}
this.setOpenFile({ passwordLength: this.get('passwordLength') });
this.forEachEntry({}, entry => entry.setSaved());
this.forEachEntry({ includeDisabled: true }, entry => entry.setSaved());
},
setPassword: function(password) {
@ -569,10 +575,11 @@ const FileModel = Backbone.Model.extend({
this.db.move(group, null);
modified = true;
}, this);
trashGroup.group.entries.forEach(function(entry) {
trashGroup.group.entries.slice().forEach(function(entry) {
this.db.move(entry, null);
modified = true;
}, this);
trashGroup.get('items').reset();
trashGroup.get('entries').reset();
if (modified) {
this.setModified();

View File

@ -38,6 +38,12 @@ _.extend(StorageBase.prototype, {
this._oauthProcessReturn(this._oauthReturnMessage);
delete this._oauthReturnMessage;
delete sessionStorage.authStorage;
if (FeatureDetector.isStandalone) {
const [url, urlParams] = location.href.split(/[?#]/);
if (urlParams) {
location.href = url;
}
}
}
return this;
},

View File

@ -1,4 +1,4 @@
const LastChar = String.fromCharCode(0xffffffff);
const LastChar = String.fromCharCode(0xfffd);
const ciCompare = (window.Intl && window.Intl.Collator && !/Edge/.test(navigator.userAgent)) // bugged in Edge: #808
? new Intl.Collator(undefined, { sensitivity: 'base' }).compare
@ -13,6 +13,10 @@ const Comparators = {
}
},
rankComparator: function() {
return function (x, y) { return y.getRank(this.filter.textLower) - x.getRank(this.filter.textLower); };
},
dateComparator: function(field, asc) {
if (asc) {
return function (x, y) { return x[field] - y[field]; };

View File

@ -47,6 +47,9 @@ const FeatureDetector = {
if (window.navigator.userAgent.indexOf('Edge/') > -1) {
return 'edge';
}
if (navigator.standalone) {
return 'standalone';
}
return '';
}
};

View File

@ -0,0 +1,21 @@
const Ranking = {
getStringRank: function(s1, s2) {
let ix = s1.indexOf(s2);
if (ix === 0 && s1.length === s2.length) {
return 10;
} else if (ix === 0) {
return 5;
} else if (ix > 0) {
return 3;
}
ix = s2.indexOf(s1);
if (ix === 0) {
return 5;
} else if (ix > 0) {
return 3;
}
return 0;
}
};
module.exports = Ranking;

View File

@ -158,6 +158,9 @@ const AppView = Backbone.View.extend({
this.hideKeyChange();
this.views.open = new OpenView({ model: this.model });
this.views.open.setElement(this.$el.find('.app__body')).render();
this.views.open.on('close', () => {
Backbone.trigger('closed-open-view');
}, this);
this.views.open.on('close', this.showEntries, this);
},

View File

@ -26,6 +26,10 @@ const AutoTypePopupView = Backbone.View.extend({
this.initScroll();
this.listenTo(Backbone, 'main-window-blur', this.mainWindowBlur);
this.listenTo(Backbone, 'main-window-will-close', this.mainWindowWillClose);
this.setupKeys();
},
setupKeys() {
KeyHandler.onKey(Keys.DOM_VK_ESCAPE, this.escPressed, this, false, true);
KeyHandler.onKey(Keys.DOM_VK_RETURN, this.enterPressed, this, false, true);
KeyHandler.onKey(Keys.DOM_VK_RETURN, this.actionEnterPressed, this, KeyHandler.SHORTCUT_ACTION, true);
@ -33,10 +37,24 @@ const AutoTypePopupView = Backbone.View.extend({
KeyHandler.onKey(Keys.DOM_VK_UP, this.upPressed, this, false, true);
KeyHandler.onKey(Keys.DOM_VK_DOWN, this.downPressed, this, false, true);
KeyHandler.onKey(Keys.DOM_VK_BACK_SPACE, this.backSpacePressed, this, false, true);
KeyHandler.onKey(Keys.DOM_VK_O, this.openKeyPressed, this, KeyHandler.SHORTCUT_ACTION, true);
KeyHandler.on('keypress:auto-type', this.keyPressed.bind(this));
KeyHandler.setModal('auto-type');
},
removeKeys() {
KeyHandler.offKey(Keys.DOM_VK_ESCAPE, this.escPressed, this);
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.enterPressed, this);
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.actionEnterPressed, this);
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.optEnterPressed, this);
KeyHandler.offKey(Keys.DOM_VK_UP, this.upPressed, this);
KeyHandler.offKey(Keys.DOM_VK_DOWN, this.downPressed, this);
KeyHandler.offKey(Keys.DOM_VK_BACK_SPACE, this.backSpacePressed, this);
KeyHandler.offKey(Keys.DOM_VK_O, this.openKeyPressed, this);
KeyHandler.off('keypress:auto-type');
KeyHandler.setModal(null);
},
render() {
let topMessage;
if (this.model.filter.title || this.model.filter.url) {
@ -76,13 +94,7 @@ const AutoTypePopupView = Backbone.View.extend({
},
remove() {
KeyHandler.offKey(Keys.DOM_VK_ESCAPE, this.escPressed, this);
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.enterPressed, this);
KeyHandler.offKey(Keys.DOM_VK_UP, this.upPressed, this);
KeyHandler.offKey(Keys.DOM_VK_DOWN, this.downPressed, this);
KeyHandler.offKey(Keys.DOM_VK_BACK_SPACE, this.backSpacePressed, this);
KeyHandler.off('keypress:auto-type');
KeyHandler.setModal(null);
this.removeKeys();
Backbone.View.prototype.remove.apply(this, arguments);
},
@ -121,6 +133,11 @@ const AutoTypePopupView = Backbone.View.extend({
this.closeWithResult(AutoTypeSequenceType.USERNAME);
},
openKeyPressed() {
this.removeKeys();
this.trigger('show-open-files');
},
upPressed(e) {
e.preventDefault();
const activeIndex = this.entries.indexOf(this.result) - 1;

View File

@ -74,9 +74,9 @@ const DetailsView = Backbone.View.extend({
this.listenTo(Backbone, 'set-locale', this.render);
this.listenTo(OtpQrReader, 'qr-read', this.otpCodeRead);
this.listenTo(OtpQrReader, 'enter-manually', this.otpEnterManually);
KeyHandler.onKey(Keys.DOM_VK_C, this.copyPassword, this, KeyHandler.SHORTCUT_ACTION, false, true);
KeyHandler.onKey(Keys.DOM_VK_B, this.copyUserName, this, KeyHandler.SHORTCUT_ACTION, false, true);
KeyHandler.onKey(Keys.DOM_VK_U, this.copyUrl, this, KeyHandler.SHORTCUT_ACTION, false, true);
KeyHandler.onKey(Keys.DOM_VK_C, this.copyPassword, this, KeyHandler.SHORTCUT_ACTION);
KeyHandler.onKey(Keys.DOM_VK_B, this.copyUserName, this, KeyHandler.SHORTCUT_ACTION);
KeyHandler.onKey(Keys.DOM_VK_U, this.copyUrl, this, KeyHandler.SHORTCUT_ACTION);
if (AutoType.enabled) {
KeyHandler.onKey(Keys.DOM_VK_T, this.autoType, this, KeyHandler.SHORTCUT_ACTION);
}

View File

@ -1,6 +1,5 @@
const Backbone = require('backbone');
const IconMap = require('../const/icon-map');
const Launcher = require('../comp/launcher');
const Logger = require('../util/logger');
const logger = new Logger('icon-select-view');
@ -56,7 +55,7 @@ const IconSelectView = Backbone.View.extend({
this.downloadingFavicon = true;
this.$el.find('.icon-select__icon-download>i').addClass('fa-spinner fa-spin');
this.$el.find('.icon-select__icon-download').removeClass('icon-select__icon--download-error');
const url = this.getIconUrl(!Launcher); // inside launcher we can load images without CORS
const url = this.getIconUrl(true);
const img = document.createElement('img');
img.crossOrigin = 'Anonymous';
img.src = url;

View File

@ -43,7 +43,8 @@ const ListSearchView = Backbone.View.extend({
{ value: '-created', icon: 'sort-numeric-desc', loc: () => Locale.searchCreated + ' ' + this.addArrow(Locale.searchNO) },
{ value: 'updated', icon: 'sort-numeric-asc', loc: () => Locale.searchUpdated + ' ' + this.addArrow(Locale.searchON) },
{ value: '-updated', icon: 'sort-numeric-desc', loc: () => Locale.searchUpdated + ' ' + this.addArrow(Locale.searchNO) },
{ value: '-attachments', icon: 'sort-amount-desc', loc: () => Locale.searchAttachments }
{ value: '-attachments', icon: 'sort-amount-desc', loc: () => Locale.searchAttachments },
{ value: '-rank', icon: 'sort-numeric-desc', loc: () => Locale.searchRank }
];
this.sortIcons = {};
this.sortOptions.forEach(function(opt) {
@ -55,7 +56,8 @@ const ListSearchView = Backbone.View.extend({
url: true, protect: false,
notes: true, pass: false,
cs: false, regex: false,
history: false, title: true
history: false, title: true,
rank: true
};
if (this.model.advancedSearch) {
this.advancedSearch = _.extend({}, this.model.advancedSearch);

View File

@ -15,6 +15,7 @@ const Comparators = require('../util/comparators');
const Storage = require('../storage');
const Launcher = require('../comp/launcher');
const FocusDetector = require('../comp/focus-detector');
const FeatureDetector = require('../util/feature-detector');
const logger = new Logger('open-view');
@ -110,8 +111,8 @@ const OpenView = Backbone.View.extend({
this.inputEl.focus();
},
focusInput: function() {
if (FocusDetector.hasFocus()) {
focusInput: function(focusOnMobile) {
if (FocusDetector.hasFocus() && (focusOnMobile || !FeatureDetector.isMobile)) {
this.inputEl.focus();
}
},
@ -384,21 +385,7 @@ const OpenView = Backbone.View.extend({
}
const fileInfo = this.model.fileInfos.get(id);
this.showOpenFileInfo(fileInfo);
if (fileInfo && Launcher && Launcher.fingerprints) {
this.openFileWithFingerprint(fileInfo);
}
},
openFileWithFingerprint(fileInfo) {
if (fileInfo.get('fingerprint')) {
Launcher.fingerprints.auth(fileInfo.id, fileInfo.get('fingerprint'), password => {
this.inputEl.val(password);
this.inputEl.trigger('input');
this.openDb();
});
}
this.showOpenFileInfo(fileInfo, true);
},
removeFile: function(id) {
@ -507,7 +494,7 @@ const OpenView = Backbone.View.extend({
}
},
showOpenFileInfo: function(fileInfo) {
showOpenFileInfo: function(fileInfo, fileWasClicked) {
if (this.busy || !fileInfo) {
return;
}
@ -522,6 +509,12 @@ const OpenView = Backbone.View.extend({
this.params.keyFileData = null;
this.displayOpenFile();
this.displayOpenKeyFile();
this.openFileWithFingerprint(fileInfo);
if (fileWasClicked) {
this.focusInput(true);
}
},
showOpenLocalFile: function(path, keyFilePath) {
@ -544,6 +537,20 @@ const OpenView = Backbone.View.extend({
}
},
openFileWithFingerprint: function(fileInfo) {
if (!fileInfo.has('fingerprint')) {
return;
}
if (Launcher && Launcher.fingerprints) {
Launcher.fingerprints.auth(fileInfo.id, fileInfo.get('fingerprint'), password => {
this.inputEl.val(password);
this.inputEl.trigger('input');
this.openDb();
});
}
},
createDemo: function() {
if (!this.busy) {
this.closeConfig();
@ -583,7 +590,7 @@ const OpenView = Backbone.View.extend({
this.inputEl.removeAttr('disabled').toggleClass('input--error', !!err);
if (err) {
logger.error('Error opening file', err);
this.focusInput();
this.focusInput(true);
this.inputEl[0].selectionStart = 0;
this.inputEl[0].selectionEnd = this.inputEl.val().length;
if (err.code === 'InvalidKey') {

View File

@ -163,6 +163,7 @@ const SettingsFileView = Backbone.View.extend({
return;
}
}
this.appModel.syncFile(this.model, arg);
},

View File

@ -37,6 +37,7 @@ const SettingsGeneralView = Backbone.View.extend({
'change .settings__general-lock-on-os-lock': 'changeLockOnOsLock',
'change .settings__general-table-view': 'changeTableView',
'change .settings__general-colorful-icons': 'changeColorfulIcons',
'change .settings__general-direct-autotype': 'changeDirectAutotype',
'change .settings__general-titlebar-style': 'changeTitlebarStyle',
'click .settings__general-update-btn': 'checkUpdate',
'click .settings__general-restart-btn': 'restartApp',
@ -46,7 +47,8 @@ const SettingsGeneralView = Backbone.View.extend({
'click .settings__general-show-advanced': 'showAdvancedSettings',
'click .settings__general-dev-tools-link': 'openDevTools',
'click .settings__general-try-beta-link': 'tryBeta',
'click .settings__general-show-logs-link': 'showLogs'
'click .settings__general-show-logs-link': 'showLogs',
'click .settings__general-reload-app-link': 'reloadApp'
},
views: null,
@ -101,9 +103,11 @@ const SettingsGeneralView = Backbone.View.extend({
updateManual: updateManual,
releaseNotesLink: Links.ReleaseNotes,
colorfulIcons: AppSettingsModel.instance.get('colorfulIcons'),
directAutotype: AppSettingsModel.instance.get('directAutotype'),
supportsTitleBarStyles: Launcher && FeatureDetector.supportsTitleBarStyles(),
titlebarStyle: AppSettingsModel.instance.get('titlebarStyle'),
storageProviders: storageProviders
storageProviders: storageProviders,
showReloadApp: FeatureDetector.isStandalone
});
this.renderProviderViews(storageProviders);
},
@ -275,6 +279,12 @@ const SettingsGeneralView = Backbone.View.extend({
Backbone.trigger('refresh');
},
changeDirectAutotype: function(e) {
const directAutotype = e.target.checked || false;
AppSettingsModel.instance.set('directAutotype', directAutotype);
Backbone.trigger('refresh');
},
restartApp: function() {
if (Launcher) {
Launcher.requestRestart();
@ -338,6 +348,10 @@ const SettingsGeneralView = Backbone.View.extend({
this.scrollToBottom();
},
reloadApp: function() {
location.reload();
},
scrollToBottom: function() {
this.$el.closest('.scroller').scrollTop(this.$el.height());
}

View File

@ -14,7 +14,12 @@
cursor: pointer;
line-height: $mobile-back-button-height;
height: $mobile-back-button-height;
>i { margin-right: $base-padding-h; }
font-size: 1.2em;
>i {
margin-right: .3em;
font-size: 1.2em;
vertical-align: text-bottom;
}
}
}
@ -41,6 +46,9 @@
@include th {
border: 1px solid th(light-border-color);
}
@include mobile {
border-color: transparent;
}
}
}
input.details__header-title-input {
@ -52,6 +60,9 @@
font-weight: bold;
position: relative;
top: -2px;
@include mobile {
width: 100%;
}
}
&-color, &-icon {
@include user-select(none);
@ -86,7 +97,9 @@
left: 6px;
font-size: $large-header-font-size;
&:hover, .details__header-color:hover & {
display: block;
@include nomobile {
display: block;
}
}
&-item {
padding: 8px 12px;
@ -147,6 +160,9 @@
align-items: stretch;
flex-direction: column;
justify-content: flex-start;
@include mobile {
width: 100%;
}
}
&-after {
@ -208,15 +224,19 @@
.details__field--editable & {
border-radius: $base-border-radius;
&:hover {
transition: border-color $base-duration $base-timing;
border: 1px solid;
@include th {
border-color: th(light-border-color);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.06);
}
.details__field-value-add-label {
@include th { color: th(muted-color); }
transition: color $base-duration $base-timing;
@include nomobile {
transition: border-color $base-duration $base-timing;
border: 1px solid;
@include th {
border-color: th(light-border-color);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.06);
}
.details__field-value-add-label {
@include th {
color: th(muted-color);
}
transition: color $base-duration $base-timing;
}
}
}
}
@ -250,6 +270,9 @@
.details__field--edit[active-mobile-action=cancel] & {
@include th { background: th(error-color); border-color: th(error-color); }
}
@include mobile {
border-color: transparent !important;
}
}
>input {
.chrome & { padding-bottom: 1px; } // TODO: find a better cross-browser way to do it
@ -333,6 +356,11 @@
@include user-select(none);
}
}
@include mobile {
@include th { border-bottom: light-border(); }
padding-bottom: .5em;
}
}
&__attachments {

View File

@ -3,6 +3,9 @@
align-items: stretch;
flex-direction: row;
justify-content: flex-start;
@include mobile {
@include th { background: th(intermediate-background-color); }
}
&__db {
flex: 0 0 auto;
@ -63,6 +66,10 @@
flex: 0 0 auto;
@include area-selectable(top);
padding: $base-padding;
.standalone & {
padding-top: $base-padding-v;
padding-bottom: 1.2em;
}
font-size: 1.4em;
text-align: center;
width: 1em;

View File

@ -38,6 +38,9 @@
flex-direction: row;
justify-content: flex-start;
flex-wrap: wrap;
@include mobile {
font-size: 1.2em;
}
}
&-field-wrap {
flex: 1;
@ -45,6 +48,14 @@
}
&-field {
width: 100%;
@include mobile {
font-size: 1.05em !important;
box-shadow: none !important;
border-radius: .6em !important;
border: none !important;
padding-left: 0.4em;
@include th { background-color: th(secondary-background-color) !important; }
}
}
&-icon-search {
@include th { color: th(muted-color); }
@ -55,6 +66,9 @@
&:hover {
@include th { color: th(medium-color); }
}
@include mobile {
top: .5em;
}
}
&-btn-new {
@include icon-btn;
@ -122,6 +136,13 @@
@include area-selected(right);
}
}
@include mobile {
margin: 0 $base-padding-h;
@include th { border-bottom: light-border(); }
&:last-of-type {
border-bottom: none;
}
}
&:not(.list__item--table) {
height: 3rem;
@ -135,6 +156,9 @@
margin-right: 2px;
width: 14px;
height: 14px;
@include mobile {
margin-right: 4px;
}
&--custom {
vertical-align: text-bottom;
&.yellow { @include filter(grayscale(1) sepia(1) hue-rotate(20deg) brightness(1.17) saturate(5.7)); }

View File

@ -36,10 +36,11 @@
}
}
@include mobile() {
&-i, &-svg { font-size: 4.6em; }
&-text { font-size: 1.1em; }
.open__icons--lower & {
margin: 8px;
&-i, &-svg { font-size: 2em; }
&-text { font-size: .5em; }
margin: 14px;
&-i, &-svg { font-size: 4.2em; margin-bottom: .1em; }
}
}
}

View File

@ -41,7 +41,12 @@
line-height: $mobile-back-button-height;
height: $mobile-back-button-height;
padding-bottom: $base-padding-v;
>i { margin-right: $base-padding-h; }
font-size: 1.2em;
>i {
margin-right: .3em;
font-size: 1.2em;
vertical-align: text-bottom;
}
&-pre { display: inline; }
}
@include nomobile {

View File

@ -3,8 +3,8 @@
<h1 class="at-select__header-text">{{res 'autoTypeHeader'}}</h1>
<div class="at-select__hint">
<div class="at-select__hint-text"><span class="shortcut">{{keyEnter}}</span>: {{selectionHintDefault}}</div>
<div class="at-select__hint-text"><span class="shortcut">{{actionSymbol}} {{keyEnter}}</span>: {{selectionHintAction}}</div>
<div class="at-select__hint-text"><span class="shortcut">{{altSymbol}} {{keyEnter}}</span>: {{selectionHintOpt}}</div>
<div class="at-select__hint-text"><span class="shortcut">{{{actionSymbol}}} {{keyEnter}}</span>: {{selectionHintAction}}</div>
<div class="at-select__hint-text"><span class="shortcut">{{{altSymbol}}} {{keyEnter}}</span>: {{selectionHintOpt}}</div>
</div>
{{#if filterText}}
<div class="at-select__header-filter">

View File

@ -1,6 +1,6 @@
<div class="details">
<div class="details__back-button">
<i class="fa fa-chevron-left"></i> {{res 'detBackToList'}}
<i class="fa fa-chevron-left"></i>{{res 'detBackToList'}}
</div>
<div class="details__header">
<i class="details__header-color fa fa-bookmark-o" title="{{res 'detSetIconColor'}}" tip-placement="left">

View File

@ -39,6 +39,8 @@
{{#if adv.regex}}checked{{/if}}><label for="list__search-adv-check-regex">{{res 'searchRegex'}}</label></div>
<div class="list__search-check"><input type="checkbox" id="list__search-adv-check-history" data-id="history"
{{#if adv.history}}checked{{/if}}><label for="list__search-adv-check-history">{{Res 'history'}}</label></div>
<div class="list__search-check"><input type="checkbox" id="list__search-adv-check-rank" data-id="rank"
{{#if adv.rank}}checked{{/if}}><label for="list__search-adv-check-rank">{{Res 'rank'}}</label></div>
</div>
</div>
</div>

View File

@ -141,6 +141,13 @@
<label for="settings__general-minimize">{{res 'setGenMinInstead'}}</label>
</div>
{{/if}}
{{#if canAutoType}}
<div>
<input type="checkbox" class="settings__input input-base settings__general-direct-autotype"
id="settings__general-direct-autotype" {{#if directAutotype}}checked{{/if}} />
<label for="settings__general-direct-autotype">{{res 'setGenDirectAutotype'}}</label>
</div>
{{/if}}
<h2>{{res 'setGenLock'}}</h2>
<div>
@ -194,8 +201,11 @@
<a class="settings__general-show-advanced">{{res 'setGenShowAdvanced'}}</a>
<div class="settings__general-advanced hide">
{{#if devTools}}
<button class="btn-silent settings__general-dev-tools-link">{{res 'setGenDevTools'}}</button>
<button class="btn-silent settings__general-try-beta-link">{{res 'setGenTryBeta'}}</button>
<button class="btn-silent settings__general-dev-tools-link">{{res 'setGenDevTools'}}</button>
<button class="btn-silent settings__general-try-beta-link">{{res 'setGenTryBeta'}}</button>
{{/if}}
{{#if showReloadApp}}
<button class="btn-silent settings__general-reload-app-link">{{res 'setGenReloadApp'}}</button>
{{/if}}
<button class="btn-silent settings__general-show-logs-link">{{res 'setGenShowAppLogs'}}</button>
</div>

View File

@ -1,6 +1,6 @@
<div class="settings">
<div class="settings__back-button">
<i class="fa fa-chevron-left settings__back-button-pre"></i> {{res 'retToApp'}} <i class="fa fa-external-link-square settings__back-button-post"></i>
<i class="fa fa-chevron-left settings__back-button-pre"></i>{{res 'retToApp'}} <i class="fa fa-external-link-square settings__back-button-post"></i>
</div>
<div class="scroller">
</div>

View File

@ -163,7 +163,7 @@ function createMainWindow() {
setMenu();
mainWindow.loadURL(htmlPath);
if (showDevToolsOnStart) {
mainWindow.openDevTools();
mainWindow.openDevTools({ mode: 'bottom' });
}
mainWindow.once('ready-to-show', () => {
mainWindow.show();
@ -327,7 +327,8 @@ function setMenu() {
{
label: 'Window',
submenu: [
{ accelerator: 'CmdOrCtrl+M', role: 'minimize' }
{ accelerator: 'CmdOrCtrl+M', role: 'minimize' },
{ accelerator: 'Command+W', role: 'close' }
]
}
];
@ -475,7 +476,7 @@ function hookRequestHeaders() {
// partially off-screen or straddling two displays if the user desires that.
function coerceMainWindowPositionToConnectedDisplay() {
const eScreen = require('electron').screen;
const eScreen = electron.screen;
const displays = eScreen.getAllDisplays();
if (!displays || !displays.length) return;
const windowBounds = mainWindow.getBounds();

View File

@ -1,6 +1,6 @@
{
"name": "KeeWeb",
"version": "1.7.8",
"version": "1.8.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "KeeWeb",
"version": "1.7.8",
"version": "1.8.0",
"description": "Free cross-platform password manager compatible with KeePass",
"main": "main.js",
"homepage": "https://keeweb.info",

37
dev-env.sh Normal file → Executable file
View File

@ -1,13 +1,32 @@
#!/usr/bin/env bash
echo Cloning KeeWeb into $PWD/keeweb...
SCHEMA=${SCHEMA:-http}
KEEWEB_GH=git@github.com:keeweb
if [[ "$SCHEMA" == 'http' ]]; then
KEEWEB_GH=https://github.com/keeweb
fi
echo "Cloning KeeWeb ($KEEWEB_GH) into $PWD/keeweb..."
mkdir keeweb
git clone git@github.com:keeweb/favicon-proxy.git keeweb/favicon-proxy
git clone git@github.com:keeweb/kdbxweb.git keeweb/kdbxweb
git clone git@github.com:keeweb/keeweb.git -b develop keeweb/keeweb
git clone git@github.com:keeweb/beta.keeweb.info.git keeweb/keeweb-beta
git clone git@github.com:keeweb/keeweb-site.git -b gh-pages keeweb/keeweb-site
git clone git@github.com:keeweb/keeweb-plugins.git keeweb/keeweb-plugins
git clone git@github.com:keeweb/keeweb.git -b gh-pages --single-branch keeweb/keeweb-dist
pushd keeweb >/dev/null
git clone $KEEWEB_GH/keeweb.git -b develop keeweb
pushd keeweb >/dev/null
git worktree add ../keeweb-dist gh-pages
popd >/dev/null
git clone $KEEWEB_GH/favicon-proxy.git favicon-proxy
git clone $KEEWEB_GH/kdbxweb.git kdbxweb
git clone $KEEWEB_GH/beta.keeweb.info.git keeweb-beta
git clone $KEEWEB_GH/keeweb-site.git -b gh-pages keeweb-site
git clone $KEEWEB_GH/keeweb-plugins.git keeweb-plugins
popd > /dev/null
mkdir keeweb/keys
echo kdbxweb/ > keeweb/.eslintignore
echo Done! KeeWeb is cloned into $PWD/keeweb
echo "Done! KeeWeb is cloned into $PWD/keeweb"

142
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "keeweb",
"version": "1.7.8",
"version": "1.8.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -4385,8 +4385,7 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"optional": true
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"aproba": {
"version": "1.2.0",
@ -4407,14 +4406,12 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"optional": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4429,20 +4426,17 @@
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"optional": true
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"optional": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"optional": true
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"core-util-is": {
"version": "1.0.2",
@ -4559,8 +4553,7 @@
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"optional": true
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ini": {
"version": "1.3.5",
@ -4572,7 +4565,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4587,7 +4579,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -4595,14 +4586,12 @@
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"optional": true
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minipass": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -4621,7 +4610,6 @@
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4702,8 +4690,7 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"optional": true
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"object-assign": {
"version": "4.1.1",
@ -4715,7 +4702,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4801,8 +4787,7 @@
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"optional": true
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"safer-buffer": {
"version": "2.1.2",
@ -4838,7 +4823,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -4858,7 +4842,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4902,14 +4885,12 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"optional": true
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"optional": true
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
}
}
},
@ -5353,7 +5334,7 @@
"version": "github:keeweb/grunt-contrib-deb#e9b6e9f6faab0f67512b4168a80b4dfbb0e0b68f",
"from": "github:keeweb/grunt-contrib-deb#e9b6e9f",
"requires": {
"ar-async": "git+https://github.com/JayCanuck/node-ar-async.git",
"ar-async": "git+https://github.com/JayCanuck/node-ar-async.git#cd5fa957b30db58d660d3f51bc64f16ab688c162",
"async": "^1.5.0",
"tar-stream": "^1.3.1"
}
@ -6193,8 +6174,7 @@
"imul": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz",
"integrity": "sha1-nVhnFh6LPelsLDjV3HyxAvNeKsk=",
"optional": true
"integrity": "sha1-nVhnFh6LPelsLDjV3HyxAvNeKsk="
},
"imurmurhash": {
"version": "0.1.4",
@ -6610,8 +6590,7 @@
"is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
"optional": true
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
},
"is-regex": {
"version": "1.0.4",
@ -6815,9 +6794,9 @@
"resolved": "https://registry.npmjs.org/kdbxweb/-/kdbxweb-1.2.6.tgz",
"integrity": "sha512-9KJlanItY6D2CmR/TN27HINwugSPNATD9yWq4V56JAxVUTY8WHveC5H0llLiyxgPHfr7eejPk8hmj98l/lq7Cw==",
"requires": {
"pako": "pako@github:keeweb/pako#653c0b00d8941c89d09ed4546d2179001ec44efc",
"text-encoding": "text-encoding@github:keeweb/text-encoding#4dfb7cb0954c222852092f8b06ae4f6b4f60bfbb",
"xmldom": "xmldom@github:keeweb/xmldom#ec8f61f723e2f403adaf7a1bbf55ced4ff1ea0c6"
"pako": "github:keeweb/pako#653c0b00d8941c89d09ed4546d2179001ec44efc",
"text-encoding": "github:keeweb/text-encoding#4dfb7cb0954c222852092f8b06ae4f6b4f60bfbb",
"xmldom": "github:keeweb/xmldom#ec8f61f723e2f403adaf7a1bbf55ced4ff1ea0c6"
},
"dependencies": {
"abbrev": {
@ -7544,8 +7523,7 @@
"ansi-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
"integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=",
"optional": true
"integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
},
"ansi-styles": {
"version": "2.2.1",
@ -7602,8 +7580,7 @@
"balanced-match": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
"integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
"optional": true
"integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
},
"bcrypt-pbkdf": {
"version": "1.0.0",
@ -7618,7 +7595,6 @@
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
"optional": true,
"requires": {
"inherits": "~2.0.0"
}
@ -7627,7 +7603,6 @@
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"optional": true,
"requires": {
"hoek": "2.x.x"
}
@ -7636,7 +7611,6 @@
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz",
"integrity": "sha1-cZfX6qm4fmSDkOph/GbIRCdCDfk=",
"optional": true,
"requires": {
"balanced-match": "^0.4.1",
"concat-map": "0.0.1"
@ -7645,8 +7619,7 @@
"buffer-shims": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
"integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
"optional": true
"integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E="
},
"caseless": {
"version": "0.11.0",
@ -7678,14 +7651,12 @@
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"optional": true
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@ -7702,20 +7673,17 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"optional": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"optional": true
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cryptiles": {
"version": "2.0.5",
@ -7761,8 +7729,7 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"optional": true
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
@ -7794,8 +7761,7 @@
"extsprintf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
"integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
"optional": true
"integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA="
},
"forever-agent": {
"version": "0.6.1",
@ -7817,14 +7783,12 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"optional": true
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fstream": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz",
"integrity": "sha1-YE6Kkv4m/9n2+uMDmdSYThqyKCI=",
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
@ -7896,7 +7860,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
"integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -7909,8 +7872,7 @@
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"optional": true
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"graceful-readlink": {
"version": "1.0.1",
@ -7960,8 +7922,7 @@
"hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
"optional": true
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
},
"http-signature": {
"version": "1.1.1",
@ -7978,7 +7939,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"optional": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@ -7987,8 +7947,7 @@
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"optional": true
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ini": {
"version": "1.3.4",
@ -8000,7 +7959,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -8032,8 +7990,7 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isstream": {
"version": "0.1.2",
@ -8088,14 +8045,12 @@
"mime-db": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
"integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I=",
"optional": true
"integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I="
},
"mime-types": {
"version": "2.1.13",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
"integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=",
"optional": true,
"requires": {
"mime-db": "~1.25.0"
}
@ -8104,7 +8059,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
"optional": true,
"requires": {
"brace-expansion": "^1.0.0"
}
@ -8112,14 +8066,12 @@
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"optional": true
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -8171,8 +8123,7 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"optional": true
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"oauth-sign": {
"version": "0.8.2",
@ -8190,7 +8141,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"optional": true,
"requires": {
"wrappy": "1"
}
@ -8198,8 +8148,7 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"optional": true
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pinkie": {
"version": "2.0.4",
@ -8219,8 +8168,7 @@
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
"optional": true
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"punycode": {
"version": "1.4.1",
@ -8301,7 +8249,6 @@
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
"integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=",
"optional": true,
"requires": {
"glob": "^7.0.5"
}
@ -8362,7 +8309,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -8372,8 +8318,7 @@
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"optional": true
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"stringstream": {
"version": "0.0.5",
@ -8385,7 +8330,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -8406,7 +8350,6 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
"optional": true,
"requires": {
"block-stream": "*",
"fstream": "^1.0.2",
@ -8485,8 +8428,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.0.1",
@ -8515,8 +8457,7 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"optional": true
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
@ -11230,8 +11171,7 @@
"path-key": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz",
"integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=",
"optional": true
"integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68="
},
"path-parse": {
"version": "1.0.6",

View File

@ -1,6 +1,6 @@
{
"name": "keeweb",
"version": "1.7.8",
"version": "1.8.0",
"description": "Free cross-platform password manager compatible with KeePass",
"main": "Gruntfile.js",
"private": true,
@ -87,6 +87,9 @@
"email": "antelle.net@gmail.com",
"url": "http://antelle.net"
},
"engines": {
"node": ">=10.0"
},
"license": "MIT",
"readme": "README.md"
}

View File

@ -1,5 +1,10 @@
Release notes
-------------
##### v1.8.0 (2019-03-31)
`+` iOS PWA improvements
`+` auto-type improvements
`*` website icons are downloaded using favicon.keeweb.info
##### v1.7.8 (2019-03-02)
`-` fix #1124: keyboard navigation issues
`*` improved link security