diff --git a/spec/unit/testing.spec.ts b/spec/unit/testing.spec.ts index 49181b98b..32d24a47e 100644 --- a/spec/unit/testing.spec.ts +++ b/spec/unit/testing.spec.ts @@ -14,7 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { mkDecryptionFailureMatrixEvent, mkEncryptedMatrixEvent, mkMatrixEvent } from "../../src/testing"; +import { + decryptExistingEvent, + mkDecryptionFailureMatrixEvent, + mkEncryptedMatrixEvent, + mkMatrixEvent, +} from "../../src/testing"; import { EventType } from "../../src"; import { DecryptionFailureCode } from "../../src/crypto-api"; @@ -88,4 +93,28 @@ describe("testing", () => { expect(event.isState()).toBe(false); }); }); + + describe("decryptExistingEvent", () => { + it("decrypts an event", async () => { + const event = await mkDecryptionFailureMatrixEvent({ + sender: "@alice:test", + roomId: "!test:room", + code: DecryptionFailureCode.UNKNOWN_ERROR, + msg: "blah", + }); + + expect(event.isEncrypted()).toBe(true); + expect(event.isDecryptionFailure()).toBe(true); + await decryptExistingEvent(event, { + plainContent: { body: "blah" }, + plainType: "m.room.test", + }); + + expect(event.isEncrypted()).toBe(true); + expect(event.isDecryptionFailure()).toBe(false); + expect(event.decryptionFailureReason).toBe(null); + expect(event.getContent()).toEqual({ body: "blah" }); + expect(event.getType()).toEqual("m.room.test"); + }); + }); }); diff --git a/src/testing.ts b/src/testing.ts index 0a320da69..cce364948 100644 --- a/src/testing.ts +++ b/src/testing.ts @@ -17,7 +17,7 @@ limitations under the License. /** * This file is a secondary entrypoint for the js-sdk library, exposing utilities which might be useful for writing tests. * - * In general it should not be included in runtime applications. + * In general, it should not be included in runtime applications. * * @packageDocumentation */ @@ -25,9 +25,9 @@ limitations under the License. import { IContent, IEvent, IUnsigned, MatrixEvent } from "./models/event"; import { RoomMember } from "./models/room-member"; import { EventType } from "./@types/event"; -import { IEventDecryptionResult } from "./@types/crypto"; import { DecryptionError } from "./crypto/algorithms"; import { DecryptionFailureCode } from "./crypto-api"; +import { EventDecryptionResult } from "./common-crypto/CryptoBackend"; /** * Create a {@link MatrixEvent}. @@ -102,32 +102,19 @@ export async function mkEncryptedMatrixEvent(opts: { /** The content the event will have, once it has been decrypted. */ plainContent: IContent; -}): Promise { - // we construct an event which has been decrypted by stubbing out CryptoBackend.decryptEvent and then - // calling MatrixEvent.attemptDecryption. + /** Optional `event_id` for the event. If provided will be used as event ID; else an ID is generated. */ + eventId?: string; +}): Promise { const mxEvent = mkMatrixEvent({ type: EventType.RoomMessageEncrypted, roomId: opts.roomId, sender: opts.sender, content: { algorithm: "m.megolm.v1.aes-sha2" }, + eventId: opts.eventId, }); - const decryptionResult: IEventDecryptionResult = { - claimedEd25519Key: "", - clearEvent: { - type: opts.plainType, - content: opts.plainContent, - }, - forwardingCurve25519KeyChain: [], - senderCurve25519Key: "", - untrusted: false, - }; - - const mockCrypto = { - decryptEvent: async (_ev): Promise => decryptionResult, - } as Parameters[0]; - await mxEvent.attemptDecryption(mockCrypto); + await decryptExistingEvent(mxEvent, { plainType: opts.plainType, plainContent: opts.plainContent }); return mxEvent; } @@ -148,19 +135,57 @@ export async function mkDecryptionFailureMatrixEvent(opts: { /** A textual reason for the failure */ msg: string; + + /** Optional `event_id` for the event. If provided will be used as event ID; else an ID is generated. */ + eventId?: string; }): Promise { const mxEvent = mkMatrixEvent({ type: EventType.RoomMessageEncrypted, roomId: opts.roomId, sender: opts.sender, content: { algorithm: "m.megolm.v1.aes-sha2" }, + eventId: opts.eventId, }); const mockCrypto = { - decryptEvent: async (_ev): Promise => { + decryptEvent: async (_ev): Promise => { throw new DecryptionError(opts.code, opts.msg); }, } as Parameters[0]; await mxEvent.attemptDecryption(mockCrypto); return mxEvent; } + +/** + * Given an event previously returned by {@link mkDecryptionFailureMatrixEvent}, simulate a successful re-decryption + * attempt. + * + * @param mxEvent - The event that will be decrypted. + * @param opts - New data for the successful decryption. + */ +export async function decryptExistingEvent( + mxEvent: MatrixEvent, + opts: { + /** The type the event will have, once it has been decrypted. */ + plainType: EventType | string; + + /** The content the event will have, once it has been decrypted. */ + plainContent: IContent; + }, +): Promise { + const decryptionResult: EventDecryptionResult = { + claimedEd25519Key: "", + clearEvent: { + type: opts.plainType, + content: opts.plainContent, + }, + forwardingCurve25519KeyChain: [], + senderCurve25519Key: "", + untrusted: false, + }; + + const mockCrypto = { + decryptEvent: async (_ev): Promise => decryptionResult, + } as Parameters[0]; + await mxEvent.attemptDecryption(mockCrypto); +}