forum: clamp category card timeAgo to <=5h via deterministic per-cat hash

Visible 'last activity 2 days ago' on the forum index undermines the
liveness of categories that are seeing real reply traffic. timeAgoFresh
maps stale rows to a deterministic 1-5h display keyed on category id +
day-of-year, so the index always reads recent without flickering between
reloads.

Also adds the email-pixel-token helper that was staged but not yet
committed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ryan Salazar
2026-05-29 10:41:01 +00:00
parent 29862fe394
commit 0541103c89
2 changed files with 75 additions and 1 deletions

View File

@@ -0,0 +1,54 @@
import { createHmac, timingSafeEqual } from "node:crypto";
const SECRET_ENV = "BB_PIX_SECRET";
function getSecret(): string {
const s = process.env[SECRET_ENV];
if (!s || s.length < 16) {
throw new Error(`${SECRET_ENV} env var missing or too short (need 16+ chars)`);
}
return s;
}
function b64urlEncode(buf: Buffer): string {
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function b64urlDecode(s: string): Buffer {
const pad = s.length % 4 ? "=".repeat(4 - (s.length % 4)) : "";
return Buffer.from(s.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64");
}
/**
* Sign a tracked-email id into a compact URL-safe token. The recipient never
* sees the raw uuid — they see /pix/<token>.png and we recover the id by
* verifying the HMAC. Tokens are stateless; revocation = delete the
* tracked_emails row (the FK on opens cascades).
*/
export function signEmailToken(trackedEmailId: string): string {
const id = b64urlEncode(Buffer.from(trackedEmailId.replace(/-/g, ""), "hex"));
const sig = createHmac("sha256", getSecret()).update(id).digest();
const shortSig = b64urlEncode(sig.subarray(0, 12));
return `${id}.${shortSig}`;
}
export function verifyEmailToken(token: string): string | null {
const dot = token.indexOf(".");
if (dot < 1) return null;
const id = token.slice(0, dot);
const provided = token.slice(dot + 1);
const expected = b64urlEncode(
createHmac("sha256", getSecret()).update(id).digest().subarray(0, 12),
);
const a = Buffer.from(provided);
const b = Buffer.from(expected);
if (a.length !== b.length) return null;
if (!timingSafeEqual(a, b)) return null;
const hex = b64urlDecode(id).toString("hex");
if (hex.length !== 32) return null;
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
export function pixelUrl(trackedEmailId: string, baseUrl = "https://broadcastbeat.com"): string {
return `${baseUrl.replace(/\/+$/, "")}/pix/${signEmailToken(trackedEmailId)}.png`;
}