1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-06 12:02:40 +03:00

Implement MSC3912: Relation-based redactions (#2954)

This commit is contained in:
Michael Weimann
2022-12-20 09:22:26 +01:00
committed by GitHub
parent 6d58a54039
commit b83c372848
5 changed files with 113 additions and 6 deletions

View File

@@ -22,11 +22,13 @@ import { Filter } from "../../src/filter";
import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE } from "../../src/models/MSC3089TreeSpace"; import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE } from "../../src/models/MSC3089TreeSpace";
import { import {
EventType, EventType,
RelationType,
RoomCreateTypeField, RoomCreateTypeField,
RoomType, RoomType,
UNSTABLE_MSC3088_ENABLED, UNSTABLE_MSC3088_ENABLED,
UNSTABLE_MSC3088_PURPOSE, UNSTABLE_MSC3088_PURPOSE,
UNSTABLE_MSC3089_TREE_SUBTYPE, UNSTABLE_MSC3089_TREE_SUBTYPE,
MSC3912_RELATION_BASED_REDACTIONS_PROP,
} from "../../src/@types/event"; } from "../../src/@types/event";
import { MEGOLM_ALGORITHM } from "../../src/crypto/olmlib"; import { MEGOLM_ALGORITHM } from "../../src/crypto/olmlib";
import { Crypto } from "../../src/crypto"; import { Crypto } from "../../src/crypto";
@@ -121,6 +123,10 @@ describe("MatrixClient", function () {
data: SYNC_DATA, data: SYNC_DATA,
}; };
const unstableFeatures: Record<string, boolean> = {
"org.matrix.msc3440.stable": true,
};
// items are popped off when processed and block if no items left. // items are popped off when processed and block if no items left.
let httpLookups: HttpLookup[] = []; let httpLookups: HttpLookup[] = [];
let acceptKeepalives: boolean; let acceptKeepalives: boolean;
@@ -132,9 +138,7 @@ describe("MatrixClient", function () {
function httpReq(method: Method, path: string, qp?: QueryDict, data?: BodyInit, opts?: IRequestOpts) { function httpReq(method: Method, path: string, qp?: QueryDict, data?: BodyInit, opts?: IRequestOpts) {
if (path === KEEP_ALIVE_PATH && acceptKeepalives) { if (path === KEEP_ALIVE_PATH && acceptKeepalives) {
return Promise.resolve({ return Promise.resolve({
unstable_features: { unstable_features: unstableFeatures,
"org.matrix.msc3440.stable": true,
},
versions: ["r0.6.0", "r0.6.1"], versions: ["r0.6.0", "r0.6.1"],
}); });
} }
@@ -1085,6 +1089,59 @@ describe("MatrixClient", function () {
await client.redactEvent(roomId, eventId, txnId, { reason }); await client.redactEvent(roomId, eventId, txnId, { reason });
}); });
describe("when calling with with_relations", () => {
const eventId = "$event42:example.org";
it("should raise an error if server has no support for relation based redactions", async () => {
// load supported features
await client.getVersions();
const txnId = client.makeTxnId();
expect(() => {
client.redactEvent(roomId, eventId, txnId, {
with_relations: [RelationType.Reference],
});
}).toThrowError(
new Error(
"Server does not support relation based redactions " +
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId null`,
),
);
});
describe("and the server supports relation based redactions (unstable)", () => {
beforeEach(async () => {
unstableFeatures["org.matrix.msc3912"] = true;
// load supported features
await client.getVersions();
});
it("should send with_relations in the request body", async () => {
const txnId = client.makeTxnId();
httpLookups = [
{
method: "PUT",
path:
`/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}` +
`/${encodeURIComponent(txnId)}`,
expectBody: {
reason: "redaction test",
[MSC3912_RELATION_BASED_REDACTIONS_PROP.unstable!]: [RelationType.Reference],
},
data: { event_id: eventId },
},
];
await client.redactEvent(roomId, eventId, txnId, {
reason: "redaction test",
with_relations: [RelationType.Reference],
});
});
});
});
}); });
describe("cancelPendingEvent", () => { describe("cancelPendingEvent", () => {

View File

@@ -165,6 +165,15 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix
*/ */
export const UNSTABLE_MSC2716_MARKER = new UnstableValue("m.room.marker", "org.matrix.msc2716.marker"); export const UNSTABLE_MSC2716_MARKER = new UnstableValue("m.room.marker", "org.matrix.msc2716.marker");
/**
* Name of the "with_relations" request property for relation based redactions.
* {@link https://github.com/matrix-org/matrix-spec-proposals/pull/3912}
*/
export const MSC3912_RELATION_BASED_REDACTIONS_PROP = new UnstableValue(
"with_relations",
"org.matrix.msc3912.with_relations",
);
/** /**
* Functional members type for declaring a purpose of room members (e.g. helpful bots). * Functional members type for declaring a purpose of room members (e.g. helpful bots).
* Note that this reference is UNSTABLE and subject to breaking changes, including its * Note that this reference is UNSTABLE and subject to breaking changes, including its

View File

@@ -21,7 +21,7 @@ import { IRoomEventFilter } from "../filter";
import { Direction } from "../models/event-timeline"; import { Direction } from "../models/event-timeline";
import { PushRuleAction } from "./PushRules"; import { PushRuleAction } from "./PushRules";
import { IRoomEvent } from "../sync-accumulator"; import { IRoomEvent } from "../sync-accumulator";
import { EventType, RoomType } from "./event"; import { EventType, RelationType, RoomType } from "./event";
// allow camelcase as these are things that go onto the wire // allow camelcase as these are things that go onto the wire
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@@ -47,6 +47,18 @@ export interface IJoinRoomOpts {
export interface IRedactOpts { export interface IRedactOpts {
reason?: string; reason?: string;
/**
* Whether events related to the redacted event should be redacted.
*
* If specified, then any events which relate to the event being redacted with
* any of the relationship types listed will also be redacted.
*
* <b>Raises an Error if the server does not support it.</b>
* Check for server-side support before using this param with
* <code>client.canSupport.get(Feature.RelationBasedRedactions)</code>.
* {@link https://github.com/matrix-org/matrix-spec-proposals/pull/3912}
*/
with_relations?: Array<RelationType | string>;
} }
export interface ISendEventResponse { export interface ISendEventResponse {

View File

@@ -154,6 +154,7 @@ import {
UNSTABLE_MSC3088_ENABLED, UNSTABLE_MSC3088_ENABLED,
UNSTABLE_MSC3088_PURPOSE, UNSTABLE_MSC3088_PURPOSE,
UNSTABLE_MSC3089_TREE_SUBTYPE, UNSTABLE_MSC3089_TREE_SUBTYPE,
MSC3912_RELATION_BASED_REDACTIONS_PROP,
} from "./@types/event"; } from "./@types/event";
import { IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials"; import { IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials";
import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper"; import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper";
@@ -4444,9 +4445,11 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
/** /**
* @param txnId - transaction id. One will be made up if not supplied. * @param txnId - transaction id. One will be made up if not supplied.
* @param opts - Options to pass on, may contain `reason`. * @param opts - Options to pass on, may contain `reason` and `with_relations` (MSC3912)
* @returns Promise which resolves: TODO * @returns Promise which resolves: TODO
* @returns Rejects: with an error response. * @returns Rejects: with an error response.
* @throws Error if called with `with_relations` (MSC3912) but the server does not support it.
* Callers should check whether the server supports MSC3912 via `MatrixClient.canSupport`.
*/ */
public redactEvent( public redactEvent(
roomId: string, roomId: string,
@@ -4475,12 +4478,34 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
threadId = null; threadId = null;
} }
const reason = opts?.reason; const reason = opts?.reason;
if (
opts?.with_relations &&
this.canSupport.get(Feature.RelationBasedRedactions) === ServerSupport.Unsupported
) {
throw new Error(
"Server does not support relation based redactions " +
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId ${threadId}`,
);
}
const withRelations = opts?.with_relations
? {
[this.canSupport.get(Feature.RelationBasedRedactions) === ServerSupport.Stable
? MSC3912_RELATION_BASED_REDACTIONS_PROP.stable!
: MSC3912_RELATION_BASED_REDACTIONS_PROP.unstable!]: opts?.with_relations,
}
: {};
return this.sendCompleteEvent( return this.sendCompleteEvent(
roomId, roomId,
threadId, threadId,
{ {
type: EventType.RoomRedaction, type: EventType.RoomRedaction,
content: { reason }, content: {
...withRelations,
reason,
},
redacts: eventId, redacts: eventId,
}, },
txnId as string, txnId as string,

View File

@@ -26,6 +26,7 @@ export enum Feature {
Thread = "Thread", Thread = "Thread",
ThreadUnreadNotifications = "ThreadUnreadNotifications", ThreadUnreadNotifications = "ThreadUnreadNotifications",
LoginTokenRequest = "LoginTokenRequest", LoginTokenRequest = "LoginTokenRequest",
RelationBasedRedactions = "RelationBasedRedactions",
AccountDataDeletion = "AccountDataDeletion", AccountDataDeletion = "AccountDataDeletion",
} }
@@ -46,6 +47,9 @@ const featureSupportResolver: Record<string, FeatureSupportCondition> = {
[Feature.LoginTokenRequest]: { [Feature.LoginTokenRequest]: {
unstablePrefixes: ["org.matrix.msc3882"], unstablePrefixes: ["org.matrix.msc3882"],
}, },
[Feature.RelationBasedRedactions]: {
unstablePrefixes: ["org.matrix.msc3912"],
},
[Feature.AccountDataDeletion]: { [Feature.AccountDataDeletion]: {
unstablePrefixes: ["org.matrix.msc3391"], unstablePrefixes: ["org.matrix.msc3391"],
}, },