diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index f704657c32..ec8662eaf5 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -22,7 +22,7 @@ import { getEmojiFromUnicode } from "@matrix-org/emojibase-bindings";
import SettingsStore from "./settings/SettingsStore";
import { stripHTMLReply, stripPlainReply } from "./utils/Reply";
import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
-import { sanitizeHtmlParams, transformTags } from "./Linkify";
+import { filterImg, sanitizeHtmlParams, transformTags } from "./Linkify";
import { graphemeSegmenter } from "./utils/strings";
export { Linkify, linkifyAndSanitizeHtml } from "./Linkify";
@@ -294,6 +294,7 @@ export interface EventRenderOpts {
disableBigEmoji?: boolean;
stripReplyFallback?: boolean;
forComposerQuote?: boolean;
+ mediaIsVisible?: boolean;
}
function analyseEvent(content: IContent, highlights: Optional, opts: EventRenderOpts = {}): EventAnalysis {
@@ -301,6 +302,9 @@ function analyseEvent(content: IContent, highlights: Optional, opts: E
if (opts.forComposerQuote) {
sanitizeParams = composerSanitizeHtmlParams;
}
+ if (!opts.mediaIsVisible) {
+ sanitizeParams.exclusiveFilter = filterImg;
+ }
try {
const isFormattedBody =
diff --git a/src/Linkify.tsx b/src/Linkify.tsx
index 1a695f315e..b67d0294fe 100644
--- a/src/Linkify.tsx
+++ b/src/Linkify.tsx
@@ -7,16 +7,14 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type ReactElement } from "react";
-import sanitizeHtml, { type IOptions } from "sanitize-html";
+import sanitizeHtml, { IFrame, type IOptions } from "sanitize-html";
import { merge } from "lodash";
import _Linkify from "linkify-react";
import { _linkifyString, ELEMENT_URL_PATTERN, options as linkifyMatrixOptions } from "./linkify-matrix";
-import SettingsStore from "./settings/SettingsStore";
import { tryTransformPermalinkToLocalHref } from "./utils/permalinks/Permalinks";
import { mediaFromMxc } from "./customisations/Media";
import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
-import { MediaPreviewValue } from "./@types/media_preview";
const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)\/(.+?)(?:[?/]|$)/;
@@ -48,11 +46,9 @@ export const transformTags: NonNullable = {
// Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag
// because transformTags is used _before_ we filter by allowedSchemesByTag and
// we don't want to allow images with `https?` `src`s.
- // We also drop inline images (as if they were not present at all) when the "show
- // images" preference is disabled. Future work might expose some UI to reveal them
- // like standalone image events have.
- // TODO: Is this a private room?
- if (!src || SettingsStore.getValue("mediaPreviewConfig").media_previews !== MediaPreviewValue.On) {
+ // Filtering out images now happens as a exlusive filter so we can conditionally apply this
+ // based on settings.
+ if (!src) {
return { tagName, attribs: {} };
}
@@ -200,6 +196,7 @@ export const sanitizeHtmlParams: IOptions = {
nestingLimit: 50,
};
+
/* Wrapper around linkify-react merging in our default linkify options */
export function Linkify({ as, options, children }: React.ComponentProps): ReactElement {
return (
@@ -230,3 +227,7 @@ export function linkifyString(str: string, options = linkifyMatrixOptions): stri
export function linkifyAndSanitizeHtml(dirtyHtml: string, options = linkifyMatrixOptions): string {
return sanitizeHtml(linkifyString(dirtyHtml, options), sanitizeHtmlParams);
}
+
+export function filterImg(frame: IFrame): boolean {
+ return frame.tag === "img";
+}
\ No newline at end of file
diff --git a/src/components/views/messages/EventContentBody.tsx b/src/components/views/messages/EventContentBody.tsx
index 3e51691c24..74018bbab7 100644
--- a/src/components/views/messages/EventContentBody.tsx
+++ b/src/components/views/messages/EventContentBody.tsx
@@ -28,6 +28,7 @@ import {
import MatrixClientContext from "../../../contexts/MatrixClientContext.tsx";
import { useSettingValue } from "../../../hooks/useSettings.ts";
import { filterBoolean } from "../../../utils/arrays.ts";
+import { useMediaVisible } from "../../../hooks/useMediaVisible.ts";
/**
* Returns a RegExp pattern for the keyword in the push rule of the given Matrix event, if any
@@ -150,6 +151,7 @@ const EventContentBody = memo(
forwardRef(
({ as, mxEvent, stripReply, content, linkify, highlights, includeDir = true, ...options }, ref) => {
const enableBigEmoji = useSettingValue("TextualBody.enableBigEmoji");
+ const [mediaIsVisible] = useMediaVisible(mxEvent?.getId()!, mxEvent?.getRoomId()!);
const replacer = useReplacer(content, mxEvent, options);
const linkifyOptions = useMemo(
@@ -167,6 +169,7 @@ const EventContentBody = memo(
disableBigEmoji: isEmote || !enableBigEmoji,
// Part of Replies fallback support
stripReplyFallback: stripReply,
+ mediaIsVisible,
}),
[content, enableBigEmoji, highlights, isEmote, stripReply],
);