Skip to content

Commit

Permalink
Add new decryptExistingEvent test helper (#4133)
Browse files Browse the repository at this point in the history
* grammar fix

* IEncryptionResult -> EncryptionResult

These are the same thing; the former is the old name.

* Support setting event IDs

* Helper for decrypting existing decryption failures
  • Loading branch information
richvdh committed Mar 25, 2024
1 parent 0b290ff commit 9f1d0c3
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 22 deletions.
31 changes: 30 additions & 1 deletion spec/unit/testing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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");
});
});
});
67 changes: 46 additions & 21 deletions src/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ 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
*/

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}.
Expand Down Expand Up @@ -102,32 +102,19 @@ export async function mkEncryptedMatrixEvent(opts: {

/** The content the event will have, once it has been decrypted. */
plainContent: IContent;
}): Promise<MatrixEvent> {
// 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<MatrixEvent> {
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<IEventDecryptionResult> => decryptionResult,
} as Parameters<MatrixEvent["attemptDecryption"]>[0];
await mxEvent.attemptDecryption(mockCrypto);
await decryptExistingEvent(mxEvent, { plainType: opts.plainType, plainContent: opts.plainContent });
return mxEvent;
}

Expand All @@ -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<MatrixEvent> {
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<IEventDecryptionResult> => {
decryptEvent: async (_ev): Promise<EventDecryptionResult> => {
throw new DecryptionError(opts.code, opts.msg);
},
} as Parameters<MatrixEvent["attemptDecryption"]>[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<void> {
const decryptionResult: EventDecryptionResult = {
claimedEd25519Key: "",
clearEvent: {
type: opts.plainType,
content: opts.plainContent,
},
forwardingCurve25519KeyChain: [],
senderCurve25519Key: "",
untrusted: false,
};

const mockCrypto = {
decryptEvent: async (_ev): Promise<EventDecryptionResult> => decryptionResult,
} as Parameters<MatrixEvent["attemptDecryption"]>[0];
await mxEvent.attemptDecryption(mockCrypto);
}

0 comments on commit 9f1d0c3

Please sign in to comment.