/**
 * @fileoverview Provides a comprehensive `Sanitization` class for various input cleaning and
 * validation tasks. Includes utilities for sanitizing HTML, strings, URLs, file paths, JSON,
 * and numbers, as well as redacting sensitive fields from data intended for logging.
 *
 * Several methods (`sanitizeHtml`, `sanitizeString`, `sanitizeUrl`, `sanitizeNumber`) are
 * **async** because they lazy-load optional peer dependencies (`sanitize-html`, `validator`)
 * on first use. If a required peer dependency is not installed, these methods throw a
 * `McpError` with `JsonRpcErrorCode.ConfigurationError`.
 *
 * Path sanitization (`sanitizePath`) is synchronous but only available in Node.js environments.
 *
 * @module src/utils/security/sanitization
 */
import type sanitizeHtml from 'sanitize-html';
/**
 * Options controlling how `sanitizePath` processes and validates file paths.
 */
export interface PathSanitizeOptions {
    /** If `true`, absolute paths are permitted (subject to `rootDir` containment). Default: `false`. */
    allowAbsolute?: boolean;
    /**
     * If provided, all paths are resolved relative to this directory and checked for containment.
     * Any path that escapes the root via traversal (`../`) throws a `McpError`.
     * The value is resolved with `path.resolve` before use.
     */
    rootDir?: string;
    /** If `true`, normalizes Windows-style backslashes (`\`) to POSIX forward slashes (`/`). */
    toPosix?: boolean;
}
/**
 * Result returned by `sanitizePath`, describing the outcome of path sanitization.
 */
export interface SanitizedPathInfo {
    /**
     * `true` if the input was absolute but was converted to a relative path because
     * `allowAbsolute` was `false` and a `rootDir` was provided.
     */
    convertedToRelative: boolean;
    /** The effective options used for sanitization, with defaults applied. */
    optionsUsed: PathSanitizeOptions;
    /** The original path string as passed to `sanitizePath`, before any processing. */
    originalInput: string;
    /** The final sanitized and normalized path string. */
    sanitizedPath: string;
    /** `true` if the input path was absolute after initial `path.normalize`. */
    wasAbsolute: boolean;
}
/**
 * Options for context-specific string sanitization passed to `sanitizeString`.
 */
export interface SanitizeStringOptions {
    /**
     * Custom allowed HTML attributes, keyed by tag name (e.g., `{ a: ['href'] }`).
     * Only used when `context` is `'html'`.
     */
    allowedAttributes?: Record<string, string[]>;
    /**
     * Custom list of allowed HTML tag names.
     * Only used when `context` is `'html'`.
     */
    allowedTags?: string[];
    /**
     * The context in which the sanitized string will be used. Determines how sanitization
     * is performed. `'javascript'` is explicitly disallowed and will throw.
     * Defaults to `'text'`.
     */
    context?: 'text' | 'html' | 'attribute' | 'url' | 'javascript';
}
/**
 * Configuration options for HTML sanitization, mirroring the `sanitize-html` library's options.
 * Passed to `sanitizeHtml` to override the default allowlist.
 */
export interface HtmlSanitizeConfig {
    /**
     * Allowed HTML attributes, keyed by tag name or `'*'` for a global allowlist.
     * Mirrors `sanitize-html`'s `IOptions['allowedAttributes']`.
     */
    allowedAttributes?: sanitizeHtml.IOptions['allowedAttributes'];
    /**
     * Allowed HTML tag names. Any tag not in this list is stripped from the output.
     * Mirrors `sanitize-html`'s `allowedTags`.
     */
    allowedTags?: string[];
    /**
     * If `true`, HTML comments (`<!-- ... -->`) are preserved in the output.
     * Internally this is implemented by adding `'!--'` to the `allowedTags` list.
     */
    preserveComments?: boolean;
    /**
     * Custom tag-transform functions applied during sanitization.
     * If omitted, `<a>` tags are automatically given `rel="noopener noreferrer"`.
     * Mirrors `sanitize-html`'s `IOptions['transformTags']`.
     */
    transformTags?: sanitizeHtml.IOptions['transformTags'];
}
/**
 * Singleton class providing input sanitization across multiple categories:
 * HTML (XSS prevention), URLs, file paths (traversal prevention), JSON, numbers,
 * and log-safe redaction of sensitive fields.
 *
 * Obtain the singleton via `Sanitization.getInstance()` or use the pre-exported
 * `sanitization` constant.
 *
 * @example
 * ```ts
 * import { sanitization } from '../../utils/security/sanitization.js';
 *
 * const clean = await sanitization.sanitizeHtml('<script>alert(1)</script><b>hi</b>');
 * // => '<b>hi</b>'
 * ```
 */
export declare class Sanitization {
    /** @private */
    private static instance;
    private sensitiveFields;
    /**
     * Default configuration for HTML sanitization.
     * @private
     */
    private defaultHtmlSanitizeConfig;
    /** @private */
    private constructor();
    private normalizedSensitiveSet;
    private wordSensitiveSet;
    /**
     * Returns the singleton instance of `Sanitization`, creating it on first call.
     *
     * @returns The singleton `Sanitization` instance.
     * @example
     * ```ts
     * const san = Sanitization.getInstance();
     * const safe = await san.sanitizeHtml(userInput);
     * ```
     */
    static getInstance(): Sanitization;
    /**
     * Extends the list of sensitive field names used by `sanitizeForLogging`.
     * New names are merged with the existing list (deduplication applied, case-insensitive).
     * Changes take effect immediately on subsequent `sanitizeForLogging` calls.
     *
     * @param fields - Field names to add to the sensitive list (e.g., `['myApiKey', 'session_id']`).
     * @returns `void`
     * @example
     * ```ts
     * sanitization.setSensitiveFields(['myApiKey', 'session_id']);
     * sanitization.sanitizeForLogging({ myApiKey: 'abc123' });
     * // => { myApiKey: '[REDACTED]' }
     * ```
     */
    setSensitiveFields(fields: string[]): void;
    /**
     * Returns a copy of the current sensitive field names list.
     * All names are lowercased. Mutating the returned array has no effect on internal state.
     *
     * @returns Array of lowercase sensitive field name strings.
     * @example
     * ```ts
     * const fields = sanitization.getSensitiveFields();
     * // => ['password', 'token', 'secret', ...]
     * ```
     */
    getSensitiveFields(): string[];
    /**
     * Returns pino-compatible redact path patterns covering sensitive field names at three
     * nesting depths: top-level, one level deep, and two levels deep.
     *
     * For example, the field `'token'` generates:
     * - `'token'` — matches `{ token: '...' }`
     * - `'*.token'` — matches `{ auth: { token: '...' } }`
     * - `'*.*.token'` — matches `{ context: { auth: { token: '...' } } }`
     *
     * Pass the result directly to pino's `redact.paths` option.
     *
     * @returns Array of fast-redact-compatible path strings for use in pino's `redact.paths`.
     * @example
     * ```ts
     * import pino from 'pino';
     * const log = pino({ redact: { paths: sanitization.getSensitivePinoFields(), censor: '[REDACTED]' } });
     * ```
     */
    getSensitivePinoFields(): string[];
    /**
     * Sanitizes an HTML string using `sanitize-html`, stripping disallowed tags and attributes.
     *
     * This method is **async** because it lazy-loads the `sanitize-html` peer dependency on
     * first call. By default, `<a>` tags receive `rel="noopener noreferrer"` automatically.
     * The `style` attribute is intentionally excluded from the default allowlist to prevent
     * CSS injection attacks.
     *
     * @param input - The HTML string to sanitize. Returns `''` immediately if falsy.
     * @param config - Optional config overriding the default tag/attribute allowlists.
     *   If omitted, the built-in defaults are used (see `defaultHtmlSanitizeConfig`).
     * @returns Promise resolving to the sanitized HTML string.
     * @throws {McpError} With `ConfigurationError` if `sanitize-html` is not installed.
     * @example
     * ```ts
     * const safe = await sanitization.sanitizeHtml('<script>alert(1)</script><b>Hello</b>');
     * // => '<b>Hello</b>'
     *
     * const custom = await sanitization.sanitizeHtml('<div class="x"><b>ok</b></div>', {
     *   allowedTags: ['b'],
     * });
     * // => '<b>ok</b>'
     * ```
     */
    sanitizeHtml(input: string, config?: HtmlSanitizeConfig): Promise<string>;
    /**
     * Sanitizes a string according to its intended usage context.
     *
     * This method is **async** because it lazy-loads `sanitize-html` and/or `validator`
     * depending on the requested context.
     *
     * | `context`      | Behavior |
     * |----------------|----------|
     * | `'text'`       | Strips all HTML tags and attributes (default). |
     * | `'html'`       | Runs full HTML sanitization via `sanitizeHtml` (respects `allowedTags`/`allowedAttributes`). |
     * | `'attribute'`  | Strips all tags and attributes — safe for use inside an HTML attribute value. |
     * | `'url'`        | Validates the URL with `validator.isURL` (http/https only); returns `''` if invalid. |
     * | `'javascript'` | **Disallowed.** Always throws `McpError`. |
     *
     * @param input - The string to sanitize. Returns `''` immediately if falsy.
     * @param options - Context and optional allowlist overrides.
     * @returns Promise resolving to the sanitized string, or `''` for invalid URLs.
     * @throws {McpError} With `ValidationError` if `context` is `'javascript'`.
     * @throws {McpError} With `ConfigurationError` if a required peer dep is not installed.
     * @example
     * ```ts
     * await sanitization.sanitizeString('<b>hello</b>', { context: 'text' });
     * // => 'hello'
     *
     * await sanitization.sanitizeString('https://example.com', { context: 'url' });
     * // => 'https://example.com'
     *
     * await sanitization.sanitizeString('javascript:alert(1)', { context: 'url' });
     * // => '' (logged as warning, not thrown)
     * ```
     */
    sanitizeString(input: string, options?: SanitizeStringOptions): Promise<string>;
    /**
     * Converts attribute format for `sanitizeHtml`.
     * @param attrs - Attributes in `{ tagName: ['attr1'] }` format.
     * @returns Attributes in `sanitize-html` expected format.
     * @private
     */
    private convertAttributesFormat;
    /**
     * Validates and sanitizes a URL string.
     *
     * This method is **async** because it lazy-loads the `validator` peer dependency on first call.
     *
     * Validation requires a protocol and host. Even if a protocol appears in `allowedProtocols`,
     * the pseudo-protocols `javascript:`, `data:`, and `vbscript:` are always rejected.
     *
     * @param input - The URL string to sanitize. Leading/trailing whitespace is trimmed.
     * @param allowedProtocols - URL schemes that are permitted. Defaults to `['http', 'https']`.
     * @returns Promise resolving to the trimmed, validated URL string.
     * @throws {McpError} With `ValidationError` if the URL is invalid, uses a disallowed protocol,
     *   or uses a blocked pseudo-protocol (`javascript:`, `data:`, `vbscript:`).
     * @throws {McpError} With `ConfigurationError` if `validator` is not installed.
     * @example
     * ```ts
     * await sanitization.sanitizeUrl('https://example.com/path');
     * // => 'https://example.com/path'
     *
     * await sanitization.sanitizeUrl('ftp://files.example.com', ['ftp', 'sftp']);
     * // => 'ftp://files.example.com'
     *
     * await sanitization.sanitizeUrl('javascript:alert(1)');
     * // throws McpError (ValidationError)
     * ```
     */
    sanitizeUrl(input: string, allowedProtocols?: string[]): Promise<string>;
    /**
     * Sanitizes a file path, preventing path traversal attacks and normalizing format.
     *
     * This method is **synchronous** and only available in Node.js (uses `node:path`).
     * Calling it in a non-Node.js environment (e.g., Cloudflare Workers) throws immediately.
     *
     * Traversal detection:
     * - With `rootDir`: resolves the full path and asserts it starts within the root.
     * - Without `rootDir`: resolves the relative path against CWD and asserts containment.
     * - Null bytes (`\0`) in paths are always rejected.
     *
     * @param input - The file path string to sanitize.
     * @param options - Options controlling absolute path permission, root directory, and POSIX normalization.
     * @returns A `SanitizedPathInfo` object with the sanitized path and operation metadata.
     * @throws {McpError} With `InternalError` if called outside a Node.js environment.
     * @throws {McpError} With `ValidationError` if the path is empty, contains a null byte,
     *   attempts traversal beyond `rootDir` or CWD, or is absolute when `allowAbsolute` is `false`.
     * @example
     * ```ts
     * const result = sanitization.sanitizePath('../../etc/passwd', { rootDir: '/app/data' });
     * // throws McpError (path traversal detected)
     *
     * const result = sanitization.sanitizePath('uploads/file.txt', { rootDir: '/app/data' });
     * // => { sanitizedPath: 'uploads/file.txt', wasAbsolute: false, convertedToRelative: false, ... }
     *
     * const result = sanitization.sanitizePath('C:\\Users\\foo\\bar', { toPosix: true, allowAbsolute: true });
     * // => { sanitizedPath: 'C:/Users/foo/bar', wasAbsolute: true, ... }
     * ```
     */
    sanitizePath(input: string, options?: PathSanitizeOptions): SanitizedPathInfo;
    /**
     * Validates and parses a JSON string, with an optional maximum byte-size guard.
     *
     * This method is **synchronous**. Byte length is computed via `Buffer.byteLength` in
     * Node.js, `TextEncoder` in environments that support it, or falls back to `string.length`.
     *
     * @template T - Expected type of the parsed value. Defaults to `unknown`.
     * @param input - The JSON string to validate and parse. Must be a `string`.
     * @param maxSize - Optional maximum allowed UTF-8 byte length. Throws if exceeded.
     * @returns The parsed JavaScript value cast to `T`.
     * @throws {McpError} With `ValidationError` if:
     *   - `input` is not a string
     *   - `input` exceeds `maxSize` bytes
     *   - `input` is not valid JSON
     * @example
     * ```ts
     * const obj = sanitization.sanitizeJson<{ id: number }>('{"id":1}');
     * // => { id: 1 }
     *
     * sanitization.sanitizeJson('{"big":"value"}', 5);
     * // throws McpError (exceeds maxSize)
     *
     * sanitization.sanitizeJson('{bad json}');
     * // throws McpError (invalid JSON)
     * ```
     */
    sanitizeJson<T = unknown>(input: string, maxSize?: number): T;
    /**
     * Validates a numeric input and optionally clamps it to a range.
     *
     * This method is **async** because string inputs are validated using the `validator` peer
     * dependency, which is lazy-loaded on first call. Numeric inputs bypass the lazy load.
     *
     * - String inputs: trimmed and checked with `validator.isNumeric`, then parsed with `parseFloat`.
     * - Number inputs: used directly.
     * - `NaN` and `Infinity` are always rejected.
     * - If `min` or `max` are provided, the value is silently clamped (a debug log is emitted).
     *
     * @param input - The number or numeric string to validate.
     * @param min - Inclusive lower bound. If the value is below this, it is clamped to `min`.
     * @param max - Inclusive upper bound. If the value is above this, it is clamped to `max`.
     * @returns Promise resolving to the validated (and potentially clamped) number.
     * @throws {McpError} With `ValidationError` if the input is not numeric, is `NaN`, or is `Infinity`.
     * @throws {McpError} With `ConfigurationError` if `validator` is not installed (string input only).
     * @example
     * ```ts
     * await sanitization.sanitizeNumber('42.5');
     * // => 42.5
     *
     * await sanitization.sanitizeNumber(150, 0, 100);
     * // => 100  (clamped to max)
     *
     * await sanitization.sanitizeNumber('abc');
     * // throws McpError (ValidationError)
     * ```
     */
    sanitizeNumber(input: number | string, min?: number, max?: number): Promise<number>;
    /**
     * Produces a log-safe deep clone of `input` with sensitive field values replaced by `'[REDACTED]'`.
     *
     * This method is **synchronous**. It uses `structuredClone` for deep cloning. Sensitive field
     * detection combines two strategies:
     * - **Exact match**: the normalized key (lowercased, non-alphanumeric stripped) matches a
     *   sensitive field name.
     * - **Word match**: splitting the key by camelCase/snake_case/kebab-case tokens and checking
     *   each token against the sensitive word set.
     *
     * Non-object/non-array inputs (primitives, `null`) are returned as-is without cloning.
     * If `structuredClone` itself throws (e.g., circular reference, uncloneable type), the method
     * returns the string `'[Log Sanitization Failed]'` and emits an error log rather than throwing.
     *
     * @param input - The value to sanitize. Non-objects are returned unchanged.
     * @returns A sanitized deep clone of `input` (with sensitive values redacted),
     *   the original primitive if not an object, or `'[Log Sanitization Failed]'` on clone error.
     * @example
     * ```ts
     * sanitization.sanitizeForLogging({ user: 'alice', password: 'secret', nested: { token: 'abc' } });
     * // => { user: 'alice', password: '[REDACTED]', nested: { token: '[REDACTED]' } }
     *
     * sanitization.sanitizeForLogging('just a string');
     * // => 'just a string'  (returned as-is)
     * ```
     */
    sanitizeForLogging(input: unknown): unknown;
    /**
     * Recursively redacts sensitive fields in an object or array in place.
     * @param obj - The object or array to redact.
     * @private
     */
    private redactSensitiveFields;
    /**
     * Normalizes a field name for sensitive-key lookup by lowercasing and stripping
     * all non-alphanumeric characters. Used for exact-match detection in `redactSensitiveFields`.
     * @param str - The raw field name string.
     * @returns Lowercased alphanumeric-only version of `str`.
     * @private
     */
    private static normalizeName;
    private rebuildSensitiveSets;
}
/**
 * Pre-constructed singleton instance of `Sanitization`.
 * Use this for all input sanitization tasks rather than calling `Sanitization.getInstance()` directly.
 *
 * @example
 * ```ts
 * import { sanitization } from '../../utils/security/sanitization.js';
 * const safe = await sanitization.sanitizeHtml(userHtml);
 * ```
 */
export declare const sanitization: Sanitization;
/**
 * Convenience wrapper around `sanitization.sanitizeForLogging`.
 * Produces a log-safe deep clone of `input` with sensitive field values replaced by `'[REDACTED]'`.
 *
 * @param input - The value to sanitize. Non-objects are returned unchanged.
 * @returns A sanitized deep clone of `input`, the original primitive if not an object,
 *   or `'[Log Sanitization Failed]'` on clone error.
 * @example
 * ```ts
 * import { sanitizeInputForLogging } from '../../utils/security/sanitization.js';
 * logger.info('Request', sanitizeInputForLogging({ user: 'alice', token: 'secret' }));
 * // logs: { user: 'alice', token: '[REDACTED]' }
 * ```
 */
export declare const sanitizeInputForLogging: (input: unknown) => unknown;
//# sourceMappingURL=sanitization.d.ts.map