← back to ClawCoder

src/middleware.ts

54 lines

import { NextResponse } from 'next/server'
import type { NextRequest } 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

const publicPaths = [
  '/login',
  '/api/',
  '/_next',
  '/favicon.ico',
]

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl

  // Allow public paths
  if (publicPaths.some(path => pathname.startsWith(path))) {
    return NextResponse.next()
  }

  // Check Basic Auth header (for API/curl access)
  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 NextResponse.next()
    }
  }

  // Check session cookie (for browser access)
  const session = request.cookies.get(SESSION_COOKIE)?.value
  if (session) {
    try {
      const data = JSON.parse(Buffer.from(session, 'base64url').toString())
      if (data.authenticated && (Date.now() - data.loginTime) < SESSION_MAX_AGE) {
        return NextResponse.next()
      }
    } catch {}
  }

  // No valid auth — redirect to login
  const loginUrl = new URL('/login', request.url)
  loginUrl.searchParams.set('redirect', pathname)
  return NextResponse.redirect(loginUrl)
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}