2019-09-15 14:16:32 +02:00
|
|
|
import kdbxweb from 'kdbxweb';
|
2016-01-17 13:23:07 +01:00
|
|
|
|
2017-01-31 07:50:28 +01:00
|
|
|
const SecureInput = function() {
|
2015-10-17 23:49:24 +02:00
|
|
|
this.el = null;
|
|
|
|
this.minChar = 0x1400 + Math.round(Math.random() * 100);
|
2016-05-21 20:13:18 +02:00
|
|
|
this.maxLen = 1024;
|
2015-10-17 23:49:24 +02:00
|
|
|
this.length = 0;
|
|
|
|
this.pseudoValue = '';
|
|
|
|
this.salt = new Uint32Array(0);
|
|
|
|
};
|
|
|
|
|
|
|
|
SecureInput.prototype.setElement = function(el) {
|
|
|
|
this.el = el;
|
|
|
|
this.el.val(this.pseudoValue);
|
|
|
|
this.el.on('input', this._input.bind(this));
|
|
|
|
};
|
|
|
|
|
|
|
|
SecureInput.prototype.reset = function() {
|
|
|
|
this.el = null;
|
|
|
|
this.length = 0;
|
|
|
|
this.pseudoValue = '';
|
2015-11-06 21:14:47 +01:00
|
|
|
|
|
|
|
if (this.salt) {
|
2017-01-31 07:50:28 +01:00
|
|
|
for (let i = 0; i < this.salt.length; i++) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.salt[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
this.salt = new Uint32Array(0);
|
|
|
|
};
|
|
|
|
|
|
|
|
SecureInput.prototype._input = function() {
|
2017-01-31 07:50:28 +01:00
|
|
|
const selStart = this.el[0].selectionStart;
|
|
|
|
const value = this.el.val();
|
|
|
|
let newPs = '';
|
|
|
|
const newSalt = new Uint32Array(this.maxLen);
|
|
|
|
let valIx = 0,
|
|
|
|
psIx = 0;
|
2015-10-17 23:49:24 +02:00
|
|
|
while (valIx < value.length) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const valCh = value.charCodeAt(valIx);
|
|
|
|
const psCh = this.pseudoValue.charCodeAt(psIx);
|
|
|
|
const isSpecial = this._isSpecialChar(valCh);
|
2015-10-17 23:49:24 +02:00
|
|
|
if (psCh === valCh) {
|
|
|
|
// not changed
|
|
|
|
newPs += this._getChar(newPs.length);
|
|
|
|
newSalt[newPs.length - 1] = psCh ^ this.salt[psIx] ^ newPs.charCodeAt(newPs.length - 1);
|
|
|
|
psIx++;
|
|
|
|
valIx++;
|
|
|
|
} else if (isSpecial) {
|
|
|
|
// deleted
|
|
|
|
psIx++;
|
|
|
|
} else {
|
|
|
|
// inserted or replaced
|
|
|
|
newPs += this._getChar(newPs.length);
|
|
|
|
newSalt[newPs.length - 1] = newPs.charCodeAt(newPs.length - 1) ^ valCh;
|
|
|
|
valIx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.length = newPs.length;
|
|
|
|
this.pseudoValue = newPs;
|
|
|
|
this.salt = newSalt;
|
|
|
|
this.el.val(newPs);
|
|
|
|
this.el[0].selectionStart = selStart;
|
|
|
|
this.el[0].selectionEnd = selStart;
|
|
|
|
};
|
|
|
|
|
|
|
|
SecureInput.prototype._getChar = function(ix) {
|
|
|
|
return String.fromCharCode(this.minChar + ix);
|
|
|
|
};
|
|
|
|
|
|
|
|
SecureInput.prototype._isSpecialChar = function(ch) {
|
|
|
|
return ch >= this.minChar && ch <= this.minChar + this.maxLen;
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.defineProperty(SecureInput.prototype, 'value', {
|
|
|
|
enumerable: true,
|
2019-08-18 10:17:09 +02:00
|
|
|
get() {
|
2017-01-31 07:50:28 +01:00
|
|
|
const pseudoValue = this.pseudoValue;
|
|
|
|
const salt = this.salt;
|
|
|
|
const len = pseudoValue.length;
|
|
|
|
let byteLength = 0;
|
|
|
|
const valueBytes = new Uint8Array(len * 4);
|
|
|
|
const saltBytes = kdbxweb.Random.getBytes(len * 4);
|
|
|
|
let ch;
|
|
|
|
let bytes;
|
|
|
|
for (let i = 0; i < len; i++) {
|
2016-01-17 13:23:07 +01:00
|
|
|
ch = String.fromCharCode(pseudoValue.charCodeAt(i) ^ salt[i]);
|
|
|
|
bytes = kdbxweb.ByteUtils.stringToBytes(ch);
|
2017-01-31 07:50:28 +01:00
|
|
|
for (let j = 0; j < bytes.length; j++) {
|
2016-01-17 13:23:07 +01:00
|
|
|
valueBytes[byteLength] = bytes[j] ^ saltBytes[byteLength];
|
|
|
|
byteLength++;
|
|
|
|
}
|
|
|
|
}
|
2019-08-16 23:05:39 +02:00
|
|
|
return new kdbxweb.ProtectedValue(
|
|
|
|
valueBytes.buffer.slice(0, byteLength),
|
|
|
|
saltBytes.buffer.slice(0, byteLength)
|
|
|
|
);
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-09-15 14:16:32 +02:00
|
|
|
export { SecureInput };
|