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'),
|
2016-04-01 23:09:16 +02:00
|
|
|
Otp = require('../util/otp'),
|
2015-10-17 23:49:24 +02:00
|
|
|
kdbxweb = require('kdbxweb');
|
|
|
|
|
|
|
|
var EntryModel = Backbone.Model.extend({
|
|
|
|
defaults: {},
|
2016-01-13 19:00:22 +01:00
|
|
|
urlRegex: /^https?:\/\//i,
|
2015-10-17 23:49:24 +02:00
|
|
|
|
2016-04-03 12:44:43 +02:00
|
|
|
builtInFields: ['Title', 'Password', 'Notes', 'URL', 'UserName', 'TOTP Seed', 'TOTP Settings'],
|
2015-10-17 23:49:24 +02:00
|
|
|
|
|
|
|
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-12-13 15:59:41 +01:00
|
|
|
this.fileName = this.file.get('name');
|
2015-10-17 23:49:24 +02:00
|
|
|
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 || '';
|
2016-01-13 19:00:22 +01:00
|
|
|
this.displayUrl = this._getDisplayUrl(entry.fields.URL);
|
2015-10-17 23:49:24 +02:00
|
|
|
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];
|
|
|
|
},
|
|
|
|
|
2016-01-13 19:00:22 +01:00
|
|
|
_getDisplayUrl: function(url) {
|
|
|
|
if (!url) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return url.replace(this.urlRegex, '');
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
_colorToModel: function(color) {
|
|
|
|
return color ? Color.getNearest(color) : null;
|
|
|
|
},
|
|
|
|
|
|
|
|
_fieldsToModel: function(fields) {
|
2016-01-13 21:33:14 +01:00
|
|
|
return _.omit(fields, this.builtInFields);
|
2015-10-17 23:49:24 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
_attachmentsToModel: function(binaries) {
|
|
|
|
var att = [];
|
|
|
|
_.forEach(binaries, function(data, title) {
|
2015-12-17 21:22:36 +01:00
|
|
|
if (data && data.ref) {
|
|
|
|
data = this.file.db.meta.binaries[data.ref];
|
|
|
|
}
|
|
|
|
if (data) {
|
|
|
|
att.push(AttachmentModel.fromAttachment({data: data, title: title}));
|
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
}, 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) &&
|
2016-01-13 21:33:14 +01:00
|
|
|
(!filter.textLower || (filter.advanced ? this.matchesAdv(filter) : this.searchText.indexOf(filter.textLower) >= 0)) &&
|
2015-10-17 23:49:24 +02:00
|
|
|
(!filter.color || filter.color === true && this.searchColor || this.searchColor === filter.color);
|
|
|
|
},
|
|
|
|
|
2016-01-13 21:33:14 +01:00
|
|
|
matchesAdv: function(filter) {
|
|
|
|
var adv = filter.advanced;
|
|
|
|
var search, match;
|
|
|
|
if (adv.regex) {
|
|
|
|
try { search = new RegExp(filter.text, adv.cs ? '' : 'i'); }
|
|
|
|
catch (e) { return false; }
|
|
|
|
match = this.matchRegex;
|
|
|
|
} else if (adv.cs) {
|
|
|
|
search = filter.text;
|
|
|
|
match = this.matchString;
|
|
|
|
} else {
|
|
|
|
search = filter.textLower;
|
|
|
|
match = this.matchStringLower;
|
|
|
|
}
|
|
|
|
if (this.matchEntry(this.entry, adv, match, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (adv.history) {
|
|
|
|
for (var i = 0, len = this.entry.history.length; i < len; i++) {
|
|
|
|
if (this.matchEntry(this.entry.history[0], adv, match, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
matchString: function(str, find) {
|
2016-01-17 12:36:52 +01:00
|
|
|
if (str.isProtected) {
|
|
|
|
return str.includes(find);
|
|
|
|
}
|
2016-01-13 21:33:14 +01:00
|
|
|
return str.indexOf(find) >= 0;
|
|
|
|
},
|
|
|
|
|
|
|
|
matchStringLower: function(str, findLower) {
|
2016-01-17 12:36:52 +01:00
|
|
|
if (str.isProtected) {
|
|
|
|
return str.includesLower(findLower);
|
|
|
|
}
|
2016-01-13 21:33:14 +01:00
|
|
|
return str.toLowerCase().indexOf(findLower) >= 0;
|
|
|
|
},
|
|
|
|
|
|
|
|
matchRegex: function(str, regex) {
|
2016-01-17 12:36:52 +01:00
|
|
|
if (str.isProtected) {
|
|
|
|
str = str.getText();
|
|
|
|
}
|
2016-01-13 21:33:14 +01:00
|
|
|
return regex.test(str);
|
|
|
|
},
|
|
|
|
|
|
|
|
matchEntry: function(entry, adv, compare, search) {
|
|
|
|
var matchField = this.matchField;
|
|
|
|
if (adv.user && matchField(entry, 'UserName', compare, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (adv.url && matchField(entry, 'URL', compare, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (adv.notes && matchField(entry, 'Notes', compare, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (adv.pass && matchField(entry, 'Password', compare, search)) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-02-25 20:50:31 +01:00
|
|
|
if (adv.title && matchField(entry, 'Title', compare, search)) {
|
2016-01-13 21:33:14 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
var matches = false;
|
|
|
|
if (adv.other || adv.protect) {
|
|
|
|
var builtInFields = this.builtInFields;
|
|
|
|
var fieldNames = Object.keys(entry.fields);
|
|
|
|
matches = fieldNames.some(function (field) {
|
|
|
|
if (builtInFields.indexOf(field) >= 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (typeof entry.fields[field] === 'string') {
|
|
|
|
return adv.other && matchField(entry, field, compare, search);
|
|
|
|
} else {
|
|
|
|
return adv.protect && matchField(entry, field, compare, search);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return matches;
|
|
|
|
},
|
|
|
|
|
|
|
|
matchField: function(entry, field, compare, search) {
|
|
|
|
var val = entry.fields[field];
|
2016-01-17 12:36:52 +01:00
|
|
|
return val ? compare(val, search) : false;
|
2016-01-13 21:33:14 +01:00
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
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) {
|
2016-01-16 15:19:33 +01:00
|
|
|
var hasValue = val && (typeof val === 'string' || val.isProtected && val.byteLength);
|
2016-01-13 21:33:14 +01:00
|
|
|
if (hasValue || this.builtInFields.indexOf(field) >= 0) {
|
2016-03-05 14:59:36 +01:00
|
|
|
this._entryModified();
|
2015-10-17 23:49:24 +02:00
|
|
|
this.entry.fields[field] = val;
|
2016-03-05 14:59:36 +01:00
|
|
|
} else if (this.entry.fields.hasOwnProperty(field)) {
|
|
|
|
this._entryModified();
|
2015-10-17 23:49:24 +02:00
|
|
|
delete this.entry.fields[field];
|
|
|
|
}
|
|
|
|
this._fillByEntry();
|
|
|
|
},
|
|
|
|
|
|
|
|
hasField: function(field) {
|
|
|
|
return this.entry.fields.hasOwnProperty(field);
|
|
|
|
},
|
|
|
|
|
|
|
|
addAttachment: function(name, data) {
|
|
|
|
this._entryModified();
|
2015-12-17 21:22:36 +01:00
|
|
|
var binaryId;
|
|
|
|
for (var i = 0; ; i++) {
|
|
|
|
if (!this.file.db.meta.binaries[i]) {
|
|
|
|
binaryId = i.toString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.file.db.meta.binaries[binaryId] = data;
|
|
|
|
this.entry.binaries[name] = { ref: binaryId };
|
2015-10-17 23:49:24 +02:00
|
|
|
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();
|
2016-04-01 23:09:16 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
initOtpGenerator: function() {
|
|
|
|
var otpUrl;
|
|
|
|
if (this.fields.otp) {
|
|
|
|
otpUrl = this.fields.otp;
|
|
|
|
if (otpUrl.isProtected) {
|
|
|
|
otpUrl = otpUrl.getText();
|
|
|
|
}
|
|
|
|
if (otpUrl.toLowerCase().lastIndexOf('otpauth:', 0) !== 0) {
|
|
|
|
// KeeOTP plugin format
|
|
|
|
var args = {};
|
|
|
|
otpUrl.split('&').forEach(function(part) {
|
|
|
|
var parts = part.split('=', 2);
|
|
|
|
args[parts[0]] = decodeURIComponent(parts[1]).replace(/=/g, '');
|
|
|
|
});
|
|
|
|
if (args.key) {
|
|
|
|
otpUrl = 'otpauth://totp/null?secret=' + args.key +
|
|
|
|
(args.step ? '&period=' + args.step : '') +
|
|
|
|
(args.size ? '&digits=' + args.size : '');
|
|
|
|
}
|
|
|
|
}
|
2016-04-03 12:44:43 +02:00
|
|
|
} else if (this.entry.fields['TOTP Seed']) {
|
2016-04-01 23:09:16 +02:00
|
|
|
// TrayTOTP plugin format
|
2016-04-03 12:44:43 +02:00
|
|
|
var key = this.entry.fields['TOTP Seed'];
|
2016-04-01 23:09:16 +02:00
|
|
|
if (key.isProtected) {
|
|
|
|
key = key.getText();
|
|
|
|
}
|
|
|
|
if (key) {
|
|
|
|
otpUrl = 'otpauth://totp/null?secret=' + key;
|
|
|
|
}
|
2016-04-03 12:44:43 +02:00
|
|
|
var settings = this.entry.fields['TOTP Settings'];
|
2016-04-01 23:09:16 +02:00
|
|
|
if (settings && settings.isProtected) {
|
|
|
|
settings = settings.getText();
|
|
|
|
}
|
|
|
|
if (settings) {
|
|
|
|
settings = settings.split(';');
|
|
|
|
if (settings.length > 0 && settings[0] > 0) {
|
|
|
|
otpUrl += '&period=' + settings[0];
|
|
|
|
}
|
|
|
|
if (settings.length > 1 && settings[1] > 0) {
|
|
|
|
otpUrl += '&digits=' + settings[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.fields.otp = kdbxweb.ProtectedValue.fromString(otpUrl);
|
|
|
|
}
|
|
|
|
if (otpUrl) {
|
2016-04-02 15:20:48 +02:00
|
|
|
if (this.otpGenerator && this.otpGenerator.url === otpUrl) {
|
|
|
|
return;
|
|
|
|
}
|
2016-04-01 23:09:16 +02:00
|
|
|
try {
|
|
|
|
this.otpGenerator = Otp.parseUrl(otpUrl);
|
|
|
|
} catch (e) {
|
|
|
|
this.otpGenerator = null;
|
|
|
|
}
|
2016-04-02 15:20:48 +02:00
|
|
|
} else {
|
|
|
|
this.otpGenerator = null;
|
2016-04-01 23:09:16 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
setOtp: function(otp) {
|
|
|
|
this.otpGenerator = otp;
|
2016-04-02 15:20:48 +02:00
|
|
|
this.setOtpUrl(otp.url);
|
|
|
|
},
|
|
|
|
|
|
|
|
setOtpUrl: function(url) {
|
|
|
|
this.setField('otp', kdbxweb.ProtectedValue.fromString(url));
|
2016-04-03 12:54:51 +02:00
|
|
|
delete this.entry.fields['TOTP Seed'];
|
|
|
|
delete this.entry.fields['TOTP Settings'];
|
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;
|