keeweb/app/scripts/auto-type/auto-type-obfuscator.js

204 lines
6.3 KiB
JavaScript
Raw Normal View History

2016-04-09 14:55:27 +02:00
'use strict';
2016-04-23 16:50:40 +02:00
var Logger = require('../util/logger');
2016-04-09 14:55:27 +02:00
var logger = new Logger('auto-type-obfuscator');
logger.setLevel(localStorage.autoTypeDebug ? Logger.Level.All : Logger.Level.Warn);
2016-04-19 19:39:17 +02:00
var MaxFakeOps = 30;
2016-04-09 14:55:27 +02:00
var MaxSteps = 1000;
2016-04-10 08:32:18 +02:00
var MaxCopy = 2;
2016-04-09 14:55:27 +02:00
var FakeCharAlphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz123456789O0oIl';
var AutoTypeObfuscator = function(chars) {
this.chars = chars;
this.inputChars = [];
this.inputCursor = 0;
this.inputSel = 0;
this.ops = [];
this.stepCount = 0;
2016-04-10 08:32:18 +02:00
this.copyCount = 0;
2016-04-09 14:55:27 +02:00
};
AutoTypeObfuscator.prototype.obfuscate = function() {
while (!this.finished()) {
this.step();
if (this.stepCount++ > MaxSteps) {
throw 'Obfuscate failed';
}
}
for (var i = 0; i < this.chars.length; i++) {
this.chars[i] = null;
this.inputChars[i] = null;
}
return this.ops;
};
AutoTypeObfuscator.prototype.finished = function() {
return this.chars.length === this.inputChars.length &&
this.chars.every(function(ch, ix) { return this.inputChars[ix].ch === ch; }, this);
};
AutoTypeObfuscator.prototype.step = function() {
var isFake = this.stepCount < MaxFakeOps && Math.random() > this.stepCount / MaxFakeOps;
if (isFake) {
this.stepFake();
} else {
this.stepReal();
}
if (logger.getLevel() >= Logger.Level.Debug) {
2016-07-17 13:30:38 +02:00
logger.debug('value', this.inputChars.map(ic => ic.ch).join(''));
2016-04-09 14:55:27 +02:00
}
};
AutoTypeObfuscator.prototype.stepFake = function() {
var pos = Math.floor(Math.random() * (this.inputChars.length + 1));
var ch = FakeCharAlphabet[Math.floor(Math.random() * FakeCharAlphabet.length)];
logger.info('step.fake', pos, ch);
this.moveToPos(pos);
var insert = this.inputChars.length === 0 || Math.random() > 0.3;
if (insert) {
2016-04-10 08:32:18 +02:00
this.inputChar(ch);
2016-04-09 14:55:27 +02:00
} else {
2016-04-10 08:32:18 +02:00
var moveLeft = Math.random() > 0.5;
2016-04-09 14:55:27 +02:00
var maxMove = moveLeft ? pos : this.inputChars.length - pos;
2016-04-10 08:32:18 +02:00
if (maxMove === 0) {
moveLeft = !moveLeft;
maxMove = moveLeft ? pos : this.inputChars.length - pos;
}
2016-04-09 14:55:27 +02:00
var moveCount = Math.max(Math.floor(Math.pow(Math.random(), 3) * maxMove), 1);
if (moveCount <= 1 && Math.random() > 0.5) {
this.deleteText(moveLeft);
} else {
this.selectText(moveLeft, moveCount);
if (Math.random() > 0.3) {
this.deleteText(Math.random() > 0.5);
} else {
this.inputChar(ch);
}
}
}
};
AutoTypeObfuscator.prototype.stepReal = function() {
var possibleActions = [];
var inputRealPositions = [];
var i;
for (i = 0; i < this.chars.length; i++) {
inputRealPositions.push(-1);
}
for (i = 0; i < this.inputChars.length; i++) {
var ix = this.inputChars[i].ix;
if (ix === undefined) {
possibleActions.push({ del: true, pos: i });
} else {
inputRealPositions[ix] = i;
}
}
for (i = 0; i < this.chars.length; i++) {
if (inputRealPositions[i] < 0) {
var from = 0, to = this.inputChars.length;
for (var j = 0; j < this.chars.length; j++) {
if (j < i && inputRealPositions[j] >= 0) {
from = inputRealPositions[j] + 1;
}
if (j > i && inputRealPositions[j] >= 0) {
to = inputRealPositions[j];
break;
}
}
possibleActions.push({ ins: true, ch: this.chars[i], ix: i, from: from, to: to });
}
}
var action = possibleActions[Math.floor(Math.random() * possibleActions.length)];
logger.info('step.real', inputRealPositions, action);
if (action.del) {
this.moveToPos(action.pos + 1);
this.deleteText(true);
} else {
var insPos = action.from + Math.floor(Math.random() * (action.to - action.from));
this.moveToPos(insPos);
2016-04-24 14:08:46 +02:00
if (this.copyCount < MaxCopy && action.ch !== '\n' && Math.random() > 0.5) {
2016-04-10 08:32:18 +02:00
this.copyCount++;
2016-04-09 14:55:27 +02:00
this.copyPaste(action.ch);
2016-04-10 08:32:18 +02:00
} else {
this.inputChar(action.ch);
2016-04-09 14:55:27 +02:00
}
this.inputChars[insPos].ix = action.ix;
}
};
AutoTypeObfuscator.prototype.moveToPos = function(pos) {
logger.debug('moveToPos', pos);
while (this.inputCursor > pos) {
this.moveLeft();
}
while (this.inputCursor < pos) {
this.moveRight();
}
};
AutoTypeObfuscator.prototype.moveLeft = function() {
logger.debug('moveLeft');
this.ops.push({ type: 'key', value: 'left' });
this.inputCursor--;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.moveRight = function() {
logger.debug('moveRight');
this.ops.push({ type: 'key', value: 'right' });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.inputChar = function(ch) {
logger.debug('inputChar', ch);
this.ops.push({ type: 'text', value: ch });
this.inputChars.splice(this.inputCursor, this.inputSel, { ch: ch });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.copyPaste = function(ch) {
logger.debug('copyPaste', ch);
2016-04-10 08:32:18 +02:00
this.ops.push({type: 'cmd', value: 'copyPaste', arg: ch});
2016-04-09 14:55:27 +02:00
this.inputChars.splice(this.inputCursor, this.inputSel, { ch: ch });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.selectText = function(backward, count) {
logger.debug('selectText', backward ? 'left' : 'right', count);
var ops = [];
for (var i = 0; i < count; i++) {
ops.push({ type: 'key', value: backward ? 'left' : 'right' });
}
if (ops.length === 1) {
ops[0].mod = {'+': true};
this.ops.push(ops[0]);
} else {
this.ops.push({type: 'group', value: ops, mod: {'+': true}});
}
if (backward) {
this.inputCursor -= count;
}
this.inputSel = count;
};
AutoTypeObfuscator.prototype.deleteText = function(backward) {
logger.debug('deleteText', backward ? 'left' : 'right');
this.ops.push({ type: 'key', value: backward ? 'bs' : 'del' });
2016-04-10 08:32:18 +02:00
if (this.inputSel) {
this.inputChars.splice(this.inputCursor, this.inputSel);
this.inputSel = 0;
} else {
this.inputChars.splice(backward ? this.inputCursor - 1 : this.inputCursor, 1);
if (backward) {
this.inputCursor--;
}
2016-04-09 14:55:27 +02:00
}
};
module.exports = AutoTypeObfuscator;