fix: hyperlinks html entities (#9063)

pull/9070/head
David Luzar 4 weeks ago committed by GitHub
parent 52eaf64591
commit a3e1619635
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -25,7 +25,7 @@ describe("normalizeLink", () => {
expect(normalizeLink("file://")).toBe("file://"); expect(normalizeLink("file://")).toBe("file://");
expect(normalizeLink("[test](https://test)")).toBe("[test](https://test)"); expect(normalizeLink("[test](https://test)")).toBe("[test](https://test)");
expect(normalizeLink("[[test]]")).toBe("[[test]]"); expect(normalizeLink("[[test]]")).toBe("[[test]]");
expect(normalizeLink("<test>")).toBe("&lt;test&gt;"); expect(normalizeLink("<test>")).toBe("<test>");
expect(normalizeLink("test&")).toBe("test&amp;"); expect(normalizeLink("test&")).toBe("test&");
}); });
}); });

@ -1,12 +1,12 @@
import { sanitizeUrl } from "@braintree/sanitize-url"; import { sanitizeUrl } from "@braintree/sanitize-url";
import { sanitizeHTMLAttribute } from "../utils"; import { escapeDoubleQuotes } from "../utils";
export const normalizeLink = (link: string) => { export const normalizeLink = (link: string) => {
link = link.trim(); link = link.trim();
if (!link) { if (!link) {
return link; return link;
} }
return sanitizeUrl(sanitizeHTMLAttribute(link)); return sanitizeUrl(escapeDoubleQuotes(link));
}; };
export const isLocalLink = (link: string | null) => { export const isLocalLink = (link: string | null) => {

@ -1,11 +1,7 @@
import { register } from "../actions/register"; import { register } from "../actions/register";
import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants"; import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants";
import type { ExcalidrawProps } from "../types"; import type { ExcalidrawProps } from "../types";
import { import { escapeDoubleQuotes, getFontString, updateActiveTool } from "../utils";
getFontString,
sanitizeHTMLAttribute,
updateActiveTool,
} from "../utils";
import { setCursorForShape } from "../cursor"; import { setCursorForShape } from "../cursor";
import { newTextElement } from "./newElement"; import { newTextElement } from "./newElement";
import { wrapText } from "./textWrapping"; import { wrapText } from "./textWrapping";
@ -212,7 +208,7 @@ export const getEmbedLink = (
// Note that we don't attempt to parse the username as it can consist of // Note that we don't attempt to parse the username as it can consist of
// non-latin1 characters, and the username in the url can be set to anything // non-latin1 characters, and the username in the url can be set to anything
// without affecting the embed. // without affecting the embed.
const safeURL = sanitizeHTMLAttribute( const safeURL = escapeDoubleQuotes(
`https://twitter.com/x/status/${postId}`, `https://twitter.com/x/status/${postId}`,
); );
@ -231,7 +227,7 @@ export const getEmbedLink = (
if (RE_REDDIT.test(link)) { if (RE_REDDIT.test(link)) {
const [, page, postId, title] = link.match(RE_REDDIT)!; const [, page, postId, title] = link.match(RE_REDDIT)!;
const safeURL = sanitizeHTMLAttribute( const safeURL = escapeDoubleQuotes(
`https://reddit.com/r/${page}/comments/${postId}/${title}`, `https://reddit.com/r/${page}/comments/${postId}/${title}`,
); );
const ret: IframeDataWithSandbox = { const ret: IframeDataWithSandbox = {
@ -249,7 +245,7 @@ export const getEmbedLink = (
if (RE_GH_GIST.test(link)) { if (RE_GH_GIST.test(link)) {
const [, user, gistId] = link.match(RE_GH_GIST)!; const [, user, gistId] = link.match(RE_GH_GIST)!;
const safeURL = sanitizeHTMLAttribute( const safeURL = escapeDoubleQuotes(
`https://gist.github.com/${user}/${gistId}`, `https://gist.github.com/${user}/${gistId}`,
); );
const ret: IframeDataWithSandbox = { const ret: IframeDataWithSandbox = {

@ -1,4 +1,4 @@
import { isTransparent, sanitizeHTMLAttribute } from "../utils"; import { isTransparent } from "../utils";
describe("Test isTransparent", () => { describe("Test isTransparent", () => {
it("should return true when color is rgb transparent", () => { it("should return true when color is rgb transparent", () => {
@ -11,9 +11,3 @@ describe("Test isTransparent", () => {
expect(isTransparent("#ced4da")).toEqual(false); expect(isTransparent("#ced4da")).toEqual(false);
}); });
}); });
describe("sanitizeHTMLAttribute()", () => {
it("should escape HTML attribute special characters & not double escape", () => {
expect(sanitizeHTMLAttribute(`&"'><`)).toBe("&amp;&quot;&#39;&gt;&lt;");
});
});

@ -1226,15 +1226,10 @@ export class PromisePool<T> {
} }
} }
export const sanitizeHTMLAttribute = (html: string) => { /**
return ( * use when you need to render unsafe string as HTML attribute, but MAKE SURE
html * the attribute is double-quoted when constructing the HTML string
// note, if we're not doing stupid things, escaping " is enough, */
// but we might end up doing stupid things export const escapeDoubleQuotes = (str: string) => {
.replace(/&/g, "&amp;") return str.replace(/"/g, "&quot;");
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;")
.replace(/>/g, "&gt;")
.replace(/</g, "&lt;")
);
}; };

Loading…
Cancel
Save