mirror of https://github.com/keeweb/keeweb.git
field references decoding
This commit is contained in:
parent
f52578f6de
commit
ae96fca478
|
@ -2,6 +2,9 @@
|
|||
|
||||
var kdbxweb = require('kdbxweb');
|
||||
|
||||
const ExpectedFieldRefChars = '{REF:0@I:00000000000000000000000000000000}'.split('');
|
||||
const ExpectedFieldRefByteLength = ExpectedFieldRefChars.length;
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.isProtected = true;
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.forEachChar = function(fn) {
|
||||
|
@ -10,30 +13,42 @@ kdbxweb.ProtectedValue.prototype.forEachChar = function(fn) {
|
|||
for (var i = 0, len = value.length; i < len; i++) {
|
||||
b = value[i] ^ salt[i];
|
||||
if (b < 128) {
|
||||
fn(b);
|
||||
if (fn(b) === false) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
i++; b1 = value[i] ^ salt[i];
|
||||
if (i === len) { break; }
|
||||
if (b >= 192 && b < 224) {
|
||||
fn(((b & 0x1f) << 6) | (b1 & 0x3f));
|
||||
if (fn(((b & 0x1f) << 6) | (b1 & 0x3f)) === false) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
i++; b2 = value[i] ^ salt[i];
|
||||
if (i === len) { break; }
|
||||
if (b >= 224 && b < 240) {
|
||||
fn(((b & 0xf) << 12) | ((b1 & 0x3f) << 6) | (b2 & 0x3f));
|
||||
if (fn(((b & 0xf) << 12) | ((b1 & 0x3f) << 6) | (b2 & 0x3f)) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
i++; b3 = value[i] ^ salt[i];
|
||||
if (i === len) { break; }
|
||||
if (b >= 240 && b < 248) {
|
||||
var c = ((b & 7) << 18) | ((b1 & 0x3f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f);
|
||||
if (c <= 0xffff) {
|
||||
fn(c);
|
||||
if (fn(c) === false) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
c ^= 0x10000;
|
||||
fn(0xd800 | (c >> 10));
|
||||
fn(0xdc00 | (c & 0x3ff));
|
||||
if (fn(0xd800 | (c >> 10)) === false) {
|
||||
return;
|
||||
}
|
||||
if (fn(0xdc00 | (c & 0x3ff)) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// skip error
|
||||
|
@ -98,4 +113,18 @@ kdbxweb.ProtectedValue.prototype.equals = function(other) {
|
|||
return true;
|
||||
};
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.isFieldReference = function() {
|
||||
if (this.byteLength !== ExpectedFieldRefByteLength) {
|
||||
return false;
|
||||
}
|
||||
let ix = 0;
|
||||
this.forEachChar(ch => {
|
||||
let expected = ExpectedFieldRefChars[ix++];
|
||||
if (expected !== '0' && ch !== expected) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = kdbxweb.ProtectedValue;
|
||||
|
|
|
@ -10,9 +10,13 @@ var Backbone = require('backbone'),
|
|||
|
||||
var EntryModel = Backbone.Model.extend({
|
||||
defaults: {},
|
||||
urlRegex: /^https?:\/\//i,
|
||||
|
||||
builtInFields: ['Title', 'Password', 'Notes', 'URL', 'UserName', 'TOTP Seed', 'TOTP Settings'],
|
||||
urlRegex: /^https?:\/\//i,
|
||||
fieldRefRegex: /^\{REF:([TNPAU])@I:(\w{32})}$/,
|
||||
|
||||
builtInFields: ['Title', 'Password', 'UserName', 'URL', 'Notes', 'TOTP Seed', 'TOTP Settings'],
|
||||
fieldRefFields: ['title', 'password', 'user', 'url', 'notes'],
|
||||
fieldRefIds: { T: 'Title', U: 'UserName', P: 'Password', A: 'URL', N: 'Notes' },
|
||||
|
||||
initialize: function() {
|
||||
},
|
||||
|
@ -24,7 +28,10 @@ var EntryModel = Backbone.Model.extend({
|
|||
if (this.get('uuid') === entry.uuid.id) {
|
||||
this._checkUpdatedEntry();
|
||||
}
|
||||
// we cannot calculate field references now because database index has not yet been built
|
||||
this.hasFieldRefs = false;
|
||||
this._fillByEntry();
|
||||
this.hasFieldRefs = true;
|
||||
},
|
||||
|
||||
_fillByEntry: function() {
|
||||
|
@ -54,6 +61,9 @@ var EntryModel = Backbone.Model.extend({
|
|||
this._buildSearchTags();
|
||||
this._buildSearchColor();
|
||||
this._buildAutoType();
|
||||
if (this.hasFieldRefs) {
|
||||
this.resolveFieldReferences();
|
||||
}
|
||||
},
|
||||
|
||||
_checkUpdatedEntry: function() {
|
||||
|
@ -261,6 +271,45 @@ var EntryModel = Backbone.Model.extend({
|
|||
return val ? compare(val, search) : false;
|
||||
},
|
||||
|
||||
resolveFieldReferences: function() {
|
||||
this.hasFieldRefs = false;
|
||||
this.fieldRefFields.forEach(field => {
|
||||
let fieldValue = this[field];
|
||||
if (!fieldValue) {
|
||||
return;
|
||||
}
|
||||
if (fieldValue.isProtected && fieldValue.isFieldReference()) {
|
||||
fieldValue = fieldValue.getText();
|
||||
}
|
||||
if (typeof fieldValue !== 'string') {
|
||||
return;
|
||||
}
|
||||
let match = fieldValue.match(this.fieldRefRegex);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
this.hasFieldRefs = true;
|
||||
let value = this._getReferenceValue(match[1], match[2]);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
this[field] = value;
|
||||
});
|
||||
},
|
||||
|
||||
_getReferenceValue: function(fieldRefId, idStr) {
|
||||
let id = new Uint8Array(16);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
id[i] = parseInt(idStr.substr(i * 2, 2), 16);
|
||||
}
|
||||
let uuid = new kdbxweb.KdbxUuid(id);
|
||||
let entry = this.file.getEntry(this.file.subId(uuid.id));
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
return entry.entry.fields[this.fieldRefIds[fieldRefId]];
|
||||
},
|
||||
|
||||
setColor: function(color) {
|
||||
this._entryModified();
|
||||
this.entry.bgColor = Color.getKnownBgColor(color);
|
||||
|
|
|
@ -156,6 +156,7 @@ var FileModel = Backbone.Model.extend({
|
|||
groups.add(groupModel);
|
||||
}, this);
|
||||
this.buildObjectMap();
|
||||
this.resolveFieldReferences();
|
||||
},
|
||||
|
||||
subId: function(id) {
|
||||
|
@ -175,6 +176,13 @@ var FileModel = Backbone.Model.extend({
|
|||
this.groupMap = groupMap;
|
||||
},
|
||||
|
||||
resolveFieldReferences: function() {
|
||||
let entryMap = this.entryMap;
|
||||
Object.keys(entryMap).forEach(e => {
|
||||
entryMap[e].resolveFieldReferences();
|
||||
});
|
||||
},
|
||||
|
||||
reload: function() {
|
||||
this.buildObjectMap();
|
||||
this.readModel();
|
||||
|
|
|
@ -13,6 +13,7 @@ Audit, generator presets, auto-type and ui improvements
|
|||
`+` save displayed table columns
|
||||
`+` confirmation in password change dialog
|
||||
`+` inline generator keyboard management
|
||||
`+` field references decoding
|
||||
`-` fix app redraw in background
|
||||
`-` fix idle timer on computer sleep
|
||||
|
||||
|
|
Loading…
Reference in New Issue