|
1 | | -import { |
2 | | - type RedirectTracker, |
3 | | - type ReferrerPolicyData, |
4 | | - type SiteDirective, |
5 | | - ScramjetDB, |
6 | | -} from "@/types"; |
7 | | -import { openDB, IDBPDatabase } from "idb"; |
8 | | - |
9 | | -// Persist the redirect trackers for an hour |
10 | | -const TRACKER_EXPIRY = 60 * 60 * 1000; |
11 | | -const SITE_HIERARCHY: Record<SiteDirective, number> = { |
12 | | - none: 0, |
13 | | - "same-origin": 1, |
14 | | - "same-site": 2, |
15 | | - "cross-site": 3, |
16 | | -}; |
17 | | - |
18 | | -/** |
19 | | - * Gets a connection to the IndexedDB database |
20 | | - * |
21 | | - * @returns Promise that resolves to the database connection |
22 | | - */ |
23 | | -async function getDB(): Promise<IDBPDatabase<ScramjetDB>> { |
24 | | - return openDB<ScramjetDB>("$scramjet", 1); |
25 | | -} |
26 | | - |
27 | | -/** |
28 | | - * Retrieves a redirect tracker for a given URL |
29 | | - * |
30 | | - * @param url The URL to look up |
31 | | - * @returns Redirect tracker if found, or `null` |
32 | | - */ |
33 | | -async function getTracker(url: string): Promise<RedirectTracker | null> { |
34 | | - const db = await getDB(); |
35 | | - return (await db.get("redirectTrackers", url)) || null; |
36 | | -} |
37 | | - |
38 | | -/** |
39 | | - * Store or update a redirect tracker for a given URL |
40 | | - * |
41 | | - * @param url URL to store the tracker for |
42 | | - * @param tracker Redirect tracker data to store |
43 | | - */ |
44 | | -async function setTracker( |
45 | | - url: string, |
46 | | - tracker: RedirectTracker |
47 | | -): Promise<void> { |
48 | | - const db = await getDB(); |
49 | | - await db.put("redirectTrackers", tracker, url); |
50 | | -} |
51 | | - |
52 | | -/** |
53 | | - * Delete a redirect tracker for a given URL |
54 | | - * |
55 | | - * @param url URL whose tracker should be deleted |
56 | | - */ |
57 | | -async function deleteTracker(url: string): Promise<void> { |
58 | | - const db = await getDB(); |
59 | | - await db.delete("redirectTrackers", url); |
60 | | -} |
61 | | - |
62 | | -/** |
63 | | - * Initialize tracking for a new request that might redirect |
64 | | - * |
65 | | - * @param requestUrl URL of the request being made |
66 | | - * @param referrer Referrer URL of the request, or `null` |
67 | | - * @param initialSite Initial Sec-Fetch-Site directive |
68 | | - */ |
69 | | -export async function initializeTracker( |
70 | | - requestUrl: string, |
71 | | - referrer: string | null, |
72 | | - initialSite: string |
73 | | -): Promise<void> { |
74 | | - const existing = await getTracker(requestUrl); |
75 | | - if (existing) { |
76 | | - return; |
77 | | - } |
78 | | - |
79 | | - await setTracker(requestUrl, { |
80 | | - originalReferrer: referrer || "", |
81 | | - mostRestrictiveSite: initialSite as SiteDirective, |
82 | | - referrerPolicy: "", |
83 | | - chainStarted: Date.now(), |
84 | | - }); |
85 | | -} |
86 | | - |
87 | | -/** |
88 | | - * Update tracker when a redirect is encountered |
89 | | - * |
90 | | - * @param originalUrl URL that is redirecting |
91 | | - * @param redirectUrl URL being redirected to |
92 | | - * @param newReferrerPolicy Referrer Policy from the redirect response |
93 | | - */ |
94 | | -export async function updateTracker( |
95 | | - originalUrl: string, |
96 | | - redirectUrl: string, |
97 | | - newReferrerPolicy?: string |
98 | | -): Promise<void> { |
99 | | - const tracker = await getTracker(originalUrl); |
100 | | - if (!tracker) return; |
101 | | - |
102 | | - await deleteTracker(originalUrl); |
103 | | - if (newReferrerPolicy) { |
104 | | - tracker.referrerPolicy = newReferrerPolicy; |
105 | | - } |
106 | | - await setTracker(redirectUrl, tracker); |
107 | | -} |
108 | | - |
109 | | -/** |
110 | | - * Get most restrictive site value for a request |
111 | | - * |
112 | | - * @param requestUrl The URL of the current request |
113 | | - * @param currentSite The current `Sec-Fetch-Site` directive for this request |
114 | | - * @returns Most restrictive `Sec-Fetch-Site` directive from the redirect chain |
115 | | - */ |
116 | | -export async function getMostRestrictiveSite( |
117 | | - requestUrl: string, |
118 | | - currentSite: string |
119 | | -): Promise<string> { |
120 | | - const tracker = await getTracker(requestUrl); |
121 | | - if (!tracker) return currentSite; |
122 | | - |
123 | | - const trackedValue = SITE_HIERARCHY[tracker.mostRestrictiveSite]; |
124 | | - const currentValue = SITE_HIERARCHY[currentSite as SiteDirective] ?? 0; |
125 | | - |
126 | | - if (currentValue > trackedValue) { |
127 | | - tracker.mostRestrictiveSite = currentSite as SiteDirective; |
128 | | - await setTracker(requestUrl, tracker); |
129 | | - |
130 | | - return currentSite; |
131 | | - } |
132 | | - |
133 | | - return tracker.mostRestrictiveSite; |
134 | | -} |
135 | | - |
136 | | -/** |
137 | | - * Clean up tracker after request completes |
138 | | - * @param requestUrl URL of the completed request |
139 | | - */ |
140 | | -export async function cleanTracker(requestUrl: string): Promise<void> { |
141 | | - await deleteTracker(requestUrl); |
142 | | -} |
143 | | - |
144 | | -/** |
145 | | - * Clean up expired trackers |
146 | | - */ |
147 | | -export async function cleanExpiredTrackers(): Promise<void> { |
148 | | - const now = Date.now(); |
149 | | - const db = await getDB(); |
150 | | - const tx = db.transaction("redirectTrackers", "readwrite"); |
151 | | - |
152 | | - for await (const cursor of tx.store) { |
153 | | - const tracker = cursor.value as RedirectTracker; |
154 | | - if (now - tracker.chainStarted > TRACKER_EXPIRY) { |
155 | | - cursor.delete(); |
156 | | - } |
157 | | - } |
158 | | - |
159 | | - await tx.done; |
160 | | -} |
161 | | - |
162 | | -/** |
163 | | - * Store referrer policy for a URL |
164 | | - * |
165 | | - * @param url URL to store the policy for |
166 | | - * @param policy Referrer policy to store |
167 | | - * @param referrer The referrer URL that set this policy |
168 | | - */ |
169 | | -export async function storeReferrerPolicy( |
170 | | - url: string, |
171 | | - policy: string, |
172 | | - referrer: string |
173 | | -): Promise<void> { |
174 | | - const db = await getDB(); |
175 | | - const data: ReferrerPolicyData = { policy, referrer }; |
176 | | - await db.put("referrerPolicies", data, url); |
177 | | -} |
178 | | - |
179 | | -/** |
180 | | - * Get referrer policy data for a URL |
181 | | - * |
182 | | - * @param url URL to get the policy for |
183 | | - * @returns Referrer policy data if found, or `null` |
184 | | - */ |
185 | | -export async function getReferrerPolicy( |
186 | | - url: string |
187 | | -): Promise<ReferrerPolicyData | null> { |
188 | | - const db = await getDB(); |
189 | | - return (await db.get("referrerPolicies", url)) || null; |
190 | | -} |
| 1 | +// import { |
| 2 | +// type RedirectTracker, |
| 3 | +// type ReferrerPolicyData, |
| 4 | +// type SiteDirective, |
| 5 | +// ScramjetDB, |
| 6 | +// } from "@/types"; |
| 7 | +// import { openDB, IDBPDatabase } from "idb"; |
| 8 | + |
| 9 | +// // Persist the redirect trackers for an hour |
| 10 | +// const TRACKER_EXPIRY = 60 * 60 * 1000; |
| 11 | +// const SITE_HIERARCHY: Record<SiteDirective, number> = { |
| 12 | +// none: 0, |
| 13 | +// "same-origin": 1, |
| 14 | +// "same-site": 2, |
| 15 | +// "cross-site": 3, |
| 16 | +// }; |
| 17 | + |
| 18 | +// /** |
| 19 | +// * Gets a connection to the IndexedDB database |
| 20 | +// * |
| 21 | +// * @returns Promise that resolves to the database connection |
| 22 | +// */ |
| 23 | +// async function getDB(): Promise<IDBPDatabase<ScramjetDB>> { |
| 24 | +// // return openDB<ScramjetDB>("$scramjet", 1); |
| 25 | +// } |
| 26 | + |
| 27 | +// /** |
| 28 | +// * Retrieves a redirect tracker for a given URL |
| 29 | +// * |
| 30 | +// * @param url The URL to look up |
| 31 | +// * @returns Redirect tracker if found, or `null` |
| 32 | +// */ |
| 33 | +// async function getTracker(url: string): Promise<RedirectTracker | null> { |
| 34 | +// // const db = await getDB(); |
| 35 | +// // return (await db.get("redirectTrackers", url)) || null; |
| 36 | +// } |
| 37 | + |
| 38 | +// /** |
| 39 | +// * Store or update a redirect tracker for a given URL |
| 40 | +// * |
| 41 | +// * @param url URL to store the tracker for |
| 42 | +// * @param tracker Redirect tracker data to store |
| 43 | +// */ |
| 44 | +// async function setTracker( |
| 45 | +// url: string, |
| 46 | +// tracker: RedirectTracker |
| 47 | +// ): Promise<void> { |
| 48 | +// // const db = await getDB(); |
| 49 | +// // await db.put("redirectTrackers", tracker, url); |
| 50 | +// } |
| 51 | + |
| 52 | +// /** |
| 53 | +// * Delete a redirect tracker for a given URL |
| 54 | +// * |
| 55 | +// * @param url URL whose tracker should be deleted |
| 56 | +// */ |
| 57 | +// async function deleteTracker(url: string): Promise<void> { |
| 58 | +// // const db = await getDB(); |
| 59 | +// // await db.delete("redirectTrackers", url); |
| 60 | +// } |
| 61 | + |
| 62 | +// /** |
| 63 | +// * Initialize tracking for a new request that might redirect |
| 64 | +// * |
| 65 | +// * @param requestUrl URL of the request being made |
| 66 | +// * @param referrer Referrer URL of the request, or `null` |
| 67 | +// * @param initialSite Initial Sec-Fetch-Site directive |
| 68 | +// */ |
| 69 | +// export async function initializeTracker( |
| 70 | +// requestUrl: string, |
| 71 | +// referrer: string | null, |
| 72 | +// initialSite: string |
| 73 | +// ): Promise<void> { |
| 74 | +// const existing = await getTracker(requestUrl); |
| 75 | +// if (existing) { |
| 76 | +// return; |
| 77 | +// } |
| 78 | + |
| 79 | +// await setTracker(requestUrl, { |
| 80 | +// originalReferrer: referrer || "", |
| 81 | +// mostRestrictiveSite: initialSite as SiteDirective, |
| 82 | +// referrerPolicy: "", |
| 83 | +// chainStarted: Date.now(), |
| 84 | +// }); |
| 85 | +// } |
| 86 | + |
| 87 | +// /** |
| 88 | +// * Update tracker when a redirect is encountered |
| 89 | +// * |
| 90 | +// * @param originalUrl URL that is redirecting |
| 91 | +// * @param redirectUrl URL being redirected to |
| 92 | +// * @param newReferrerPolicy Referrer Policy from the redirect response |
| 93 | +// */ |
| 94 | +// export async function updateTracker( |
| 95 | +// originalUrl: string, |
| 96 | +// redirectUrl: string, |
| 97 | +// newReferrerPolicy?: string |
| 98 | +// ): Promise<void> { |
| 99 | +// const tracker = await getTracker(originalUrl); |
| 100 | +// if (!tracker) return; |
| 101 | + |
| 102 | +// await deleteTracker(originalUrl); |
| 103 | +// if (newReferrerPolicy) { |
| 104 | +// tracker.referrerPolicy = newReferrerPolicy; |
| 105 | +// } |
| 106 | +// await setTracker(redirectUrl, tracker); |
| 107 | +// } |
| 108 | + |
| 109 | +// /** |
| 110 | +// * Get most restrictive site value for a request |
| 111 | +// * |
| 112 | +// * @param requestUrl The URL of the current request |
| 113 | +// * @param currentSite The current `Sec-Fetch-Site` directive for this request |
| 114 | +// * @returns Most restrictive `Sec-Fetch-Site` directive from the redirect chain |
| 115 | +// */ |
| 116 | +// export async function getMostRestrictiveSite( |
| 117 | +// requestUrl: string, |
| 118 | +// currentSite: string |
| 119 | +// ): Promise<string> { |
| 120 | +// const tracker = await getTracker(requestUrl); |
| 121 | +// if (!tracker) return currentSite; |
| 122 | + |
| 123 | +// const trackedValue = SITE_HIERARCHY[tracker.mostRestrictiveSite]; |
| 124 | +// const currentValue = SITE_HIERARCHY[currentSite as SiteDirective] ?? 0; |
| 125 | + |
| 126 | +// if (currentValue > trackedValue) { |
| 127 | +// tracker.mostRestrictiveSite = currentSite as SiteDirective; |
| 128 | +// await setTracker(requestUrl, tracker); |
| 129 | + |
| 130 | +// return currentSite; |
| 131 | +// } |
| 132 | + |
| 133 | +// return tracker.mostRestrictiveSite; |
| 134 | +// } |
| 135 | + |
| 136 | +// /** |
| 137 | +// * Clean up tracker after request completes |
| 138 | +// * @param requestUrl URL of the completed request |
| 139 | +// */ |
| 140 | +// export async function cleanTracker(requestUrl: string): Promise<void> { |
| 141 | +// await deleteTracker(requestUrl); |
| 142 | +// } |
| 143 | + |
| 144 | +// /** |
| 145 | +// * Clean up expired trackers |
| 146 | +// */ |
| 147 | +// export async function cleanExpiredTrackers(): Promise<void> { |
| 148 | +// const now = Date.now(); |
| 149 | +// const db = await getDB(); |
| 150 | +// const tx = db.transaction("redirectTrackers", "readwrite"); |
| 151 | + |
| 152 | +// for await (const cursor of tx.store) { |
| 153 | +// const tracker = cursor.value as RedirectTracker; |
| 154 | +// if (now - tracker.chainStarted > TRACKER_EXPIRY) { |
| 155 | +// cursor.delete(); |
| 156 | +// } |
| 157 | +// } |
| 158 | + |
| 159 | +// await tx.done; |
| 160 | +// } |
| 161 | + |
| 162 | +// /** |
| 163 | +// * Store referrer policy for a URL |
| 164 | +// * |
| 165 | +// * @param url URL to store the policy for |
| 166 | +// * @param policy Referrer policy to store |
| 167 | +// * @param referrer The referrer URL that set this policy |
| 168 | +// */ |
| 169 | +// export async function storeReferrerPolicy( |
| 170 | +// url: string, |
| 171 | +// policy: string, |
| 172 | +// referrer: string |
| 173 | +// ): Promise<void> { |
| 174 | +// const db = await getDB(); |
| 175 | +// const data: ReferrerPolicyData = { policy, referrer }; |
| 176 | +// await db.put("referrerPolicies", data, url); |
| 177 | +// } |
| 178 | + |
| 179 | +// /** |
| 180 | +// * Get referrer policy data for a URL |
| 181 | +// * |
| 182 | +// * @param url URL to get the policy for |
| 183 | +// * @returns Referrer policy data if found, or `null` |
| 184 | +// */ |
| 185 | +// export async function getReferrerPolicy( |
| 186 | +// url: string |
| 187 | +// ): Promise<ReferrerPolicyData | null> { |
| 188 | +// const db = await getDB(); |
| 189 | +// return (await db.get("referrerPolicies", url)) || null; |
| 190 | +// } |
0 commit comments