From 10d45e8d14cdc3672cc65dc7f5ae79e63fb2da1a Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sat, 21 Jun 2025 11:32:42 +0000 Subject: fix: Change public image's signed tokens to be time aligned for better caching --- packages/shared/signedTokens.ts | 42 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) (limited to 'packages/shared/signedTokens.ts') diff --git a/packages/shared/signedTokens.ts b/packages/shared/signedTokens.ts index b5e27f3e..14a26f60 100644 --- a/packages/shared/signedTokens.ts +++ b/packages/shared/signedTokens.ts @@ -1,8 +1,6 @@ import crypto from "node:crypto"; import { z } from "zod"; -import serverConfig from "./config"; - const zTokenPayload = z.object({ payload: z.unknown(), expiresAt: z.number(), @@ -13,10 +11,45 @@ const zSignedTokenPayload = z.object({ signature: z.string(), }); +/** + * Returns the expiry date aligned to the specified interval. + * If the time left until the next interval is less than the grace period, + * it skips to the following interval. + * + * @param now - The current date and time (defaults to new Date()). + * @param intervalSeconds - The interval in seconds (e.g., 1800 for 30 mins). + * @param gracePeriodSeconds - The grace period in seconds. + * @returns The calculated expiry Date. + */ +export function getAlignedExpiry( + intervalSeconds: number, + gracePeriodSeconds: number, + now: Date = new Date(), +): number { + const ms = now.getTime(); + const intervalMs = intervalSeconds * 1000; + + // Find the next interval + const nextIntervalTime = + Math.floor(ms / intervalMs) * intervalMs + intervalMs; + + // Time left until the next interval + const timeLeft = nextIntervalTime - ms; + + // Decide which interval to use + const finalIntervalTime = + timeLeft < gracePeriodSeconds * 1000 + ? nextIntervalTime + intervalMs + : nextIntervalTime; + + return finalIntervalTime; +} + export type SignedTokenPayload = z.infer; export function createSignedToken( payload: unknown, + secret: string, expiryEpoch?: number, ): string { const expiresAt = expiryEpoch ?? Date.now() + 5 * 60 * 1000; // 5 minutes from now @@ -28,7 +61,7 @@ export function createSignedToken( const payloadString = JSON.stringify(toBeSigned); const signature = crypto - .createHmac("sha256", serverConfig.signingSecret()) + .createHmac("sha256", secret) .update(payloadString) .digest("hex"); @@ -42,6 +75,7 @@ export function createSignedToken( export function verifySignedToken( token: string, + secret: string, schema: z.ZodSchema, ): T | null { try { @@ -52,7 +86,7 @@ export function verifySignedToken( // Verify signature const expectedSignature = crypto - .createHmac("sha256", serverConfig.signingSecret()) + .createHmac("sha256", secret) .update(JSON.stringify(payload)) .digest("hex"); -- cgit v1.2.3-70-g09d2