initial commit
[squeep-mystery-box] / test / lib / mystery-box.js
1 /* eslint-env mocha */
2 /* eslint-disable capitalized-comments */
3 'use strict';
4
5 const assert = require('assert');
6 const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
7 const MysteryBox = require('../../lib/mystery-box');
8 const stubLogger = require('../stub-logger');
9
10 describe('MysteryBox', function () {
11 const noExpectedException = 'did not get expected exception';
12 let mb, options, object;
13 beforeEach(function () {
14 options = {
15 encryptionSecret: 'this is not a very good secret',
16 };
17 });
18 afterEach(function () {
19 sinon.restore();
20 });
21
22 describe('constructor', function () {
23 it('needs a secret', async function () {
24 options = {};
25 try {
26 mb = new MysteryBox(stubLogger, options);
27 assert.fail(noExpectedException);
28 } catch (e) {
29 assert.strictEqual(e.message, 'missing encryption secret', noExpectedException);
30 }
31 });
32
33 it('covers options', function () {
34 try {
35 mb = new MysteryBox(stubLogger);
36 assert.fail(noExpectedException);
37 } catch (e) {
38 assert.strictEqual(e.message, 'missing encryption secret', noExpectedException);
39 }
40 });
41
42 it('covers bad flags', function () {
43 options.defaultFlags = 300;
44 try {
45 mb = new MysteryBox(stubLogger, options);
46 assert.fail(noExpectedException);
47 } catch (e) {
48 assert(e instanceof RangeError, noExpectedException);
49 }
50 });
51
52 it('covers missing ciphers', function () {
53 sinon.stub(MysteryBox._test.crypto, 'getCiphers').returns(['rot13']);
54 try {
55 mb = new MysteryBox(stubLogger, options);
56 assert.fail(noExpectedException);
57 } catch (e) {
58 assert.strictEqual(e.message, 'no supported versions available', noExpectedException);
59 }
60 });
61 }); // constructor
62
63 describe('pack, unpack', function () {
64 beforeEach(function () {
65 mb = new MysteryBox(stubLogger, options);
66 });
67
68 it('covers packing unsupported version', async function () {
69 try {
70 await mb.pack({}, 0);
71 assert.fail(noExpectedException);
72 } catch (e) {
73 assert(e instanceof RangeError, noExpectedException);
74 }
75 });
76
77 it('covers unpacking unsupported version', async function () {
78 const badBuffer = Buffer.alloc(128);
79 badBuffer.writeUInt8(0, 0); // No such thing as version 0
80 const badPayload = badBuffer.toString('base64');
81 try {
82 await mb.unpack(badPayload);
83 assert.fail(noExpectedException);
84 } catch (e) {
85 assert(e instanceof RangeError, noExpectedException);
86 }
87 });
88
89 it('encrypts and decrypts default version', async function () {
90 this.slow(500);
91 object = {
92 foo: 'bar',
93 baz: 'quux',
94 flarp: 13,
95 };
96 const encryptedResult = await mb.pack(object);
97 const decryptedResult = await mb.unpack(encryptedResult);
98 assert.deepStrictEqual(decryptedResult, object);
99 });
100
101 it('encrypts and decrypts default version, buffer contents', async function () {
102 this.slow(500);
103 object = Buffer.from('a fine little buffer');
104 const encryptedResult = await mb.pack(object);
105 const decryptedResult = await mb.unpack(encryptedResult);
106 assert.deepStrictEqual(decryptedResult, object);
107 });
108
109 it('encrypts and decrypts all available versions +brotli', async function () {
110 Object.keys(mb.versionParameters).map((v) => Number(v)).forEach(async (version) => {
111 object = {
112 foo: 'bar',
113 baz: 'quux',
114 flarp: 13,
115 };
116 const encryptedResult = await mb.pack(object, version, 0x00);
117 const decryptedResult = await mb.unpack(encryptedResult);
118 assert.deepStrictEqual(decryptedResult, object, `${version} results not symmetric`);
119 });
120 });
121
122 it('encrypts and decrypts all available versions +flate', async function () {
123 Object.keys(mb.versionParameters).map((v) => Number(v)).forEach(async (version) => {
124 object = {
125 foo: 'bar',
126 baz: 'quux',
127 flarp: 13,
128 };
129 const encryptedResult = await mb.pack(object, version, 0x01);
130 const decryptedResult = await mb.unpack(encryptedResult);
131 assert.deepStrictEqual(decryptedResult, object, `${version} results not symmetric`);
132 });
133 });
134
135 it('handles large object +brotli', async function () {
136 this.timeout(5000);
137 this.slow(2000);
138 const firstChar = 32, lastChar = 126;
139 const rnd = () => {
140 return Math.floor(firstChar + (lastChar - firstChar + 1) * Math.random());
141 }
142 object = {
143 longProperty: 'x'.repeat(384 * 1024).split('').map(() => String.fromCharCode(rnd())).join(''),
144 };
145 const encryptedResult = await mb.pack(object, mb.bestVersion, 0x00);
146 const decryptedResult = await mb.unpack(encryptedResult);
147 assert.deepStrictEqual(decryptedResult, object);
148 });
149
150 it('handles large object +flate', async function () {
151 this.timeout(5000);
152 this.slow(2000);
153 const firstChar = 32, lastChar = 126;
154 const rnd = () => {
155 return Math.floor(firstChar + (lastChar - firstChar + 1) * Math.random());
156 }
157 object = {
158 longProperty: 'x'.repeat(384 * 1024).split('').map(() => String.fromCharCode(rnd())).join(''),
159 };
160 const encryptedResult = await mb.pack(object, mb.bestVersion, 0x01);
161 const decryptedResult = await mb.unpack(encryptedResult);
162 assert.deepStrictEqual(decryptedResult, object);
163 });
164 }); // pack, unpack
165
166 }); // MysteryBox