fixes
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Timo Hocker 2021-01-07 15:43:54 +01:00
parent fd4f891b3e
commit 4c42a682d5
7 changed files with 69 additions and 84 deletions

View File

@ -42,30 +42,32 @@ async function create_key (valid_for: number) {
}; };
} }
function garbage_collect (set: KeyStoreData): void {
const time = (new Date)
.getTime ();
for (const index of Object.keys (set)) {
const entry = set[index];
if (typeof entry.private_key !== 'undefined'
&& entry.private_key.valid_until < time
)
delete entry.private_key;
if (entry.public_key.valid_until < time)
delete set[index];
}
}
class KeyStore { class KeyStore {
private _keys: KeyStoreData = {}; private _keys: KeyStoreData = {};
private _interval: NodeJS.Timeout; private _interval: NodeJS.Timeout;
public constructor () { public constructor () {
this._interval = setInterval (() => { this._interval = setInterval (() => {
garbage_collect (this._keys); this.garbage_collect ();
}, renew_interval); }, renew_interval);
} }
private garbage_collect (set: KeyStoreData = this._keys): void {
const time = (new Date)
.getTime ();
const keys = Object.keys (set);
for (const index of keys) {
const entry = set[index];
if (typeof entry.private_key !== 'undefined'
&& entry.private_key.valid_until < time
)
delete entry.private_key;
if (entry.public_key.valid_until < time)
delete set[index];
}
}
public async get_sign_key (iat: number, valid_for: number): Promise<string> { public async get_sign_key (iat: number, valid_for: number): Promise<string> {
if (valid_for <= 0) if (valid_for <= 0)
throw new Error ('cannot create infinitely valid key'); throw new Error ('cannot create infinitely valid key');
@ -87,7 +89,7 @@ class KeyStore {
return key.private_key?.key as string; return key.private_key?.key as string;
} }
this._keys[index] = await create_key (valid_until); this._keys[index] = await create_key (valid_for);
return this._keys[index].private_key?.key as string; return this._keys[index].private_key?.key as string;
} }
@ -102,7 +104,7 @@ class KeyStore {
} }
public export_verification_data (): KeyStoreData { public export_verification_data (): KeyStoreData {
garbage_collect (this._keys); this.garbage_collect ();
const out: KeyStoreData = {}; const out: KeyStoreData = {};
for (const index of Object.keys (this._keys)) for (const index of Object.keys (this._keys))
out[index] = { public_key: this._keys[index].public_key }; out[index] = { public_key: this._keys[index].public_key };
@ -112,7 +114,7 @@ class KeyStore {
public import_verification_data (data: KeyStoreData): void { public import_verification_data (data: KeyStoreData): void {
const import_set = { ...data }; const import_set = { ...data };
garbage_collect (import_set); this.garbage_collect (import_set);
// TODO: import // TODO: import
} }

View File

@ -7,6 +7,7 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import http from 'http'; import http from 'http';
import { type } from 'os';
import ks from '../lib/KeyStore'; import ks from '../lib/KeyStore';
export class Response extends http.IncomingMessage { export class Response extends http.IncomingMessage {
@ -46,24 +47,35 @@ export function modify_signature (signature: string): string {
/* eslint-disable dot-notation */ /* eslint-disable dot-notation */
export function assert_keystore_state (): void { export function assert_keystore_state (): void {
if (Object.keys (ks['_keys']).length !== 0) { const set = ks['_keys'];
const keys = Object.keys (set);
if (keys.length !== 0) {
const has_sign = keys.filter (
(v) => typeof set[v].private_key !== 'undefined'
).length;
console.warn ('keystore gc not running!'); console.warn ('keystore gc not running!');
console.warn (`${keys.length} keys with ${has_sign} signature keys left`);
ks['_keys'] = {}; ks['_keys'] = {};
} }
} }
/* eslint-enable dot-notation */ /* eslint-enable dot-notation */
export function flush_routine (install_clock = true):void { export function clock_setup ():void {
if (install_clock) { assert_keystore_state ();
jasmine.clock ()
.install (); const date = (new Date);
} date.setSeconds (2, 0);
jasmine.clock () jasmine.clock ()
.mockDate (new Date); .install ();
jasmine.clock ()
.mockDate (date);
}
export function clock_finalize ():void {
jasmine.clock () jasmine.clock ()
.tick (30 * 24 * 60 * 60 * 1000); .tick (30 * 24 * 60 * 60 * 1000);
if (install_clock) { // eslint-disable-next-line dot-notation
jasmine.clock () ks['garbage_collect'] ();
.uninstall (); jasmine.clock ()
} .uninstall ();
} }

View File

@ -9,7 +9,8 @@ import http, { IncomingMessage, ServerResponse } from 'http';
import { to_b64 } from '@sapphirecode/encoding-helper'; import { to_b64 } from '@sapphirecode/encoding-helper';
import auth from '../../lib/Authority'; import auth from '../../lib/Authority';
import { import {
assert_keystore_state, flush_routine, clock_finalize,
clock_setup,
get, modify_signature, Response get, modify_signature, Response
} from '../Helper'; } from '../Helper';
import { create_auth_handler } from '../../lib/index'; import { create_auth_handler } from '../../lib/index';
@ -52,8 +53,7 @@ describe ('auth handler', () => {
let server: http.Server|null = null; let server: http.Server|null = null;
// eslint-disable-next-line max-lines-per-function // eslint-disable-next-line max-lines-per-function
beforeAll (() => { beforeAll (() => {
flush_routine (); clock_setup ();
assert_keystore_state ();
const ah = create_auth_handler ((req) => { const ah = create_auth_handler ((req) => {
if (!req.is_basic && !req.is_bearer) { if (!req.is_basic && !req.is_bearer) {
@ -100,19 +100,13 @@ describe ('auth handler', () => {
ah (req, res); ah (req, res);
}); });
server.listen (3000); server.listen (3000);
jasmine.clock ()
.install ();
jasmine.clock ()
.mockDate (new Date);
}); });
afterAll (() => { afterAll (() => {
if (server === null) if (server === null)
throw new Error ('server is null'); throw new Error ('server is null');
server.close (); server.close ();
jasmine.clock () clock_finalize ();
.uninstall ();
}); });
it ('auth test sequence', async () => { it ('auth test sequence', async () => {

View File

@ -8,24 +8,19 @@
import auth from '../../lib/Authority'; import auth from '../../lib/Authority';
import bl from '../../lib/Blacklist'; import bl from '../../lib/Blacklist';
import { import {
assert_keystore_state, clock_finalize,
flush_routine, modify_signature clock_setup,
modify_signature
} from '../Helper'; } from '../Helper';
// eslint-disable-next-line max-lines-per-function // eslint-disable-next-line max-lines-per-function
describe ('authority', () => { describe ('authority', () => {
beforeEach (() => { beforeEach (() => {
jasmine.clock () clock_setup ();
.install ();
jasmine.clock ()
.mockDate (new Date);
}); });
afterEach (() => { afterEach (() => {
flush_routine (false); clock_finalize ();
assert_keystore_state ();
jasmine.clock ()
.uninstall ();
}); });
it ('should create an access token', async () => { it ('should create an access token', async () => {

View File

@ -6,19 +6,16 @@
*/ */
import blacklist from '../../lib/Blacklist'; import blacklist from '../../lib/Blacklist';
import { clock_finalize, clock_setup } from '../Helper';
// eslint-disable-next-line max-lines-per-function // eslint-disable-next-line max-lines-per-function
describe ('blacklist', () => { describe ('blacklist', () => {
beforeAll (() => { beforeAll (() => {
jasmine.clock () clock_setup ();
.install ();
jasmine.clock ()
.mockDate (new Date);
}); });
afterAll (() => { afterAll (() => {
jasmine.clock () clock_finalize ();
.uninstall ();
}); });
it ('should validate any string', () => { it ('should validate any string', () => {

View File

@ -9,19 +9,14 @@ import http from 'http';
import { create_gateway } from '../../lib/index'; import { create_gateway } from '../../lib/index';
import authority from '../../lib/Authority'; import authority from '../../lib/Authority';
import blacklist from '../../lib/Blacklist'; import blacklist from '../../lib/Blacklist';
import { assert_keystore_state, flush_routine, get } from '../Helper'; import { clock_finalize, clock_setup, get } from '../Helper';
// eslint-disable-next-line max-lines-per-function // eslint-disable-next-line max-lines-per-function
describe ('gateway', () => { describe ('gateway', () => {
let server: http.Server|null = null; let server: http.Server|null = null;
beforeAll (() => { beforeAll (() => {
flush_routine (); clock_setup ();
assert_keystore_state ();
jasmine.clock ()
.install ();
jasmine.clock ()
.mockDate (new Date);
const g = create_gateway ({ const g = create_gateway ({
redirect_url: 'http://localhost/auth', redirect_url: 'http://localhost/auth',
@ -44,8 +39,7 @@ describe ('gateway', () => {
throw new Error ('server is null'); throw new Error ('server is null');
server.close (); server.close ();
jasmine.clock () clock_finalize ();
.uninstall ();
}); });
it ('should redirect any unauthorized request', async () => { it ('should redirect any unauthorized request', async () => {

View File

@ -6,21 +6,18 @@
*/ */
import ks from '../../lib/KeyStore'; import ks from '../../lib/KeyStore';
import { assert_keystore_state, flush_routine } from '../Helper'; import { clock_finalize, clock_setup } from '../Helper';
const frame = 60; const frame = 60;
/* eslint-disable-next-line max-lines-per-function */ /* eslint-disable-next-line max-lines-per-function */
describe ('key store', () => { describe ('key store', () => {
beforeAll (() => { beforeAll (() => {
flush_routine (); clock_setup ();
assert_keystore_state (); });
jasmine.clock ()
.install (); afterAll (() => {
const base_date = (new Date); clock_finalize ();
base_date.setSeconds (2);
jasmine.clock ()
.mockDate (base_date);
}); });
const keys: {key:string, sign:string, iat:number}[] = []; const keys: {key:string, sign:string, iat:number}[] = [];
@ -91,8 +88,11 @@ describe ('key store', () => {
}); });
it ('should delete a key after it expires', () => { it ('should delete a key after it expires', () => {
// go to 10 frames + 1ms after key creation
jasmine.clock () jasmine.clock ()
.tick (10000 * frame); .tick ((frame * 9e3) + 1);
// eslint-disable-next-line dot-notation
ks['garbage_collect'] ();
expect (() => ks.get_key (keys[0].iat)) expect (() => ks.get_key (keys[0].iat))
.toThrowError ('key could not be found'); .toThrowError ('key could not be found');
}); });
@ -117,12 +117,8 @@ describe ('key store', () => {
}); });
it ('key should live as long as the longest created token', async () => { it ('key should live as long as the longest created token', async () => {
const base = new Date;
base.setSeconds (2, 0);
jasmine.clock () jasmine.clock ()
.mockDate (base); .tick (frame * 10e3);
jasmine.clock ()
.tick (24 * 60 * 60 * 1000);
const iat = (new Date) const iat = (new Date)
.getTime () / 1000; .getTime () / 1000;
const duration1 = frame; const duration1 = frame;
@ -151,9 +147,4 @@ describe ('key store', () => {
}); });
// TODO: required use case: insert keys for verification of old tokens // TODO: required use case: insert keys for verification of old tokens
afterAll (() => {
jasmine.clock ()
.uninstall ();
});
}); });