Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.local.backup
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
POSTGRES_URL="postgres://postgres.hxijjvnsrxynegthasmh:pcE680j67rhFfDRr@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?sslmode=require&supa=base-pooler.x"
POSTGRES_USER="postgres"
POSTGRES_HOST="db.hxijjvnsrxynegthasmh.supabase.co"
SUPABASE_JWT_SECRET="998Vo+CP+u2rNnH6fv9w4KWGb+8I1P9bXjrM2tKiFE5YcIlQ1Tr+NBNPNGw1de2drhvoXX0dSZJZ84toPkxBtA=="
NEXT_PUBLIC_SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imh4aWpqdm5zcnh5bmVndGhhc21oIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDc3Mzk5NDcsImV4cCI6MjA2MzMxNTk0N30.zWILyiJA1K5L0w2rynsWqhMVU6jySaal5lC9IBO05bc"
POSTGRES_PRISMA_URL="postgres://postgres.hxijjvnsrxynegthasmh:pcE680j67rhFfDRr@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?sslmode=require&supa=base-pooler.x"
POSTGRES_PASSWORD="pcE680j67rhFfDRr"
POSTGRES_DATABASE="postgres"
SUPABASE_URL="https://hxijjvnsrxynegthasmh.supabase.co"
NEXT_PUBLIC_SUPABASE_URL="https://hxijjvnsrxynegthasmh.supabase.co"
SUPABASE_SERVICE_ROLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imh4aWpqdm5zcnh5bmVndGhhc21oIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0NzczOTk0NywiZXhwIjoyMDYzMzE1OTQ3fQ.poV3TJW7eJULdQ_yYHhygUPbEMYW-SSrIVWSsnRXRAk"
POSTGRES_URL_NON_POOLING="postgres://postgres.hxijjvnsrxynegthasmh:pcE680j67rhFfDRr@aws-0-eu-central-1.pooler.supabase.com:5432/postgres?sslmode=require"
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/1326548524657016842/rJrqRnK7lZQKKh_kzT2bz_rjBx6T0BDz8vym4SVeMt-sLXl4PaMycrYuM8pbbr1JNpSm"
NEXT_PUBLIC_SITE_URL = "https://orange-engine-q6gpjxwwqg9h9pw5-3001.app.github.dev"

AUTHORIZED_ADMINS=Sparths,sparths,f8adc96a-496f-412b-af15-20bd3cd66b3c
NEXT_PUBLIC_AUTHORIZED_ADMINS=Sparths,sparths
45 changes: 21 additions & 24 deletions app/api/admin/verify/route.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { NextResponse } from "next/server";
import { createClient } from '@supabase/supabase-js';
import { createSecureAdminToken, verifySecureAdminToken } from '@/lib/security/secure-token';
import { sanitizeInput } from '@/lib/security/sanitization';

// Admin verification with service role
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
Expand All @@ -19,11 +21,6 @@ const getAuthorizedAdmins = (): string[] => {
return adminList.split(',').map(admin => admin.trim());
};

// Input sanitization
const sanitizeInput = (input: string): string => {
return input.replace(/[<>]/g, '').trim();
};

export async function POST(request: Request) {
try {
const body = await request.json();
Expand Down Expand Up @@ -52,15 +49,8 @@ export async function POST(request: Request) {
if (authorizedAdmins.includes(sanitizedUserId)) {
console.log("User found in direct admin list:", sanitizedUserId);

// Create admin session token for subsequent requests
const adminSession = {
userId: sanitizedUserId,
timestamp: Date.now(),
verified: true,
isAdmin: true
};

const adminToken = Buffer.from(JSON.stringify(adminSession)).toString('base64');
// Create secure admin session token
const adminToken = createSecureAdminToken(sanitizedUserId);

return NextResponse.json({
success: true,
Expand Down Expand Up @@ -108,15 +98,8 @@ export async function POST(request: Request) {
if (isAdmin) {
console.log("User verified as admin");

// Create admin session token for subsequent requests
const adminSession = {
userId: sanitizedUserId,
timestamp: Date.now(),
verified: true,
isAdmin: true
};

const adminToken = Buffer.from(JSON.stringify(adminSession)).toString('base64');
// Create secure admin session token
const adminToken = createSecureAdminToken(sanitizedUserId);

return NextResponse.json({
success: true,
Expand Down Expand Up @@ -160,12 +143,26 @@ export async function POST(request: Request) {
}
}

// Optional: GET method to check current admin status
// GET method to check current admin status
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const userId = searchParams.get("userId");

// Check for admin token in Authorization header
const authHeader = request.headers.get('authorization');
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.substring(7);
const verification = verifySecureAdminToken(token);

if (verification.isValid) {
return NextResponse.json({
isAdmin: true,
userId: verification.userId
});
}
}

if (!userId) {
return NextResponse.json(
{ error: "User ID is required" },
Expand Down
40 changes: 40 additions & 0 deletions app/api/auth/csrf/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// =================================
// app/api/auth/csrf/route.tsx
// =================================

import { NextResponse } from 'next/server';
import { generateCSRFToken } from '@/lib/security/csrf-protection';
import { rateLimit, createRateLimitHeaders } from "@/lib/security/rate-limiter-config";

// GET: Get CSRF token
export async function GET(request: Request) {
try {
// Apply rate limiting
const rateLimitResult = await rateLimit(request, 'default');
if (!rateLimitResult.success) {
return new NextResponse(
JSON.stringify({ error: 'Too many requests. Please try again later.' }),
{
status: 429,
headers: {
'Content-Type': 'application/json',
...createRateLimitHeaders(rateLimitResult),
}
}
);
}

const token = generateCSRFToken();

return NextResponse.json(
{ token },
{ headers: createRateLimitHeaders(rateLimitResult) }
);
} catch (error) {
console.error("Error generating CSRF token:", error);
return NextResponse.json(
{ error: "Failed to generate CSRF token" },
{ status: 500 }
);
}
}
117 changes: 117 additions & 0 deletions app/api/auth/session/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// =================================
// app/api/auth/session/route.tsx
// =================================

import { NextResponse } from 'next/server';
import { rateLimit, createRateLimitHeaders } from "@/lib/security/rate-limiter-config";
import supabase from '@/lib/supabase';

// GET: Get current session information
export async function GET(request: Request) {
try {
// Apply rate limiting
const rateLimitResult = await rateLimit(request, 'default');
if (!rateLimitResult.success) {
return new NextResponse(
JSON.stringify({ error: 'Too many requests. Please try again later.' }),
{
status: 429,
headers: {
'Content-Type': 'application/json',
...createRateLimitHeaders(rateLimitResult),
}
}
);
}

// Get session from Supabase Auth
const authHeader = request.headers.get('authorization');
if (!authHeader) {
return NextResponse.json(
{ session: null },
{ headers: createRateLimitHeaders(rateLimitResult) }
);
}

// For now, return a basic response
// In a full implementation, you would verify the session token
return NextResponse.json(
{ session: null },
{ headers: createRateLimitHeaders(rateLimitResult) }
);
} catch (error) {
console.error("Error getting session:", error);
return NextResponse.json(
{ error: "Failed to get session" },
{ status: 500 }
);
}
}

// POST: Create a new session (login)
export async function POST(request: Request) {
try {
// Apply rate limiting
const rateLimitResult = await rateLimit(request, 'users_login');
if (!rateLimitResult.success) {
return new NextResponse(
JSON.stringify({ error: 'Too many login attempts. Please try again later.' }),
{
status: 429,
headers: {
'Content-Type': 'application/json',
...createRateLimitHeaders(rateLimitResult),
}
}
);
}

// This would handle session creation
// For now, redirect to the main users login endpoint
return NextResponse.json(
{ message: "Use /api/users?action=login for authentication" },
{
status: 400,
headers: createRateLimitHeaders(rateLimitResult)
}
);
} catch (error) {
console.error("Error creating session:", error);
return NextResponse.json(
{ error: "Failed to create session" },
{ status: 500 }
);
}
}

// DELETE: Logout/destroy session
export async function DELETE(request: Request) {
try {
// Apply rate limiting
const rateLimitResult = await rateLimit(request, 'default');
if (!rateLimitResult.success) {
return new NextResponse(
JSON.stringify({ error: 'Too many requests. Please try again later.' }),
{
status: 429,
headers: {
'Content-Type': 'application/json',
...createRateLimitHeaders(rateLimitResult),
}
}
);
}

// Handle logout logic here
return NextResponse.json(
{ success: true },
{ headers: createRateLimitHeaders(rateLimitResult) }
);
} catch (error) {
console.error("Error destroying session:", error);
return NextResponse.json(
{ error: "Failed to destroy session" },
{ status: 500 }
);
}
}
Loading