-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathauth-cache.ts
More file actions
77 lines (67 loc) · 2.15 KB
/
auth-cache.ts
File metadata and controls
77 lines (67 loc) · 2.15 KB
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
export interface UserContext {
userId: number;
consumerId: string;
orgId: string;
email: string;
}
const CONSUMER_ME_URL =
process.env.DRIVER_CONSUMER_ME_URL?.trim() ||
"https://lisa-taurine.tera.space/v1/consumer/me";
const CACHE_TTL_MS = 60_000;
const AUTH_TIMEOUT_MS = 5_000;
const MAX_RETRIES = 2;
const cache = new Map<string, { context: UserContext; expiresAt: number }>();
setInterval(() => {
const now = Date.now();
for (const [key, entry] of cache) {
if (entry.expiresAt <= now) cache.delete(key);
}
}, 5 * 60 * 1000).unref();
async function fetchConsumerMe(apiKey: string): Promise<Response> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), AUTH_TIMEOUT_MS);
try {
return await fetch(CONSUMER_ME_URL, {
headers: {
Authorization: `Bearer ${apiKey}`,
"User-Agent": "driver-cdp-proxy/1.0",
},
signal: controller.signal,
});
} finally {
clearTimeout(timer);
}
}
export async function validateApiKey(apiKey: string): Promise<UserContext | null> {
const now = Date.now();
const cached = cache.get(apiKey);
if (cached && cached.expiresAt > now) return cached.context;
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
try {
const response = await fetchConsumerMe(apiKey);
if (response.status === 401 || response.status === 403) return null;
if (response.ok) {
const data = (await response.json()) as {
user: { id: number; consumerId: string; orgId: string; email: string };
};
const context: UserContext = {
userId: data.user.id,
consumerId: data.user.consumerId,
orgId: data.user.orgId,
email: data.user.email,
};
cache.set(apiKey, { context, expiresAt: now + CACHE_TTL_MS });
return context;
}
if (attempt < MAX_RETRIES) {
await new Promise((resolve) => setTimeout(resolve, 300 * (attempt + 1)));
}
} catch {
if (attempt < MAX_RETRIES) {
await new Promise((resolve) => setTimeout(resolve, 300 * (attempt + 1)));
}
}
}
if (cached) return cached.context;
return null;
}