1
0
mirror of https://github.com/keeweb/keeweb.git synced 2024-06-20 06:56:40 +02:00
keeweb/app/scripts/mixins/protected-value-ex.js
2019-08-18 16:14:47 +02:00

181 lines
4.8 KiB
JavaScript

const 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) {
const value = this._value;
const salt = this._salt;
let b, b1, b2, b3;
for (let i = 0, len = value.length; i < len; i++) {
b = value[i] ^ salt[i];
if (b < 128) {
if (fn(b) === false) {
return;
}
continue;
}
i++;
b1 = value[i] ^ salt[i];
if (i === len) {
break;
}
if (b >= 192 && b < 224) {
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) {
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) {
let c = ((b & 7) << 18) | ((b1 & 0x3f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f);
if (c <= 0xffff) {
if (fn(c) === false) {
return;
}
} else {
c ^= 0x10000;
if (fn(0xd800 | (c >> 10)) === false) {
return;
}
if (fn(0xdc00 | (c & 0x3ff)) === false) {
return;
}
}
}
// skip error
}
};
Object.defineProperty(kdbxweb.ProtectedValue.prototype, 'length', {
get() {
return this.textLength;
}
});
Object.defineProperty(kdbxweb.ProtectedValue.prototype, 'textLength', {
get() {
let textLength = 0;
this.forEachChar(() => {
textLength++;
});
return textLength;
}
});
kdbxweb.ProtectedValue.prototype.includesLower = function(findLower) {
return this.indexOfLower(findLower) !== -1;
};
kdbxweb.ProtectedValue.prototype.indexOfLower = function(findLower) {
let index = -1;
const foundSeqs = [];
const len = findLower.length;
let chIndex = -1;
this.forEachChar(ch => {
chIndex++;
ch = String.fromCharCode(ch).toLowerCase();
if (index !== -1) {
return;
}
for (let i = 0; i < foundSeqs.length; i++) {
const seqIx = ++foundSeqs[i];
if (findLower[seqIx] !== ch) {
foundSeqs.splice(i, 1);
i--;
continue;
}
if (seqIx === len - 1) {
index = chIndex - len + 1;
return;
}
}
if (findLower[0] === ch) {
if (len === 1) {
index = chIndex - len + 1;
} else {
foundSeqs.push(0);
}
}
});
return index;
};
kdbxweb.ProtectedValue.prototype.indexOfSelfInLower = function(targetLower) {
let firstCharIndex = -1;
let found = false;
do {
let chIndex = -1;
this.forEachChar(ch => {
chIndex++;
ch = String.fromCharCode(ch).toLowerCase();
if (chIndex === 0) {
firstCharIndex = targetLower.indexOf(ch, firstCharIndex + 1);
found = firstCharIndex !== -1;
return;
}
if (!found) {
return;
}
found = targetLower[firstCharIndex + chIndex] === ch;
});
} while (!found && firstCharIndex >= 0);
return firstCharIndex;
};
window.PV = kdbxweb.ProtectedValue;
kdbxweb.ProtectedValue.prototype.equals = function(other) {
if (!other) {
return false;
}
if (!other.isProtected) {
return this.textLength === other.length && this.includes(other);
}
if (other === this) {
return true;
}
const len = this.byteLength;
if (len !== other.byteLength) {
return false;
}
for (let i = 0; i < len; i++) {
if ((this._value[i] ^ this._salt[i]) !== (other._value[i] ^ other._salt[i])) {
return false;
}
}
return true;
};
kdbxweb.ProtectedValue.prototype.isFieldReference = function() {
if (this.byteLength !== ExpectedFieldRefByteLength) {
return false;
}
let ix = 0;
this.forEachChar(ch => {
const expected = ExpectedFieldRefChars[ix++];
if (expected !== '0' && ch !== expected) {
return false;
}
});
return true;
};
module.exports = kdbxweb.ProtectedValue;