diff --git a/packages/core/src/events/m.room.member.ts b/packages/core/src/events/m.room.member.ts index 16469c22..1802479a 100644 --- a/packages/core/src/events/m.room.member.ts +++ b/packages/core/src/events/m.room.member.ts @@ -10,6 +10,7 @@ declare module "./eventBase" { age_ts: number; }; content: { + join_authorised_via_users_server?: string; membership: Membership; }; }; @@ -25,6 +26,7 @@ export interface RoomMemberEvent extends EventBase { type: "m.room.member"; content: { membership: Membership; + join_authorised_via_users_server?: string; }; state_key: string; unsigned: { diff --git a/packages/homeserver/src/plugins/mongodb.ts b/packages/homeserver/src/plugins/mongodb.ts index 82e641c9..274a1504 100644 --- a/packages/homeserver/src/plugins/mongodb.ts +++ b/packages/homeserver/src/plugins/mongodb.ts @@ -125,7 +125,8 @@ export const routerWithMongodb = (db: Db) => } const [, publicKey] = Object.entries(server.keys).find( - ([protocolAndVersion, value]) => protocolAndVersion === key && value.validUntil > Date.now(), + ([protocolAndVersion, value]) => + protocolAndVersion === key && value.validUntil > Date.now(), ) ?? []; return publicKey?.key; }; @@ -145,8 +146,8 @@ export const routerWithMongodb = (db: Db) => key: value, validUntil, }, - } - } + }, + }, }, { upsert: true }, ); @@ -171,4 +172,5 @@ export type Context = InferContext>; export type EventStore = { _id: string; event: EventBase; + staged?: true; }; diff --git a/packages/homeserver/src/routes/federation/sendTransaction.ts b/packages/homeserver/src/routes/federation/sendTransaction.ts index b9c2e3ca..9179474a 100644 --- a/packages/homeserver/src/routes/federation/sendTransaction.ts +++ b/packages/homeserver/src/routes/federation/sendTransaction.ts @@ -16,6 +16,7 @@ import { } from "../../procedures/getPublicKeyFromServer"; import { isConfigContext } from "../../plugins/isConfigContext"; import { MatrixError } from "../../errors"; +import { isRoomMemberEvent } from "@hs/core/src/events/m.room.member"; export const sendTransactionRoute = new Elysia().put( "/send/:txnId", @@ -99,42 +100,63 @@ export const sendTransactionRoute = new Elysia().put( } const validatePdu = async (pdu: SignedJson>) => { - const origin = pdu.sender.split(":").pop() as string; - - if (!origin) { - throw new MatrixError("400", "Invalid origin"); + const extractOrigin = (sender: string) => + sender.split(":").pop() as string; + + const isInviteVia3pid = (event: EventBase) => + isRoomMemberEvent(event) && + event.content.membership === "invite" && + "third_party_invite" in event.content; + + const origins = [ + !isInviteVia3pid(pdu) && extractOrigin(pdu.sender), + // extractOrigin(pdu.sender) !== extractOrigin(pdu.event_id) && + // extractOrigin(pdu.event_id), + isRoomMemberEvent(pdu) && + pdu.content.join_authorised_via_users_server && + extractOrigin(pdu.content.join_authorised_via_users_server), + ].filter(Boolean) as string[]; + + if (!origins.length) { + throw new MatrixError("400", "Invalid Signature"); } - const [signature] = await getSignaturesFromRemote(pdu, origin); - const { signatures, unsigned, ...rest } = pdu; - const getPublicKeyFromServer = makeGetPublicKeyFromServerProcedure( - context.mongo.getValidPublicKeyFromLocal, - () => - getPublicKeyFromRemoteServer( - origin, - config.name, - `${signature.algorithm}:${signature.version}`, - ), + for await (const origin of origins) { + const { signatures, unsigned, ...rest } = pdu; - context.mongo.storePublicKey, - ); + const [signature] = await getSignaturesFromRemote(pdu, origin); - const publicKey = await getPublicKeyFromServer( - origin, - `${signature.algorithm}:${signature.version}`, - ); + const getPublicKeyFromServer = makeGetPublicKeyFromServerProcedure( + context.mongo.getValidPublicKeyFromLocal, + () => + getPublicKeyFromRemoteServer( + origin, + config.name, + `${signature.algorithm}:${signature.version}`, + ), - if ( - !verifyJsonSignature( - pruneEventDict(rest), + context.mongo.storePublicKey, + ); + + const publicKey = await getPublicKeyFromServer( origin, - Uint8Array.from(atob(signature.signature), (c) => c.charCodeAt(0)), - Uint8Array.from(atob(publicKey), (c) => c.charCodeAt(0)), - signature.algorithm, - signature.version, - ) - ) { - throw new MatrixError("400", "Invalid signature"); + `${signature.algorithm}:${signature.version}`, + ); + + if ( + !verifyJsonSignature( + pruneEventDict(rest), + origin, + Uint8Array.from(atob(signature.signature), (c) => + c.charCodeAt(0), + ), + Uint8Array.from(atob(publicKey), (c) => c.charCodeAt(0)), + signature.algorithm, + signature.version, + ) + ) { + throw new MatrixError("400", "Invalid signature"); + } } };