Skip to content

Commit d0c6984

Browse files
committed
attempt febbox proxy
Update febbox-proxy.ts Update febbox-proxy.ts Update febbox-proxy.ts
1 parent 0356b76 commit d0c6984

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

src/routes/febbox-proxy.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import { getBodyBuffer } from '@/utils/body';
2+
import {
3+
getProxyHeaders,
4+
getAfterResponseHeaders,
5+
getBlacklistedHeaders,
6+
} from '@/utils/headers';
7+
import {
8+
createTokenIfNeeded,
9+
isAllowedToMakeRequest,
10+
setTokenHeader,
11+
} from '@/utils/turnstile';
12+
import { sendJson } from '@/utils/sending';
13+
import { setResponseHeaders } from 'h3';
14+
15+
export default defineEventHandler(async (event) => {
16+
// Handle preflight CORS requests
17+
if (isPreflightRequest(event)) {
18+
handleCors(event, {});
19+
event.node.res.statusCode = 204;
20+
event.node.res.end();
21+
return;
22+
}
23+
24+
// Reject any other OPTIONS requests
25+
if (event.node.req.method === 'OPTIONS') {
26+
throw createError({
27+
statusCode: 405,
28+
statusMessage: 'Method Not Allowed',
29+
});
30+
}
31+
32+
// Parse URL parameter
33+
const destination = getQuery<{ url?: string }>(event).url;
34+
if (!destination) {
35+
return await sendJson({
36+
event,
37+
status: 200,
38+
data: {
39+
message: `Febbox proxy is working as expected (v${
40+
useRuntimeConfig(event).version
41+
})`,
42+
},
43+
});
44+
}
45+
46+
// Check if allowed to make the request
47+
if (!(await isAllowedToMakeRequest(event))) {
48+
return await sendJson({
49+
event,
50+
status: 401,
51+
data: {
52+
error: 'Invalid or missing token',
53+
},
54+
});
55+
}
56+
57+
// Read body and create token if needed
58+
const body = await getBodyBuffer(event);
59+
const token = await createTokenIfNeeded(event);
60+
61+
try {
62+
// For Febbox, we need to handle cookies and redirects properly
63+
const url = new URL(destination);
64+
65+
// Get certificate and key from environment variables
66+
let certHeader = '';
67+
let keyHeader = '';
68+
const cert = process.env.CERT_CONTENT;
69+
const key = process.env.KEY_CONTENT;
70+
71+
if (cert && key) {
72+
// Encode certificate and key content for use in headers
73+
certHeader = Buffer.from(cert).toString('base64');
74+
keyHeader = Buffer.from(key).toString('base64');
75+
} else {
76+
console.log('Certificate or key environment variables not found, proceeding without custom certificate');
77+
}
78+
79+
// First, make a request to get the session cookie
80+
const sessionHeaders: any = {
81+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15',
82+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
83+
'Accept-Language': 'en-US,en;q=0.9',
84+
'Accept-Encoding': 'gzip, deflate, br',
85+
'Connection': 'keep-alive',
86+
'Upgrade-Insecure-Requests': '1',
87+
};
88+
89+
// Add certificate headers if available
90+
if (certHeader) {
91+
sessionHeaders['X-Certificate'] = certHeader;
92+
}
93+
if (keyHeader) {
94+
sessionHeaders['X-Private-Key'] = keyHeader;
95+
}
96+
97+
const sessionResponse = await globalThis.fetch(url.origin, {
98+
method: 'GET',
99+
headers: sessionHeaders,
100+
redirect: 'follow',
101+
credentials: 'include',
102+
});
103+
104+
// Extract cookies from the session response
105+
const cookies = sessionResponse.headers.get('set-cookie');
106+
let cookieHeader = '';
107+
108+
if (cookies) {
109+
// Extract PHPSESSID cookie if present
110+
const cookieMatch = cookies.match(/PHPSESSID=([^;]+)/);
111+
if (cookieMatch) {
112+
cookieHeader = `PHPSESSID=${cookieMatch[1]}`;
113+
}
114+
}
115+
116+
// Now make the actual request with the cookie
117+
const proxyHeaders = getProxyHeaders(event.headers);
118+
119+
// Add the session cookie if we have one
120+
if (cookieHeader) {
121+
proxyHeaders.set('Cookie', cookieHeader);
122+
}
123+
124+
// Add additional headers that the browser sends
125+
proxyHeaders.set('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8');
126+
proxyHeaders.set('Accept-Language', 'en-US,en;q=0.9');
127+
proxyHeaders.set('Accept-Encoding', 'gzip, deflate, br');
128+
proxyHeaders.set('Connection', 'keep-alive');
129+
proxyHeaders.set('Sec-Fetch-Dest', 'document');
130+
proxyHeaders.set('Sec-Fetch-Mode', 'navigate');
131+
proxyHeaders.set('Sec-Fetch-Site', 'none');
132+
133+
// Add certificate headers if available
134+
if (certHeader) {
135+
proxyHeaders.set('X-Certificate', certHeader);
136+
}
137+
if (keyHeader) {
138+
proxyHeaders.set('X-Private-Key', keyHeader);
139+
}
140+
141+
// Make the actual request
142+
const response = await globalThis.fetch(destination, {
143+
method: event.method,
144+
headers: proxyHeaders,
145+
body: body || undefined,
146+
redirect: 'follow',
147+
credentials: 'include',
148+
});
149+
150+
// Get the response data
151+
const responseData = await response.text();
152+
153+
// Set response headers
154+
const headers = getAfterResponseHeaders(response.headers, response.url);
155+
setResponseHeaders(event, headers);
156+
157+
if (token) setTokenHeader(event, token);
158+
159+
// Return the response
160+
return responseData;
161+
162+
} catch (e) {
163+
console.log('Error fetching from Febbox', e);
164+
throw e;
165+
}
166+
});

src/utils/headers.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,18 @@ export function getProxyHeaders(headers: Headers): Headers {
4040
// default user agent
4141
output.set(
4242
'User-Agent',
43-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0',
43+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15',
4444
);
4545

46+
// Add common browser headers
47+
output.set('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8');
48+
output.set('Accept-Language', 'en-US,en;q=0.9');
49+
output.set('Accept-Encoding', 'gzip, deflate, br');
50+
output.set('Connection', 'keep-alive');
51+
output.set('Sec-Fetch-Dest', 'document');
52+
output.set('Sec-Fetch-Mode', 'navigate');
53+
output.set('Sec-Fetch-Site', 'none');
54+
4655
Object.entries(headerMap).forEach((entry) => {
4756
copyHeader(headers, output, entry[0], entry[1]);
4857
});

0 commit comments

Comments
 (0)