@@ -14,6 +14,44 @@ const STELLAR_NETWORK =
1414
1515// In-memory challenge store: publicKey -> { nonce, expiresAt }
1616const challenges = new Map < string , { nonce : string ; expiresAt : number } > ( ) ;
17+ const DEFAULT_CHALLENGE_SWEEP_INTERVAL_MS = 5 * 60 * 1000 ;
18+ let challengeSweepTimer : NodeJS . Timeout | undefined ;
19+
20+ function resolveChallengeSweepIntervalMs ( ) : number {
21+ const raw = process . env . AUTH_CHALLENGE_SWEEP_INTERVAL_MS ;
22+ if ( ! raw ) return DEFAULT_CHALLENGE_SWEEP_INTERVAL_MS ;
23+ const parsed = Number ( raw ) ;
24+ return Number . isFinite ( parsed ) && parsed > 0
25+ ? parsed
26+ : DEFAULT_CHALLENGE_SWEEP_INTERVAL_MS ;
27+ }
28+
29+ export function sweepExpiredChallenges ( now = Date . now ( ) ) : number {
30+ let deleted = 0 ;
31+ for ( const [ publicKey , challenge ] of challenges . entries ( ) ) {
32+ if ( challenge . expiresAt < now ) {
33+ challenges . delete ( publicKey ) ;
34+ deleted += 1 ;
35+ }
36+ }
37+ return deleted ;
38+ }
39+
40+ export function startChallengeSweep ( intervalMs = resolveChallengeSweepIntervalMs ( ) ) : void {
41+ if ( challengeSweepTimer ) return ;
42+ challengeSweepTimer = setInterval ( ( ) => {
43+ sweepExpiredChallenges ( ) ;
44+ } , intervalMs ) ;
45+ challengeSweepTimer . unref ?.( ) ;
46+ }
47+
48+ export function stopChallengeSweep ( ) : void {
49+ if ( ! challengeSweepTimer ) return ;
50+ clearInterval ( challengeSweepTimer ) ;
51+ challengeSweepTimer = undefined ;
52+ }
53+
54+ startChallengeSweep ( ) ;
1755
1856// ─── Minimal JWT (no external dep) ──────────────────────────────────────────
1957
@@ -62,6 +100,13 @@ export function issueChallenge(req: Request, res: Response): void {
62100 res . json ( { nonce, expiresAt : Date . now ( ) + 60_000 } ) ;
63101}
64102
103+ export const __authChallengeTestUtils = {
104+ challenges,
105+ startChallengeSweep,
106+ stopChallengeSweep,
107+ sweepExpiredChallenges,
108+ } ;
109+
65110export function verifyChallenge ( req : Request , res : Response ) : void {
66111 const { publicKey, signedTransaction } = req . body as {
67112 publicKey ?: string ;
0 commit comments