From 3b523677fda487562361b7670e40d6c224b6c0b0 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 24 Mar 2022 12:17:42 +0000
Subject: [PATCH] Don't try (and fail) to show replies for redacted events
(#8141)
---
src/utils/Reply.ts | 25 +++--
test/Reply-test.ts | 148 ++++++++++++++++++++++++++
test/__snapshots__/Reply-test.ts.snap | 10 ++
3 files changed, 173 insertions(+), 10 deletions(-)
create mode 100644 test/Reply-test.ts
create mode 100644 test/__snapshots__/Reply-test.ts.snap
diff --git a/src/utils/Reply.ts b/src/utils/Reply.ts
index 3d62bb946c..43144a34a1 100644
--- a/src/utils/Reply.ts
+++ b/src/utils/Reply.ts
@@ -18,13 +18,14 @@ import { IContent, MatrixEvent } from "matrix-js-sdk/src/models/event";
import sanitizeHtml from "sanitize-html";
import escapeHtml from "escape-html";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
+import { MsgType } from "matrix-js-sdk/src/@types/event";
import { PERMITTED_URL_SCHEMES } from "../HtmlUtils";
import { makeUserPermalink, RoomPermalinkCreator } from "./permalinks/Permalinks";
import { RecursivePartial } from "../@types/common";
import SettingsStore from "../settings/SettingsStore";
-export function getParentEventId(ev: MatrixEvent): string | undefined {
+export function getParentEventId(ev?: MatrixEvent): string | undefined {
if (!ev || ev.isRedacted()) return;
if (ev.replyEventId) {
return ev.replyEventId;
@@ -70,7 +71,7 @@ export function getNestedReplyText(
): { body: string, html: string } | null {
if (!ev) return null;
- let { body, formatted_body: html } = ev.getContent();
+ let { body, formatted_body: html, msgtype } = ev.getContent();
if (getParentEventId(ev)) {
if (body) body = stripPlainReply(body);
}
@@ -94,9 +95,9 @@ export function getNestedReplyText(
const mxid = ev.getSender();
// This fallback contains text that is explicitly EN.
- switch (ev.getContent().msgtype) {
- case 'm.text':
- case 'm.notice': {
+ switch (msgtype) {
+ case MsgType.Text:
+ case MsgType.Notice: {
html = `In reply to ${mxid}`
+ `
${html}
`;
const lines = body.trim().split('\n');
@@ -106,27 +107,27 @@ export function getNestedReplyText(
}
break;
}
- case 'm.image':
+ case MsgType.Image:
html = `In reply to ${mxid}`
+ `
sent an image.
`;
body = `> <${mxid}> sent an image.\n\n`;
break;
- case 'm.video':
+ case MsgType.Video:
html = `In reply to ${mxid}`
+ `
sent a video.
`;
body = `> <${mxid}> sent a video.\n\n`;
break;
- case 'm.audio':
+ case MsgType.Audio:
html = `In reply to ${mxid}`
+ `
sent an audio file.
`;
body = `> <${mxid}> sent an audio file.\n\n`;
break;
- case 'm.file':
+ case MsgType.File:
html = `In reply to ${mxid}`
+ `
sent a file.
`;
body = `> <${mxid}> sent a file.\n\n`;
break;
- case 'm.emote': {
+ case MsgType.Emote: {
html = `In reply to * `
+ `${mxid}
${html}
`;
const lines = body.trim().split('\n');
@@ -173,6 +174,10 @@ export function makeReplyMixIn(ev?: MatrixEvent): RecursivePartial {
}
export function shouldDisplayReply(event: MatrixEvent): boolean {
+ if (event.isRedacted()) {
+ return false;
+ }
+
const inReplyTo = event.getWireContent()?.["m.relates_to"]?.["m.in_reply_to"];
if (!inReplyTo) {
return false;
diff --git a/test/Reply-test.ts b/test/Reply-test.ts
new file mode 100644
index 0000000000..54863341cc
--- /dev/null
+++ b/test/Reply-test.ts
@@ -0,0 +1,148 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import './skinned-sdk';
+import {
+ getNestedReplyText,
+ getParentEventId,
+ shouldDisplayReply,
+ stripHTMLReply,
+ stripPlainReply,
+} from "../src/utils/Reply";
+import { mkEvent } from "./test-utils";
+import { RoomPermalinkCreator } from "../src/utils/permalinks/Permalinks";
+
+// don't litter test console with logs
+jest.mock("matrix-js-sdk/src/logger");
+
+describe("Reply", () => {
+ describe("getParentEventId", () => {
+ it("returns undefined if given a falsey value", async () => {
+ expect(getParentEventId()).toBeUndefined();
+ });
+ it("returns undefined if given a redacted event", async () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {},
+ });
+ event.makeRedacted(event);
+
+ expect(getParentEventId(event)).toBeUndefined();
+ });
+ it("returns undefined if the given event is not a reply", async () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {},
+ });
+
+ expect(getParentEventId(event)).toBeUndefined();
+ });
+ it("returns id of the event being replied to", async () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {
+ "m.relates_to": {
+ "m.in_reply_to": {
+ "event_id": "$event1",
+ },
+ },
+ },
+ });
+
+ expect(getParentEventId(event)).toBe("$event1");
+ });
+ });
+
+ describe("stripPlainReply", () => {
+ it("Removes leading quotes until the first blank line", () => {
+ expect(stripPlainReply(`
+> This is part
+> of the quote
+
+But this is not
+ `.trim())).toBe("But this is not");
+ });
+ });
+
+ describe("stripHTMLReply", () => {
+ it("Removes from the input", () => {
+ expect(stripHTMLReply(`
+
+ This is part
+ of the quote
+
+ But this is not
+ `).trim()).toBe("But this is not");
+ });
+ });
+
+ describe("getNestedReplyText", () => {
+ it("Returns valid reply fallback text for m.text msgtypes", () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {
+ body: "body",
+ msgtype: "m.text",
+ },
+ });
+
+ expect(getNestedReplyText(event, {
+ forEvent(eventId: string): string {
+ return "$$permalink$$";
+ },
+ } as RoomPermalinkCreator)).toMatchSnapshot();
+ });
+ });
+
+ describe("shouldDisplayReply", () => {
+ it("Returns false for redacted events", () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {},
+ });
+ event.makeRedacted(event);
+
+ expect(shouldDisplayReply(event)).toBe(false);
+ });
+
+ it("Returns false for non-reply events", () => {
+ const event = mkEvent({
+ event: true,
+ type: "m.room.message",
+ user: "@user1:server",
+ room: "!room1:server",
+ content: {},
+ });
+
+ expect(shouldDisplayReply(event)).toBe(false);
+ });
+ });
+});
diff --git a/test/__snapshots__/Reply-test.ts.snap b/test/__snapshots__/Reply-test.ts.snap
new file mode 100644
index 0000000000..df1a11eeb5
--- /dev/null
+++ b/test/__snapshots__/Reply-test.ts.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Reply getNestedReplyText Returns valid reply fallback text for m.text msgtypes 1`] = `
+Object {
+ "body": "> <@user1:server> body
+
+",
+ "html": "In reply to @user1:server
body
",
+}
+`;