f79f816f916c2d16098c42c89cc1c385bf4fd270
[squeep-totp] / test / hotp.js
1 /* eslint-env: mocha */
2 'use strict';
3
4 const assert = require('assert');
5 const HOTP = require('../lib/hotp');
6
7 describe('HOTP', function () {
8 let options, hotp;
9
10 const tests = [
11 { count: 0n, hmac: Buffer.from('cc93cf18508d94934c64b65d8ba7667fb7cde4b0', 'hex'), hex: '4c93cf18', dec: 1284755224, hotp: '755224' },
12 { count: 1n, hmac: Buffer.from('75a48a19d4cbe100644e8ac1397eea747a2d33ab', 'hex'), hex: '41397eea', dec: 1094287082, hotp: '287082' },
13 { count: 2n, hmac: Buffer.from('0bacb7fa082fef30782211938bc1c5e70416ff44', 'hex'), hex: '82fef30', dec: 137359152, hotp: '359152' },
14 { count: 3n, hmac: Buffer.from('66c28227d03a2d5529262ff016a1e6ef76557ece', 'hex'), hex: '66ef7655', dec: 1726969429, hotp: '969429' },
15 { count: 4n, hmac: Buffer.from('a904c900a64b35909874b33e61c5938a8e15ed1c', 'hex'), hex: '61c5938a', dec: 1640338314, hotp: '338314' },
16 { count: 5n, hmac: Buffer.from('a37e783d7b7233c083d4f62926c7a25f238d0316', 'hex'), hex: '33c083d4', dec: 868254676, hotp: '254676' },
17 { count: 6n, hmac: Buffer.from('bc9cd28561042c83f219324d3c607256c03272ae', 'hex'), hex: '7256c032', dec: 1918287922, hotp: '287922' },
18 { count: 7n, hmac: Buffer.from('a4fb960c0bc06e1eabb804e5b397cdc4b45596fa', 'hex'), hex: '4e5b397', dec: 82162583, hotp: '162583' },
19 { count: 8n, hmac: Buffer.from('1b3c89f65e6c9e883012052823443f048b4332db', 'hex'), hex: '2823443f', dec: 673399871, hotp: '399871' },
20 { count: 9n, hmac: Buffer.from('1637409809a679dc698207310c8c7fc07290d9e5', 'hex'), hex: '2679dc69', dec: 645520489, hotp: '520489' },
21 ];
22
23 beforeEach(function () {
24 options = {
25 key: Buffer.from('12345678901234567890'),
26 };
27 hotp = new HOTP(options);
28 });
29
30 describe('constructor', function () {
31 it('covers invalid key', function () {
32 options.key = Buffer.from('blah');
33 assert.throws(() => new HOTP(options), RangeError);
34 });
35 it('covers invalid algorithm', function () {
36 options.algorithm = 'md5';
37 assert.throws(() => new HOTP(options), RangeError);
38 });
39 it('covers missing options', function () {
40 assert.throws(() => new HOTP());
41 });
42 it('covers counter', function () {
43 options.counter = 4;
44 hotp = new HOTP(options);
45 assert.strictEqual(hotp.counter, 4n);
46 });
47 }); // constructor
48
49 it('_hmac sanity', function () {
50 for (const test of tests) {
51 const result = hotp._hmac(test.count);
52 assert.strictEqual(Buffer.compare(result, test.hmac), 0, `count: ${test.count} result: ${result.toString('hex')} expected: ${test.hmac.toString('hex')}`);
53 }
54 }); // _hmac sanity
55
56 it('_truncate sanity', function () {
57 for (const test of tests) {
58 const result = hotp._truncate(test.count);
59 assert.strictEqual(result, test.dec, `count: ${test.count} result: ${result} expected: ${test.dec} (hex: ${result.toString(16)} hexpected: ${test.hex})`);
60 }
61 }); // _truncate sanity
62
63 it('generate', function () {
64 for (const test of tests) {
65 const result = hotp.generate();
66 assert.strictEqual(result, test.hotp, `count: ${test.count} htop.counter: ${hotp.counter} result: ${result} expected: ${test.hotp}`);
67 assert.strictEqual(hotp.counter, test.count + 1n);
68 }
69 }); // generate
70
71 it('covers generate with count', function () {
72 const result = hotp.generate(3n);
73 assert.strictEqual(result, tests[3].hotp);
74 }); // generate coverage
75
76 describe('validate', function () {
77 it('accepts correct hotp', function () {
78 const result = hotp.validate(tests[2].hotp, 2n);
79 assert.strictEqual(result, true);
80 });
81 }); // validate
82
83 }); // HOTP