Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Scope DOMPurify config to call sites
Rūdolfs Ošiņš committed 13 days ago
commit 9e268d9ac092b10e9a06b6e4e7e623a40a6aeb04
parent faadd2906bda9fd0e93b73ce23dce3094e6df31c
6 files changed +24 -13
modified src/components/Markdown.svelte
@@ -18,7 +18,7 @@
    canonicalize,
    isCommit,
  } from "@app/lib/utils";
-
  import { Renderer, markdown } from "@app/lib/markdown";
+
  import { Renderer, markdown, sanitizeConfig } from "@app/lib/markdown";

  export let content: string;
  export let path: string = "/";
@@ -97,7 +97,8 @@
        renderer: new Renderer($activeUnloadedRouteStore),
        breaks,
      }) as string,
-
    );
+
      sanitizeConfig,
+
    ) as string;
  }

  afterUpdate(async () => {
modified src/lib/commit.ts
@@ -142,10 +142,10 @@ export function renderCommitDescription(text: string): string {
  out += escape(trimmed.slice(cursor));
  return dompurify.sanitize(out, {
    /* eslint-disable @typescript-eslint/naming-convention */
-
    ADD_TAGS: ["radicle-external-link"],
-
    ADD_ATTR: ["href"],
+
    ALLOWED_TAGS: ["radicle-external-link"],
+
    ALLOWED_ATTR: ["href"],
    /* eslint-enable @typescript-eslint/naming-convention */
-
  });
+
  }) as string;
}

export async function loadRepoActivity(
modified src/lib/markdown.ts
@@ -1,7 +1,7 @@
+
import type { Config } from "dompurify";
import type { MarkedExtension, Tokens } from "marked";
import type { Route } from "@app/lib/router";

-
import dompurify from "dompurify";
import footnoteMarkedExtension from "marked-footnote";
import katexMarkedExtension from "marked-katex-extension";
import linkifyMarkedExtension from "marked-linkify-it";
@@ -12,7 +12,14 @@ import emojis from "@app/lib/emojis";
import { canonicalize, isUrl } from "@app/lib/utils";
import { routeToPath } from "@app/lib/router";

-
dompurify.setConfig({
+
/**
+
 * DOMPurify configuration for sanitizing markdown-derived HTML. Pass this as
+
 * the second argument to `dompurify.sanitize` at each call site instead of
+
 * setting it globally — a global config leaks into other consumers of the
+
 * DOMPurify singleton (e.g. mermaid's internal strict-mode sanitization),
+
 * which would strip the SVG output of valid diagrams.
+
 */
+
export const sanitizeConfig: Config = {
  /* eslint-disable @typescript-eslint/naming-convention */
  ALLOWED_ATTR: [
    "align",
@@ -67,7 +74,7 @@ dompurify.setConfig({
    "ul",
  ],
  /* eslint-enable @typescript-eslint/naming-convention */
-
});
+
};

export class Renderer extends BaseRenderer {
  #route: Route;
modified src/views/nodes/View.svelte
@@ -2,7 +2,7 @@
  import type { BaseUrl, Node, NodeStats } from "@http-client";

  import dompurify from "dompurify";
-
  import { markdown } from "@app/lib/markdown";
+
  import { markdown, sanitizeConfig } from "@app/lib/markdown";

  import Command from "@app/components/Command.svelte";
  import Icon from "@app/components/Icon.svelte";
@@ -25,7 +25,8 @@
  function render(content: string): string {
    return dompurify.sanitize(
      markdown({ linkify: true, emojis: true }).parse(content) as string,
-
    );
+
      sanitizeConfig,
+
    ) as string;
  }
</script>

modified src/views/repos/Source/RepoNameHeader.svelte
@@ -2,7 +2,7 @@
  import type { BaseUrl, Repo, SeedingPolicy } from "@http-client";

  import dompurify from "dompurify";
-
  import { markdown } from "@app/lib/markdown";
+
  import { markdown, sanitizeConfig } from "@app/lib/markdown";
  import { formatRepositoryId, twemoji } from "@app/lib/utils";

  import Badge from "@app/components/Badge.svelte";
@@ -19,7 +19,8 @@
  function render(content: string): string {
    return dompurify.sanitize(
      markdown({ linkify: true, emojis: true }).parseInline(content) as string,
-
    );
+
      sanitizeConfig,
+
    ) as string;
  }

  $: project = repo.payloads["xyz.radicle.project"];
modified src/views/repos/components/InlineTitle.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
  import dompurify from "dompurify";
  import escape from "lodash/escape";
+
  import { sanitizeConfig } from "@app/lib/markdown";
  import { formatInlineTitle } from "@app/lib/utils";

  export let content: string;
@@ -23,5 +24,5 @@
  class:txt-heading-l={fontSize === "heading-l"}
  class:txt-body-l-medium={fontSize === "body-l-medium"}
  class:txt-body-m-regular={fontSize === "body-m-regular"}>
-
  {@html dompurify.sanitize(formatInlineTitle(escape(content)))}
+
  {@html dompurify.sanitize(formatInlineTitle(escape(content)), sanitizeConfig)}
</span>