From 24174826674caa5b6a2e5484ad27922e5c1adb63 Mon Sep 17 00:00:00 2001 From: Clark Fischer <439978+clarkf@users.noreply.github.com> Date: Sun, 15 Jan 2023 16:22:59 +0000 Subject: [PATCH] Fix error when viewing source of redacted events (#9914) * Fix viewing source of redacted events Clicking 'View Source' in the context menu of a redacted event causes an error, and the user gets no visible result. This fixes to indicate that the source is unavailable when a message has been redacted. The original source remains available. requires a non-null string for its `content` prop, and, in the case of redacted events, was passing `undefined`. This is ultimately because redacting an event causes `MatrixEvent.clearEvent` to be `undefined`, which wasn't checking. Fixes https://github.com/vector-im/element-web/issues/24165 Signed-off-by: Clark Fischer * Use correct highlight.js call Previous call signature was deprecated. See https://github.com/highlightjs/highlight.js/issues/2277 Signed-off-by: Clark Fischer Signed-off-by: Clark Fischer --- src/components/structures/ViewSource.tsx | 13 ++-- .../views/elements/SyntaxHighlight.tsx | 3 +- src/i18n/strings/en_EN.json | 1 + .../components/structures/ViewSource-test.tsx | 59 +++++++++++++++++++ .../views/elements/SyntaxHighlight-test.tsx | 38 ++++++++++++ .../SyntaxHighlight-test.tsx.snap | 30 ++++++++++ 6 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 test/components/structures/ViewSource-test.tsx create mode 100644 test/components/views/elements/SyntaxHighlight-test.tsx create mode 100644 test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx index b87194f251..245c1587c5 100644 --- a/src/components/structures/ViewSource.tsx +++ b/src/components/structures/ViewSource.tsx @@ -1,7 +1,6 @@ /* -Copyright 2015, 2016 OpenMarket Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2015, 2016, 2019, 2023 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. @@ -77,9 +76,13 @@ export default class ViewSource extends React.Component { {_t("Decrypted event source")} - - {stringify(decryptedEventSource)} - + {decryptedEventSource ? ( + + {stringify(decryptedEventSource)} + + ) : ( +
{_t("Decrypted source unavailable")}
+ )}
diff --git a/src/components/views/elements/SyntaxHighlight.tsx b/src/components/views/elements/SyntaxHighlight.tsx index 886c68c916..3e8828d94e 100644 --- a/src/components/views/elements/SyntaxHighlight.tsx +++ b/src/components/views/elements/SyntaxHighlight.tsx @@ -1,5 +1,6 @@ /* Copyright 2017 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2023 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. @@ -25,7 +26,7 @@ interface IProps { export default class SyntaxHighlight extends React.PureComponent { public render(): JSX.Element { const { children: content, language } = this.props; - const highlighted = language ? hljs.highlight(language, content) : hljs.highlightAuto(content); + const highlighted = language ? hljs.highlight(content, { language }) : hljs.highlightAuto(content); return (
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 4da12e366b..54272b871c 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -3452,6 +3452,7 @@
     "User menu": "User menu",
     "Could not load user profile": "Could not load user profile",
     "Decrypted event source": "Decrypted event source",
+    "Decrypted source unavailable": "Decrypted source unavailable",
     "Original event source": "Original event source",
     "Event ID: %(eventId)s": "Event ID: %(eventId)s",
     "Thread root ID: %(threadRootId)s": "Thread root ID: %(threadRootId)s",
diff --git a/test/components/structures/ViewSource-test.tsx b/test/components/structures/ViewSource-test.tsx
new file mode 100644
index 0000000000..a4bc8b1eca
--- /dev/null
+++ b/test/components/structures/ViewSource-test.tsx
@@ -0,0 +1,59 @@
+/*
+Copyright 2023 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 { render } from "@testing-library/react";
+import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import React from "react";
+
+import ViewSource from "../../../src/components/structures/ViewSource";
+import { mkEvent, stubClient } from "../../test-utils/test-utils";
+
+describe("ThreadView", () => {
+    const ROOM_ID = "!roomId:example.org";
+    const SENDER = "@alice:example.org";
+
+    let messageEvent: MatrixEvent;
+
+    const redactionEvent = mkEvent({
+        user: SENDER,
+        event: true,
+        type: EventType.RoomRedaction,
+        content: {},
+    });
+
+    beforeEach(() => {
+        messageEvent = new MatrixEvent({
+            type: EventType.RoomMessageEncrypted,
+            room_id: ROOM_ID,
+            sender: SENDER,
+            content: {},
+            state_key: undefined,
+        });
+        messageEvent.makeRedacted(redactionEvent);
+    });
+
+    beforeEach(stubClient);
+
+    // See https://github.com/vector-im/element-web/issues/24165
+    it("doesn't error when viewing redacted encrypted messages", () => {
+        // Sanity checks
+        expect(messageEvent.isEncrypted()).toBeTruthy();
+        // @ts-ignore clearEvent is private, but it's being used directly 
+        expect(messageEvent.clearEvent).toBe(undefined);
+
+        expect(() => render( {}} />)).not.toThrow();
+    });
+});
diff --git a/test/components/views/elements/SyntaxHighlight-test.tsx b/test/components/views/elements/SyntaxHighlight-test.tsx
new file mode 100644
index 0000000000..bdd3e50cf0
--- /dev/null
+++ b/test/components/views/elements/SyntaxHighlight-test.tsx
@@ -0,0 +1,38 @@
+/* eslint @typescript-eslint/no-unused-vars: ["error", { "varsIgnorePattern": "^_" }] */
+/*
+Copyright 2023 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 { render } from "@testing-library/react";
+import hljs, { type HighlightOptions } from "highlight.js";
+import React from "react";
+
+import SyntaxHighlight from "../../../../src/components/views/elements/SyntaxHighlight";
+
+describe("", () => {
+    it("renders", () => {
+        const { container } = render(console.log("Hello, World!"););
+        expect(container).toMatchSnapshot();
+    });
+
+    it.each(["json", "javascript", "css"])("uses the provided language", (lang) => {
+        const mock = jest.spyOn(hljs, "highlight");
+
+        render(// Hello, World);
+
+        const [_lang, opts] = mock.mock.lastCall!;
+        expect((opts as HighlightOptions)["language"]).toBe(lang);
+    });
+});
diff --git a/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap b/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap
new file mode 100644
index 0000000000..e7ad9c057b
--- /dev/null
+++ b/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` renders 1`] = `
+
+
+    
+      
+        console
+      
+      .
+      
+        log
+      
+      (
+      
+        "Hello, World!"
+      
+      );
+    
+  
+
+`;