1
0
silverbullet/server/crypto.ts
2023-12-11 12:11:56 +01:00

88 lines
2.3 KiB
TypeScript

import {
create,
getNumericDate,
verify,
} from "https://deno.land/x/djwt@v3.0.1/mod.ts";
import { KvPrimitives } from "../plugos/lib/kv_primitives.ts";
const jwtSecretKey = "jwtSecretKey";
export class JWTIssuer {
private key!: CryptoKey;
constructor(readonly kv: KvPrimitives) {
}
async init(authString: string) {
const [secret] = await this.kv.batchGet([[jwtSecretKey]]);
if (!secret) {
return this.generateNewKey();
} else {
this.key = await crypto.subtle.importKey(
"raw",
secret,
{ name: "HMAC", hash: "SHA-512" },
true,
["sign", "verify"],
);
}
// Check if the authentication has changed since last run
const [currentAuthHash] = await this.kv.batchGet([[
"authHash",
]]);
const newAuthHash = await this.hashSHA256(authString);
if (currentAuthHash && currentAuthHash !== newAuthHash) {
// It has, so we need to generate a new key to invalidate all existing tokens
await this.generateNewKey();
}
if (currentAuthHash !== newAuthHash) {
// Persist new auth hash
await this.kv.batchSet([{
key: ["authHash"],
value: newAuthHash,
}]);
}
}
async generateNewKey() {
this.key = await crypto.subtle.generateKey(
{ name: "HMAC", hash: "SHA-512" },
true,
["sign", "verify"],
);
await this.kv.batchSet([{
key: [jwtSecretKey],
value: await crypto.subtle.exportKey("raw", this.key),
}]);
}
createJWT(
payload: Record<string, unknown>,
expirySeconds: number,
): Promise<string> {
return create({ alg: "HS512", typ: "JWT" }, {
...payload,
exp: getNumericDate(expirySeconds),
}, this.key);
}
verifyAndDecodeJWT(jwt: string): Promise<Record<string, unknown>> {
return verify(jwt, this.key);
}
async hashSHA256(message: string): Promise<string> {
// Transform the string into an ArrayBuffer
const encoder = new TextEncoder();
const data = encoder.encode(message);
// Generate the hash
const hashBuffer = await window.crypto.subtle.digest("SHA-256", data);
// Transform the hash into a hex string
return Array.from(new Uint8Array(hashBuffer)).map((b) =>
b.toString(16).padStart(2, "0")
).join("");
}
}