Spaces:
Running
Running
File size: 1,765 Bytes
6c3af4e 765119d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /**
* Tokens that have already failed argon2 verification.
*
* A process verifies against one search token for its whole life, so a token
* that failed once cannot become valid again in this process: the lookup is
* exact rather than a heuristic. A replay of a dead token then costs a Set
* check instead of a full argon2id verification, which is what a stream of
* dead search URLs from earlier deployments used to pay.
*/
const rejectedTokens = new Set<string>();
/**
* Bounds the set against a flood of distinct junk tokens: once full, the
* oldest entry is evicted and that token pays for one verification again if
* it comes back.
*/
export const MAX_REJECTED_TOKENS = 1024;
/**
* Rejections served from this set without a second argon2 verification, so
* `/status` can show how much of the dead-token traffic stopped costing a
* verification.
*/
let rejectedTokenCacheHits = 0;
export function isRejectedToken(token: string) {
return rejectedTokens.has(token);
}
export function addRejectedToken(token: string) {
if (rejectedTokens.has(token)) return;
if (rejectedTokens.size >= MAX_REJECTED_TOKENS) {
const oldest = rejectedTokens.values().next().value;
if (oldest !== undefined) rejectedTokens.delete(oldest);
}
rejectedTokens.add(token);
}
export function recordRejectedTokenCacheHit(): void {
rejectedTokenCacheHits++;
}
export function getRejectedTokenCacheHits(): number {
return rejectedTokenCacheHits;
}
/**
* How many distinct dead tokens the set holds, so `/status` can tell one stuck
* client replaying a single token from many stale links, which the hit count
* alone cannot. Never exceeds `MAX_REJECTED_TOKENS`.
*/
export function getRejectedTokenCount(): number {
return rejectedTokens.size;
}
|