From aaf6a7b03fadc791aea65d7d1096598317733d64 Mon Sep 17 00:00:00 2001 From: m004 <38407173+m004@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:11:36 +0100 Subject: [PATCH] Add authenticated media to getAvatarURL in room and room-member models --- spec/unit/room-member.spec.ts | 34 ++++++++++++++++++++++++++++ spec/unit/room.spec.ts | 42 +++++++++++++++++++++++++++++++++++ src/models/room-member.ts | 17 +++++++++++++- src/models/room.ts | 17 +++++++++++++- 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/spec/unit/room-member.spec.ts b/spec/unit/room-member.spec.ts index eb53989d47f..2b0e223f9fa 100644 --- a/spec/unit/room-member.spec.ts +++ b/spec/unit/room-member.spec.ts @@ -65,6 +65,40 @@ describe("RoomMember", function () { const url = member.getAvatarUrl(hsUrl, 64, 64, "crop", false, false); expect(url).toEqual(null); }); + + it("should return unauthenticated media URL if useAuthentication is not set", function () { + member.events.member = utils.mkEvent({ + event: true, + type: "m.room.member", + skey: userA, + room: roomId, + user: userA, + content: { + membership: KnownMembership.Join, + avatar_url: "mxc://flibble/wibble", + }, + }); + const url = member.getAvatarUrl(hsUrl, 1, 1, "", false, false); + // Check for unauthenticated media prefix + expect(url?.indexOf("/_matrix/media/v3/")).not.toEqual(-1); + }); + + it("should return authenticated media URL if useAuthentication=true", function () { + member.events.member = utils.mkEvent({ + event: true, + type: "m.room.member", + skey: userA, + room: roomId, + user: userA, + content: { + membership: KnownMembership.Join, + avatar_url: "mxc://flibble/wibble", + }, + }); + const url = member.getAvatarUrl(hsUrl, 1, 1, "", false, false, true); + // Check for authenticated media prefix + expect(url?.indexOf("/_matrix/client/v1/media/")).not.toEqual(-1); + }); }); describe("setPowerLevelEvent", function () { diff --git a/spec/unit/room.spec.ts b/spec/unit/room.spec.ts index 1f3efc0bf57..9a31e492f3c 100644 --- a/spec/unit/room.spec.ts +++ b/spec/unit/room.spec.ts @@ -299,6 +299,48 @@ describe("Room", function () { const url = room.getAvatarUrl(hsUrl, 64, 64, "crop", false); expect(url).toEqual(null); }); + + it("should return unauthenticated media URL if useAuthentication is not set", function () { + // @ts-ignore - mocked doesn't handle overloads sanely + mocked(room.currentState.getStateEvents).mockImplementation(function (type, key) { + if (type === EventType.RoomAvatar && key === "") { + return utils.mkEvent({ + event: true, + type: EventType.RoomAvatar, + skey: "", + room: roomId, + user: userA, + content: { + url: "mxc://flibble/wibble", + }, + }); + } + }); + const url = room.getAvatarUrl(hsUrl, 100, 100, "scale"); + // Check for unauthenticated media prefix + expect(url?.indexOf("/_matrix/media/v3/")).not.toEqual(-1); + }); + + it("should return authenticated media URL if useAuthentication=true", function () { + // @ts-ignore - mocked doesn't handle overloads sanely + mocked(room.currentState.getStateEvents).mockImplementation(function (type, key) { + if (type === EventType.RoomAvatar && key === "") { + return utils.mkEvent({ + event: true, + type: EventType.RoomAvatar, + skey: "", + room: roomId, + user: userA, + content: { + url: "mxc://flibble/wibble", + }, + }); + } + }); + const url = room.getAvatarUrl(hsUrl, 100, 100, "scale", undefined, true); + // Check for authenticated media prefix + expect(url?.indexOf("/_matrix/client/v1/media/")).not.toEqual(-1); + }); }); describe("getMember", function () { diff --git a/src/models/room-member.ts b/src/models/room-member.ts index 0f7e0b8dd62..8f1aea8533c 100644 --- a/src/models/room-member.ts +++ b/src/models/room-member.ts @@ -368,6 +368,11 @@ export class RoomMember extends TypedEventEmitter { * "crop" or "scale". * @param allowDefault - True to allow an identicon for this room if an * avatar URL wasn't explicitly set. Default: true. (Deprecated) + * @param useAuthentication - (optional) If true, the caller supports authenticated + * media and wants an authentication-required URL. Note that server support for + * authenticated media will not be checked - it is the caller's responsibility + * to do so before calling this function. Note also that useAuthentication + * implies allowRedirects. Defaults to false (unauthenticated endpoints). * @returns the avatar URL or null. */ public getAvatarUrl( @@ -1669,6 +1674,7 @@ export class Room extends ReadReceipt { height: number, resizeMethod: ResizeMethod, allowDefault = true, + useAuthentication: boolean = false, ): string | null { const roomAvatarEvent = this.currentState.getStateEvents(EventType.RoomAvatar, ""); if (!roomAvatarEvent && !allowDefault) { @@ -1677,7 +1683,16 @@ export class Room extends ReadReceipt { const mainUrl = roomAvatarEvent ? roomAvatarEvent.getContent().url : null; if (mainUrl) { - return getHttpUriForMxc(baseUrl, mainUrl, width, height, resizeMethod); + return getHttpUriForMxc( + baseUrl, + mainUrl, + width, + height, + resizeMethod, + undefined, + undefined, + useAuthentication, + ); } return null;