← back to ClawCoder
src/lib/auth.ts
68 lines
import { NextRequest, NextResponse } from 'next/server'
const AUTH_USER = 'Steve'
const AUTH_PASS = 'DWSecure2024!'
const SESSION_COOKIE = 'clawcoder_session'
const SESSION_MAX_AGE = 30 * 24 * 60 * 60 * 1000 // 30 days
export interface SessionData {
authenticated: boolean
username: string
loginTime: number
}
/**
* Parse session from cookie value (base64-encoded JSON).
* Returns null if invalid or expired.
*/
export function parseSession(cookieValue: string | undefined): SessionData | null {
if (!cookieValue) return null
try {
const data = JSON.parse(Buffer.from(cookieValue, 'base64').toString()) as SessionData
if (data.authenticated && (Date.now() - data.loginTime) < SESSION_MAX_AGE) {
return data
}
} catch {
// malformed cookie
}
return null
}
/**
* Check Basic Auth header (for curl/API access).
* Returns the username if valid, null otherwise.
*/
export function checkBasicAuth(request: NextRequest): string | null {
const authHeader = request.headers.get('authorization')
if (authHeader?.startsWith('Basic ')) {
const decoded = Buffer.from(authHeader.slice(6), 'base64').toString()
const [user, pass] = decoded.split(':')
if (user === AUTH_USER && pass === AUTH_PASS) {
return user
}
}
return null
}
/**
* Authenticate an API request. Checks session cookie first, then Basic Auth.
* Returns the username if authenticated, or a 401 NextResponse if not.
*/
export function authenticateRequest(request: NextRequest): string | NextResponse {
// Check session cookie
const session = parseSession(request.cookies.get(SESSION_COOKIE)?.value)
if (session) {
return session.username
}
// Check Basic Auth
const basicUser = checkBasicAuth(request)
if (basicUser) {
return basicUser
}
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
export { AUTH_USER, AUTH_PASS, SESSION_COOKIE, SESSION_MAX_AGE }