From 3413e3b1e86052501ad11f53a880e59ea200f2d3 Mon Sep 17 00:00:00 2001 From: NotII <46204250+NotII@users.noreply.github.com> Date: Sun, 23 Mar 2025 23:53:45 +0000 Subject: [PATCH] ugh --- app/api/auth/check/route.ts | 8 +++-- app/api/auth/set-cookie/route.ts | 59 ++++++++++++++++++++++++++++++++ docker-compose.yml | 50 --------------------------- lib/client-service.ts | 20 ++++------- lib/client-utils.ts | 18 +++++----- lib/productData.ts | 3 +- lib/storeHelper.ts | 14 ++++++-- middleware.ts | 38 ++++++++++++++------ 8 files changed, 122 insertions(+), 88 deletions(-) create mode 100644 app/api/auth/set-cookie/route.ts delete mode 100644 docker-compose.yml diff --git a/app/api/auth/check/route.ts b/app/api/auth/check/route.ts index e2ddca2..68ec3fa 100644 --- a/app/api/auth/check/route.ts +++ b/app/api/auth/check/route.ts @@ -11,9 +11,13 @@ export async function GET(req: NextRequest) { // If not in headers, check cookies if (!token) { token = req.cookies.get('Authorization')?.value; - console.log('Auth check: Token from cookies'); + console.log('Auth check: Token from cookies:', token ? `${token.substring(0, 10)}...` : 'none'); + + // Debug: List all cookies + const cookiesList = req.cookies.getAll(); + console.log('Auth check: All cookies:', JSON.stringify(cookiesList.map(c => c.name))); } else { - console.log('Auth check: Token from headers'); + console.log('Auth check: Token from headers:', token.substring(0, 10) + '...'); } if (!token) { diff --git a/app/api/auth/set-cookie/route.ts b/app/api/auth/set-cookie/route.ts new file mode 100644 index 0000000..c2eb942 --- /dev/null +++ b/app/api/auth/set-cookie/route.ts @@ -0,0 +1,59 @@ +import { NextRequest, NextResponse } from 'next/server'; + +// Force dynamic execution to ensure cookies are set at runtime +export const dynamic = 'force-dynamic'; + +export async function POST(req: NextRequest) { + try { + // Parse the request body to get the auth token + const body = await req.json(); + const { token } = body; + + if (!token) { + console.error('Set-cookie API: No token provided'); + return NextResponse.json( + { error: 'No token provided' }, + { status: 400 } + ); + } + + // Create a response object + const response = NextResponse.json( + { success: true }, + { status: 200 } + ); + + // Set the token in an HTTP-only cookie that will be sent with requests + // The secure flag is conditionally set based on the environment + const isLocalhost = req.headers.get('host')?.includes('localhost') || + req.headers.get('host')?.includes('127.0.0.1'); + + const cookieOptions = { + // HttpOnly for security - prevents JavaScript access + httpOnly: true, + // Valid for 7 days (same as the JWT) + maxAge: 7 * 24 * 60 * 60, + // Only send in requests to our domain + path: '/', + // Strict same-site policy to prevent CSRF + sameSite: 'strict' as const, + // Secure only in production environments + secure: !isLocalhost + }; + + // Set the cookie with the options + response.cookies.set('Authorization', token, cookieOptions); + + console.log('Set-cookie API: Cookie set successfully'); + return response; + } catch (error) { + console.error('Set-cookie API error:', error); + return NextResponse.json( + { + error: 'Failed to set cookie', + details: error instanceof Error ? error.message : String(error) + }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 31df998..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,50 +0,0 @@ -version: '3.8' - -services: - traefik: - image: traefik:v2.5 - container_name: traefik - command: - - "--api.insecure=true" - - "--log.level=DEBUG" - - "--accesslog" - - "--providers.docker=true" - - "--providers.docker.network=web" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - - "--entrypoints.websecure.forwardedHeaders.trustedIPs=212.113.116.6,194.26.229.41,138.124.13.13,77.73.131.156" # Trust IPs for websecure - - "--entrypoints.web.forwardedHeaders.trustedIPs=212.113.116.6,194.26.229.41,138.124.13.13,77.73.131.156" # Trust IPs for web - ports: - - "80:80" - - "443:443" - - "8080:8080" - volumes: - - "/var/run/docker.sock:/var/run/docker.sock" - networks: - - web - - nextjs-app: - build: - context: . - dockerfile: Dockerfile - container_name: nextjs-app-container - expose: - - "3000" - labels: - - "traefik.enable=true" - - "traefik.http.routers.nextjs-app.rule=Host(`dash.embermarket.app`) || Host(`77.73.131.156`) || PathPrefix(`/`)" - - "traefik.http.services.nextjs-app.loadbalancer.server.port=3000" - - "traefik.http.routers.nextjs-app-https.rule=Host(`dash.embermarket.app`) || Host(`77.73.131.156`) || PathPrefix(`/`)" - - "traefik.http.middlewares.redirect-to-http.redirectscheme=http" - - "traefik.http.routers.nextjs-app-https.middlewares=redirect-to-http" - - networks: - - web - environment: - - NODE_ENV=production - - NEXT_PUBLIC_API_URL=https://internal-api.inboxi.ng/api - restart: unless-stopped - -networks: - web: - external: true diff --git a/lib/client-service.ts b/lib/client-service.ts index b6a2ebe..3e9bcbf 100644 --- a/lib/client-service.ts +++ b/lib/client-service.ts @@ -27,24 +27,16 @@ export async function fetchClient( ): Promise { const { method = 'GET', body, headers = {}, ...rest } = options; - // Get the base API URL from environment or fallback - const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; - - // Ensure the endpoint starts with a slash + // Always use the Next.js API proxy by creating a path starting with /api/ + // This ensures requests go through Next.js rewrites const normalizedEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`; - // For the specific case of internal-api.inboxi.ng - remove duplicate /api + // Construct the URL to always use the Next.js API routes let url; - if (apiUrl.includes('internal-api.inboxi.ng')) { - // Special case for internal-api.inboxi.ng - if (normalizedEndpoint.startsWith('/api/')) { - url = `${apiUrl}${normalizedEndpoint.substring(4)}`; // Remove the /api part - } else { - url = `${apiUrl}${normalizedEndpoint}`; - } + if (normalizedEndpoint.startsWith('/api/')) { + url = normalizedEndpoint; // Already has /api/ prefix } else { - // Normal case for other environments - url = `${apiUrl}${normalizedEndpoint}`; + url = `/api${normalizedEndpoint}`; // Add /api/ prefix } // Get auth token from cookies diff --git a/lib/client-utils.ts b/lib/client-utils.ts index dec31df..07cacdf 100644 --- a/lib/client-utils.ts +++ b/lib/client-utils.ts @@ -14,15 +14,17 @@ export async function clientFetch(url: string, options: RequestInit = {}): Promi ...options.headers, }; - // Ensure the url doesn't start with a slash if it's going to be appended to a URL that ends with one - const cleanUrl = url.startsWith('/') ? url.substring(1) : url; - const baseUrl = process.env.NEXT_PUBLIC_API_URL || '/api'; + // Always use the Next.js API proxy for consistent routing + // Format the URL to ensure it has the /api prefix + let fullUrl; + if (url.startsWith('/api/')) { + fullUrl = url; // Already has /api/ prefix + } else { + // Add /api prefix if not already present + const cleanUrl = url.startsWith('/') ? url : `/${url}`; + fullUrl = `/api${cleanUrl}`; + } - // Ensure there's only one slash between the base URL and endpoint - const fullUrl = baseUrl.endsWith('/') - ? `${baseUrl}${cleanUrl}` - : `${baseUrl}/${cleanUrl}`; - const res = await fetch(fullUrl, { ...options, headers, diff --git a/lib/productData.ts b/lib/productData.ts index 1576440..3b6f6ea 100644 --- a/lib/productData.ts +++ b/lib/productData.ts @@ -91,7 +91,8 @@ export const updateProductStock = async ( authToken: string ) => { try { - const url = `${process.env.NEXT_PUBLIC_API_URL}/stock/${productId}`; + // Use Next.js API proxy to ensure request goes through rewrites + const url = `/api/stock/${productId}`; return await fetchData(url, { method: "PUT", headers: { diff --git a/lib/storeHelper.ts b/lib/storeHelper.ts index ddb4167..1350952 100644 --- a/lib/storeHelper.ts +++ b/lib/storeHelper.ts @@ -29,10 +29,18 @@ export const apiRequest = async (endpoint: string, method: string = "GE options.body = JSON.stringify(body); } - const API_URL = process.env.NEXT_PUBLIC_API_URL; - if (!API_URL) throw new Error("NEXT_PUBLIC_API_URL is not set in environment variables"); + // Always use the Next.js API proxy to ensure all requests go through rewrites + // Format the endpoint to ensure it has the /api prefix + let url; + if (endpoint.startsWith('/api/')) { + url = endpoint; // Already has /api/ prefix + } else { + // Add /api prefix and ensure no duplicate slashes + const cleanEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`; + url = `/api${cleanEndpoint}`; + } - const res = await fetchData(`${API_URL}${endpoint}`, options); + const res = await fetchData(url, options); if (!res) { const errorResponse = await res.json().catch(() => null); diff --git a/middleware.ts b/middleware.ts index 6b07ae1..7a5b474 100644 --- a/middleware.ts +++ b/middleware.ts @@ -2,15 +2,29 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; export async function middleware(req: NextRequest) { + // Check for auth token in cookies const token = req.cookies.get("Authorization")?.value; - + + // Debug info about all cookies + const allCookies = req.cookies.getAll(); + console.log("Middleware: All cookies:", allCookies.map(c => c.name).join(', ')); + if (!token) { - console.log("Middleware: No token found, redirecting to login..."); - return NextResponse.redirect(new URL("/auth/login", req.url)); + // Try to get from Authorization header as fallback + const authHeader = req.headers.get('Authorization'); + + if (authHeader?.startsWith('Bearer ')) { + console.log("Middleware: Token found in Authorization header"); + // Continue with validation using header auth + // The authCheckUrl will handle extracting the token from header + } else { + console.log("Middleware: No token found in cookies or headers, redirecting to login..."); + return NextResponse.redirect(new URL("/auth/login", req.url)); + } + } else { + console.log("Middleware: Token found in cookies, validating..."); } - console.log("Middleware: Token found, validating..."); - try { // Get the origin but handle localhost differently to avoid SSL issues const origin = req.nextUrl.origin; @@ -24,13 +38,17 @@ export async function middleware(req: NextRequest) { console.log(`Using internal auth check URL: ${authCheckUrl}`); + // Clone headers to avoid modifying the original request + const headers = new Headers(req.headers); + + // If token is in cookie, ensure it's also in Authorization header + if (token && !headers.has('Authorization')) { + headers.set('Authorization', `Bearer ${token}`); + } + const res = await fetch(authCheckUrl, { method: "GET", - headers: { - "Content-Type": "application/json", - // Explicitly pass the token in headers as well - "Authorization": `Bearer ${token}` - }, + headers, credentials: 'include', });