/* * Copyright (C) Sapphirecode - All Rights Reserved * This file is part of Auth-Server-Helper which is released under MIT. * See file 'LICENSE' for full license details. * Created by Timo Hocker , December 2020 */ import ks, { KeyStore } from '../../lib/KeyStore'; import { clock_finalize, clock_setup } from '../Helper'; const frame = 3600; /* eslint-disable-next-line max-lines-per-function */ describe ('key store', () => { beforeAll (() => { clock_setup (); }); afterAll (() => { clock_finalize (); }); const keys: {key: string, sign: string, iat: number}[] = []; it ('should generate a new key', async () => { const iat = (new Date) .getTime () / 1000; const duration = 10 * frame; const key = await ks.get_sign_key (iat, duration); const sign = await ks.get_key (iat); expect (typeof key) .toEqual ('string'); expect (typeof sign) .toEqual ('string'); keys.push ({ iat, key, sign }); }); it ('should return the generated key', async () => { const key = await ks.get_sign_key (keys[0].iat, 1); expect (key) .toEqual (keys[0].key); const sign = await ks.get_key (keys[0].iat); expect (sign) .toEqual (keys[0].sign); }); it ('should return the same key on a different time', async () => { const key = await ks.get_sign_key (keys[0].iat + (frame / 2), 1); expect (key) .toEqual (keys[0].key); const sign = await ks.get_key (keys[0].iat + (frame / 2)); expect (sign) .toEqual (keys[0].sign); }); it ('should generate a new key after time frame is over', async () => { jasmine.clock () .tick (frame * 1000); const iat = (new Date) .getTime () / 1000; const duration = 10 * frame; const key = await ks.get_sign_key (iat, duration); const sign = await ks.get_key (iat); expect (typeof key) .toEqual ('string'); expect (key).not.toEqual (keys[0].key); expect (sign).not.toEqual (keys[0].sign); keys.push ({ iat, key, sign }); }); it ('should return both keys, but not the first sign key', async () => { const sign = await ks.get_key (keys[0].iat); expect (sign) .toEqual (keys[0].sign); await expectAsync (ks.get_sign_key (keys[0].iat, 1)) .toBeRejectedWithError ('cannot access already expired keys'); const k2 = await ks.get_sign_key (keys[1].iat, 1); const s2 = await ks.get_key (keys[1].iat); expect (k2) .toEqual (keys[1].key); expect (s2) .toEqual (keys[1].sign); }); it ('should throw on non existing key', async () => { await expectAsync (ks.get_key (keys[1].iat + frame)) .toBeRejectedWithError ('key could not be found'); }); it ('should delete a key after it expires', async () => { // go to 10 frames + 1ms after key creation jasmine.clock () .tick ((frame * 9e3) + 1); // eslint-disable-next-line dot-notation ks['garbage_collect'] (); await expectAsync (ks.get_key (keys[0].iat)) .toBeRejectedWithError ('key could not be found'); }); it ( 'should still retrieve the second key, but not its sign key', async () => { await expectAsync (ks.get_sign_key (keys[1].iat, 1)) .toBeRejectedWithError ('cannot access already expired keys'); const sign = await ks.get_key (keys[1].iat); expect (sign) .toEqual (keys[1].sign); } ); it ('should reject key generation of expired keys', async () => { const iat = ((new Date) .getTime () / 1000) - 2; const duration = 5; await expectAsync (ks.get_sign_key (iat, duration)) .toBeRejectedWithError ('cannot access already expired keys'); }); it ('key should live as long as the longest created token', async () => { jasmine.clock () .tick (frame * 10e3); const iat = (new Date) .getTime () / 1000; const duration1 = frame; const duration2 = frame * 10; const key1 = await ks.get_sign_key (iat, duration1); const step = 0.9 * frame; jasmine.clock () .tick (step * 1000); const key2 = await ks.get_sign_key (iat + step, duration2); const sign = await ks.get_key (iat); expect (key1) .toEqual (key2); jasmine.clock () .tick (5000 * frame); const signv = await ks.get_key (iat + step); expect (signv) .toEqual (sign); }); it ('should not allow invalid expiry times', async () => { await expectAsync (ks.get_sign_key (0, 0)) .toBeRejectedWithError ('cannot create infinitely valid key'); await expectAsync (ks.get_sign_key (0, -1)) .toBeRejectedWithError ('cannot create infinitely valid key'); }); it ('should export and import all keys', async () => { const iat = (new Date) .getTime () / 1000; const sign = await ks.get_sign_key (iat, frame); const ver = await ks.get_key (iat); const exp = ks.export_verification_data (); // eslint-disable-next-line dot-notation expect (Object.keys (ks['_keys'])) .toEqual (exp.map ((v) => v.index)); const ks2 = (new KeyStore); expect (ks2.instance_id).not.toEqual (ks.instance_id); ks2.import_verification_data (exp); // eslint-disable-next-line dot-notation expect (Object.keys (ks2['_keys'])) .toEqual (exp.map ((v) => v.index)); const sign2 = await ks2.get_sign_key (iat, frame); const ver2 = await ks2.get_key (iat); expect (sign).not.toEqual (sign2); expect (ver).not.toEqual (ver2); await expectAsync (ks2.get_sign_key (iat, 60, ks.instance_id)) .toBeRejectedWithError ('cannot access already expired keys'); expect (await ks2.get_key (iat, ks.instance_id)) .toEqual (ver); }); it ('should disallow importing to itself', () => { const exp = ks.export_verification_data (); expect (() => ks.import_verification_data (exp)) .toThrowError ('cannot import to the same instance'); }); it ('should clear all', () => { // eslint-disable-next-line dot-notation expect (Object.keys (ks['_keys']).length) .toBeGreaterThan (0); const instance = ks.instance_id; ks.reset_instance (); // eslint-disable-next-line dot-notation expect (Object.keys (ks['_keys']).length) .toEqual (0); expect (instance).not.toEqual (ks.instance_id); }); });