blacklist sync
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2022-08-27 16:39:07 +02:00
parent e80e3f9a94
commit 31f739d4b8
15 changed files with 271 additions and 207 deletions

View File

@ -74,7 +74,7 @@ class Authority {
log ('parsing token %s %s', result.type, result.id);
if (!blacklist.is_valid (data.id)) {
if (!(await blacklist.is_valid (data.id))) {
log ('token is blacklisted');
result.error = 'blacklisted';
return result;

View File

@ -6,6 +6,7 @@
*/
import { debug } from './debug';
import { redis_blacklist_store } from './RedisData/RedisBlacklistStore';
const logger = debug ('blacklist');
@ -21,24 +22,31 @@ class Blacklist {
this._signatures = [];
}
public clear (before: number = Number.POSITIVE_INFINITY): void {
public async clear (
before: number = Number.POSITIVE_INFINITY
): Promise<void> {
logger.extend ('clear') ('clearing blacklist');
for (let i = this._signatures.length - 1; i >= 0; i--) {
if (this._signatures[i].iat < before)
this.remove_signature (i);
if (this._signatures[i].iat < before) {
// eslint-disable-next-line no-await-in-loop
await this.remove_signature (i);
}
}
}
public add_signature (hash: string): void {
public async add_signature (hash: string): Promise<void> {
logger.extend ('add_signature') ('blacklisting signature %s', hash);
this._signatures.push ({ iat: Date.now (), hash });
await redis_blacklist_store.add (hash);
}
public remove_signature (signature: number | string): void {
public async remove_signature (signature: number | string): Promise<void> {
const log = logger.extend ('remove_signature');
log ('removing signature from blacklist %s', signature);
let key = '';
if (typeof signature === 'string') {
log ('received string, searching through signatures');
key = signature;
for (let i = this._signatures.length - 1; i >= 0; i--) {
if (this._signatures[i].hash === signature)
this._signatures.splice (i, 1);
@ -46,11 +54,13 @@ class Blacklist {
}
else {
log ('received index, removing at index');
key = this._signatures[signature].hash;
this._signatures.splice (signature, 1);
}
await redis_blacklist_store.remove (key);
}
public is_valid (hash: string): boolean {
public async is_valid (hash: string): Promise<boolean> {
const log = logger.extend ('is_valid');
log ('checking signature for blacklist entry %s', hash);
for (const sig of this._signatures) {
@ -60,6 +70,12 @@ class Blacklist {
}
}
log ('signature is not blacklisted locally, checking redis');
if (await redis_blacklist_store.get (hash)) {
log ('signature is blacklisted in redis');
return false;
}
log ('signature is not blacklisted');
return true;
}
@ -76,6 +92,10 @@ class Blacklist {
);
this._signatures.push (...data);
}
public sync_redis (url: string): void {
redis_blacklist_store.connect (url);
}
}
const bl = (new Blacklist);

View File

@ -209,8 +209,10 @@ class GatewayClass {
log ('found %d tokens: %O', tokens.length, tokens);
for (const token of tokens)
blacklist.add_signature (token.id);
for (const token of tokens) {
// eslint-disable-next-line no-await-in-loop
await blacklist.add_signature (token.id);
}
log ('complete');
}

View File

@ -9,7 +9,6 @@ import { generate_keypair, random_hex } from '@sapphirecode/crypto-helper';
import { to_b58 } from '@sapphirecode/encoding-helper';
import { debug } from './debug';
import { KeyStoreData, KeyStoreExport } from './Key';
import { redis } from './Redis';
import { redis_key_store } from './RedisData/RedisKeyStore';
const logger = debug ('keystore');
@ -20,7 +19,6 @@ class KeyStore {
private _keys: KeyStoreData = {};
private _interval: NodeJS.Timeout;
private _instance: string;
private _sync_redis = false;
public get instance_id (): string {
return this._instance;
@ -58,8 +56,7 @@ class KeyStore {
valid_until: time + (valid_for * 1000)
}
};
if (this._sync_redis)
await redis_key_store.set ({ ...result.public_key, index });
await redis_key_store.set ({ ...result.public_key, index });
this._keys[index] = result;
}
@ -135,11 +132,11 @@ class KeyStore {
let key = null;
if (typeof this._keys[index] === 'undefined') {
if (this._sync_redis)
key = await redis_key_store.get (index);
}
else { key = this._keys[index].public_key; }
if (typeof this._keys[index] === 'undefined')
key = await redis_key_store.get (index);
else
key = this._keys[index].public_key;
if (key === null)
throw new Error ('key could not be found');
@ -182,13 +179,11 @@ class KeyStore {
logger.extend ('reset_instance') ('resetting keystore');
this._instance = to_b58 (random_hex (16), 'hex');
this._keys = {};
this._sync_redis = false;
redis.disconnect ();
redis_key_store.disconnect ();
}
public sync_redis (url: string): void {
redis.connect (url);
this._sync_redis = true;
redis_key_store.connect (url);
}
}

View File

@ -51,16 +51,14 @@ export class Redis {
log ('done');
}
public get redis (): IORedis {
protected get redis (): IORedis {
if (this._redis === null)
throw new Error ('redis is not connected');
return this._redis;
}
public get is_active (): boolean {
protected get is_active (): boolean {
return this._redis !== null;
}
}
export const redis = (new Redis);

View File

@ -6,31 +6,44 @@
*/
import { debug } from '../debug';
import { redis } from '../Redis';
import { Redis } from '../Redis';
const logger = debug ('RedisBlacklistStore');
export class RedisBlacklistStore {
export class RedisBlacklistStore extends Redis {
public async add (key: string): Promise<void> {
const log = logger.extend ('set');
log ('trying to add key %s to redis blacklist', key);
if (!redis.is_active) {
if (!this.is_active) {
log ('redis is inactive, skipping');
return;
}
await redis.redis.sadd ('blacklist', key);
await this.redis.sadd ('blacklist', key);
log ('saved key');
}
public async remove (key: string): Promise<void> {
const log = logger.extend ('remove');
log ('removing key %s from redis', key);
if (!this.is_active) {
log ('redis is inactive, skipping');
return;
}
await this.redis.srem ('blacklist', key);
log ('removed key');
}
public async get (key: string): Promise<boolean> {
const log = logger.extend ('get');
log ('trying to find key %s in redis blacklist', key);
if (!redis.is_active) {
if (!this.is_active) {
log ('redis is inactive, skipping');
return false;
}
const res = await redis.redis.sismember ('blacklist', key) === 1;
const res = await this.redis.sismember ('blacklist', key) === 1;
log ('found key %s', res);
return res;
}
}
export const redis_blacklist_store = new RedisBlacklistStore;

View File

@ -7,15 +7,15 @@
import { debug } from '../debug';
import { LabelledKey } from '../Key';
import { redis } from '../Redis';
import { Redis } from '../Redis';
const logger = debug ('RedisKeyStore');
export class RedisKeyStore {
export class RedisKeyStore extends Redis {
public async set (value: LabelledKey): Promise<void> {
const log = logger.extend ('set');
log ('trying to set key %s to redis', value.index);
if (!redis.is_active) {
if (!this.is_active) {
log ('redis is inactive, skipping');
return;
}
@ -24,7 +24,7 @@ export class RedisKeyStore {
.getTime ()) / 1000
);
log ('key is valid for %d seconds', valid_for);
await redis.redis.setex (
await this.redis.setex (
`keystore_${value.index}`,
valid_for,
JSON.stringify (value)
@ -35,11 +35,11 @@ export class RedisKeyStore {
public async get (index: string): Promise<LabelledKey | null> {
const log = logger.extend ('get');
log ('trying to get key %s from redis', index);
if (!redis.is_active) {
if (!this.is_active) {
log ('redis is inactive, skipping');
return null;
}
const res = await redis.redis.get (`keystore_${index}`);
const res = await this.redis.get (`keystore_${index}`);
if (res === null) {
log ('key not found in redis');
return null;