Add DOMPurify

This commit is contained in:
Alex Gleason
2024-01-17 12:21:19 -06:00
parent e281fbade9
commit 4aa6fdb4dd
7 changed files with 34 additions and 10 deletions

View File

@@ -1,3 +1,4 @@
import * as DOMPurify from 'dompurify';
import React from 'react';
import Markup from 'soapbox/components/markup';
@@ -9,7 +10,7 @@ import { LogoText } from './logo-text';
const SiteBanner: React.FC = () => {
const instance = useInstance();
const description = instance.description;
const description = DOMPurify.sanitize(instance.description);
return (
<Stack space={3}>

View File

@@ -1,6 +1,7 @@
/**
* Status edit normalizer
*/
*/
import * as DOMPurify from 'dompurify';
import escapeTextContentForBrowser from 'escape-html';
import {
Map as ImmutableMap,
@@ -60,8 +61,8 @@ const normalizeStatusPoll = (statusEdit: ImmutableMap<string, any>) => {
const normalizeContent = (statusEdit: ImmutableMap<string, any>) => {
const emojiMap = makeEmojiMap(statusEdit.get('emojis'));
const contentHtml = stripCompatibilityFeatures(emojify(statusEdit.get('content'), emojiMap));
const spoilerHtml = emojify(escapeTextContentForBrowser(statusEdit.get('spoiler_text')), emojiMap);
const contentHtml = DOMPurify.sanitize(stripCompatibilityFeatures(emojify(statusEdit.get('content'), emojiMap)), { ADD_ATTR: ['target'] });
const spoilerHtml = DOMPurify.sanitize(emojify(escapeTextContentForBrowser(statusEdit.get('spoiler_text')), emojiMap), { ADD_ATTR: ['target'] });
return statusEdit
.set('contentHtml', contentHtml)

View File

@@ -1,3 +1,4 @@
import * as DOMPurify from 'dompurify';
import escapeTextContentForBrowser from 'escape-html';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
@@ -117,8 +118,8 @@ export const calculateStatus = (
return status.merge({
search_index: domParser.parseFromString(searchContent, 'text/html').documentElement.textContent || '',
contentHtml: stripCompatibilityFeatures(emojify(status.content, emojiMap)),
spoilerHtml: emojify(escapeTextContentForBrowser(spoilerText), emojiMap),
contentHtml: DOMPurify.sanitize(stripCompatibilityFeatures(emojify(status.content, emojiMap)), { USE_PROFILES: { html: true } }),
spoilerHtml: DOMPurify.sanitize(emojify(escapeTextContentForBrowser(spoilerText), emojiMap), { USE_PROFILES: { html: true } }),
hidden: expandSpoilers ? false : spoilerText.length > 0 || status.sensitive,
});
}

View File

@@ -1,3 +1,4 @@
import * as DOMPurify from 'dompurify';
import escapeTextContentForBrowser from 'escape-html';
import z from 'zod';
@@ -112,7 +113,7 @@ const transformAccount = <T extends TransformableAccount>({ pleroma, other_setti
const newFields = fields.map((field) => ({
...field,
name_emojified: emojify(escapeTextContentForBrowser(field.name), customEmojiMap),
name_emojified: DOMPurify.sanitize(emojify(escapeTextContentForBrowser(field.name), customEmojiMap), { USE_PROFILES: { html: true } }),
value_emojified: emojify(field.value, customEmojiMap),
value_plain: unescapeHTML(field.value),
}));
@@ -130,7 +131,7 @@ const transformAccount = <T extends TransformableAccount>({ pleroma, other_setti
avatar_static: account.avatar_static || account.avatar,
discoverable: account.discoverable || account.source?.pleroma?.discoverable || false,
display_name: displayName,
display_name_html: emojify(escapeTextContentForBrowser(displayName), customEmojiMap),
display_name_html: DOMPurify.sanitize(emojify(escapeTextContentForBrowser(displayName), customEmojiMap), { USE_PROFILES: { html: true } }),
domain,
fields: newFields,
fqn: account.fqn || (account.acct.includes('@') ? account.acct : `${account.acct}@${domain}`),
@@ -138,7 +139,7 @@ const transformAccount = <T extends TransformableAccount>({ pleroma, other_setti
moderator: pleroma?.is_moderator || false,
local: pleroma?.is_local !== undefined ? pleroma.is_local : account.acct.split('@')[1] === undefined,
location: account.location || pleroma?.location || other_settings?.location || '',
note_emojified: emojify(account.note, customEmojiMap),
note_emojified: DOMPurify.sanitize(emojify(account.note, customEmojiMap), { USE_PROFILES: { html: true } }),
pleroma: (() => {
if (!pleroma) return undefined;
const { relationship, ...rest } = pleroma;

View File

@@ -1,3 +1,4 @@
import * as DOMPurify from 'dompurify';
import escapeTextContentForBrowser from 'escape-html';
import { z } from 'zod';
@@ -30,7 +31,7 @@ const pollSchema = z.object({
const emojifiedOptions = poll.options.map((option) => ({
...option,
title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
title_emojified: DOMPurify.sanitize(emojify(escapeTextContentForBrowser(option.title), emojiMap), { ALLOWED_TAGS: [] }),
}));
// If the user has votes, they have certainly voted.