UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

125 lines (124 loc) • 5.08 kB
/** * Content sniffing for text-shaped image formats. * * SVG is markup, so it has no byte signature — but it does have an unambiguous * root element, and identifying it matters twice over: the detector routes SVG * to the sanitizer rather than to a vision API, and the image path must not let * SVG bytes travel under some other format's MIME type. * * ## Why this is a scan and not a regular expression * * The obvious implementation strips the prolog with a pattern like * `(?:<!--[\s\S]*?-->\s*)*<svg`. That is two nested quantifiers, and CodeQL * rightly flags it as `js/redos`: input beginning `<!--` and repeating * `--><!--` drives exponential backtracking, so a hostile (or merely odd) * upload can burn CPU inside what is supposed to be a cheap type check. * * The `.replace()`-chain alternative is unsound for a different reason — * removing a multi-character construct can join the surrounding text into a * fresh instance of that same construct, so one pass does not converge * (`<!--<!-- -->-->` leaves a comment behind). CodeQL flags that shape too, as * `js/incomplete-multi-character-sanitization`. * * A single forward scan has neither problem: the cursor only ever advances, so * the work is linear in the input and no construct can re-form behind it. * * @module utils/markupSniff */ /** Bytes inspected when sniffing for a markup root element. */ const MARKUP_SNIFF_LIMIT = 1024; /** * Whether the leading bytes are an SVG document. * * Requires `<svg` to be the *root element* rather than merely present, so an * HTML page embedding an inline `<svg>` icon is not mistaken for a standalone * image. A BOM, XML declaration, DOCTYPE and comments may precede it. * * @param input - Buffer or string to inspect; only the head is read. */ export function looksLikeSvgMarkup(input) { const head = typeof input === "string" ? input.slice(0, MARKUP_SNIFF_LIMIT) : input.toString("utf8", 0, Math.min(input.length, MARKUP_SNIFF_LIMIT)); if (!head.includes("<svg")) { return false; } let cursor = head.charCodeAt(0) === 0xfeff ? 1 : 0; while (cursor < head.length) { while (cursor < head.length && /\s/.test(head[cursor])) { cursor++; } if (head[cursor] !== "<") { // Text before any element — not a well-formed XML document. return false; } // Each prolog construct ends at a known delimiter; an unterminated one // means the document is truncated or malformed, so stop rather than guess. let end; if (head.startsWith("<?", cursor)) { end = head.indexOf("?>", cursor + 2); cursor = end === -1 ? head.length : end + 2; } else if (head.startsWith("<!--", cursor)) { end = head.indexOf("-->", cursor + 4); cursor = end === -1 ? head.length : end + 3; } else if (head.startsWith("<!", cursor)) { // DOCTYPE. Stopping at the first '>' is wrong for two legal forms: a // quoted public/system identifier may contain '>', and an internal // subset (`<!DOCTYPE svg [ <!ENTITY x "y"> ]>`) certainly does. Either // one left the cursor mid-declaration and made a valid SVG classify as // not-SVG. Track quotes and subset depth to find the real terminator. cursor = skipDoctype(head, cursor); } else { // First real element decides. return /^<svg[\s>/]/i.test(head.slice(cursor)); } } return false; } /** * Return the index just past a DOCTYPE declaration beginning at `start`. * * Handles quoted identifiers and a bracketed internal subset. Returns * `head.length` when the declaration is unterminated within the sniffed * window, which stops the caller rather than letting it guess. */ function skipDoctype(head, start) { let quote = null; let subsetDepth = 0; for (let i = start + 2; i < head.length; i++) { const ch = head[i]; if (quote) { if (ch === quote) { quote = null; } continue; } // A comment inside the internal subset may itself contain ']' and '>'. // Treating those as structural closed the subset early and terminated the // DOCTYPE on the comment's own '-->', so valid SVG classified as not-SVG. if (head.startsWith("<!--", i)) { const commentEnd = head.indexOf("-->", i + 4); if (commentEnd === -1) { return head.length; } i = commentEnd + 2; // loop increment steps past the final '>' continue; } if (ch === '"' || ch === "'") { quote = ch; } else if (ch === "[") { subsetDepth++; } else if (ch === "]") { subsetDepth = Math.max(0, subsetDepth - 1); } else if (ch === ">" && subsetDepth === 0) { return i + 1; } } return head.length; }