This commit is contained in:
103
lib/KeyStore.ts
103
lib/KeyStore.ts
@ -7,34 +7,66 @@
|
||||
|
||||
import { generate_keypair } from '@sapphirecode/crypto-helper';
|
||||
|
||||
interface Keypair {
|
||||
private_key: string;
|
||||
public_key: string;
|
||||
}
|
||||
const renew_interval = 60;
|
||||
|
||||
interface Key {
|
||||
key: Keypair;
|
||||
key: string;
|
||||
valid_until: number;
|
||||
timeout: NodeJS.Timeout;
|
||||
}
|
||||
|
||||
interface KeyPair {
|
||||
private_key?: Key;
|
||||
public_key: Key;
|
||||
}
|
||||
|
||||
type KeyStoreData = Record<string, KeyPair>;
|
||||
|
||||
function get_index (iat: number): string {
|
||||
return Math.floor (iat / 60)
|
||||
return Math.floor (iat / renew_interval)
|
||||
.toFixed (0);
|
||||
}
|
||||
|
||||
class KeyStore {
|
||||
private _keys: Record<string, Key> = {};
|
||||
async function create_key (valid_for: number) {
|
||||
const time = (new Date)
|
||||
.getTime ();
|
||||
const pair = await generate_keypair ();
|
||||
return {
|
||||
private_key: {
|
||||
key: pair.private_key,
|
||||
valid_until: time + (renew_interval * 1000)
|
||||
},
|
||||
public_key: {
|
||||
key: pair.public_key,
|
||||
valid_until: time + (valid_for * 1000)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private set_timeout (index: string, valid_for: number): NodeJS.Timeout {
|
||||
return setTimeout (() => {
|
||||
delete this._keys[index];
|
||||
}, (valid_for + 5) * 1000);
|
||||
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 {
|
||||
private _keys: KeyStoreData = {};
|
||||
private _interval: NodeJS.Timeout;
|
||||
|
||||
public constructor () {
|
||||
this._interval = setInterval (() => {
|
||||
garbage_collect (this._keys);
|
||||
}, renew_interval);
|
||||
}
|
||||
|
||||
public async get_sign_key (iat: number, valid_for: number): Promise<string> {
|
||||
const index = get_index (iat);
|
||||
|
||||
if (valid_for <= 0)
|
||||
throw new Error ('cannot create infinitely valid key');
|
||||
|
||||
@ -42,26 +74,21 @@ class KeyStore {
|
||||
.getTime ())
|
||||
throw new Error ('cannot access already expired keys');
|
||||
|
||||
const index = get_index (iat);
|
||||
|
||||
const valid_until = (new Date)
|
||||
.getTime () + (valid_for * 1000);
|
||||
|
||||
if (typeof this._keys[index] !== 'undefined') {
|
||||
const key = this._keys[index];
|
||||
if (key.valid_until < valid_until) {
|
||||
clearTimeout (key.timeout);
|
||||
key.timeout = this.set_timeout (index, valid_for);
|
||||
key.valid_until = valid_until;
|
||||
}
|
||||
return key.key.private_key;
|
||||
if (key.public_key.valid_until < valid_until)
|
||||
key.public_key.valid_until = valid_until;
|
||||
|
||||
return key.private_key?.key as string;
|
||||
}
|
||||
|
||||
this._keys[index] = {
|
||||
key: await generate_keypair (),
|
||||
timeout: this.set_timeout (index, valid_for),
|
||||
valid_until
|
||||
};
|
||||
|
||||
return this._keys[index].key.private_key;
|
||||
this._keys[index] = await create_key (valid_until);
|
||||
return this._keys[index].private_key?.key as string;
|
||||
}
|
||||
|
||||
public get_key (iat: number): string {
|
||||
@ -71,10 +98,26 @@ class KeyStore {
|
||||
throw new Error ('key could not be found');
|
||||
|
||||
const key = this._keys[index];
|
||||
return key.key.public_key;
|
||||
return key.public_key.key;
|
||||
}
|
||||
|
||||
public export_verification_data (): KeyStoreData {
|
||||
garbage_collect (this._keys);
|
||||
const out: KeyStoreData = {};
|
||||
for (const index of Object.keys (this._keys))
|
||||
out[index] = { public_key: this._keys[index].public_key };
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public import_verification_data (data: KeyStoreData): void {
|
||||
const import_set = { ...data };
|
||||
garbage_collect (import_set);
|
||||
|
||||
// TODO: import
|
||||
}
|
||||
}
|
||||
|
||||
const ks: KeyStore = (new KeyStore);
|
||||
export default ks;
|
||||
export { KeyStore };
|
||||
export { KeyStore, KeyStoreData, Key, KeyPair };
|
||||
|
@ -28,7 +28,7 @@ import create_gateway, {
|
||||
Gateway,
|
||||
AnyFunc
|
||||
} from './Gateway';
|
||||
import { KeyStore } from './KeyStore';
|
||||
import { KeyStore, KeyStoreData } from './KeyStore';
|
||||
|
||||
export {
|
||||
create_gateway,
|
||||
@ -52,5 +52,6 @@ export {
|
||||
GatewayClass,
|
||||
Gateway,
|
||||
AnyFunc,
|
||||
KeyStore
|
||||
KeyStore,
|
||||
KeyStoreData
|
||||
};
|
||||
|
Reference in New Issue
Block a user