// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-2026 Vorion LLC
/**
 * Security Headers Type Definitions
 *
 * Comprehensive type definitions and Zod schemas for security headers management.
 * Includes CSP, HSTS, CORS, and Permissions Policy configurations.
 *
 * @packageDocumentation
 * @module security/headers/types
 */
import { z } from 'zod';
/**
 * Zod schema for CSP source value
 */
export const cspSourceValueSchema = z.string();
/**
 * Zod schema for CSP sandbox value
 */
export const cspSandboxValueSchema = z.enum([
    'allow-downloads',
    'allow-downloads-without-user-activation',
    'allow-forms',
    'allow-modals',
    'allow-orientation-lock',
    'allow-pointer-lock',
    'allow-popups',
    'allow-popups-to-escape-sandbox',
    'allow-presentation',
    'allow-same-origin',
    'allow-scripts',
    'allow-storage-access-by-user-activation',
    'allow-top-navigation',
    'allow-top-navigation-by-user-activation',
    'allow-top-navigation-to-custom-protocols',
]);
/**
 * Zod schema for CSP directives
 */
export const cspDirectivesSchema = z.object({
    'default-src': z.array(cspSourceValueSchema).optional(),
    'child-src': z.array(cspSourceValueSchema).optional(),
    'connect-src': z.array(cspSourceValueSchema).optional(),
    'font-src': z.array(cspSourceValueSchema).optional(),
    'frame-src': z.array(cspSourceValueSchema).optional(),
    'img-src': z.array(cspSourceValueSchema).optional(),
    'manifest-src': z.array(cspSourceValueSchema).optional(),
    'media-src': z.array(cspSourceValueSchema).optional(),
    'object-src': z.array(cspSourceValueSchema).optional(),
    'prefetch-src': z.array(cspSourceValueSchema).optional(),
    'script-src': z.array(cspSourceValueSchema).optional(),
    'script-src-elem': z.array(cspSourceValueSchema).optional(),
    'script-src-attr': z.array(cspSourceValueSchema).optional(),
    'style-src': z.array(cspSourceValueSchema).optional(),
    'style-src-elem': z.array(cspSourceValueSchema).optional(),
    'style-src-attr': z.array(cspSourceValueSchema).optional(),
    'worker-src': z.array(cspSourceValueSchema).optional(),
    'base-uri': z.array(cspSourceValueSchema).optional(),
    sandbox: z.array(cspSandboxValueSchema).optional(),
    'form-action': z.array(cspSourceValueSchema).optional(),
    'frame-ancestors': z.array(cspSourceValueSchema).optional(),
    'navigate-to': z.array(cspSourceValueSchema).optional(),
    'report-uri': z.array(z.string().url()).optional(),
    'report-to': z.string().optional(),
    'require-trusted-types-for': z.array(z.literal('script')).optional(),
    'trusted-types': z.array(z.string()).optional(),
    'upgrade-insecure-requests': z.boolean().optional(),
    'block-all-mixed-content': z.boolean().optional(),
}).strict();
/**
 * Minimum max-age for HSTS preload list submission (1 year in seconds)
 */
export const HSTS_MIN_MAX_AGE_FOR_PRELOAD = 31536000;
/**
 * Recommended max-age for HSTS (2 years in seconds)
 */
export const HSTS_RECOMMENDED_MAX_AGE = 63072000;
/**
 * Zod schema for HSTS configuration
 */
export const hstsConfigSchema = z.object({
    maxAge: z.number().int().min(0).default(HSTS_RECOMMENDED_MAX_AGE),
    includeSubDomains: z.boolean().default(true),
    preload: z.boolean().default(false),
}).refine((config) => {
    // If preload is enabled, maxAge must be at least 1 year and includeSubDomains must be true
    if (config.preload) {
        return config.maxAge >= HSTS_MIN_MAX_AGE_FOR_PRELOAD && config.includeSubDomains;
    }
    return true;
}, {
    message: `HSTS preload requires maxAge >= ${HSTS_MIN_MAX_AGE_FOR_PRELOAD} (1 year) and includeSubDomains: true`,
});
/**
 * Zod schema for CORS configuration
 */
export const corsConfigSchema = z.object({
    allowedOrigins: z.array(z.string()).min(1, 'At least one origin must be specified'),
    allowedMethods: z.array(z.string()).default(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']),
    allowedHeaders: z.array(z.string()).default([
        'Accept',
        'Accept-Language',
        'Content-Language',
        'Content-Type',
        'Authorization',
        'X-Requested-With',
        'X-CSRF-Token',
    ]),
    exposedHeaders: z.array(z.string()).default([]),
    credentials: z.boolean().default(false),
    maxAge: z.number().int().min(0).max(86400).default(600),
    privateNetworkAccess: z.boolean().default(false),
}).refine((config) => {
    // Credentials cannot be used with wildcard origin
    if (config.credentials && config.allowedOrigins.includes('*')) {
        return false;
    }
    return true;
}, {
    message: 'credentials: true cannot be used with wildcard (*) origin',
});
/**
 * Zod schema for Permissions Policy value
 */
export const permissionsPolicyValueSchema = z.string();
/**
 * Zod schema for Permissions Policy configuration
 */
export const permissionsPolicyConfigSchema = z.object({
    accelerometer: permissionsPolicyValueSchema.optional(),
    'ambient-light-sensor': permissionsPolicyValueSchema.optional(),
    autoplay: permissionsPolicyValueSchema.optional(),
    battery: permissionsPolicyValueSchema.optional(),
    camera: permissionsPolicyValueSchema.optional(),
    'display-capture': permissionsPolicyValueSchema.optional(),
    'document-domain': permissionsPolicyValueSchema.optional(),
    'encrypted-media': permissionsPolicyValueSchema.optional(),
    fullscreen: permissionsPolicyValueSchema.optional(),
    gamepad: permissionsPolicyValueSchema.optional(),
    geolocation: permissionsPolicyValueSchema.optional(),
    gyroscope: permissionsPolicyValueSchema.optional(),
    hid: permissionsPolicyValueSchema.optional(),
    'identity-credentials-get': permissionsPolicyValueSchema.optional(),
    'idle-detection': permissionsPolicyValueSchema.optional(),
    'local-fonts': permissionsPolicyValueSchema.optional(),
    magnetometer: permissionsPolicyValueSchema.optional(),
    microphone: permissionsPolicyValueSchema.optional(),
    midi: permissionsPolicyValueSchema.optional(),
    'otp-credentials': permissionsPolicyValueSchema.optional(),
    payment: permissionsPolicyValueSchema.optional(),
    'picture-in-picture': permissionsPolicyValueSchema.optional(),
    'publickey-credentials-create': permissionsPolicyValueSchema.optional(),
    'publickey-credentials-get': permissionsPolicyValueSchema.optional(),
    'screen-wake-lock': permissionsPolicyValueSchema.optional(),
    serial: permissionsPolicyValueSchema.optional(),
    'speaker-selection': permissionsPolicyValueSchema.optional(),
    'storage-access': permissionsPolicyValueSchema.optional(),
    usb: permissionsPolicyValueSchema.optional(),
    'web-share': permissionsPolicyValueSchema.optional(),
    'window-management': permissionsPolicyValueSchema.optional(),
    'xr-spatial-tracking': permissionsPolicyValueSchema.optional(),
    'interest-cohort': permissionsPolicyValueSchema.optional(),
}).strict();
/**
 * Zod schema for CSP reporting configuration
 */
export const cspReportingConfigSchema = z.object({
    reportUri: z.array(z.string().url()).optional(),
    reportTo: z.string().optional(),
    reportingEndpoints: z.record(z.string().url()).optional(),
});
/**
 * Zod schema for Security Headers Configuration
 */
export const securityHeadersConfigSchema = z.object({
    mode: z.enum(['production', 'development', 'testing']).default('production'),
    csp: z.object({
        enabled: z.boolean().default(true),
        directives: cspDirectivesSchema,
        reportOnly: z.boolean().default(false),
        reporting: cspReportingConfigSchema.optional(),
    }),
    hsts: z.object({
        enabled: z.boolean().default(true),
        config: hstsConfigSchema,
    }),
    cors: z.object({
        enabled: z.boolean().default(true),
        config: corsConfigSchema,
    }),
    permissionsPolicy: z.object({
        enabled: z.boolean().default(true),
        config: permissionsPolicyConfigSchema,
    }),
    coep: z.object({
        enabled: z.boolean().default(false),
        value: z.enum(['unsafe-none', 'require-corp', 'credentialless']).default('unsafe-none'),
    }),
    coop: z.object({
        enabled: z.boolean().default(false),
        value: z.enum(['unsafe-none', 'same-origin-allow-popups', 'same-origin']).default('unsafe-none'),
    }),
    corp: z.object({
        enabled: z.boolean().default(false),
        value: z.enum(['same-site', 'same-origin', 'cross-origin']).default('same-origin'),
    }),
    referrerPolicy: z.object({
        enabled: z.boolean().default(true),
        value: z.enum([
            'no-referrer',
            'no-referrer-when-downgrade',
            'origin',
            'origin-when-cross-origin',
            'same-origin',
            'strict-origin',
            'strict-origin-when-cross-origin',
            'unsafe-url',
        ]).default('strict-origin-when-cross-origin'),
    }),
    xFrameOptions: z.object({
        enabled: z.boolean().default(true),
        value: z.enum(['DENY', 'SAMEORIGIN']).default('DENY'),
    }),
    xContentTypeOptions: z.object({
        enabled: z.boolean().default(true),
    }),
    xXssProtection: z.object({
        enabled: z.boolean().default(true),
    }),
    xDnsPrefetchControl: z.object({
        enabled: z.boolean().default(true),
        value: z.enum(['on', 'off']).default('off'),
    }),
    xPermittedCrossDomainPolicies: z.object({
        enabled: z.boolean().default(true),
        value: z.enum(['none', 'master-only', 'by-content-type', 'all']).default('none'),
    }),
    excludePaths: z.array(z.string()).optional(),
});
/**
 * Zod schema for validation issue
 */
export const validationIssueSchema = z.object({
    severity: z.enum(['error', 'warning', 'info']),
    header: z.string(),
    message: z.string(),
    recommendation: z.string().optional(),
});
/**
 * Zod schema for validation result
 */
export const headerValidationResultSchema = z.object({
    valid: z.boolean(),
    score: z.number().min(0),
    maxScore: z.number().min(0),
    grade: z.enum(['A+', 'A', 'B', 'C', 'D', 'F']),
    issues: z.array(validationIssueSchema),
    summary: z.object({
        errors: z.number().int().min(0),
        warnings: z.number().int().min(0),
        info: z.number().int().min(0),
    }),
});
/**
 * Zod schema for CSP violation report
 */
export const cspViolationReportSchema = z.object({
    'csp-report': z.object({
        'document-uri': z.string(),
        'violated-directive': z.string(),
        'effective-directive': z.string(),
        'original-policy': z.string(),
        'blocked-uri': z.string(),
        'status-code': z.number().int(),
        'source-file': z.string().optional(),
        'line-number': z.number().int().optional(),
        'column-number': z.number().int().optional(),
        'script-sample': z.string().optional(),
        disposition: z.enum(['enforce', 'report']).optional(),
        referrer: z.string().optional(),
    }),
});
//# sourceMappingURL=types.js.map