Skip to main content

Middleware & Route Protection

1.1 routePipelines

Location: src/middleware/routePipelines.ts

Purpose: Defines route patterns and their associated handler pipelines for middleware-based access control.

Description: This configuration array maps URL patterns (using regex) to arrays of handler functions that execute sequentially. Each handler can allow or deny access, redirect users, or perform other middleware operations.

Structure:

{
pattern: RegExp, // Regex pattern to match URL paths
handlers: Array<HandlerFunction> // Array of handler functions to execute
}

Key Routes:

  • /[primaryTeam] - Primary team access validation
  • /[primaryTeam]/campaign/* - Campaign-specific routes
  • /api/essearch - Elasticsearch API access
  • /api/duplicate - Duplicate checking API

Example:

{
pattern: /^\/[^/]+\/campaign\/[^/]+\/add-signatures$/,
handlers: [
checkCampaignHome,
genCampaignHandler("campaigns-signatures-create")
]
}

Notes:

  • Handlers execute in order
  • If any handler returns a redirect, subsequent handlers are skipped
  • Patterns use regex for flexible matching

1.2 checkCampaignHome

Location: src/middleware/validators/campaign-route.ts

Purpose: Validates that a user has access to a specific campaign before allowing access to campaign routes.

Signature:

async function checkCampaignHome({ 
session,
request
}: HandlerContext): Promise<NextResponse>

Parameters:

  • session - User session object containing allowed_campaigns array
  • request - Next.js request object

Returns: NextResponse - Either continues to next handler or redirects

Logic:

  1. Extracts teamId from URL path (first segment)
  2. Extracts campaignId from URL path (third segment)
  3. Checks if campaignId exists in session.allowed_campaigns
  4. Redirects to team home if access denied

Example:

// URL: /my-team/campaign/campaign-123/dashboard
// Checks if "campaign-123" is in session.allowed_campaigns

Error Handling:

  • Redirects to /{teamId} if campaign access denied
  • Returns NextResponse.next() if access granted

1.3 checkCampaignGenFeat

Location: src/middleware/validators/campaign-route.ts

Purpose: Validates that a user has a specific permission for a campaign route.

Signature:

async function checkCampaignGenFeat({
session,
request,
checkID
}: CheckGenFeatContext): Promise<NextResponse>

Parameters:

  • session - User session with permissions array
  • request - Next.js request object
  • checkID - Permission ID to check (e.g., "campaigns-signatures-create")

Returns: NextResponse - Either continues or redirects to campaign home

Logic:

  1. Extracts team and campaign IDs from URL
  2. Checks if checkID exists in session.permissions
  3. Redirects to campaign home if permission missing

Common Permission IDs:

  • campaigns-signatures-create - Create signatures
  • campaigns-signatures-read - View signatures
  • campaigns-rates-create - Create rates
  • campaigns-dashboard - View dashboard

1.4 checkPrimaryTeamAllowed

Location: src/middleware/validators/team-route.ts

Purpose: Validates that a user has access to the primary team in the URL.

Signature:

async function checkPrimaryTeamAllowed({
session,
request
}: HandlerContext): Promise<NextResponse>

Parameters:

  • session - User session with allowed_teams array
  • request - Next.js request object

Returns: NextResponse - Either continues or redirects to home

Logic:

  1. Extracts team ID from first URL segment
  2. Checks if team ID exists in session.allowed_teams
  3. Redirects to home (/) if access denied

Example:

// URL: /my-team/campaigns
// Checks if "my-team" is in session.allowed_teams

1.5 checkGenFeat

Location: src/middleware/validators/team-route.ts

Purpose: Generic permission checker for team-level features.

Signature:

async function checkGenFeat({
session,
request,
checkID
}: CheckGenFeatContext): Promise<NextResponse>

Parameters:

  • session - User session with permissions array
  • request - Next.js request object
  • checkID - Permission ID to validate

Returns: NextResponse - Either continues or redirects to team home

Logic:

  1. Extracts team ID from URL
  2. Checks if checkID exists in session.permissions
  3. Redirects to /{teamId} if permission missing

1.6 checkVoterSearchControl

Location: src/middleware/validators/api-routes.ts

Purpose: Validates voter search API access permissions.

Signature:

async function checkVoterSearchControl({
session,
request
}: HandlerContext): Promise<NextResponse>

Logic:

  • Checks for voter-search OR admin-voter-search permissions
  • Redirects to home if neither permission exists

1.7 checkEssearchFeat

Location: src/middleware/validators/api-routes.ts

Purpose: Validates Elasticsearch API access for signature creation.

Signature:

async function checkEssearchFeat({
session,
request
}: HandlerContext): Promise<NextResponse>

Logic:

  • Requires campaigns-signatures-create permission
  • Used for /api/essearch and /api/duplicate routes