const
clipText = (str, length) => `${str.slice(0, length)}…`,
fill = (size, fn) => new Array(size).fill(0).map((_, i) => fn ? fn(i) : i);
/** test.js */
const main = () => {
const
generator = new PasswordGenerator({ symbols: true, length: 16 }),
passwords = fill(100, () => generator.next());
mocha.setup('bdd');
chai.should();
describe('Test JettyUtil', () =>
passwords.forEach(pw => {
const
ciphertext = JettyUtil.obfuscate(pw),
plaintext = JettyUtil.deobfuscate(ciphertext);
it(clipText(`${pw} → ${ciphertext}`, 64), () =>
pw.should.equal(plaintext))
}));
mocha.run();
};
/** jetty-util.js */
const
OBF_PREFIX = 'OBF:',
divmod = (m, n) => [ Math.trunc(m / n), m % n ],
unpack = (str) => str.split('').map(c => c.charCodeAt(0) & 0xFF),
chunk = (str, size) => str.match(new RegExp(`.{1,${size}}`, 'g'));
class JettyUtil {
static deobfuscate(ciphertext) {
return chunk(ciphertext.slice(OBF_PREFIX.length), 4)
.reduce((plaintext, i0) => {
const [ i1, i2 ] = divmod(parseInt(i0, 36), 256);
return plaintext + String.fromCharCode((i1 + i2 - 254) >> 1);
}, '');
}
static obfuscate(plaintext) {
return unpack(plaintext).reduce((ciphertext, b1, index, bytes) => {
const b2 = bytes[bytes.length - (index + 1)],
[ i1, i2 ] = [ 127 + b1 + b2, 127 + b1 - b2 ];
return ciphertext + (i1 * 256 + i2).toString(36).padStart(4, '0');
}, OBF_PREFIX);
}
}
// export default JettyUtil;
/** password-generator.js */
const Alphabet = {
UPPERCASE : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
LOWERCASE : 'abcdefghijklmnopqrstuvwxyz',
NUMBERS : '0123456789',
SYMBOLS : ' !"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'
};
class PasswordGenerator {
constructor(config) {
this.opts = { ...PasswordGenerator.defaultOptions, ...config };
this.alphabet = Object.entries(this.opts)
.map(([k, v]) => v === true ? Alphabet[k.toUpperCase()] : null)
.filter(v => v != null)
.join('');
}
next() {
return fill(this.opts.length, () => rando(this.alphabet)).join('');
}
}
PasswordGenerator.defaultOptions = {
uppercase : true,
lowercase : true,
numbers : true,
symbols : false,
length : 12
};
// export default PasswordGenerator;
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://randojs.com/2.0.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/7.2.0/mocha.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/7.2.0/mocha.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>
<div id="mocha"></div>