import { createLogger } from '@sim/logger' import { authorizeWorkflowByWorkspacePermission } from '@sim/platform-authz/workflow' import type { NextRequest } from 'next/server' import { type ApiKeyAuthResult, authenticateApiKeyFromHeader, updateApiKeyLastUsed, } from '@/lib/api-key/service' import { type AuthResult, checkHybridAuth } from '@/lib/auth/hybrid' import { getWorkflowById } from '@/lib/workflows/utils' const logger = createLogger('WorkflowMiddleware') export interface ValidationResult { error?: { message: string; status: number } workflow?: any auth?: AuthResult } export async function validateWorkflowAccess( request: NextRequest, workflowId: string, requireDeployment = true ): Promise { try { const workflow = await getWorkflowById(workflowId) if (!workflow) { return { error: { message: 'Workflow not found', status: 404, }, } } if (!workflow.workspaceId) { return { error: { message: 'This workflow is not attached to a workspace. Personal workflows are deprecated and cannot be accessed.', status: 403, }, } } if (!requireDeployment) { const auth = await checkHybridAuth(request, { requireWorkflowId: false }) if (!auth.success || !auth.userId) { return { error: { message: auth.error || 'Unauthorized', status: 401, }, } } if (auth.apiKeyType === 'workspace' && auth.workspaceId !== workflow.workspaceId) { return { error: { message: 'API key is not authorized for this workspace', status: 403, }, } } const authorization = await authorizeWorkflowByWorkspacePermission({ workflowId, userId: auth.userId, action: 'read', }) if (!authorization.allowed) { return { error: { message: authorization.message || 'Access denied', status: authorization.status, }, } } return { workflow, auth } } if (requireDeployment) { if (!workflow.isDeployed) { return { error: { message: 'Workflow is not deployed', status: 403, }, } } let apiKeyHeader = null for (const [key, value] of request.headers.entries()) { if (key.toLowerCase() === 'x-api-key' && value) { apiKeyHeader = value break } } if (!apiKeyHeader) { return { error: { message: 'Unauthorized: API key required', status: 401, }, } } let validResult: ApiKeyAuthResult | null = null const workspaceResult = await authenticateApiKeyFromHeader(apiKeyHeader, { workspaceId: workflow.workspaceId as string, keyTypes: ['workspace', 'personal'], }) if (workspaceResult.success) { validResult = workspaceResult } if (!validResult) { return { error: { message: 'Unauthorized: Invalid API key', status: 401, }, } } if (validResult.keyId) { await updateApiKeyLastUsed(validResult.keyId) } } return { workflow } } catch (error) { logger.error('Validation error:', { error }) return { error: { message: 'Internal server error', status: 500, }, } } }