pull/1233/head
antelle 2019-08-16 23:05:39 +02:00
parent 68245629e4
commit 84a23e4aea
179 changed files with 7485 additions and 5091 deletions

View File

@ -1,7 +1,6 @@
{
"extends": "standard",
"extends": ["standard", "plugin:prettier/recommended"],
"rules": {
"indent": ["error", 4, { "SwitchCase": 1 }],
"semi": ["error", "always"],
"one-var": "off",
"space-before-function-paren": "off",

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"tabWidth": 4,
"singleQuote": true,
"printWidth": 120,
"trailingComma": "none",
"quoteProps": "preserve"
}

View File

@ -144,7 +144,7 @@ module.exports = function(grunt) {
eslint: {
app: ['app/scripts/**/*.js'],
desktop: ['desktop/**/*.js', '!desktop/node_modules/**'],
grunt: ['Gruntfile.js', 'grunt/**/*.js']
grunt: ['Gruntfile.js', 'build/**/*.js']
},
inline: {
app: {
@ -182,12 +182,21 @@ module.exports = function(grunt) {
files: { 'tmp/desktop/app/index.html': 'dist/index.html' }
},
'desktop-public-key': {
options: { replacements: [{ pattern: '\'@@PUBLIC_KEY_CONTENT\'', replacement:
'`' + fs.readFileSync('app/resources/public-key.pem', {encoding: 'utf8'}).trim() + '`' }] },
options: {
replacements: [
{
pattern: "'@@PUBLIC_KEY_CONTENT'",
replacement:
'`' + fs.readFileSync('app/resources/public-key.pem', { encoding: 'utf8' }).trim() + '`'
}
]
},
files: { 'tmp/desktop/app/main.js': 'desktop/main.js' }
},
'cordova-html': {
options: { replacements: [{ pattern: '<script', replacement: '<script src="cordova.js"></script><script' }] },
options: {
replacements: [{ pattern: '<script', replacement: '<script src="cordova.js"></script><script' }]
},
files: { 'tmp/cordova/app/index.html': 'dist/index.html' }
}
},
@ -239,9 +248,9 @@ module.exports = function(grunt) {
electronVersion: electronVersion,
overwrite: true,
asar: true,
'appCopyright': `Copyright © ${year} Antelle`,
'appVersion': pkg.version,
'buildVersion': '<%= gitinfo.local.branch.current.shortSHA %>'
appCopyright: `Copyright © ${year} Antelle`,
appVersion: pkg.version,
buildVersion: '<%= gitinfo.local.branch.current.shortSHA %>'
},
linux: {
options: {
@ -255,9 +264,9 @@ module.exports = function(grunt) {
platform: 'darwin',
arch: ['x64'],
icon: 'graphics/icon.icns',
'appBundleId': 'net.antelle.keeweb',
'appCategoryType': 'public.app-category.productivity',
'extendInfo': 'package/osx/extend.plist'
appBundleId: 'net.antelle.keeweb',
appCategoryType: 'public.app-category.productivity',
extendInfo: 'package/osx/extend.plist'
}
},
win32: {
@ -265,13 +274,13 @@ module.exports = function(grunt) {
platform: 'win32',
arch: ['ia32', 'x64'],
icon: 'graphics/icon.ico',
'buildVersion': pkg.version,
buildVersion: pkg.version,
'version-string': {
'CompanyName': 'KeeWeb',
'FileDescription': pkg.description,
'OriginalFilename': 'KeeWeb.exe',
'ProductName': 'KeeWeb',
'InternalName': 'KeeWeb'
CompanyName: 'KeeWeb',
FileDescription: pkg.description,
OriginalFilename: 'KeeWeb.exe',
ProductName: 'KeeWeb',
InternalName: 'KeeWeb'
}
}
}
@ -297,9 +306,7 @@ module.exports = function(grunt) {
},
'desktop-update': {
options: { archive: 'dist/desktop/UpdateDesktop.zip', comment: zipCommentPlaceholder },
files: [
{ cwd: 'tmp/desktop/update', src: '**', expand: true, nonull: true }
]
files: [{ cwd: 'tmp/desktop/update', src: '**', expand: true, nonull: true }]
},
'win32-x64': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.x64.zip` },
@ -311,13 +318,17 @@ module.exports = function(grunt) {
},
'linux-x64': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.x64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }]
files: [
{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }
]
},
'linux-ia32': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.ia32.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-ia32', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }]
files: [
{ cwd: 'tmp/desktop/KeeWeb-linux-ia32', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }
]
}
},
appdmg: {
@ -341,7 +352,9 @@ module.exports = function(grunt) {
options: {
vars: {
version: pkg.version,
rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); },
rev: function() {
return grunt.config.get('gitinfo.local.branch.current.shortSHA');
},
homepage: pkg.homepage
}
},
@ -383,7 +396,9 @@ module.exports = function(grunt) {
description: pkg.description,
author: pkg.author,
homepage: pkg.homepage,
rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); }
rev: function() {
return grunt.config.get('gitinfo.local.branch.current.shortSHA');
}
}
},
'linux-x64': {
@ -401,8 +416,18 @@ module.exports = function(grunt) {
},
files: [
{ cwd: 'package/deb/usr', src: '**', dest: '/usr', expand: true, nonull: true },
{ cwd: 'tmp/desktop/KeeWeb-linux-x64/', src: '**', dest: '/opt/keeweb-desktop', expand: true, nonull: true },
{ src: 'graphics/128x128.png', dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png', nonull: true }
{
cwd: 'tmp/desktop/KeeWeb-linux-x64/',
src: '**',
dest: '/opt/keeweb-desktop',
expand: true,
nonull: true
},
{
src: 'graphics/128x128.png',
dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png',
nonull: true
}
]
},
'linux-ia32': {
@ -420,8 +445,18 @@ module.exports = function(grunt) {
},
files: [
{ cwd: 'package/deb/usr', src: '**', dest: '/usr', expand: true, nonull: true },
{ cwd: 'tmp/desktop/KeeWeb-linux-ia32/', src: '**', dest: '/opt/keeweb-desktop', expand: true, nonull: true },
{ src: 'graphics/128x128.png', dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png', nonull: true }
{
cwd: 'tmp/desktop/KeeWeb-linux-ia32/',
src: '**',
dest: '/opt/keeweb-desktop',
expand: true,
nonull: true
},
{
src: 'graphics/128x128.png',
dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png',
nonull: true
}
]
}
},
@ -444,18 +479,14 @@ module.exports = function(grunt) {
desktop: {
options: {
file: 'dist/desktop/UpdateDesktop.zip',
expected: [
'app.asar',
'helper/darwin/KeeWebHelper',
'helper/win32/KeeWebHelper.exe'
],
expected: ['app.asar', 'helper/darwin/KeeWebHelper', 'helper/win32/KeeWebHelper.exe'],
expectedCount: 7,
publicKey: 'app/resources/public-key.pem'
}
}
},
'sign-html': {
'app': {
app: {
options: {
file: 'dist/index.html',
skip: grunt.option('skip-sign')
@ -521,7 +552,7 @@ module.exports = function(grunt) {
}
},
'sign-dist': {
'dist': {
dist: {
options: {
sign: 'dist/desktop/Verify.sign.sha256'
},

View File

@ -24,7 +24,7 @@ const FeatureDetector = require('./util/feature-detector');
const KdbxwebInit = require('./util/kdbxweb-init');
const Locale = require('./util/locale');
const ready = Launcher && Launcher.ready || $;
const ready = (Launcher && Launcher.ready) || $;
ready(() => {
if (AuthReceiver.receive() || FeatureDetector.isFrame) {
@ -51,16 +51,17 @@ ready(() => {
}
function ensureCanRun() {
return FeatureTester.test()
.catch(e => {
Alerts.error({
header: Locale.appSettingsError,
body: Locale.appNotSupportedError + '<br/><br/>' + e,
buttons: [],
esc: false, enter: false, click: false
});
throw 'Feature testing failed: ' + e;
return FeatureTester.test().catch(e => {
Alerts.error({
header: Locale.appSettingsError,
body: Locale.appNotSupportedError + '<br/><br/>' + e,
buttons: [],
esc: false,
enter: false,
click: false
});
throw 'Feature testing failed: ' + e;
});
}
function loadConfigs() {
@ -87,7 +88,9 @@ ready(() => {
header: Locale.appSettingsError,
body: Locale.appSettingsErrorBody,
buttons: [],
esc: false, enter: false, click: false
esc: false,
enter: false,
click: false
});
}
@ -96,42 +99,46 @@ ready(() => {
SettingsManager.setBySettings(appModel.settings);
const configParam = getConfigParam();
if (configParam) {
return appModel.loadConfig(configParam).then(() => {
SettingsManager.setBySettings(appModel.settings);
}).catch(e => {
if (!appModel.settings.get('cacheConfigSettings')) {
showSettingsLoadError();
throw e;
}
});
return appModel
.loadConfig(configParam)
.then(() => {
SettingsManager.setBySettings(appModel.settings);
})
.catch(e => {
if (!appModel.settings.get('cacheConfigSettings')) {
showSettingsLoadError();
throw e;
}
});
}
});
}
function showApp() {
return Promise.resolve()
.then(() => {
const skipHttpsWarning = localStorage.skipHttpsWarning || appModel.settings.get('skipHttpsWarning');
const protocolIsInsecure = ['https:', 'file:', 'app:'].indexOf(location.protocol) < 0;
const hostIsInsecure = location.hostname !== 'localhost';
if (protocolIsInsecure && hostIsInsecure && !skipHttpsWarning) {
return new Promise(resolve => {
Alerts.error({
header: Locale.appSecWarn, icon: 'user-secret', esc: false, enter: false, click: false,
body: Locale.appSecWarnBody1 + '<br/><br/>' + Locale.appSecWarnBody2,
buttons: [
{result: '', title: Locale.appSecWarnBtn, error: true}
],
complete: () => {
showView();
resolve();
}
});
return Promise.resolve().then(() => {
const skipHttpsWarning = localStorage.skipHttpsWarning || appModel.settings.get('skipHttpsWarning');
const protocolIsInsecure = ['https:', 'file:', 'app:'].indexOf(location.protocol) < 0;
const hostIsInsecure = location.hostname !== 'localhost';
if (protocolIsInsecure && hostIsInsecure && !skipHttpsWarning) {
return new Promise(resolve => {
Alerts.error({
header: Locale.appSecWarn,
icon: 'user-secret',
esc: false,
enter: false,
click: false,
body: Locale.appSecWarnBody1 + '<br/><br/>' + Locale.appSecWarnBody2,
buttons: [{ result: '', title: Locale.appSecWarnBtn, error: true }],
complete: () => {
showView();
resolve();
}
});
} else {
showView();
}
});
});
} else {
showView();
}
});
}
function postInit() {

View File

@ -17,14 +17,13 @@ AutoTypeFilter.prototype.getEntries = function() {
autoType: true
};
this.prepareFilter();
let entries = this.appModel.getEntriesByFilter(filter)
.map(e => [e, this.getEntryRank(e)]);
let entries = this.appModel.getEntriesByFilter(filter).map(e => [e, this.getEntryRank(e)]);
if (!this.ignoreWindowInfo) {
entries = entries.filter(e => e[1]);
}
entries = entries.sort((x, y) => x[1] === y[1] ? x[0].title.localeCompare(y[0].title) : y[1] - x[1]);
entries = entries.sort((x, y) => (x[1] === y[1] ? x[0].title.localeCompare(y[0].title) : y[1] - x[1]));
entries = entries.map(p => p[0]);
return new EntryCollection(entries, {comparator: 'none'});
return new EntryCollection(entries, { comparator: 'none' });
};
AutoTypeFilter.prototype.hasWindowInfo = function() {
@ -40,10 +39,7 @@ AutoTypeFilter.prototype.prepareFilter = function() {
AutoTypeFilter.prototype.getEntryRank = function(entry) {
let rank = 0;
if (this.titleLower && entry.title) {
rank += Ranking.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());

View File

@ -33,8 +33,12 @@ AutoTypeObfuscator.prototype.obfuscate = function() {
};
AutoTypeObfuscator.prototype.finished = function() {
return this.chars.length === this.inputChars.length &&
this.chars.every(function(ch, ix) { return this.inputChars[ix].ch === ch; }, this);
return (
this.chars.length === this.inputChars.length &&
this.chars.every(function(ch, ix) {
return this.inputChars[ix].ch === ch;
}, this)
);
};
AutoTypeObfuscator.prototype.step = function() {
@ -161,7 +165,7 @@ AutoTypeObfuscator.prototype.inputChar = function(ch) {
AutoTypeObfuscator.prototype.copyPaste = function(ch) {
logger.debug('copyPaste', ch);
this.ops.push({type: 'cmd', value: 'copyPaste', arg: ch});
this.ops.push({ type: 'cmd', value: 'copyPaste', arg: ch });
this.inputChars.splice(this.inputCursor, this.inputSel, { ch: ch });
this.inputCursor++;
this.inputSel = 0;
@ -174,10 +178,10 @@ AutoTypeObfuscator.prototype.selectText = function(backward, count) {
ops.push({ type: 'key', value: backward ? 'left' : 'right' });
}
if (ops.length === 1) {
ops[0].mod = {'+': true};
ops[0].mod = { '+': true };
this.ops.push(ops[0]);
} else {
this.ops.push({type: 'group', value: ops, mod: {'+': true}});
this.ops.push({ type: 'group', value: ops, mod: { '+': true } });
}
if (backward) {
this.inputCursor -= count;

View File

@ -16,39 +16,127 @@ const AutoTypeRunner = function(ops) {
AutoTypeRunner.PendingResolve = { pending: true };
AutoTypeRunner.Keys = {
tab: 'tab', enter: 'enter', space: 'space',
up: 'up', down: 'down', left: 'left', right: 'right', home: 'home', end: 'end', pgup: 'pgup', pgdn: 'pgdn',
insert: 'ins', ins: 'ins', delete: 'del', del: 'del', backspace: 'bs', bs: 'bs', bksp: 'bs', esc: 'esc',
win: 'win', lwin: 'win', rwin: 'rwin', f1: 'f1', f2: 'f2', f3: 'f3', f4: 'f4', f5: 'f5', f6: 'f6',
f7: 'f7', f8: 'f8', f9: 'f9', f10: 'f10', f11: 'f11', f12: 'f12', f13: 'f13', f14: 'f14', f15: 'f15', f16: 'f16',
add: 'add', subtract: 'subtract', multiply: 'multiply', divide: 'divide',
numpad0: 'n0', numpad1: 'n1', numpad2: 'n2', numpad3: 'n3', numpad4: 'n4',
numpad5: 'n5', numpad6: 'n6', numpad7: 'n7', numpad8: 'n8', numpad9: 'n9'
tab: 'tab',
enter: 'enter',
space: 'space',
up: 'up',
down: 'down',
left: 'left',
right: 'right',
home: 'home',
end: 'end',
pgup: 'pgup',
pgdn: 'pgdn',
insert: 'ins',
ins: 'ins',
delete: 'del',
del: 'del',
backspace: 'bs',
bs: 'bs',
bksp: 'bs',
esc: 'esc',
win: 'win',
lwin: 'win',
rwin: 'rwin',
f1: 'f1',
f2: 'f2',
f3: 'f3',
f4: 'f4',
f5: 'f5',
f6: 'f6',
f7: 'f7',
f8: 'f8',
f9: 'f9',
f10: 'f10',
f11: 'f11',
f12: 'f12',
f13: 'f13',
f14: 'f14',
f15: 'f15',
f16: 'f16',
add: 'add',
subtract: 'subtract',
multiply: 'multiply',
divide: 'divide',
numpad0: 'n0',
numpad1: 'n1',
numpad2: 'n2',
numpad3: 'n3',
numpad4: 'n4',
numpad5: 'n5',
numpad6: 'n6',
numpad7: 'n7',
numpad8: 'n8',
numpad9: 'n9'
};
AutoTypeRunner.Substitutions = {
title: function(runner, op) { return runner.getEntryFieldKeys('Title', op); },
username: function(runner, op) { return runner.getEntryFieldKeys('UserName', op); },
url: function(runner, op) { return runner.getEntryFieldKeys('URL', op); },
password: function(runner, op) { return runner.getEntryFieldKeys('Password', op); },
notes: function(runner, op) { return runner.getEntryFieldKeys('Notes', op); },
group: function(runner) { return runner.getEntryGroupName(); },
totp: function(runner, op) { return runner.getOtp(op); },
s: function(runner, op) { return runner.getEntryFieldKeys(op.arg, op); },
'dt_simple': function(runner) { return runner.dt('simple'); },
'dt_year': function(runner) { return runner.dt('Y'); },
'dt_month': function(runner) { return runner.dt('M'); },
'dt_day': function(runner) { return runner.dt('D'); },
'dt_hour': function(runner) { return runner.dt('h'); },
'dt_minute': function(runner) { return runner.dt('m'); },
'dt_second': function(runner) { return runner.dt('s'); },
'dt_utc_simple': function(runner) { return runner.udt('simple'); },
'dt_utc_year': function(runner) { return runner.udt('Y'); },
'dt_utc_month': function(runner) { return runner.udt('M'); },
'dt_utc_day': function(runner) { return runner.udt('D'); },
'dt_utc_hour': function(runner) { return runner.udt('h'); },
'dt_utc_minute': function(runner) { return runner.udt('m'); },
'dt_utc_second': function(runner) { return runner.udt('s'); }
title: function(runner, op) {
return runner.getEntryFieldKeys('Title', op);
},
username: function(runner, op) {
return runner.getEntryFieldKeys('UserName', op);
},
url: function(runner, op) {
return runner.getEntryFieldKeys('URL', op);
},
password: function(runner, op) {
return runner.getEntryFieldKeys('Password', op);
},
notes: function(runner, op) {
return runner.getEntryFieldKeys('Notes', op);
},
group: function(runner) {
return runner.getEntryGroupName();
},
totp: function(runner, op) {
return runner.getOtp(op);
},
s: function(runner, op) {
return runner.getEntryFieldKeys(op.arg, op);
},
'dt_simple': function(runner) {
return runner.dt('simple');
},
'dt_year': function(runner) {
return runner.dt('Y');
},
'dt_month': function(runner) {
return runner.dt('M');
},
'dt_day': function(runner) {
return runner.dt('D');
},
'dt_hour': function(runner) {
return runner.dt('h');
},
'dt_minute': function(runner) {
return runner.dt('m');
},
'dt_second': function(runner) {
return runner.dt('s');
},
'dt_utc_simple': function(runner) {
return runner.udt('simple');
},
'dt_utc_year': function(runner) {
return runner.udt('Y');
},
'dt_utc_month': function(runner) {
return runner.udt('M');
},
'dt_utc_day': function(runner) {
return runner.udt('D');
},
'dt_utc_hour': function(runner) {
return runner.udt('h');
},
'dt_utc_minute': function(runner) {
return runner.udt('m');
},
'dt_utc_second': function(runner) {
return runner.udt('s');
}
};
AutoTypeRunner.prototype.resolve = function(entry, callback) {
@ -103,7 +191,7 @@ AutoTypeRunner.prototype.resolveOp = function(op) {
op.value = [];
const count = +op.arg;
for (let i = 0; i < count; i++) {
op.value.push({type: 'key', value: key});
op.value.push({ type: 'key', value: key });
}
} else {
// {TAB}
@ -179,9 +267,9 @@ AutoTypeRunner.prototype.getEntryFieldKeys = function(field, op) {
const ops = [];
value.forEachChar(ch => {
if (ch === 10 || ch === 13) {
ops.push({type: 'key', value: 'enter'});
ops.push({ type: 'key', value: 'enter' });
} else {
ops.push({type: 'text', value: String.fromCharCode(ch)});
ops.push({ type: 'text', value: String.fromCharCode(ch) });
}
});
return ops;
@ -194,10 +282,10 @@ AutoTypeRunner.prototype.getEntryFieldKeys = function(field, op) {
const partsOps = [];
parts.forEach(part => {
if (partsOps.length) {
partsOps.push({type: 'key', value: 'enter'});
partsOps.push({ type: 'key', value: 'enter' });
}
if (part) {
partsOps.push({type: 'text', value: part});
partsOps.push({ type: 'text', value: part });
}
});
return partsOps;

View File

@ -3,15 +3,53 @@ const AutoTypeNativeHelper = require('../helper/auto-type-native-helper');
// http://eastmanreference.com/complete-list-of-applescript-key-codes/
const KeyMap = {
tab: 48, enter: 36, space: 49,
up: 126, down: 125, left: 123, right: 124, home: 115, end: 119, pgup: 116, pgdn: 121,
ins: 114, del: 117, bs: 51, esc: 53,
win: 55, rwin: 55,
f1: 122, f2: 120, f3: 99, f4: 118, f5: 96, f6: 97, f7: 98, f8: 100, f9: 101,
f10: 109, f11: 103, f12: 111, f13: 105, f14: 107, f15: 113, f16: 106,
add: 69, subtract: 78, multiply: 67, divide: 75,
n0: 82, n1: 83, n2: 84, n3: 85, n4: 86,
n5: 87, n6: 88, n7: 89, n8: 91, n9: 92
tab: 48,
enter: 36,
space: 49,
up: 126,
down: 125,
left: 123,
right: 124,
home: 115,
end: 119,
pgup: 116,
pgdn: 121,
ins: 114,
del: 117,
bs: 51,
esc: 53,
win: 55,
rwin: 55,
f1: 122,
f2: 120,
f3: 99,
f4: 118,
f5: 96,
f6: 97,
f7: 98,
f8: 100,
f9: 101,
f10: 109,
f11: 103,
f12: 111,
f13: 105,
f14: 107,
f15: 113,
f16: 106,
add: 69,
subtract: 78,
multiply: 67,
divide: 75,
n0: 82,
n1: 83,
n2: 84,
n3: 85,
n4: 86,
n5: 87,
n6: 88,
n7: 89,
n8: 91,
n9: 92
};
const ModMap = {

View File

@ -3,15 +3,53 @@ const Locale = require('../../util/locale');
// https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
const KeyMap = {
tab: 'Tab', enter: 'KP_Enter', space: 'KP_Space',
up: 'Up', down: 'Down', left: 'Left', right: 'Right', home: 'Home', end: 'End', pgup: 'Page_Up', pgdn: 'Page_Down',
ins: 'Insert', del: 'Delete', bs: 'BackSpace', esc: 'Escape',
win: 'Meta_L', rwin: 'Meta_R',
f1: 'F1', f2: 'F2', f3: 'F3', f4: 'F4', f5: 'F5', f6: 'F6', f7: 'F7', f8: 'F8', f9: 'F9',
f10: 'F10', f11: 'F11', f12: 'F12', f13: 'F13', f14: 'F14', f15: 'F15', f16: 'F16',
add: 'KP_Add', subtract: 'KP_Subtract', multiply: 'KP_Multiply', divide: 'KP_Divide',
n0: 'KP_0', n1: 'KP_1', n2: 'KP_2', n3: 'KP_3', n4: 'KP_4',
n5: 'KP_5', n6: 'KP_6', n7: 'KP_7', n8: 'KP_8', n9: 'KP_9'
tab: 'Tab',
enter: 'KP_Enter',
space: 'KP_Space',
up: 'Up',
down: 'Down',
left: 'Left',
right: 'Right',
home: 'Home',
end: 'End',
pgup: 'Page_Up',
pgdn: 'Page_Down',
ins: 'Insert',
del: 'Delete',
bs: 'BackSpace',
esc: 'Escape',
win: 'Meta_L',
rwin: 'Meta_R',
f1: 'F1',
f2: 'F2',
f3: 'F3',
f4: 'F4',
f5: 'F5',
f6: 'F6',
f7: 'F7',
f8: 'F8',
f9: 'F9',
f10: 'F10',
f11: 'F11',
f12: 'F12',
f13: 'F13',
f14: 'F14',
f15: 'F15',
f16: 'F16',
add: 'KP_Add',
subtract: 'KP_Subtract',
multiply: 'KP_Multiply',
divide: 'KP_Divide',
n0: 'KP_0',
n1: 'KP_1',
n2: 'KP_2',
n3: 'KP_3',
n4: 'KP_4',
n5: 'KP_5',
n6: 'KP_6',
n7: 'KP_7',
n8: 'KP_8',
n9: 'KP_9'
};
const ModMap = {
@ -69,7 +107,7 @@ AutoTypeEmitter.prototype.copyPaste = function(text) {
};
AutoTypeEmitter.prototype.wait = function(time) {
this.pendingScript.push('sleep ' + (time / 1000));
this.pendingScript.push('sleep ' + time / 1000);
this.callback();
};

View File

@ -3,15 +3,53 @@ const AutoTypeNativeHelper = require('../helper/auto-type-native-helper');
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
const KeyMap = {
tab: 0x09, enter: 0x0D, space: 0x20,
up: 0x26, down: 0x28, left: 0x25, right: 0x27, home: 0x24, end: 0x23, pgup: 0x21, pgdn: 0x22,
ins: 0x2D, del: 0x2E, bs: 0x08, esc: 0x1B,
win: 0x5B, rwin: 0x5C,
f1: 0x70, f2: 0x71, f3: 0x72, f4: 0x73, f5: 0x74, f6: 0x75, f7: 0x76, f8: 0x77, f9: 0x78,
f10: 0x79, f11: 0x7A, f12: 0x7B, f13: 0x7C, f14: 0x7D, f15: 0x7E, f16: 0x7F,
add: 0x6B, subtract: 0x6D, multiply: 0x6A, divide: 0x6F,
n0: 0x30, n1: 0x31, n2: 0x32, n3: 0x33, n4: 0x34,
n5: 0x35, n6: 0x36, n7: 0x37, n8: 0x38, n9: 0x39
tab: 0x09,
enter: 0x0d,
space: 0x20,
up: 0x26,
down: 0x28,
left: 0x25,
right: 0x27,
home: 0x24,
end: 0x23,
pgup: 0x21,
pgdn: 0x22,
ins: 0x2d,
del: 0x2e,
bs: 0x08,
esc: 0x1b,
win: 0x5b,
rwin: 0x5c,
f1: 0x70,
f2: 0x71,
f3: 0x72,
f4: 0x73,
f5: 0x74,
f6: 0x75,
f7: 0x76,
f8: 0x77,
f9: 0x78,
f10: 0x79,
f11: 0x7a,
f12: 0x7b,
f13: 0x7c,
f14: 0x7d,
f15: 0x7e,
f16: 0x7f,
add: 0x6b,
subtract: 0x6d,
multiply: 0x6a,
divide: 0x6f,
n0: 0x30,
n1: 0x31,
n2: 0x32,
n3: 0x33,
n4: 0x34,
n5: 0x35,
n6: 0x36,
n7: 0x37,
n8: 0x38,
n9: 0x39
};
const ModMap = {

View File

@ -1,13 +1,17 @@
const Launcher = require('../../comp/launcher');
const ForeMostAppScript = 'tell application "System Events" to set frontApp to name of first process whose frontmost is true';
const ChromeScript = 'tell application "{}" to set appUrl to URL of active tab of front window\n' +
const ForeMostAppScript =
'tell application "System Events" to set frontApp to name of first process whose frontmost is true';
const ChromeScript =
'tell application "{}" to set appUrl to URL of active tab of front window\n' +
'tell application "{}" to set appTitle to title of active tab of front window\n' +
'return appUrl & "\n" & appTitle';
const SafariScript = 'tell application "{}" to set appUrl to URL of front document\n' +
const SafariScript =
'tell application "{}" to set appUrl to URL of front document\n' +
'tell application "{}" to set appTitle to name of front document\n' +
'return appUrl & "\n" & appTitle';
const OtherAppsScript = 'tell application "System Events"\n' +
const OtherAppsScript =
'tell application "System Events"\n' +
' tell process "{}"\n' +
' tell (1st window whose value of attribute "AXMain" is true)\n' +
' set windowTitle to value of attribute "AXTitle"\n' +
@ -15,12 +19,13 @@ const OtherAppsScript = 'tell application "System Events"\n' +
' end tell\n' +
'end tell';
const AutoTypeHelper = function() {
};
const AutoTypeHelper = function() {};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
AutoTypeHelper.exec(ForeMostAppScript, (err, out) => {
if (err) { return callback(err); }
if (err) {
return callback(err);
}
const appName = out.trim();
// getting urls and titles from Chrome or Safari:
// - will suit in 90% cases
@ -28,20 +33,26 @@ AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
// - allows to get url
if (['Google Chrome', 'Chromium', 'Google Chrome Canary'].indexOf(appName) >= 0) {
AutoTypeHelper.exec(ChromeScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
if (err) {
return callback(err);
}
const parts = out.split('\n');
return callback(null, (parts[1] || '').trim(), parts[0].trim());
});
} else if (['Safari', 'Webkit'].indexOf(appName) >= 0) {
AutoTypeHelper.exec(SafariScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
if (err) {
return callback(err);
}
const parts = out.split('\n');
return callback(null, (parts[1] || '').trim(), parts[0].trim());
});
} else {
// special cases are not available. this method may ask the user about assistive access
AutoTypeHelper.exec(OtherAppsScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
if (err) {
return callback(err);
}
return callback(null, out.trim());
});
}

View File

@ -1,7 +1,6 @@
const Launcher = require('../../comp/launcher');
const AutoTypeHelper = function() {
};
const AutoTypeHelper = function() {};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
Launcher.spawn({

View File

@ -1,18 +1,18 @@
const Launcher = require('../../comp/launcher');
const AutoTypeNativeHelper = require('./auto-type-native-helper');
const AutoTypeHelper = function() {
};
const AutoTypeHelper = function() {};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
Launcher.spawn({
cmd: AutoTypeNativeHelper.getHelperPath(),
args: ['--window-info'],
complete: function(err, out) {
if (err) { return callback(err); }
if (err) {
return callback(err);
}
const parts = out.split('\n');
return callback(null, (parts[0] || '').trim(),
parts[1] ? parts[1].trim() : undefined);
return callback(null, (parts[0] || '').trim(), parts[1] ? parts[1].trim() : undefined);
}
});
};

View File

@ -31,14 +31,16 @@ const AutoType = {
},
handleEvent(e) {
const entry = e && e.entry || null;
const entry = (e && e.entry) || null;
logger.debug('Auto type event', entry);
if (this.running) {
logger.debug('Already running, skipping event');
return;
}
if (entry) {
this.hideWindow(() => { this.runAndHandleResult({ entry }); });
this.hideWindow(() => {
this.runAndHandleResult({ entry });
});
} else {
if (this.selectEntryView) {
return;
@ -180,7 +182,7 @@ const AutoType = {
selectEntryAndRun() {
this.getActiveWindowTitle((e, title, url) => {
const filter = new AutoTypeFilter({title, url}, this.appModel);
const filter = new AutoTypeFilter({ title, url }, this.appModel);
const evt = { filter };
if (!this.appModel.files.hasOpenFiles()) {
this.pendingEvent = evt;
@ -224,10 +226,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);
Backbone.once(
'closed-open-view',
() => {
this.selectEntryView.show();
this.selectEntryView.setupKeys();
},
this
);
});
},

View File

@ -19,7 +19,9 @@ 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()
},
@ -28,7 +30,7 @@ const EntryCollection = Backbone.Collection.extend({
filter: null,
initialize: function(models, options) {
const comparatorName = options && options.comparator || this.defaultComparator;
const comparatorName = (options && options.comparator) || this.defaultComparator;
this.comparator = this.comparators[comparatorName];
},

View File

@ -5,30 +5,31 @@ const SettingsStore = require('../comp/settings-store');
const FileInfoCollection = Backbone.Collection.extend({
model: FileInfoModel,
initialize: function () {
},
initialize: function() {},
load: function () {
load: function() {
return SettingsStore.load('file-info').then(data => {
if (data) {
this.reset(data, {silent: true});
this.reset(data, { silent: true });
}
});
},
save: function () {
save: function() {
SettingsStore.save('file-info', this.toJSON());
},
getLast: function () {
getLast: function() {
return this.first();
},
getMatch: function (storage, name, path) {
getMatch: function(storage, name, path) {
return this.find(fi => {
return (fi.get('storage') || '') === (storage || '') &&
return (
(fi.get('storage') || '') === (storage || '') &&
(fi.get('name') || '') === (name || '') &&
(fi.get('path') || '') === (path || '');
(fi.get('path') || '') === (path || '')
);
});
},

View File

@ -5,10 +5,30 @@ const Alerts = {
alertDisplayed: false,
buttons: {
ok: {result: 'yes', get title() { return Locale.alertOk; }},
yes: {result: 'yes', get title() { return Locale.alertYes; }},
no: {result: '', get title() { return Locale.alertNo; }},
cancel: {result: '', get title() { return Locale.alertCancel; }}
ok: {
result: 'yes',
get title() {
return Locale.alertOk;
}
},
yes: {
result: 'yes',
get title() {
return Locale.alertYes;
}
},
no: {
result: '',
get title() {
return Locale.alertNo;
}
},
cancel: {
result: '',
get title() {
return Locale.alertCancel;
}
}
},
alert: function(config) {
@ -46,39 +66,54 @@ const Alerts = {
},
info: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'info',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
}, config));
this.alert(
_.extend(
{
header: '',
body: '',
icon: 'info',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
},
config
)
);
},
error: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'exclamation-circle',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
}, config));
this.alert(
_.extend(
{
header: '',
body: '',
icon: 'exclamation-circle',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
},
config
)
);
},
yesno: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'question',
buttons: [this.buttons.yes, this.buttons.no],
esc: '',
click: '',
enter: 'yes'
}, config));
this.alert(
_.extend(
{
header: '',
body: '',
icon: 'question',
buttons: [this.buttons.yes, this.buttons.no],
esc: '',
click: '',
enter: 'yes'
},
config
)
);
}
};

View File

@ -37,13 +37,13 @@ const AppRightsChecker = {
this.alert = Alerts.alert({
icon: 'lock',
header: Locale.appRightsAlert,
body: Locale.appRightsAlertBody1.replace('{}', `<code>${this.AppPath}</code>`) +
'<br/>' + Locale.appRightsAlertBody2 + `: <pre>${command}</pre>`,
buttons: [
{result: 'skip', title: Locale.alertDoNotAsk, error: true},
Alerts.buttons.ok
],
success: (result) => {
body:
Locale.appRightsAlertBody1.replace('{}', `<code>${this.AppPath}</code>`) +
'<br/>' +
Locale.appRightsAlertBody2 +
`: <pre>${command}</pre>`,
buttons: [{ result: 'skip', title: Locale.alertDoNotAsk, error: true }, Alerts.buttons.ok],
success: result => {
if (result === 'skip') {
this.dontAskAnymore();
}
@ -54,7 +54,7 @@ const AppRightsChecker = {
runInstaller() {
Launcher.spawn({
cmd: this.AppPath + '/Contents/Installer/KeeWeb\ Installer.app/Contents/MacOS/applet',
cmd: this.AppPath + '/Contents/Installer/KeeWeb Installer.app/Contents/MacOS/applet',
complete: () => {
this.needRunInstaller(needRun => {
if (this.alert && !needRun) {

View File

@ -21,13 +21,13 @@ const CopyPaste = {
Backbone.off('main-window-will-close', clearClipboard);
}, clipboardSeconds * 1000);
}
return {success: true, seconds: clipboardSeconds};
return { success: true, seconds: clipboardSeconds };
} else {
try {
if (document.execCommand('copy')) {
return {success: true};
return { success: true };
}
} catch (e) { }
} catch (e) {}
return false;
}
},
@ -41,8 +41,12 @@ const CopyPaste = {
hiddenInput[0].selectionEnd = text.length;
hiddenInput.focus();
hiddenInput.on({
'copy cut paste': function() { setTimeout(() => hiddenInput.blur(), 0); },
blur: function() { hiddenInput.remove(); }
'copy cut paste': function() {
setTimeout(() => hiddenInput.blur(), 0);
},
blur: function() {
hiddenInput.remove();
}
});
}
};

View File

@ -37,7 +37,12 @@ DropboxChooser.prototype.buildUrl = function() {
iframe: 'false',
version: 2
};
return 'https://www.dropbox.com/chooser?' + Object.keys(urlParams).map(key => key + '=' + urlParams[key]).join('&');
return (
'https://www.dropbox.com/chooser?' +
Object.keys(urlParams)
.map(key => key + '=' + urlParams[key])
.join('&')
);
};
DropboxChooser.prototype.onMessage = function(e) {

View File

@ -2,9 +2,15 @@ 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); },
del: function(key) { AppSettingsModel.instance.unset(key); }
get: function(key) {
return key ? AppSettingsModel.instance.get(key) : AppSettingsModel.instance.toJSON();
},