← back to Letsbegin

middleware.ts

101 lines

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { AUTH_CONFIG } from '@/lib/auth'

// Routes that don't require authentication
const publicPaths = [
  '/login',
  '/live',
  '/api/auth/login',
  '/api/auth/logout',
  '/api/auth/session',
  '/api/processes',
  '/api/ralph',
  '/api/live',
  '/api/url-info',
  '/_next',
  '/favicon.ico',
]

// DW Central SSO: Check if user has a valid DW Central session
function verifyDWCentralSession(token: string): boolean {
  try {
    // DW Central uses base64 encoded "username:timestamp" format
    const decoded = Buffer.from(token, 'base64').toString('utf-8');
    const [username, timestamp] = decoded.split(':');
    if (username && timestamp) {
      const sessionTime = parseInt(timestamp, 10);
      const now = Date.now();
      const maxAge = 86400000; // 24 hours
      return (now - sessionTime) < maxAge;
    }
    return false;
  } catch {
    return false;
  }
}

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

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

  // Check for DW Central SSO session first (from dw.greendomainbrokers.com)
  const dwCentralToken = request.cookies.get('dw_central_session')?.value;
  if (dwCentralToken && verifyDWCentralSession(dwCentralToken)) {
    return NextResponse.next()
  }

  // Bypass internal auth if already authenticated via nginx basic auth (DW Central portal)
  const authHeader = request.headers.get('authorization')
  if (authHeader?.startsWith('Basic ')) {
    return NextResponse.next()
  }

  // Check for session cookie
  const sessionCookie = request.cookies.get(AUTH_CONFIG.sessionName)

  if (!sessionCookie?.value) {
    // No session - redirect to login
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('redirect', pathname)
    return NextResponse.redirect(loginUrl)
  }

  // Validate session token
  try {
    const sessionData = JSON.parse(Buffer.from(sessionCookie.value, 'base64').toString())

    if (!sessionData.authenticated) {
      // Invalid session - redirect to login
      const loginUrl = new URL('/login', request.url)
      return NextResponse.redirect(loginUrl)
    }

    // Check session age (30 days max)
    const sessionAge = Date.now() - sessionData.loginTime
    if (sessionAge > AUTH_CONFIG.cookieMaxAge) {
      // Session expired - redirect to login
      const loginUrl = new URL('/login', request.url)
      return NextResponse.redirect(loginUrl)
    }

    // Valid session - proceed
    return NextResponse.next()
  } catch (error) {
    // Invalid session data - redirect to login
    const loginUrl = new URL('/login', request.url)
    return NextResponse.redirect(loginUrl)
  }
}

export const config = {
  matcher: [
    // Match all paths except static files and images
    '/((?!_next/static|_next/image|favicon.ico).*)',
  ],
}