Skip to content

Commit

Permalink
fixed caching issue on signature generation
Browse files Browse the repository at this point in the history
  • Loading branch information
JulienR1 committed Nov 28, 2023
1 parent e3d7c28 commit b122bb4
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 9 deletions.
21 changes: 14 additions & 7 deletions src/auth/cached.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { sign, verify } from "./ed25519.js";

// Keep in memory the latest generated signature. We do not regenerate it it is still valid.
let latestSignature: ReturnType<typeof sign> = { signature: "", publicKey: "", expirationTime: 0 };
// Keep in memory the latest generated signature for every secret key.
// We do not regenerate them if they are still valid.
const latestSignatures = new Map<string, ReturnType<typeof sign>>();

export function cachedSign(...args: Parameters<typeof sign>): ReturnType<typeof sign> {
const [_, expirationTimeInSecs] = args;
const [secretKey, durationInSecs] = args;

// Do not recalculate a signature it the latest one expires in less than 40% of the expiryTime
if (latestSignature.expirationTime - new Date().getTime() <= 0.4 * expirationTimeInSecs * 1000) {
let latestSignature = latestSignatures.get(secretKey);
if (!latestSignature || generatedSignatureIsExpired(latestSignature.expirationTime, durationInSecs)) {
latestSignature = sign(...args);
latestSignatures.set(secretKey, latestSignature);
}

return latestSignature;
}

function generatedSignatureIsExpired(expirationTime: number, signatureDurationInSecs: number) {
return expirationTime - new Date().getTime() <= 0.4 * signatureDurationInSecs * 1000;
}

// Keep in memory which signatures are currently valid, and at what time they become invalid.
// This allows to skip the ed25519 validation process each time and only compare the expiration time.
const validSignatures = new Map<string, number>();
Expand All @@ -24,7 +31,7 @@ export function cachedVerify(...args: Parameters<typeof verify>): ReturnType<typ
// Quick return if the signature is already known
const cachedSignatureExpiry = validSignatures.get(signature);
if (cachedSignatureExpiry !== undefined) {
if (isExpired(cachedSignatureExpiry)) {
if (receivedSignatureIsExpired(cachedSignatureExpiry)) {
return new Error("signature is expired");
}

Expand All @@ -33,7 +40,7 @@ export function cachedVerify(...args: Parameters<typeof verify>): ReturnType<typ

// Cleanup expired values from cache
for (const [signature, expiry] of validSignatures) {
if (isExpired(expiry)) {
if (receivedSignatureIsExpired(expiry)) {
validSignatures.delete(signature);
}
}
Expand All @@ -44,6 +51,6 @@ export function cachedVerify(...args: Parameters<typeof verify>): ReturnType<typ
return result;
}

function isExpired(expirationTime: number): boolean {
function receivedSignatureIsExpired(expirationTime: number): boolean {
return new Date().getTime() >= expirationTime;
}
4 changes: 2 additions & 2 deletions src/auth/ed25519.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import nacl from "tweetnacl";

export function sign(secretKey: string, expirationTimeInSecs: number) {
export function sign(secretKey: string, durationInSecs: number) {
const publicKey = secretKey.substring(nacl.sign.secretKeyLength);
const expirationTime = new Date().getTime() + expirationTimeInSecs * 1000;
const expirationTime = new Date().getTime() + durationInSecs * 1000;

const payload = JSON.stringify({ exp: expirationTime, id: publicKey });
const signedBuffer = nacl.sign.detached(Buffer.from(payload), Buffer.from(secretKey, "hex"));
Expand Down

0 comments on commit b122bb4

Please sign in to comment.