mirror of https://github.com/keeweb/keeweb.git
added fingerprint hooks
This commit is contained in:
parent
0820394e50
commit
159d08d6c2
|
@ -0,0 +1,194 @@
|
|||
'use strict';
|
||||
|
||||
const Alerts = require('../comp/alerts');
|
||||
// const Locale = require('../util/locale');
|
||||
|
||||
const Launcher = {
|
||||
name: 'android',
|
||||
version: '6.0.0',
|
||||
autoTypeSupported: false,
|
||||
ready: function(callback) {
|
||||
document.addEventListener('deviceready', () => {
|
||||
callback();
|
||||
// window.addEventListener('filePluginIsReady', () => {}, false);
|
||||
}, false);
|
||||
},
|
||||
platform: function() {
|
||||
return 'cordova';
|
||||
},
|
||||
openLink: function(href) {
|
||||
window.open(href, '_system');
|
||||
},
|
||||
getSaveFileName: function(defaultPath, callback) {
|
||||
if (defaultPath) {
|
||||
defaultPath = [this.externalRoot, defaultPath].join('/');
|
||||
|
||||
Alerts.yesno({
|
||||
header: 'Save file',
|
||||
body: defaultPath,
|
||||
success: () => {
|
||||
callback(defaultPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getDir: function() {
|
||||
const storagePath = window.cordova.file.externalDataDirectory;
|
||||
return [storagePath].concat(Array.from(arguments)).filter(s => !!s);
|
||||
},
|
||||
getUserDataPath: function(fileName) {
|
||||
return this.getDir('userdata', fileName).join('/');
|
||||
},
|
||||
getTempPath: function(fileName) {
|
||||
return this.getDir('temp', fileName).join('/');
|
||||
},
|
||||
getDocumentsPath: function(fileName) {
|
||||
return this.getDir('documents', fileName).join('/');
|
||||
},
|
||||
getAppPath: function(fileName) {
|
||||
return this.getDir(fileName).join('/');
|
||||
},
|
||||
getWorkDirPath: function(fileName) {
|
||||
return this.getDir(fileName).join('/');
|
||||
},
|
||||
writeFile: function(path, data, callback) {
|
||||
const writeFile = fileEntry => {
|
||||
fileEntry.createWriter(fileWriter => {
|
||||
fileWriter.onerror = callback;
|
||||
fileWriter.onwriteend = () => callback();
|
||||
fileWriter.write(data);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
const createDir = (dirEntry, path, callback) => {
|
||||
const name = path.shift();
|
||||
dirEntry.getDirectory(name, { create: true }, dirEntry => {
|
||||
if (path.length) { // there is more to create
|
||||
createDir(dirEntry, path, callback);
|
||||
} else {
|
||||
callback(dirEntry);
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
if (path.startsWith(this.appStorage)) { // file://
|
||||
const localPath = path.replace(this.appStorage, '').split('/').filter(s => !!s);
|
||||
const fileName = localPath.pop();
|
||||
|
||||
if (localPath.length) {
|
||||
window.resolveLocalFileSystemURL(this.appStorage, dirEntry => {
|
||||
createDir(dirEntry, localPath, destDir => {
|
||||
destDir.getFile(fileName, { create: true }, writeFile, callback, callback);
|
||||
});
|
||||
}, callback);
|
||||
} else {
|
||||
window.resolveLocalFileSystemURL(path, writeFile, callback, callback);
|
||||
}
|
||||
} else { // cdvfile://
|
||||
window.resolveLocalFileSystemURL(path, writeFile, callback, callback);
|
||||
}
|
||||
},
|
||||
readFile: function(path, encoding, callback) {
|
||||
window.resolveLocalFileSystemURL(path, fileEntry => {
|
||||
fileEntry.file(file => {
|
||||
const reader = new FileReader();
|
||||
reader.onerror = callback;
|
||||
reader.onloadend = () => {
|
||||
const contents = new Uint8Array(reader.result);
|
||||
callback(encoding ? String.fromCharCode.apply(null, contents) : contents);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}, err => callback(undefined, err));
|
||||
}, err => callback(undefined, err));
|
||||
},
|
||||
fileExists: function(path, callback) {
|
||||
window.resolveLocalFileSystemURL(path, fileEntry => callback(true), err => callback(false)); // eslint-disable-line handle-callback-err
|
||||
},
|
||||
deleteFile: function(path, callback) {
|
||||
window.resolveLocalFileSystemURL(path, fileEntry => {
|
||||
fileEntry.remove(callback, callback, callback);
|
||||
}, callback);
|
||||
},
|
||||
statFile: function(path, callback) {
|
||||
window.resolveLocalFileSystemURL(path, fileEntry => {
|
||||
fileEntry.file(file => {
|
||||
callback({
|
||||
ctime: new Date(file.lastModified),
|
||||
mtime: new Date(file.lastModified)
|
||||
});
|
||||
}, err => callback(undefined, err));
|
||||
}, err => callback(undefined, err));
|
||||
},
|
||||
mkdir: function(dir) {
|
||||
// TODO
|
||||
},
|
||||
parsePath: function(fileName) {
|
||||
const parts = fileName.split('/');
|
||||
|
||||
return {
|
||||
path: fileName,
|
||||
dir: parts.pop(),
|
||||
file: parts.join('/')
|
||||
};
|
||||
},
|
||||
createFsWatcher: function(path) {
|
||||
return null; // not in android with content provider
|
||||
},
|
||||
preventExit: function(e) {
|
||||
e.returnValue = false;
|
||||
return false;
|
||||
},
|
||||
exit: function() {
|
||||
// skip
|
||||
},
|
||||
requestRestart: function() {
|
||||
window.location.reload();
|
||||
},
|
||||
cancelRestart: function() {
|
||||
// skip
|
||||
},
|
||||
setClipboardText: function(text) {
|
||||
return document.execCommand('copy');
|
||||
},
|
||||
getClipboardText: function() {
|
||||
// TODO
|
||||
},
|
||||
clearClipboardText: function() {
|
||||
// TODO
|
||||
},
|
||||
minimizeApp: function() {
|
||||
this.hideApp();
|
||||
},
|
||||
canMinimize: function() {
|
||||
return true;
|
||||
},
|
||||
updaterEnabled: function() {
|
||||
return false;
|
||||
},
|
||||
resolveProxy: function(url, callback) {
|
||||
// TODO
|
||||
},
|
||||
openWindow: function(opts) {
|
||||
// skip
|
||||
},
|
||||
hideApp: function() { // home button
|
||||
// TODO
|
||||
},
|
||||
isAppFocused: function() {
|
||||
return false; // skip
|
||||
},
|
||||
showMainWindow: function() {
|
||||
// skip
|
||||
},
|
||||
|
||||
fingerprints: {
|
||||
register: function(appModel, fileInfo, password) {
|
||||
|
||||
},
|
||||
auth: function(fileInfo, callback) {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Launcher;
|
|
@ -3,7 +3,7 @@ let Launcher;
|
|||
if (window.process && window.process.versions && window.process.versions.electron) {
|
||||
Launcher = require('./launcher-electron');
|
||||
} else if (window.cordova) {
|
||||
// Launcher = require('./launcher-cordova');
|
||||
Launcher = require('./launcher-cordova');
|
||||
}
|
||||
|
||||
module.exports = Launcher;
|
||||
|
|
|
@ -16,6 +16,7 @@ const FeatureDetector = require('../util/feature-detector');
|
|||
const Format = require('../util/format');
|
||||
const UrlUtil = require('../util/url-util');
|
||||
const AutoType = require('../auto-type');
|
||||
const Launcher = require('../comp/launcher');
|
||||
|
||||
require('../mixins/protected-value-ex');
|
||||
|
||||
|
@ -489,7 +490,7 @@ const AppModel = Backbone.Model.extend({
|
|||
}
|
||||
const rev = params.rev || fileInfo && fileInfo.get('rev');
|
||||
this.setFileOpts(file, params.opts);
|
||||
this.addToLastOpenFiles(file, rev);
|
||||
this.addToLastOpenFiles(file, fileInfo, params.password, rev);
|
||||
this.addFile(file);
|
||||
callback(null, file);
|
||||
this.fileOpened(file, data);
|
||||
|
@ -515,7 +516,7 @@ const AppModel = Backbone.Model.extend({
|
|||
});
|
||||
},
|
||||
|
||||
addToLastOpenFiles: function(file, rev) {
|
||||
addToLastOpenFiles: function(file, existing, password, rev) {
|
||||
this.appLogger.debug('Add last open file', file.id, file.get('name'), file.get('storage'), file.get('path'), rev);
|
||||
const dt = new Date();
|
||||
const fileInfo = new FileInfoModel({
|
||||
|
@ -529,7 +530,8 @@ const AppModel = Backbone.Model.extend({
|
|||
rev: rev,
|
||||
syncDate: file.get('syncDate') || dt,
|
||||
openDate: dt,
|
||||
backup: file.get('backup')
|
||||
backup: file.get('backup'),
|
||||
fingerprint: existing && existing.get('fingerprint')
|
||||
});
|
||||
switch (this.settings.get('rememberKeyFiles')) {
|
||||
case 'data':
|
||||
|
@ -547,6 +549,10 @@ const AppModel = Backbone.Model.extend({
|
|||
this.fileInfos.remove(file.id);
|
||||
this.fileInfos.unshift(fileInfo);
|
||||
this.fileInfos.save();
|
||||
|
||||
if (Launcher.fingerprints && !existing) {
|
||||
Launcher.fingerprints.register(this, fileInfo, password);
|
||||
}
|
||||
},
|
||||
|
||||
getStoreOpts: function(file) {
|
||||
|
|
|
@ -14,7 +14,8 @@ const FileInfoModel = Backbone.Model.extend({
|
|||
keyFileName: null,
|
||||
keyFileHash: null,
|
||||
opts: null,
|
||||
backup: null
|
||||
backup: null,
|
||||
fingerprint: null
|
||||
},
|
||||
|
||||
initialize: function(data, options) {
|
||||
|
|
|
@ -11,10 +11,12 @@ const Locale = require('../util/locale');
|
|||
const UrlUtil = require('../util/url-util');
|
||||
const InputFx = require('../util/input-fx');
|
||||
const Storage = require('../storage');
|
||||
const Launcher = require('../comp/launcher');
|
||||
|
||||
const logger = new Logger('open-view');
|
||||
|
||||
const OpenView = Backbone.View.extend({
|
||||
|
||||
template: require('templates/open.hbs'),
|
||||
|
||||
events: {
|
||||
|
@ -317,7 +319,12 @@ const OpenView = Backbone.View.extend({
|
|||
openAny: function(reading, ext) {
|
||||
this.reading = reading;
|
||||
this.params[reading] = null;
|
||||
this.$el.find('.open__file-ctrl').attr('accept', ext || '').val(null).click();
|
||||
|
||||
if (Launcher && Launcher.openFileChooser) {
|
||||
Launcher.openFileChooser(this);
|
||||
} else {
|
||||
this.$el.find('.open__file-ctrl').attr('accept', ext || '').val(null).click();
|
||||
}
|
||||
},
|
||||
|
||||
openLast: function(e) {
|
||||
|
@ -344,6 +351,16 @@ const OpenView = Backbone.View.extend({
|
|||
this.removeFile(id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Launcher && Launcher.fingerprints) {
|
||||
const fileInfo = this.model.fileInfos.get(id);
|
||||
Launcher.fingerprints.auth(fileInfo, password => {
|
||||
this.inputEl.val(password);
|
||||
this.inputEl.trigger('input');
|
||||
this.openDb();
|
||||
});
|
||||
}
|
||||
|
||||
this.showOpenFileInfo(this.model.fileInfos.get(id));
|
||||
},
|
||||
|
||||
|
|
|
@ -35,3 +35,99 @@
|
|||
@import "areas/menu";
|
||||
@import "areas/open";
|
||||
@import "areas/settings";
|
||||
|
||||
@include mobile {
|
||||
|
||||
.app {
|
||||
&__menu {
|
||||
position: absolute;
|
||||
top: 4em;
|
||||
bottom: 0;
|
||||
width: 75%;
|
||||
z-index: 1;
|
||||
box-shadow: 0 0.1em 0.5em rgba(0, 0, 0, 0.5);
|
||||
|
||||
&-drag {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@include th {
|
||||
background: background-color();
|
||||
}
|
||||
|
||||
@include mobile {
|
||||
transition: .3s ease-in-out;
|
||||
left: 0;
|
||||
|
||||
&:not(.menu-visible) {
|
||||
transform: translate(-100%, 0);
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
&__search {
|
||||
box-shadow: 0 0 .5em rgba(0, 0, 0, 0.5);
|
||||
|
||||
&-icon-search {
|
||||
@include th {
|
||||
color: text-color();
|
||||
}
|
||||
}
|
||||
|
||||
&-btn-menu {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
&-adv {
|
||||
padding: 1em .6em 0em .6em;
|
||||
|
||||
&-text {
|
||||
font-weight: 600;
|
||||
font-size: 0.9em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
&-check {
|
||||
padding: .3em 0;
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
@include th {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
box-shadow: 0 0 0 !important;
|
||||
border-bottom: 1px solid action-color();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__items .scroller {
|
||||
:first-child {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
:last-child {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
}
|
||||
&__item {
|
||||
padding: .5em 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
&__item-body {
|
||||
padding: 1em;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue