mirror of https://github.com/keeweb/keeweb
file save/open
parent
058b82f722
commit
874477c5c4
|
@ -25,7 +25,8 @@ $(function() {
|
|||
}
|
||||
|
||||
function showApp() {
|
||||
new AppView({ model: new AppModel() }).render().showOpenFile();
|
||||
var appModel = new AppModel();
|
||||
new AppView({ model: appModel }).render().showOpenFile(appModel.settings.get('lastOpenFile'));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ var AppModel = Backbone.Model.extend({
|
|||
page: 'file',
|
||||
file: file
|
||||
});
|
||||
if (file.get('path')) {
|
||||
AppSettingsModel.instance.set('lastOpenFile', file.get('path'));
|
||||
}
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
|
|
|
@ -5,19 +5,18 @@ var Backbone = require('backbone');
|
|||
var AppSettingsModel = Backbone.Model.extend({
|
||||
defaults: {
|
||||
theme: 'd',
|
||||
genOpts: {
|
||||
length: 16, upper: true, lower: true, digits: true, special: false, brackets: false, high: false, ambiguous: false
|
||||
}
|
||||
lastOpenFile: ''
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.listenTo(this, 'change', this.save);
|
||||
},
|
||||
|
||||
load: function() {
|
||||
if (typeof localStorage !== 'undefined' && localStorage.appSettings) {
|
||||
try {
|
||||
var data = JSON.parse(localStorage.appSettings);
|
||||
this.set(data);
|
||||
this.set(data, { silent: true });
|
||||
} catch (e) { /* failed to load settings */ }
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
var Backbone = require('backbone'),
|
||||
GroupCollection = require('../collections/group-collection'),
|
||||
GroupModel = require('./group-model'),
|
||||
Launcher = require('../util/launcher'),
|
||||
kdbxweb = require('kdbxweb'),
|
||||
demoFileData = require('base64!../../resources/Demo.kdbx');
|
||||
|
||||
|
@ -54,9 +55,6 @@ var FileModel = Backbone.Model.extend({
|
|||
}
|
||||
this.readModel(this.get('name'));
|
||||
this.setOpenFile({ passwordLength: len });
|
||||
this._oldPasswordHash = this.db.credentials.passwordHash;
|
||||
this._oldKeyFileHash = this.db.credentials.keyFileHash;
|
||||
this._oldKeyChangeDate = this.db.meta.keyChanged;
|
||||
},
|
||||
|
||||
create: function(name) {
|
||||
|
@ -82,9 +80,14 @@ var FileModel = Backbone.Model.extend({
|
|||
opening: false,
|
||||
error: false,
|
||||
oldKeyFileName: this.get('keyFileName'),
|
||||
oldPasswordLength: props.passwordLength
|
||||
oldPasswordLength: props.passwordLength,
|
||||
passwordChanged: false,
|
||||
keyFileChanged: false
|
||||
});
|
||||
this.set(props);
|
||||
this._oldPasswordHash = this.db.credentials.passwordHash;
|
||||
this._oldKeyFileHash = this.db.credentials.keyFileHash;
|
||||
this._oldKeyChangeDate = this.db.meta.keyChanged;
|
||||
},
|
||||
|
||||
readModel: function(topGroupTitle) {
|
||||
|
@ -154,6 +157,10 @@ var FileModel = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
|
||||
autoSave: function() {
|
||||
Launcher.writeFile(this.get('path'), this.getData());
|
||||
},
|
||||
|
||||
getData: function() {
|
||||
return this.db.save();
|
||||
},
|
||||
|
@ -162,6 +169,14 @@ var FileModel = Backbone.Model.extend({
|
|||
return this.db.saveXml();
|
||||
},
|
||||
|
||||
saved: function(path) {
|
||||
this.set({ path: path || '', modified: false, created: false });
|
||||
this.setOpenFile({ passwordLength: this.get('passwordLength') });
|
||||
this.forEachEntry({}, function(entry) {
|
||||
entry.unsaved = false;
|
||||
});
|
||||
},
|
||||
|
||||
setPassword: function(password) {
|
||||
this.db.credentials.setPassword(password);
|
||||
this.db.meta.keyChanged = new Date();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone');
|
||||
var Launcher;
|
||||
|
||||
if (window.process && window.process.versions && window.process.versions.electron) {
|
||||
|
@ -13,8 +14,36 @@ if (window.process && window.process.versions && window.process.versions.electro
|
|||
devTools: true,
|
||||
openDevTools: function() {
|
||||
this.req('remote').getCurrentWindow().openDevTools();
|
||||
},
|
||||
getSaveFileName: function(defaultPath, cb) {
|
||||
var remote = this.req('remote');
|
||||
if (defaultPath) {
|
||||
var homePath = remote.require('app').getPath('userDesktop');
|
||||
defaultPath = this.req('path').join(homePath, defaultPath);
|
||||
}
|
||||
remote.require('dialog').showSaveDialog({
|
||||
title: 'Save Passwords Database',
|
||||
defaultPath: defaultPath,
|
||||
filters: [{ name: 'KeePass files', extensions: ['kdbx'] }]
|
||||
}, cb);
|
||||
},
|
||||
writeFile: function(path, data) {
|
||||
this.req('fs').writeFileSync(path, new window.Buffer(data));
|
||||
},
|
||||
readFile: function(path) {
|
||||
return new Uint8Array(this.req('fs').readFileSync(path));
|
||||
},
|
||||
fileExists: function(path) {
|
||||
return this.req('fs').existsSync(path);
|
||||
}
|
||||
};
|
||||
window.launcherOpen = function(path) {
|
||||
Backbone.trigger('launcher-open-file', path);
|
||||
};
|
||||
if (window.launcherOpenedFile) {
|
||||
Backbone.trigger('launcher-open-file', window.launcherOpenedFile);
|
||||
delete window.launcherOpenedFile;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Launcher;
|
||||
|
|
|
@ -51,6 +51,7 @@ var AppView = Backbone.View.extend({
|
|||
this.listenTo(Backbone, 'switch-view', this.switchView);
|
||||
this.listenTo(Backbone, 'toggle-settings', this.toggleSettings);
|
||||
this.listenTo(Backbone, 'toggle-menu', this.toggleMenu);
|
||||
this.listenTo(Backbone, 'launcher-open-file', this.launcherOpenFile);
|
||||
|
||||
window.onbeforeunload = this.beforeUnload.bind(this);
|
||||
window.onresize = this.windowResize.bind(this);
|
||||
|
@ -71,7 +72,7 @@ var AppView = Backbone.View.extend({
|
|||
return this;
|
||||
},
|
||||
|
||||
showOpenFile: function() {
|
||||
showOpenFile: function(filePath) {
|
||||
this.views.menu.hide();
|
||||
this.views.menuDrag.hide();
|
||||
this.views.list.hide();
|
||||
|
@ -83,6 +84,15 @@ var AppView = Backbone.View.extend({
|
|||
this.views.open = new OpenView({ model: this.model });
|
||||
this.views.open.setElement(this.$el.find('.app__body')).render();
|
||||
this.views.open.on('cancel', this.showEntries, this);
|
||||
if (Launcher && filePath) {
|
||||
this.views.open.showOpenLocalFile(filePath);
|
||||
}
|
||||
},
|
||||
|
||||
launcherOpenFile: function(path) {
|
||||
if (path && /\.kdbx$/i.test(path)) {
|
||||
this.showOpenFile(path);
|
||||
}
|
||||
},
|
||||
|
||||
showEntries: function() {
|
||||
|
@ -189,7 +199,21 @@ var AppView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
saveAll: function() {
|
||||
this.showFileSettings({ fileId: this.model.files.first().cid });
|
||||
var fileId;
|
||||
this.model.files.forEach(function(file) {
|
||||
if (file.get('path')) {
|
||||
try {
|
||||
file.autoSave();
|
||||
} catch (e) {
|
||||
fileId = file.cid;
|
||||
}
|
||||
} else if (!fileId) {
|
||||
fileId = file.cid;
|
||||
}
|
||||
});
|
||||
if (fileId) {
|
||||
this.showFileSettings({fileId: fileId});
|
||||
}
|
||||
},
|
||||
|
||||
toggleSettings: function(page) {
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
var Backbone = require('backbone'),
|
||||
PasswordGenerator = require('../util/password-generator'),
|
||||
AppSettingsModel = require('../models/app-settings-model'),
|
||||
CopyPaste = require('../util/copy-paste');
|
||||
|
||||
var DefaultGenOpts = {
|
||||
length: 16, upper: true, lower: true, digits: true, special: false, brackets: false, high: false, ambiguous: false
|
||||
};
|
||||
|
||||
var GeneratorView = Backbone.View.extend({
|
||||
el: 'body',
|
||||
|
||||
|
@ -21,7 +24,7 @@ var GeneratorView = Backbone.View.extend({
|
|||
|
||||
initialize: function () {
|
||||
$('body').one('click', this.remove.bind(this));
|
||||
this.gen = _.clone(AppSettingsModel.instance.get('genOpts'));
|
||||
this.gen = _.clone(DefaultGenOpts);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
var Backbone = require('backbone'),
|
||||
OpenFileView = require('./open-file-view'),
|
||||
FileModel = require('../models/file-model');
|
||||
FileModel = require('../models/file-model'),
|
||||
Launcher = require('../util/launcher');
|
||||
|
||||
var OpenView = Backbone.View.extend({
|
||||
template: require('templates/open.html'),
|
||||
|
@ -94,6 +95,22 @@ var OpenView = Backbone.View.extend({
|
|||
if (dataFile) {
|
||||
this.views.openFile.setFile(dataFile, keyFile);
|
||||
}
|
||||
},
|
||||
|
||||
showOpenLocalFile: function(path) {
|
||||
if (path && Launcher) {
|
||||
try {
|
||||
var name = path.match(/[^/\\]*$/)[0];
|
||||
var data = Launcher.readFile(path);
|
||||
var file = new Blob([data]);
|
||||
Object.defineProperties(file, {
|
||||
path: { value: path },
|
||||
name: { value: name }
|
||||
});
|
||||
this.views.openFile.setFile(file);
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone'),
|
||||
AppSettingsModel = require('../../models/app-settings-model'),
|
||||
FeatureDetector = require('../../util/feature-detector'),
|
||||
PasswordDisplay = require('../../util/password-display'),
|
||||
Alerts = require('../../util/alerts'),
|
||||
RuntimeInfo = require('../../util/runtime-info'),
|
||||
Launcher = require('../../util/launcher'),
|
||||
Links = require('../../const/links'),
|
||||
kdbxweb = require('kdbxweb'),
|
||||
FileSaver = require('filesaver');
|
||||
|
@ -96,8 +98,37 @@ var SettingsAboutView = Backbone.View.extend({
|
|||
return;
|
||||
}
|
||||
var data = this.model.getData();
|
||||
var blob = new Blob([data], {type: 'application/octet-stream'});
|
||||
FileSaver.saveAs(blob, this.model.get('name') + '.kdbx');
|
||||
var fileName = this.model.get('name') + '.kdbx';
|
||||
if (Launcher) {
|
||||
if (this.model.get('path')) {
|
||||
this.saveToFileWithPath(this.model.get('path'), data);
|
||||
} else {
|
||||
Launcher.getSaveFileName(fileName, (function (path) {
|
||||
if (path) {
|
||||
this.saveToFileWithPath(path, data);
|
||||
}
|
||||
}).bind(this));
|
||||
}
|
||||
} else {
|
||||
var blob = new Blob([data], {type: 'application/octet-stream'});
|
||||
FileSaver.saveAs(blob, fileName);
|
||||
this.model.saved();
|
||||
}
|
||||
},
|
||||
|
||||
saveToFileWithPath: function(path, data) {
|
||||
try {
|
||||
Launcher.writeFile(path, data);
|
||||
this.model.saved(path);
|
||||
if (!AppSettingsModel.instance.get('lastOpenFile')) {
|
||||
AppSettingsModel.instance.set('lastOpenFile', path);
|
||||
}
|
||||
} catch (e) {
|
||||
Alerts.error({
|
||||
header: 'Save error',
|
||||
body: 'Error saving to file ' + path + ': \n' + e
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
exportAsXml: function() {
|
||||
|
|
|
@ -30,7 +30,6 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
changeTheme: function(e) {
|
||||
var theme = e.target.value;
|
||||
AppSettingsModel.instance.set('theme', theme);
|
||||
AppSettingsModel.instance.save();
|
||||
},
|
||||
|
||||
openDevTools: function() {
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
<div class="open__file-password">
|
||||
<div class="open__file-title">
|
||||
<% if (name) { %>
|
||||
<a class="open__file-link-name <%= opening ? 'disabled' : '' %> muted-color"><%- name %></a>
|
||||
<a class="open__file-link-name <%= opening ? 'disabled' : '' %> muted-color"><%- name %></a> / <a
|
||||
class="open__file-link-name muted-color" <%= opening ? 'disabled' : '' %>>Another</a>
|
||||
<% } else { %>
|
||||
<a class="open__file-link-open muted-color" <%= opening ? 'disabled' : '' %>>Open</a> / <a
|
||||
class="open__file-link-new muted-color" <%= opening ? 'disabled' : '' %>>New</a> / <a
|
||||
|
@ -27,4 +28,4 @@
|
|||
<i class="open__file-btn-key fa fa-key <%= (keyFileName && !opening) ? 'open__file-btn-key--active' : '' %>"
|
||||
<%= (name && !opening) ? '' : 'disabled' %>></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,14 +5,16 @@ var app = require('app'),
|
|||
path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
var mainWindow = null;
|
||||
var mainWindow = null,
|
||||
openFile = null,
|
||||
ready = false;
|
||||
|
||||
app.on('window-all-closed', function() { app.quit(); });
|
||||
|
||||
app.on('ready', function() {
|
||||
var htmlPath = path.join(app.getPath('userData'), 'index.html');
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
width: 1000, height: 700, 'min-width': 600, 'min-height': 300,
|
||||
icon: path.join(__dirname, 'icon.png')
|
||||
});
|
||||
|
@ -22,5 +24,22 @@ app.on('ready', function() {
|
|||
} else {
|
||||
mainWindow.loadUrl('https://antelle.github.io/keeweb/index.html');
|
||||
}
|
||||
mainWindow.webContents.on('dom-ready', function() {
|
||||
mainWindow.show();
|
||||
ready = true;
|
||||
notifyOpenFile();
|
||||
});
|
||||
mainWindow.on('closed', function() { mainWindow = null; });
|
||||
});
|
||||
app.on('open-file', function(e, path) {
|
||||
e.preventDefault();
|
||||
openFile = path.replace(/"/g, '\\"');
|
||||
notifyOpenFile();
|
||||
});
|
||||
|
||||
function notifyOpenFile() {
|
||||
if (ready && openFile && mainWindow) {
|
||||
mainWindow.webContents.executeJavaScript('if (window.launcherOpen) { window.launcherOpen("' + openFile + '"); } ' +
|
||||
' else { window.launcherOpenedFile="' + openFile + '"; }');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue