UNPKG

@itwin/core-react

Version:

A react component library of iTwin.js UI general purpose components

80 lines 3.56 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Notification */ import * as React from "react"; import DOMPurify from "dompurify"; import { isHTMLElement, isReactMessage } from "./MessageType.js"; /** React component renders a string, HTMLElement or React node in a `div` or `span` * @public * @deprecated in 4.15.0. Used internally. */ // eslint-disable-next-line @typescript-eslint/no-deprecated export function MessageRenderer(props) { let messageNode = null; const OutElement = props.useSpan ? "span" : "div"; if (typeof props.message === "string") { messageNode = (React.createElement(OutElement, { className: props.className }, props.message)); } else if (isHTMLElement(props.message)) { let validAnchors = false; let hasAnchors = false; // verify that the tag has proper relationships const isAnchorValid = (anchor) => { return (anchor.hasAttribute("rel") && (anchor.rel.includes("noopener") || anchor.rel.includes("noreferrer"))); }; // recursively check child elements for valid anchor tags const checkChildAnchors = (parent) => { const children = Array.from(parent.children); for (const child of children) { if (child.hasAttribute("target") && child.target === "_blank") { hasAnchors = true; validAnchors = isAnchorValid(child); if (!validAnchors) { return; } } checkChildAnchors(child); } }; // check for anchor tags in the message that have target _blank also have a relationship that avoids security holes // https://web.dev/external-anchors-use-rel-noopener/ // first check the message element if (props.message.hasAttribute("target") && props.message.target === "_blank") { hasAnchors = true; validAnchors = isAnchorValid(props.message); } else { // if the message element is not an anchor, recursively verify it's children if (props.message.children) { checkChildAnchors(props.message); } } let sanitizedHtml; if (hasAnchors && validAnchors) { // all anchors are valid. do not remove the target attr sanitizedHtml = DOMPurify.sanitize(props.message.outerHTML, { ADD_ATTR: ["target"], }); } else { sanitizedHtml = DOMPurify.sanitize(props.message.outerHTML); } messageNode = (React.createElement(OutElement, { className: props.className, // we can safely disable jam3/no-sanitizer-with-danger as we are sanitizing above // eslint-disable-next-line jam3/no-sanitizer-with-danger dangerouslySetInnerHTML: { __html: sanitizedHtml } })); } else { if (isReactMessage(props.message)) messageNode = (React.createElement(OutElement, { className: props.className }, props.message.reactNode)); } return messageNode; } //# sourceMappingURL=MessageRenderer.js.map