keeweb/app/scripts/comp/browser/secure-input.js

102 lines
3.0 KiB
JavaScript
Raw Normal View History

2021-05-08 11:38:23 +02:00
import * as kdbxweb from 'kdbxweb';
2016-01-17 13:23:07 +01:00
2020-06-01 16:53:51 +02:00
const SecureInput = function () {
2015-10-17 23:49:24 +02:00
this.el = null;
this.minChar = 0x1400 + Math.round(Math.random() * 100);
this.maxLen = 1024;
2015-10-17 23:49:24 +02:00
this.length = 0;
this.pseudoValue = '';
this.salt = new Uint32Array(0);
};
2020-06-01 16:53:51 +02:00
SecureInput.prototype.setElement = function (el) {
2015-10-17 23:49:24 +02:00
this.el = el;
this.el.val(this.pseudoValue);
this.el.on('input', this._input.bind(this));
};
2020-06-01 16:53:51 +02:00
SecureInput.prototype.reset = function () {
2015-10-17 23:49:24 +02:00
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);
};
2020-06-01 16:53:51 +02:00
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;
};
2020-06-01 16:53:51 +02:00
SecureInput.prototype._getChar = function (ix) {
2015-10-17 23:49:24 +02:00
return String.fromCharCode(this.minChar + ix);
};
2020-06-01 16:53:51 +02:00
SecureInput.prototype._isSpecialChar = function (ch) {
2015-10-17 23:49:24 +02:00
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);
2021-05-08 11:38:23 +02:00
const saltBytes = kdbxweb.CryptoEngine.random(len * 4);
2017-01-31 07:50:28 +01:00
let ch;
let bytes;
for (let i = 0; i < len; i++) {
2020-12-30 12:44:48 +01:00
const pseudoCharCode = pseudoValue.charCodeAt(i);
ch = String.fromCharCode(salt[i] ^ pseudoCharCode);
2016-01-17 13:23:07 +01:00
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 };