2015-10-17 23:49:24 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var Backbone = require('backbone'),
|
|
|
|
AttachmentModel = require('./attachment-model'),
|
|
|
|
IconMap = require('../const/icon-map'),
|
|
|
|
Color = require('../util/color'),
|
2015-11-21 21:14:21 +01:00
|
|
|
IconUrl = require('../util/icon-url'),
|
2015-10-17 23:49:24 +02:00
|
|
|
kdbxweb = require('kdbxweb');
|
|
|
|
|
|
|
|
var EntryModel = Backbone.Model.extend({
|
|
|
|
defaults: {},
|
|
|
|
|
|
|
|
buildInFields: ['Title', 'Password', 'Notes', 'URL', 'UserName'],
|
|
|
|
|
|
|
|
initialize: function() {
|
|
|
|
},
|
|
|
|
|
|
|
|
setEntry: function(entry, group, file) {
|
|
|
|
this.entry = entry;
|
|
|
|
this.group = group;
|
|
|
|
this.file = file;
|
2015-12-05 14:04:09 +01:00
|
|
|
if (this.id === entry.uuid.id) {
|
|
|
|
this._checkUpdatedEntry();
|
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
_fillByEntry: function() {
|
|
|
|
var entry = this.entry;
|
2015-12-05 14:04:09 +01:00
|
|
|
this.set({id: entry.uuid.id}, {silent: true});
|
2015-10-17 23:49:24 +02:00
|
|
|
this.fileName = this.file.db.meta.name;
|
|
|
|
this.title = entry.fields.Title || '';
|
2015-10-31 20:27:31 +01:00
|
|
|
this.password = entry.fields.Password || kdbxweb.ProtectedValue.fromString('');
|
2015-10-17 23:49:24 +02:00
|
|
|
this.notes = entry.fields.Notes || '';
|
|
|
|
this.url = entry.fields.URL || '';
|
|
|
|
this.user = entry.fields.UserName || '';
|
|
|
|
this.iconId = entry.icon;
|
|
|
|
this.icon = this._iconFromId(entry.icon);
|
|
|
|
this.tags = entry.tags;
|
|
|
|
this.color = this._colorToModel(entry.bgColor) || this._colorToModel(entry.fgColor);
|
|
|
|
this.fields = this._fieldsToModel(entry.fields);
|
|
|
|
this.attachments = this._attachmentsToModel(entry.binaries);
|
|
|
|
this.created = entry.times.creationTime;
|
|
|
|
this.updated = entry.times.lastModTime;
|
|
|
|
this.expires = entry.times.expires ? entry.times.expiryTime : undefined;
|
|
|
|
this.expired = entry.times.expires && entry.times.expiryTime <= new Date();
|
|
|
|
this.historyLength = entry.history.length;
|
2015-11-12 22:52:28 +01:00
|
|
|
this._buildCustomIcon();
|
2015-10-17 23:49:24 +02:00
|
|
|
this._buildSearchText();
|
|
|
|
this._buildSearchTags();
|
|
|
|
this._buildSearchColor();
|
|
|
|
},
|
|
|
|
|
2015-12-05 14:04:09 +01:00
|
|
|
_checkUpdatedEntry: function() {
|
|
|
|
if (this.isJustCreated) {
|
|
|
|
this.isJustCreated = false;
|
|
|
|
}
|
|
|
|
if (this.unsaved && +this.updated !== +this.entry.times.lastModTime) {
|
|
|
|
this.unsaved = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
_buildSearchText: function() {
|
|
|
|
var text = '';
|
|
|
|
_.forEach(this.entry.fields, function(value) {
|
|
|
|
if (typeof value === 'string') {
|
|
|
|
text += value.toLowerCase() + '\n';
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.entry.tags.forEach(function(tag) {
|
|
|
|
text += tag.toLowerCase() + '\n';
|
|
|
|
});
|
|
|
|
this.attachments.forEach(function(att) {
|
|
|
|
text += att.title.toLowerCase() + '\n';
|
|
|
|
});
|
|
|
|
this.searchText = text;
|
|
|
|
},
|
|
|
|
|
2015-11-12 22:52:28 +01:00
|
|
|
_buildCustomIcon: function() {
|
|
|
|
this.customIcon = null;
|
2015-11-21 23:15:51 +01:00
|
|
|
this.customIconId = null;
|
2015-11-12 22:52:28 +01:00
|
|
|
if (this.entry.customIcon) {
|
2015-11-21 21:14:21 +01:00
|
|
|
this.customIcon = IconUrl.toDataUrl(this.file.db.meta.customIcons[this.entry.customIcon]);
|
2015-11-21 23:15:51 +01:00
|
|
|
this.customIconId = this.entry.customIcon.toString();
|
2015-11-12 22:52:28 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
_buildSearchTags: function() {
|
|
|
|
this.searchTags = this.entry.tags.map(function(tag) { return tag.toLowerCase(); });
|
|
|
|
},
|
|
|
|
|
|
|
|
_buildSearchColor: function() {
|
|
|
|
this.searchColor = this.color;
|
|
|
|
},
|
|
|
|
|
|
|
|
_iconFromId: function(id) {
|
|
|
|
return IconMap[id];
|
|
|
|
},
|
|
|
|
|
|
|
|
_colorToModel: function(color) {
|
|
|
|
return color ? Color.getNearest(color) : null;
|
|
|
|
},
|
|
|
|
|
|
|
|
_fieldsToModel: function(fields) {
|
|
|
|
return _.omit(fields, this.buildInFields);
|
|
|
|
},
|
|
|
|
|
|
|
|
_attachmentsToModel: function(binaries) {
|
|
|
|
var att = [];
|
|
|
|
_.forEach(binaries, function(data, title) {
|
|
|
|
att.push(AttachmentModel.fromAttachment({ data: data, title: title }));
|
|
|
|
}, this);
|
|
|
|
return att;
|
|
|
|
},
|
|
|
|
|
|
|
|
_entryModified: function() {
|
|
|
|
if (!this.unsaved) {
|
|
|
|
this.unsaved = true;
|
|
|
|
this.entry.pushHistory();
|
|
|
|
this.file.setModified();
|
|
|
|
}
|
2015-10-27 22:07:48 +01:00
|
|
|
if (this.isJustCreated) {
|
|
|
|
this.isJustCreated = false;
|
2015-10-27 20:40:34 +01:00
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
this.entry.times.update();
|
|
|
|
},
|
|
|
|
|
|
|
|
matches: function(filter) {
|
2015-12-05 14:04:09 +01:00
|
|
|
return !filter ||
|
|
|
|
(!filter.tagLower || this.searchTags.indexOf(filter.tagLower) >= 0) &&
|
2015-10-17 23:49:24 +02:00
|
|
|
(!filter.textLower || this.searchText.indexOf(filter.textLower) >= 0) &&
|
|
|
|
(!filter.color || filter.color === true && this.searchColor || this.searchColor === filter.color);
|
|
|
|
},
|
|
|
|
|
|
|
|
setColor: function(color) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.bgColor = Color.getKnownBgColor(color);
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
setIcon: function(iconId) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.icon = iconId;
|
2015-11-21 23:15:51 +01:00
|
|
|
this.entry.customIcon = undefined;
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
setCustomIcon: function(customIconId) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.customIcon = new kdbxweb.KdbxUuid(customIconId);
|
2015-10-17 23:49:24 +02:00
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
setExpires: function(dt) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.times.expiryTime = dt instanceof Date ? dt : undefined;
|
|
|
|
this.entry.times.expires = !!dt;
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
setTags: function(tags) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.tags = tags;
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
setField: function(field, val) {
|
|
|
|
this._entryModified();
|
2015-11-10 18:23:50 +01:00
|
|
|
var hasValue = val && (typeof val === 'string' || val instanceof kdbxweb.ProtectedValue && val.byteLength);
|
|
|
|
if (hasValue || this.buildInFields.indexOf(field) >= 0) {
|
2015-10-17 23:49:24 +02:00
|
|
|
this.entry.fields[field] = val;
|
|
|
|
} else {
|
|
|
|
delete this.entry.fields[field];
|
|
|
|
}
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
hasField: function(field) {
|
|
|
|
return this.entry.fields.hasOwnProperty(field);
|
|
|
|
},
|
|
|
|
|
|
|
|
addAttachment: function(name, data) {
|
|
|
|
this._entryModified();
|
|
|
|
this.entry.binaries[name] = kdbxweb.ProtectedValue.fromBinary(data);
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
removeAttachment: function(name) {
|
|
|
|
this._entryModified();
|
|
|
|
delete this.entry.binaries[name];
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
getHistory: function() {
|
|
|
|
var history = this.entry.history.map(function(rec) {
|
|
|
|
return EntryModel.fromEntry(rec, this.group, this.file);
|
|
|
|
}, this);
|
|
|
|
history.push(this);
|
|
|
|
history.sort(function(x, y) { return x.updated - y.updated; });
|
|
|
|
return history;
|
|
|
|
},
|
|
|
|
|
|
|
|
deleteHistory: function(historyEntry) {
|
|
|
|
var ix = this.entry.history.indexOf(historyEntry);
|
|
|
|
if (ix >= 0) {
|
2015-12-05 14:04:09 +01:00
|
|
|
this.entry.removeHistory(ix);
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
revertToHistoryState: function(historyEntry) {
|
|
|
|
var ix = this.entry.history.indexOf(historyEntry);
|
|
|
|
if (ix < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.entry.pushHistory();
|
|
|
|
this.unsaved = true;
|
|
|
|
this.file.setModified();
|
|
|
|
this.entry.fields = {};
|
|
|
|
this.entry.binaries = {};
|
|
|
|
this.entry.copyFrom(historyEntry);
|
|
|
|
this._entryModified();
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
discardUnsaved: function() {
|
2015-12-05 14:04:09 +01:00
|
|
|
if (this.unsaved && this.entry.history.length) {
|
2015-10-17 23:49:24 +02:00
|
|
|
this.unsaved = false;
|
2015-12-05 14:04:09 +01:00
|
|
|
var historyEntry = this.entry.history[this.entry.history.length - 1];
|
|
|
|
this.entry.removeHistory(this.entry.history.length - 1);
|
2015-10-17 23:49:24 +02:00
|
|
|
this.entry.fields = {};
|
|
|
|
this.entry.binaries = {};
|
|
|
|
this.entry.copyFrom(historyEntry);
|
|
|
|
this._fillByEntry();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
moveToTrash: function() {
|
2015-11-19 06:55:45 +01:00
|
|
|
this.file.setModified();
|
|
|
|
if (this.isJustCreated) {
|
|
|
|
this.isJustCreated = false;
|
|
|
|
}
|
2015-11-04 09:06:49 +01:00
|
|
|
this.file.db.remove(this.entry);
|
2015-12-05 14:04:09 +01:00
|
|
|
this.file.reload();
|
2015-10-27 20:40:34 +01:00
|
|
|
},
|
|
|
|
|
2015-11-09 19:15:39 +01:00
|
|
|
deleteFromTrash: function() {
|
2015-11-19 06:55:45 +01:00
|
|
|
this.file.setModified();
|
2015-11-09 19:15:39 +01:00
|
|
|
this.file.db.move(this.entry, null);
|
2015-12-05 14:04:09 +01:00
|
|
|
this.file.reload();
|
2015-11-09 19:15:39 +01:00
|
|
|
},
|
|
|
|
|
2015-10-27 20:40:34 +01:00
|
|
|
removeWithoutHistory: function() {
|
|
|
|
var ix = this.group.group.entries.indexOf(this.entry);
|
|
|
|
if (ix >= 0) {
|
|
|
|
this.group.group.entries.splice(ix, 1);
|
|
|
|
}
|
2015-12-05 14:04:09 +01:00
|
|
|
this.file.reload();
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
EntryModel.fromEntry = function(entry, group, file) {
|
|
|
|
var model = new EntryModel();
|
|
|
|
model.setEntry(entry, group, file);
|
|
|
|
return model;
|
|
|
|
};
|
|
|
|
|
|
|
|
EntryModel.newEntry = function(group, file) {
|
|
|
|
var model = new EntryModel();
|
|
|
|
var entry = file.db.createEntry(group.group);
|
|
|
|
model.setEntry(entry, group, file);
|
|
|
|
model.entry.times.update();
|
|
|
|
model.unsaved = true;
|
2015-10-27 22:07:48 +01:00
|
|
|
model.isJustCreated = true;
|
2015-10-27 20:40:34 +01:00
|
|
|
group.addEntry(model);
|
2015-10-17 23:49:24 +02:00
|
|
|
file.setModified();
|
|
|
|
return model;
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = EntryModel;
|