"use strict";
/**
 * Framework-Aware Fix Suggestions Registry (PRO-83)
 *
 * Provides framework-specific fix suggestions that transform generic advice
 * into actionable guidance based on the user's detected tech stack.
 *
 * When a Next.js + Prisma project has a SQL injection finding, this registry
 * provides Prisma-specific fixes instead of generic SQL advice.
 *
 * Falls back gracefully to generic fixes (from metadata.ts) when no match.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.FRAMEWORK_FIX_REGISTRY = void 0;
exports.getFrameworkFix = getFrameworkFix;
// ============================================================================
// Framework Fix Registry
// ============================================================================
/**
 * Registry mapping vulnerability categories to framework-specific fixes.
 *
 * Structure: category -> framework -> fix
 *
 * Priority categories (Tier 1):
 * - sql_injection: Fixes vary dramatically by ORM
 * - missing_auth: Framework-specific middleware patterns
 * - xss: React/Vue/vanilla have different approaches
 * - hardcoded_secret: Framework-specific env handling
 * - cors_misconfiguration: Very framework-specific
 */
exports.FRAMEWORK_FIX_REGISTRY = {
    // ==========================================================================
    // SQL Injection - Fixes vary dramatically by ORM
    // ==========================================================================
    sql_injection: {
        prisma: {
            fixSteps: [
                'Use Prisma query methods: prisma.user.findUnique({ where: { id } })',
                'For raw SQL, use Prisma.$queryRaw with template literals (auto-parameterized)',
                'Never concatenate user input into query strings',
                'Validate input with Zod before passing to queries',
            ],
            codeExample: `// Safe: Prisma parameterized query
const user = await prisma.user.findUnique({
  where: { email: userInput }
})

// Safe: Raw query with parameters
await prisma.$queryRaw\`SELECT * FROM users WHERE id = \${userId}\``,
        },
        drizzle: {
            fixSteps: [
                'Use Drizzle query builder with eq(), and(), or() operators',
                'For raw SQL, use sql`` template literal (auto-parameterized)',
                'Never concatenate user input into query strings',
                'Validate input with Zod before passing to queries',
            ],
            codeExample: `// Safe: Drizzle query builder
const users = await db.select().from(usersTable)
  .where(eq(usersTable.email, userInput))

// Safe: Raw query with parameters
await db.execute(sql\`SELECT * FROM users WHERE id = \${userId}\`)`,
        },
        supabase: {
            fixSteps: [
                'Use Supabase client methods: supabase.from("users").select().eq("id", userId)',
                'Rely on Row Level Security (RLS) for access control',
                'For complex queries, use stored procedures with parameters',
                'Never use .rpc() with string concatenation for query building',
            ],
            codeExample: `// Safe: Supabase client with RLS
const { data } = await supabase
  .from('users')
  .select('*')
  .eq('email', userInput)
  .single()`,
        },
        mongoose: {
            fixSteps: [
                'Use Mongoose query methods with conditions object: User.find({ email: userInput })',
                'Avoid $where with user input - it allows JavaScript execution',
                'Validate ObjectIds before querying: mongoose.Types.ObjectId.isValid(id)',
                'Use schema validation to ensure expected data types',
            ],
            codeExample: `// Safe: Mongoose query with conditions
const user = await User.findOne({ email: userInput })

// Validate ObjectId before use
if (!mongoose.Types.ObjectId.isValid(id)) {
  throw new Error('Invalid ID')
}`,
        },
        knex: {
            fixSteps: [
                'Use Knex query builder: knex("users").where({ email: userInput })',
                'For raw SQL, use knex.raw() with parameter binding: knex.raw("SELECT * FROM users WHERE id = ?", [userId])',
                'Never use string concatenation in queries',
                'Validate input types before passing to queries',
            ],
            codeExample: `// Safe: Knex query builder
const user = await knex('users')
  .where({ email: userInput })
  .first()

// Safe: Raw query with parameters
await knex.raw('SELECT * FROM users WHERE id = ?', [userId])`,
        },
    },
    // ==========================================================================
    // Missing Authentication - Framework-specific middleware patterns
    // ==========================================================================
    missing_auth: {
        nextjs: {
            fixSteps: [
                'Add auth check in middleware.ts with matcher config for protected routes',
                'Call auth() or getServerSession() at the start of route handlers',
                'Return 401/redirect for unauthenticated requests',
                'Use throwing auth helpers (getCurrentUserId) that guarantee authenticated context',
            ],
            codeExample: `// middleware.ts
export { auth as middleware } from '@/auth'
export const config = { matcher: ['/dashboard/:path*', '/api/:path*'] }

// In route handler
import { auth } from '@/auth'

export async function GET() {
  const session = await auth()
  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }
  // ... authenticated code
}`,
        },
        express: {
            fixSteps: [
                'Use authentication middleware (passport, express-session, or custom)',
                'Apply middleware to routes: app.use("/api", authMiddleware)',
                'Verify JWT tokens or session cookies in middleware',
                'Return 401 status for unauthenticated requests',
            ],
            codeExample: `// authMiddleware.js
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1]
  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  try {
    req.user = jwt.verify(token, process.env.JWT_SECRET)
    next()
  } catch {
    return res.status(401).json({ error: 'Invalid token' })
  }
}

// Apply to routes
app.use('/api', authMiddleware)`,
        },
        fastify: {
            fixSteps: [
                'Use @fastify/auth or @fastify/jwt for authentication',
                'Register auth plugin and apply to routes with onRequest hook',
                'Decorate request with user info after authentication',
                'Return 401 status for unauthenticated requests',
            ],
            codeExample: `// Register JWT plugin
await fastify.register(fastifyJwt, { secret: process.env.JWT_SECRET })

// Auth decorator
fastify.decorate('authenticate', async (request, reply) => {
  try {
    await request.jwtVerify()
  } catch (err) {
    reply.code(401).send({ error: 'Unauthorized' })
  }
})

// Protected route
fastify.get('/api/data', { onRequest: [fastify.authenticate] }, handler)`,
        },
        nestjs: {
            fixSteps: [
                'Use @nestjs/passport with Guards for authentication',
                'Apply AuthGuard to controllers or routes with @UseGuards()',
                'Implement custom guards for role-based access control',
                'Use @Public() decorator for intentionally public endpoints',
            ],
            codeExample: `// auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

// controller.ts
@Controller('api')
@UseGuards(JwtAuthGuard)
export class ApiController {
  @Get('data')
  getData(@Request() req) {
    return this.service.getData(req.user.id)
  }
}`,
        },
    },
    // ==========================================================================
    // XSS - React/Vue/vanilla have different approaches
    // ==========================================================================
    xss: {
        react: {
            fixSteps: [
                'Use JSX expressions {variable} - React auto-escapes by default',
                'Avoid dangerouslySetInnerHTML unless absolutely necessary',
                'If you must use dangerouslySetInnerHTML, sanitize with DOMPurify first',
                'Validate and sanitize user input on the server side as well',
            ],
            codeExample: `// Safe: JSX auto-escapes
function Comment({ text }) {
  return <div>{text}</div> // Safe - auto-escaped
}

// If HTML is required, sanitize first
import DOMPurify from 'dompurify'

function RichContent({ html }) {
  const clean = DOMPurify.sanitize(html)
  return <div dangerouslySetInnerHTML={{ __html: clean }} />
}`,
        },
        vue: {
            fixSteps: [
                'Use v-text or {{ }} interpolation - Vue auto-escapes by default',
                'Avoid v-html with user-controlled content',
                'If you must use v-html, sanitize with DOMPurify first',
                'Use Content Security Policy headers as additional protection',
            ],
            codeExample: `<!-- Safe: Vue interpolation auto-escapes -->
<template>
  <div>{{ userContent }}</div>
</template>

<!-- If HTML is required, sanitize first -->
<script setup>
import DOMPurify from 'dompurify'
const sanitizedHtml = computed(() => DOMPurify.sanitize(props.html))
</script>

<template>
  <div v-html="sanitizedHtml"></div>
</template>`,
        },
    },
    // ==========================================================================
    // Hardcoded Secrets - Framework-specific env handling
    // ==========================================================================
    hardcoded_secret: {
        nextjs: {
            fixSteps: [
                'Store secrets in .env.local (gitignored by default)',
                'Access via process.env.SECRET_NAME in server components/API routes',
                'Only use NEXT_PUBLIC_ prefix for intentionally client-exposed values',
                'Use Vercel Environment Variables for production deployments',
            ],
            codeExample: `// .env.local
DATABASE_URL=postgres://...
API_SECRET=your-secret-here

// Server-side code (API route, server component)
const secret = process.env.API_SECRET

// Client-safe public values only
// NEXT_PUBLIC_ANALYTICS_ID=xxx`,
        },
        express: {
            fixSteps: [
                'Use dotenv package to load from .env files',
                'Add .env to .gitignore immediately',
                'Access secrets via process.env.SECRET_NAME',
                'Use different .env files per environment (.env.production)',
            ],
            codeExample: `// At app entry point
import 'dotenv/config'

// .env (gitignored)
DATABASE_URL=postgres://...
JWT_SECRET=your-secret-here

// Access in code
const jwtSecret = process.env.JWT_SECRET
if (!jwtSecret) throw new Error('JWT_SECRET required')`,
        },
    },
    // ==========================================================================
    // CORS Misconfiguration - Very framework-specific
    // ==========================================================================
    cors_misconfiguration: {
        nextjs: {
            fixSteps: [
                'Configure CORS in next.config.js headers or middleware',
                'Specify exact allowed origins instead of wildcard "*"',
                'Use environment variables for origin configuration',
                'Consider using middleware for dynamic origin validation',
            ],
            codeExample: `// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/api/:path*',
      headers: [
        { key: 'Access-Control-Allow-Origin', value: process.env.ALLOWED_ORIGIN },
        { key: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,DELETE' },
        { key: 'Access-Control-Allow-Headers', value: 'Content-Type,Authorization' },
      ],
    }]
  },
}

// Or in middleware.ts for dynamic validation
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com']`,
        },
        express: {
            fixSteps: [
                'Use the cors package with specific origin configuration',
                'Replace origin: "*" with an allowlist of origins',
                'Use a function for dynamic origin validation',
                'Disable credentials for cross-origin requests unless necessary',
            ],
            codeExample: `import cors from 'cors'

const allowedOrigins = ['https://app.example.com', 'https://admin.example.com']

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  },
  credentials: true, // Only if you need cookies/auth headers
}))`,
        },
        fastify: {
            fixSteps: [
                'Use @fastify/cors with specific origin configuration',
                'Specify allowed origins instead of true/wildcard',
                'Use a function for dynamic origin validation',
                'Configure allowed methods and headers explicitly',
            ],
            codeExample: `import cors from '@fastify/cors'

const allowedOrigins = ['https://app.example.com']

await fastify.register(cors, {
  origin: (origin, cb) => {
    if (!origin || allowedOrigins.includes(origin)) {
      cb(null, true)
    } else {
      cb(new Error('Not allowed'), false)
    }
  },
  credentials: true,
})`,
        },
    },
    // ==========================================================================
    // Dangerous Function (eval, innerHTML) - Context-specific
    // ==========================================================================
    dangerous_function: {
        react: {
            fixSteps: [
                'Replace innerHTML with React JSX (auto-escapes content)',
                'Use textContent or innerText for plain text updates',
                'If dynamic HTML is required, use DOMPurify before dangerouslySetInnerHTML',
                'Consider using a markdown renderer (react-markdown) for rich content',
            ],
            codeExample: `// Instead of innerHTML
const element = document.getElementById('content')
element.innerHTML = userInput // Dangerous!

// Use React JSX
function SafeContent({ content }) {
  return <div>{content}</div> // Safe - auto-escaped
}`,
        },
        vue: {
            fixSteps: [
                'Use Vue template interpolation {{ }} instead of v-html',
                'If HTML rendering is required, sanitize with DOMPurify first',
                'Consider component-based approaches for dynamic content',
                'Validate and sanitize on the server before sending to client',
            ],
        },
    },
};
// ============================================================================
// Lookup Function
// ============================================================================
/**
 * Get framework-specific fix for a vulnerability category.
 *
 * Priority order for ORM-related categories (sql_injection):
 * 1. ORM (prisma, drizzle, supabase, mongoose, knex)
 * 2. Backend framework (nextjs, express, fastify, nestjs)
 *
 * Priority order for other categories:
 * 1. Frontend framework for XSS (react, vue)
 * 2. Backend framework for auth/cors/secrets
 *
 * @returns FrameworkFix if a match is found, undefined otherwise (falls back to generic)
 */
function getFrameworkFix(category, frameworks, dataAccess) {
    const categoryFixes = exports.FRAMEWORK_FIX_REGISTRY[category];
    if (!categoryFixes) {
        return undefined;
    }
    // For SQL injection, prioritize ORM-specific fixes
    if (category === 'sql_injection' && dataAccess?.orm) {
        const ormFix = categoryFixes[dataAccess.orm];
        if (ormFix) {
            return ormFix;
        }
    }
    // For XSS and dangerous_function, prioritize frontend framework
    if ((category === 'xss' || category === 'dangerous_function') && frameworks.frontend) {
        const frontendFix = categoryFixes[frameworks.frontend];
        if (frontendFix) {
            return frontendFix;
        }
    }
    // For other categories, try backend framework
    if (frameworks.primary) {
        const backendFix = categoryFixes[frameworks.primary];
        if (backendFix) {
            return backendFix;
        }
    }
    // No framework-specific fix found
    return undefined;
}
//# sourceMappingURL=framework-fixes.js.map