/**
 * Generic Webhook Alert Channel
 *
 * Sends security alerts to any webhook endpoint.
 * Supports custom headers, authentication, and payload transformation.
 *
 * @packageDocumentation
 * @module security/alerting/channels/webhook
 */
import { createLogger } from '../../../common/logger.js';
import { AlertChannel, } from '../types.js';
import { HttpAlertChannel } from './http-base.js';
import { createHmac } from 'crypto';
const logger = createLogger({ component: 'webhook-alert-channel' });
// =============================================================================
// Constants
// =============================================================================
const DEFAULT_TIMEOUT = 10000;
const DEFAULT_MAX_RETRIES = 3;
const PAYLOAD_VERSION = '1.0';
// =============================================================================
// WebhookAlertChannel Class
// =============================================================================
/**
 * Generic webhook integration for security alerts
 */
export class WebhookAlertChannel extends HttpAlertChannel {
    channelType = AlertChannel.WEBHOOK;
    channelName = 'Webhook';
    logger = logger;
    url;
    method;
    customHeaders;
    auth;
    transformPayload;
    contentType;
    includeTimestamp;
    timestampHeader;
    constructor(config) {
        super({
            timeout: config.timeout ?? DEFAULT_TIMEOUT,
            maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
        });
        if (!config.url) {
            throw new Error('Webhook URL is required');
        }
        this.url = config.url;
        this.method = config.method ?? 'POST';
        this.customHeaders = config.headers ?? {};
        this.auth = config.auth;
        this.transformPayload = config.transformPayload;
        this.contentType = config.contentType ?? 'application/json';
        this.includeTimestamp = config.includeTimestamp ?? true;
        this.timestampHeader = config.timestampHeader ?? 'X-Timestamp';
        logger.info({ url: this.maskUrl(config.url) }, 'WebhookAlertChannel initialized');
    }
    /**
     * Send an alert to the webhook
     */
    async sendInternal(alert) {
        const timestamp = new Date().toISOString();
        // Build payload
        let payload;
        if (this.transformPayload) {
            payload = this.transformPayload(alert);
        }
        else {
            payload = {
                alert,
                timestamp,
                version: PAYLOAD_VERSION,
            };
        }
        const body = JSON.stringify(payload);
        // Build headers
        const headers = {
            'Content-Type': this.contentType,
            ...this.customHeaders,
        };
        // Add timestamp header
        if (this.includeTimestamp) {
            headers[this.timestampHeader] = timestamp;
        }
        // Add authentication
        this.addAuthHeaders(headers, body);
        // Make request
        const response = await this.httpRequestOrThrow({
            url: this.url,
            method: this.method,
            headers,
            body: payload,
        });
        // Try to get message ID from response
        const messageId = response.data?.id || response.data?.messageId || `webhook-${Date.now()}`;
        return { messageId };
    }
    /**
     * Add authentication headers
     */
    addAuthHeaders(headers, body) {
        if (!this.auth)
            return;
        const { type, credentials, username, headerName, secret, algorithm, signatureHeader } = this.auth;
        switch (type) {
            case 'basic':
                if (username && credentials) {
                    const encoded = Buffer.from(`${username}:${credentials}`).toString('base64');
                    headers['Authorization'] = `Basic ${encoded}`;
                }
                break;
            case 'bearer':
                if (credentials) {
                    headers['Authorization'] = `Bearer ${credentials}`;
                }
                break;
            case 'api-key':
                if (credentials) {
                    headers[headerName ?? 'X-API-Key'] = credentials;
                }
                break;
            case 'hmac':
                if (secret) {
                    const hmac = createHmac(algorithm ?? 'sha256', secret);
                    hmac.update(body);
                    const signature = hmac.digest('hex');
                    headers[signatureHeader ?? 'X-Signature'] = signature;
                }
                break;
        }
    }
    /**
     * Test the webhook connection
     */
    async test() {
        try {
            const testAlert = {
                id: 'test-' + Date.now(),
                severity: 'info',
                type: 'custom',
                title: 'Webhook Connection Test',
                message: 'This is a test message from the security alerting system.',
                context: {},
                timestamp: new Date(),
                fingerprint: `test-${Date.now()}`,
                source: 'webhook-test',
                acknowledged: false,
                resolved: false,
            };
            const result = await this.send(testAlert);
            if (result.success) {
                logger.info('Webhook connection test successful');
                return true;
            }
            return false;
        }
        catch (error) {
            logger.error({ error }, 'Webhook connection test failed');
            return false;
        }
    }
    /**
     * Get the webhook URL (masked for debugging)
     */
    getUrl() {
        return this.maskUrl(this.url);
    }
    /**
     * Mask sensitive parts of URL
     */
    maskUrl(urlString) {
        try {
            const url = new URL(urlString);
            if (url.password) {
                url.password = '***';
            }
            return url.toString();
        }
        catch {
            return '[invalid url]';
        }
    }
}
/**
 * Create a new webhook alert channel
 */
export function createWebhookChannel(config) {
    return new WebhookAlertChannel(config);
}
/**
 * Create a webhook channel with HMAC signing
 */
export function createSignedWebhookChannel(url, secret, options) {
    return new WebhookAlertChannel({
        url,
        auth: {
            type: 'hmac',
            secret,
            algorithm: 'sha256',
        },
        ...options,
    });
}
//# sourceMappingURL=webhook.js.map