/**
* Shared allowlist HTML sanitizer — pure string functions, Node-safe (no DOM).
*
* One implementation for every sink that turns translation data into HTML:
* core's HTMLSerializer/auto-translator, the editor text sinks, the snapshot
* viewer, react ``, and WordPress TS. The WordPress PHP port must
* mirror `SAFE_TAGS`/`SAFE_ATTRS` exactly (see improvement-plan §4 item 2).
*
* Threat model: translation values (and their `raw:` styles) come from the
* server/KV and may be attacker-controlled — they are NOT guaranteed to be in
* canonical form. Everything here is allowlist-based: unknown tags are
* rejected, unknown attributes dropped, URL schemes checked after entity
* decoding.
*
* @module content/sanitizer/HTMLSanitizer
*/
import type { ContentUnit } from '../types.js';
/**
* Inline formatting elements allowed inside translated content. Block
* structure lives outside ContentUnit (block-level pipeline), so anything
* that isn't inline text formatting is rejected outright.
*/
export declare const SAFE_TAGS: Set;
/**
* Flat attribute allowlist (plus `data-*`/`aria-*` prefixes, handled in
* `sanitizeOpeningTag`). Kept flat — not per-tag — so the PHP mirror stays
* trivial; an allowed attribute on the wrong tag is inert.
*/
export declare const SAFE_ATTRS: Set;
/**
* CSS properties allowed through an inline `style` attribute.
*
* RISK NOTE — why `style` never passes through verbatim: with zero
* JavaScript, an attacker who controls a style value can render a
* full-viewport overlay (`position:fixed;inset:0` → pixel-perfect fake
* login UI on the customer's real domain), fire tracking/exfiltration
* beacons via `url(...)`, or hide and deface content. Translation data is
* attacker-writable in our threat model, so `sanitizeStyle` re-parses the
* declarations and keeps only the properties below: cosmetic text/font
* properties whose value grammar cannot fetch a URL and cannot reposition
* or restack the element (no `position`/`inset`/`display`/`z-index`/
* `opacity`/`transform`, no `background` shorthand). A smuggled `url(...)`
* inside an allowed property is doubly inert: the value is rejected here,
* and these properties ignore URL values anyway.
*
* CONTINUOUS DEVELOPMENT: this allowlist is intentionally minimal and is
* expected to grow deliberately as real sites surface legitimate inline
* styling the strict set drops (tracked as a WATCH item in
* IMPLEMENTATION.md). When extending it: (1) never add a property that
* accepts `url()`/`image()`/`element()` values or that affects layout,
* positioning, or stacking; (2) add both hostile and benign cases to
* html-sanitizer.test.ts; (3) mirror the change in the WordPress PHP port.
*/
export declare const SAFE_STYLE_PROPS: Set;
/** HTML-escape text for safe use in element content or attribute values. */
export declare function escapeHtml(text: string): string;
/**
* Validate a URL attribute value. Returns the value unchanged when safe,
* or `null` when it must be dropped.
*
* Entity-decodes first, then strips the control/whitespace characters
* browsers ignore inside a scheme (`jav\tascript:`), then requires any
* explicit scheme to be on the allowlist. Scheme-less (relative) URLs pass.
*/
export declare function sanitizeUrl(value: string): string | null;
/**
* Sanitize an inline `style` attribute value by re-parsing its declarations
* and keeping only `SAFE_STYLE_PROPS` with clean values (see the risk note
* on `SAFE_STYLE_PROPS`). Returns the rebuilt declaration list in canonical
* `prop: value; prop: value` form, or `null` when nothing survives — the
* caller then drops the attribute entirely.
*/
export declare function sanitizeStyle(value: string): string | null;
/**
* Relaxed CSS profile for the snapshot viewer: keeps ANY standard property
* (a snapshot is a full captured page — `position:fixed` navbars and layout
* styles are legitimate and must render) but still rejects value-level
* dangers: `url(...)` beacons, `expression()`, CSS escape smuggling. The
* residual risk (page-authored overlay styles) is accepted for snapshots:
* the PM is deliberately viewing arbitrary captured pages, and the editor
* UI itself lives in a Shadow DOM host stacked above the snapshot root.
*/
export declare function sanitizeCssDeclarations(value: string): string | null;
/**
* Sanitize a raw opening tag (`raw:` style payload). Returns the canonical
* rebuilt tag with only allowlisted attributes, or `null` when the element
* itself is not allowed — callers must then drop the tag entirely (emit the
* indexed marker verbatim / skip the element).
*/
export declare function sanitizeOpeningTag(rawOpen: string): string | null;
/**
* Sanitize a ContentUnit at an ingest boundary: run every `raw:` style
* through {@link sanitizeOpeningTag} so no dangerous element/attribute/scheme
* enters the translation store. Render-time sinks (HTMLSerializer etc.)
* sanitize again — this is the store-side half, protecting every other
* consumer of stored units (server, MT/TM, exports, the WP PHP port).
*
* `text` is never modified, so `generateAutoKey(unit.text)` is unaffected —
* key parity across surfaces holds even for hostile input. A rejected
* element's `raw:` style is dropped entirely; the indexed tag left in the
* text is emitted by serializers as an inert marker. Returns the SAME object
* when nothing changed, so benign units round-trip identically.
*/
export declare function sanitizeContentUnit(unit: ContentUnit): ContentUnit;
//# sourceMappingURL=HTMLSanitizer.d.ts.map