Open-source marketplace for AI Agent skills. Features: - Next.js 15 web app with i18n (en/fa) - CLI tool for skill installation (npx skillhub) - GitHub crawler/indexer with multi-strategy discovery - Security scanning for all indexed skills - Self-hostable with Docker Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
115 lines
2.7 KiB
TypeScript
115 lines
2.7 KiB
TypeScript
'use client';
|
|
|
|
/**
|
|
* Client-side CSRF utilities for @edge-csrf/nextjs
|
|
*
|
|
* The CSRF token is received in the 'x-csrf-token' response header from the server.
|
|
* We store it in memory and include it in subsequent requests.
|
|
* For API requests, include the token in the 'x-csrf-token' header.
|
|
* For form submissions, include it in a hidden field named '_csrf'.
|
|
*/
|
|
|
|
const CSRF_HEADER_NAME = 'x-csrf-token';
|
|
|
|
// Store the CSRF token in memory (will be populated on first page load)
|
|
let csrfToken: string | null = null;
|
|
|
|
/**
|
|
* Set the CSRF token (called when receiving a response with the token)
|
|
*/
|
|
export function setCsrfToken(token: string): void {
|
|
csrfToken = token;
|
|
}
|
|
|
|
/**
|
|
* Get the current CSRF token
|
|
*/
|
|
export function getCsrfToken(): string | null {
|
|
return csrfToken;
|
|
}
|
|
|
|
/**
|
|
* Create headers object with CSRF token included
|
|
* Use this when making fetch requests
|
|
*/
|
|
export function createHeadersWithCsrf(additionalHeaders?: HeadersInit): Headers {
|
|
const headers = new Headers(additionalHeaders);
|
|
const token = getCsrfToken();
|
|
|
|
if (token) {
|
|
headers.set(CSRF_HEADER_NAME, token);
|
|
}
|
|
|
|
return headers;
|
|
}
|
|
|
|
/**
|
|
* Create a fetch wrapper that automatically includes the CSRF token
|
|
* and extracts new tokens from responses
|
|
*/
|
|
export async function fetchWithCsrf(
|
|
url: string | URL,
|
|
options?: RequestInit
|
|
): Promise<Response> {
|
|
const token = getCsrfToken();
|
|
|
|
const headers = new Headers(options?.headers);
|
|
|
|
if (token) {
|
|
headers.set(CSRF_HEADER_NAME, token);
|
|
}
|
|
|
|
// Ensure content-type is set for JSON requests if body is present
|
|
if (options?.body && typeof options.body === 'string' && !headers.has('Content-Type')) {
|
|
headers.set('Content-Type', 'application/json');
|
|
}
|
|
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers,
|
|
});
|
|
|
|
// Update token from response if present
|
|
const newToken = response.headers.get(CSRF_HEADER_NAME);
|
|
if (newToken) {
|
|
setCsrfToken(newToken);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* Initialize CSRF token by making a request to any page/API
|
|
* Call this early in your app (e.g., in a layout or provider)
|
|
*/
|
|
export async function initializeCsrfToken(): Promise<string | null> {
|
|
try {
|
|
// Make a simple GET request to get the CSRF token
|
|
const response = await fetch('/api/health', {
|
|
method: 'GET',
|
|
credentials: 'same-origin',
|
|
});
|
|
|
|
const token = response.headers.get(CSRF_HEADER_NAME);
|
|
if (token) {
|
|
setCsrfToken(token);
|
|
}
|
|
return token;
|
|
} catch {
|
|
console.warn('Failed to initialize CSRF token');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the header name for CSRF token (useful for custom request libraries)
|
|
*/
|
|
export function getCsrfHeaderName(): string {
|
|
return CSRF_HEADER_NAME;
|
|
}
|
|
|
|
/**
|
|
* Export constants for use in forms
|
|
*/
|
|
export const CSRF_FIELD_NAME = '_csrf';
|