50 lines
1.2 KiB
TypeScript
50 lines
1.2 KiB
TypeScript
|
|
const DASHBOARD_USER = 'admin';
|
||
|
|
const REALM = 'Claude Code Proxy';
|
||
|
|
|
||
|
|
function decodeBasicAuthHeader(authHeader: string): { user: string; pass: string } | null {
|
||
|
|
if (!authHeader.startsWith('Basic ')) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const decoded = atob(authHeader.slice(6));
|
||
|
|
const colonIndex = decoded.indexOf(':');
|
||
|
|
if (colonIndex === -1) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
user: decoded.slice(0, colonIndex),
|
||
|
|
pass: decoded.slice(colonIndex + 1),
|
||
|
|
};
|
||
|
|
} catch {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function isDashboardAuthorized(authHeader: string, password: string): boolean {
|
||
|
|
if (!password) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
const credentials = decodeBasicAuthHeader(authHeader);
|
||
|
|
return credentials !== null && credentials.user === DASHBOARD_USER && credentials.pass === password;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function backendAuthHeaders(password: string): Record<string, string> {
|
||
|
|
if (!password) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
const credentials = btoa(`${DASHBOARD_USER}:${password}`);
|
||
|
|
return { Authorization: `Basic ${credentials}` };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function dashboardUnauthorizedResponse(): Response {
|
||
|
|
return new Response('Unauthorized', {
|
||
|
|
status: 401,
|
||
|
|
headers: {
|
||
|
|
'WWW-Authenticate': `Basic realm="${REALM}"`,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|