Skip to content
File

Blob: src/worker/lib/origins.ts

typescript52 lines
1const ALLOWED_ORIGINS_ERROR = "ALLOWED_ORIGINS must be a comma-separated list of http(s) origins";
2 
3function normalizeConfiguredOrigin(rawOrigin: string): string {
4 let url: URL;
5 try {
6 url = new URL(rawOrigin);
7 } catch {
8 throw new Error(`${ALLOWED_ORIGINS_ERROR}: invalid origin "${rawOrigin}"`);
9 }
10 
11 if (url.protocol !== "http:" && url.protocol !== "https:") {
12 throw new Error(`${ALLOWED_ORIGINS_ERROR}: invalid protocol "${url.protocol}" in "${rawOrigin}"`);
13 }
14 
15 return url.origin;
16}
17 
18function normalizeRequestOrigin(origin: string): string | null {
19 try {
20 const url = new URL(origin);
21 return url.protocol === "http:" || url.protocol === "https:" ? url.origin : null;
22 } catch {
23 return null;
24 }
25}
26 
27export function getAllowedOrigins(env: Pick<Env, "ALLOWED_ORIGINS">): string[] {
28 const rawValue = env.ALLOWED_ORIGINS?.trim();
29 if (!rawValue) {
30 throw new Error(`${ALLOWED_ORIGINS_ERROR}: value is missing`);
31 }
32 
33 const rawOrigins = rawValue
34 .split(",")
35 .map((origin) => origin.trim())
36 .filter(Boolean);
37 if (rawOrigins.length === 0) {
38 throw new Error(`${ALLOWED_ORIGINS_ERROR}: value is empty`);
39 }
40 
41 return [...new Set(rawOrigins.map(normalizeConfiguredOrigin))];
42}
43 
44export function isAllowedOrigin(origin: string | null | undefined, env: Pick<Env, "ALLOWED_ORIGINS">): boolean {
45 if (!origin) return false;
46 
47 const normalizedOrigin = normalizeRequestOrigin(origin);
48 if (!normalizedOrigin) return false;
49 
50 return getAllowedOrigins(env).includes(normalizedOrigin);
51}