This commit is contained in:
parent
05f2e53a8f
commit
df8de9e0c8
@ -7,26 +7,50 @@
|
||||
|
||||
import { create_salt } from '@sapphirecode/crypto-helper';
|
||||
|
||||
interface Key {
|
||||
key: string;
|
||||
valid_until: number;
|
||||
timeout: NodeJS.Timeout;
|
||||
}
|
||||
|
||||
class KeyStore {
|
||||
private _keys: Record<string, string> = {};
|
||||
private _keys: Record<string, Key> = {};
|
||||
|
||||
private set_timeout (index: string, valid_for: number): NodeJS.Timeout {
|
||||
return setTimeout (() => {
|
||||
delete this._keys[index];
|
||||
}, (valid_for + 5) * 1000);
|
||||
}
|
||||
|
||||
public get_key (iat: number, valid_for = 0): string {
|
||||
const key = Math.floor (iat / 60)
|
||||
const index = Math.floor (iat / 60)
|
||||
.toFixed (0);
|
||||
|
||||
if (typeof this._keys[key] === 'string')
|
||||
return this._keys[key];
|
||||
const valid_until = (new Date)
|
||||
.getTime () + (valid_for * 1000);
|
||||
|
||||
if (typeof this._keys[index] !== 'undefined') {
|
||||
const key = this._keys[index];
|
||||
if (valid_for !== 0 && key.valid_until < valid_until) {
|
||||
clearTimeout (key.timeout);
|
||||
key.timeout = this.set_timeout (index, valid_for);
|
||||
key.valid_until = valid_until;
|
||||
}
|
||||
return key.key;
|
||||
}
|
||||
|
||||
if (valid_for !== 0) {
|
||||
if ((iat + valid_for) * 1000 < (new Date)
|
||||
if ((iat + 1) * 1000 < (new Date)
|
||||
.getTime ())
|
||||
throw new Error ('cannot create already expired keys');
|
||||
|
||||
this._keys[key] = create_salt ();
|
||||
setTimeout (() => {
|
||||
delete this._keys[key];
|
||||
}, (valid_for + 5) * 1000);
|
||||
return this._keys[key];
|
||||
this._keys[index] = {
|
||||
key: create_salt (),
|
||||
timeout: this.set_timeout (index, valid_for),
|
||||
valid_until
|
||||
};
|
||||
|
||||
return this._keys[index].key;
|
||||
}
|
||||
|
||||
throw new Error ('key could not be found');
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
import ks from '../../lib/KeyStore';
|
||||
|
||||
const frame = 60;
|
||||
|
||||
/* eslint-disable-next-line max-lines-per-function */
|
||||
describe ('key store', () => {
|
||||
beforeAll (() => {
|
||||
@ -23,7 +25,7 @@ describe ('key store', () => {
|
||||
it ('should generate a new key', () => {
|
||||
const iat = (new Date)
|
||||
.getTime () / 1000;
|
||||
const duration = 600;
|
||||
const duration = 10 * frame;
|
||||
const key = ks.get_key (iat, duration);
|
||||
expect (typeof key)
|
||||
.toEqual ('string');
|
||||
@ -39,17 +41,17 @@ describe ('key store', () => {
|
||||
});
|
||||
|
||||
it ('should return the same key on a different time', () => {
|
||||
const key = ks.get_key (keys[0].iat + 30);
|
||||
const key = ks.get_key (keys[0].iat + (frame / 2));
|
||||
expect (key)
|
||||
.toEqual (keys[0].key);
|
||||
});
|
||||
|
||||
it ('should generate a new key after 60 seconds', () => {
|
||||
it ('should generate a new key after time frame is over', () => {
|
||||
jasmine.clock ()
|
||||
.tick (60000);
|
||||
.tick (frame * 1000);
|
||||
const iat = (new Date)
|
||||
.getTime () / 1000;
|
||||
const duration = 600;
|
||||
const duration = 10 * frame;
|
||||
const key = ks.get_key (iat, duration);
|
||||
expect (typeof key)
|
||||
.toEqual ('string');
|
||||
@ -69,13 +71,13 @@ describe ('key store', () => {
|
||||
});
|
||||
|
||||
it ('should throw on non existing key', () => {
|
||||
expect (() => ks.get_key (keys[1].iat + 60))
|
||||
expect (() => ks.get_key (keys[1].iat + frame))
|
||||
.toThrowError ('key could not be found');
|
||||
});
|
||||
|
||||
it ('should delete a key after it expires', () => {
|
||||
jasmine.clock ()
|
||||
.tick (600000);
|
||||
.tick (10000 * frame);
|
||||
expect (() => ks.get_key (keys[0].iat))
|
||||
.toThrowError ('key could not be found');
|
||||
});
|
||||
@ -88,12 +90,40 @@ describe ('key store', () => {
|
||||
|
||||
it ('should reject key generation of expired keys', () => {
|
||||
const iat = ((new Date)
|
||||
.getTime () / 1000) - 10;
|
||||
.getTime () / 1000) - 2;
|
||||
const duration = 5;
|
||||
expect (() => ks.get_key (iat, duration))
|
||||
.toThrowError ('cannot create already expired keys');
|
||||
});
|
||||
|
||||
it ('key should live as long as the longest created token', () => {
|
||||
const base = new Date;
|
||||
base.setSeconds (2, 0);
|
||||
jasmine.clock ()
|
||||
.mockDate (base);
|
||||
jasmine.clock ()
|
||||
.tick (24 * 60 * 60 * 1000);
|
||||
const iat = (new Date)
|
||||
.getTime () / 1000;
|
||||
const duration1 = frame;
|
||||
const duration2 = frame * 10;
|
||||
|
||||
const key1 = ks.get_key (iat, duration1);
|
||||
const step = 0.9 * frame;
|
||||
jasmine.clock ()
|
||||
.tick (step * 1000);
|
||||
const key2 = ks.get_key (iat + step, duration2);
|
||||
expect (key1)
|
||||
.toEqual (key2);
|
||||
jasmine.clock ()
|
||||
.tick (5000 * frame);
|
||||
const keyv = ks.get_key (iat + step);
|
||||
expect (keyv)
|
||||
.toEqual (key1);
|
||||
});
|
||||
|
||||
// required use case: insert keys for verification of old tokens
|
||||
|
||||
afterAll (() => {
|
||||
jasmine.clock ()
|
||||
.tick (24 * 60 * 60 * 1000);
|
||||
|
Loading…
x
Reference in New Issue
Block a user