mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 11:45:20 +02:00
fix: require auth on cookie-picker data routes (CRITICAL-01)
- Add Bearer token auth gate on all /cookie-picker/* data/action routes - GET /cookie-picker HTML page stays unauthenticated (UI shell) - Token embedded in served HTML for picker's fetch calls - CORS preflight now allows Authorization header
This commit is contained in:
@@ -53,6 +53,7 @@ export async function handleCookiePickerRoute(
|
||||
url: URL,
|
||||
req: Request,
|
||||
bm: BrowserManager,
|
||||
authToken?: string,
|
||||
): Promise<Response> {
|
||||
const pathname = url.pathname;
|
||||
const port = parseInt(url.port, 10) || 9400;
|
||||
@@ -64,7 +65,7 @@ export async function handleCookiePickerRoute(
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': corsOrigin(port),
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -72,13 +73,24 @@ export async function handleCookiePickerRoute(
|
||||
try {
|
||||
// GET /cookie-picker — serve the picker UI
|
||||
if (pathname === '/cookie-picker' && req.method === 'GET') {
|
||||
const html = getCookiePickerHTML(port);
|
||||
const html = getCookiePickerHTML(port, authToken);
|
||||
return new Response(html, {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Auth gate: all data/action routes below require Bearer token ───
|
||||
if (authToken) {
|
||||
const authHeader = req.headers.get('authorization');
|
||||
if (!authHeader || authHeader !== `Bearer ${authToken}`) {
|
||||
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
||||
status: 401,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// GET /cookie-picker/browsers — list installed browsers
|
||||
if (pathname === '/cookie-picker/browsers' && req.method === 'GET') {
|
||||
const browsers = findInstalledBrowsers();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* No cookie values exposed anywhere.
|
||||
*/
|
||||
|
||||
export function getCookiePickerHTML(serverPort: number): string {
|
||||
export function getCookiePickerHTML(serverPort: number, authToken?: string): string {
|
||||
const baseUrl = `http://127.0.0.1:${serverPort}`;
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
@@ -330,6 +330,7 @@ export function getCookiePickerHTML(serverPort: number): string {
|
||||
<script>
|
||||
(function() {
|
||||
const BASE = '${baseUrl}';
|
||||
const AUTH_TOKEN = '${authToken || ''}';
|
||||
let activeBrowser = null;
|
||||
let activeProfile = 'Default';
|
||||
let allProfiles = [];
|
||||
@@ -372,7 +373,9 @@ export function getCookiePickerHTML(serverPort: number): string {
|
||||
|
||||
// ─── API ────────────────────────────────
|
||||
async function api(path, opts) {
|
||||
const res = await fetch(BASE + '/cookie-picker' + path, opts);
|
||||
const headers = { ...(opts?.headers || {}) };
|
||||
if (AUTH_TOKEN) headers['Authorization'] = 'Bearer ' + AUTH_TOKEN;
|
||||
const res = await fetch(BASE + '/cookie-picker' + path, { ...opts, headers });
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
const err = new Error(data.error || 'Request failed');
|
||||
|
||||
Reference in New Issue
Block a user