This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

rookery / src / oauth / nonce.ts
1.1 kB 43 lines
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4import { base64urlEncode } from "../auth"; 5 6const NONCE_WINDOW_SECONDS = 300; 7 8function assertNonceSecret(secret: string): void { 9 if (!secret) { 10 throw new Error("OAuth nonce secret is required"); 11 } 12} 13 14// `now` is epoch seconds. 15export async function deriveDpopNonce(secret: string, now: number): Promise<string> { 16 assertNonceSecret(secret); 17 const key = await crypto.subtle.importKey( 18 "raw", 19 new TextEncoder().encode(secret), 20 { name: "HMAC", hash: "SHA-256" }, 21 false, 22 ["sign"], 23 ); 24 const window = Math.floor(now / NONCE_WINDOW_SECONDS); 25 const signature = await crypto.subtle.sign( 26 "HMAC", 27 key, 28 new TextEncoder().encode(String(window)), 29 ); 30 return base64urlEncode(signature); 31} 32 33export async function isValidDpopNonce( 34 secret: string, 35 nonce: string, 36 now: number, 37): Promise<boolean> { 38 assertNonceSecret(secret); 39 const current = await deriveDpopNonce(secret, now); 40 if (nonce === current) return true; 41 const previous = await deriveDpopNonce(secret, now - NONCE_WINDOW_SECONDS); 42 return nonce === previous; 43}