Skip to content

Commit

Permalink
Merge pull request #27 from blinkafrica/main
Browse files Browse the repository at this point in the history
Release v0.7.0
  • Loading branch information
zerothebahdman authored Sep 7, 2024
2 parents f5a2f67 + de42567 commit f85de77
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@blinkclaud/octobus",
"version": "0.6.1",
"version": "0.7.0",
"description": "A toolkit for Blink HQ's microservices",
"author": "Blink HQ",
"private": false,
Expand Down Expand Up @@ -69,6 +69,7 @@
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/lodash": "^4.17.7",
"@types/ms": "^0.7.34",
"@types/node": "^20.3.1",
"@types/node-cron": "^3.0.11",
"@types/request-ip": "^0.0.41",
Expand Down
70 changes: 70 additions & 0 deletions src/tokens/redis.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import crypto from "crypto";

import { Redis } from "ioredis";
import ms from "ms";

import { dateReviver } from "../strings";
import { AsyncNullable, TokenStore } from "./store";

export class RedisStore implements TokenStore {
constructor(private secret: string, private redis: Redis) {}

async commision<T = any>(key: string, val: T, time: string): Promise<string> {
const token = crypto.createHmac("sha256", this.secret).update(key).digest("hex");

const content = JSON.stringify(val);
await this.redis.set(token, content, "PX", ms(time));

return token;
}

async peek<T = any>(token: string): AsyncNullable<T> {
const result = await this.redis.get(token);
if (!result) {
return null;
}

return JSON.parse(result, dateReviver);
}

async extend<T = any>(token: string, time: string): AsyncNullable<T> {
const result = await this.redis.get(token);
if (!result) {
return null;
}

await this.redis.pexpire(token, ms(time));

return JSON.parse(result, dateReviver);
}

async reset<T = any>(key: string, newVal: T): Promise<void> {
const token = crypto.createHmac("sha256", this.secret).update(key).digest("hex");

// make sure the token exists
const result = await this.redis.get(token);
if (!result) return;

const content = JSON.stringify(newVal);
const ttl = await this.redis.pttl(token);

await this.redis.set(token, content, "PX", ttl);
}

async decommission<T = any>(token: string): AsyncNullable<T> {
const result = await this.redis.get(token);
if (!result) {
return null;
}

await this.redis.del(token);

return JSON.parse(result, dateReviver);
}

async revoke(key: string): Promise<void> {
const token = crypto.createHmac("sha256", this.secret).update(key).digest("hex");

await this.redis.del(token);
}
}
45 changes: 45 additions & 0 deletions src/tokens/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export type AsyncNullable<T> = Promise<T | null>;

/**
* Contract of stores used to manage single use tokens. What's most important of
* said tokens(vs JWT for instance) is the ability to revoke said token.
*/
export interface TokenStore {
/**
* Create a single use token that expires after the given timeout
* @param key key to enabled reset and revoke
* @param val value the token will refer to
* @param time timeout before expiry
*/
commision<T = any>(key: string, val: T, time: string): Promise<string>;
/**
* Get the data the token references without changing its lifetime
* @param token token to check for
*/
peek<T = any>(token: string): AsyncNullable<T>;
/**
* Set the new duration before an existing token times out. Note that it doesn't
* take into account how long the old token had to expire, as it uses the new duration
* entirely.
* @param token generated token
* @param time the new expiry duration of the token
*/
extend<T = any>(token: string, time: string): AsyncNullable<T>;
/**
* Change the contents of the token without changing it's TTL
* @param key key used to generate the token
* @param newVal value to replace token content
*/
reset<T = any>(key: string, newVal: T): Promise<void>;
/**
* Load the value referenced by the token and dispenses of the token,
* making it unvailable for further use.
* @param token token to be decomissioned
*/
decommission<T = any>(token: string): AsyncNullable<T>;
/**
* Render the token generated for the given key useless.
* @param key key used to generate the token
*/
revoke(key: string): Promise<void>;
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,11 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==

"@types/ms@^0.7.34":
version "0.7.34"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==

"@types/node-cron@^3.0.11":
version "3.0.11"
resolved "https://registry.yarnpkg.com/@types/node-cron/-/node-cron-3.0.11.tgz#70b7131f65038ae63cfe841354c8aba363632344"
Expand Down

0 comments on commit f85de77

Please sign in to comment.