Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit cbc671b

Browse files
authored
Share e2ee keys when using /invite SlashCommand (#7655)
1 parent 15276ea commit cbc671b

File tree

6 files changed

+53
-35
lines changed

6 files changed

+53
-35
lines changed

src/RoomInvite.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,19 @@ export interface IInviteResult {
4343
*
4444
* @param {string} roomId The ID of the room to invite to
4545
* @param {string[]} addresses Array of strings of addresses to invite. May be matrix IDs or 3pids.
46+
* @param {boolean} sendSharedHistoryKeys whether to share e2ee keys with the invitees if applicable.
4647
* @param {function} progressCallback optional callback, fired after each invite.
4748
* @returns {Promise} Promise
4849
*/
4950
export function inviteMultipleToRoom(
5051
roomId: string,
5152
addresses: string[],
53+
sendSharedHistoryKeys = false,
5254
progressCallback?: () => void,
5355
): Promise<IInviteResult> {
5456
const inviter = new MultiInviter(roomId, progressCallback);
55-
return inviter.invite(addresses).then(states => Promise.resolve({ states, inviter }));
57+
return inviter.invite(addresses, undefined, sendSharedHistoryKeys)
58+
.then(states => Promise.resolve({ states, inviter }));
5659
}
5760

5861
export function showStartChatInviteDialog(initialText = ""): void {
@@ -110,8 +113,13 @@ export function isValid3pidInvite(event: MatrixEvent): boolean {
110113
return true;
111114
}
112115

113-
export function inviteUsersToRoom(roomId: string, userIds: string[], progressCallback?: () => void): Promise<void> {
114-
return inviteMultipleToRoom(roomId, userIds, progressCallback).then((result) => {
116+
export function inviteUsersToRoom(
117+
roomId: string,
118+
userIds: string[],
119+
sendSharedHistoryKeys = false,
120+
progressCallback?: () => void,
121+
): Promise<void> {
122+
return inviteMultipleToRoom(roomId, userIds, sendSharedHistoryKeys, progressCallback).then((result) => {
115123
const room = MatrixClientPeg.get().getRoom(roomId);
116124
showAnyInviteErrors(result.states, room, result.inviter);
117125
}).catch((err) => {

src/SlashCommands.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { linkifyAndSanitizeHtml } from './HtmlUtils';
3535
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
3636
import WidgetUtils from "./utils/WidgetUtils";
3737
import { textToHtmlRainbow } from "./utils/colour";
38-
import { getAddressType } from './UserAddress';
38+
import { AddressType, getAddressType } from './UserAddress';
3939
import { abbreviateUrl } from './utils/UrlUtils';
4040
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils';
4141
import { isPermalinkHost, parsePermalink } from "./utils/permalinks/Permalinks";
@@ -500,7 +500,7 @@ export const Commands = [
500500
// meaningful.
501501
let prom = Promise.resolve();
502502
if (
503-
getAddressType(address) === 'email' &&
503+
getAddressType(address) === AddressType.Email &&
504504
!MatrixClientPeg.get().getIdentityServerUrl()
505505
) {
506506
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
@@ -541,7 +541,7 @@ export const Commands = [
541541
}
542542
const inviter = new MultiInviter(roomId);
543543
return success(prom.then(() => {
544-
return inviter.invite([address], reason);
544+
return inviter.invite([address], reason, true);
545545
}).then(() => {
546546
if (inviter.getCompletionState(address) !== "invited") {
547547
throw new Error(inviter.getErrorText(address));

src/components/views/dialogs/CreateSpaceFromCommunityDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ const CreateSpaceFromCommunityDialog: React.FC<IProps> = ({ matrixClient: cli, g
208208
setProgress(Progress.InvitingUsers);
209209

210210
const userIds = [...members, ...invitedMembers].map(m => m.userId).filter(m => m !== cli.getUserId());
211-
await inviteUsersToRoom(roomId, userIds, () => setProgress(p => p + 1));
211+
await inviteUsersToRoom(roomId, userIds, false, () => setProgress(p => p + 1));
212212

213213
// eagerly remove it from the community panel
214214
dis.dispatch(TagOrderActions.removeTag(cli, groupId));

src/components/views/dialogs/InviteDialog.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -761,31 +761,11 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
761761
}
762762

763763
try {
764-
const result = await inviteMultipleToRoom(this.props.roomId, targetIds);
764+
const result = await inviteMultipleToRoom(this.props.roomId, targetIds, true);
765765
CountlyAnalytics.instance.trackSendInvite(startTime, this.props.roomId, targetIds.length);
766766
if (!this.shouldAbortAfterInviteError(result, room)) { // handles setting error message too
767767
this.props.onFinished();
768768
}
769-
770-
if (cli.isRoomEncrypted(this.props.roomId)) {
771-
const visibilityEvent = room.currentState.getStateEvents(
772-
"m.room.history_visibility", "",
773-
);
774-
const visibility = visibilityEvent && visibilityEvent.getContent() &&
775-
visibilityEvent.getContent().history_visibility;
776-
if (visibility == "world_readable" || visibility == "shared") {
777-
const invitedUsers = [];
778-
for (const [addr, state] of Object.entries(result.states)) {
779-
if (state === "invited" && getAddressType(addr) === "mx-user-id") {
780-
invitedUsers.push(addr);
781-
}
782-
}
783-
logger.log("Sharing history with", invitedUsers);
784-
cli.sendSharedHistoryKeys(
785-
this.props.roomId, invitedUsers,
786-
);
787-
}
788-
}
789769
} catch (err) {
790770
logger.error(err);
791771
this.setState({

src/utils/MultiInviter.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
import { MatrixError } from "matrix-js-sdk/src/http-api";
1818
import { defer, IDeferred } from "matrix-js-sdk/src/utils";
1919
import { logger } from "matrix-js-sdk/src/logger";
20+
import { MatrixClient } from "matrix-js-sdk/src/client";
21+
import { EventType } from "matrix-js-sdk/src/@types/event";
22+
import { HistoryVisibility } from "matrix-js-sdk/src/@types/partials";
2023

2124
import { MatrixClientPeg } from '../MatrixClientPeg';
2225
import { AddressType, getAddressType } from '../UserAddress';
@@ -49,6 +52,7 @@ const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED";
4952
export default class MultiInviter {
5053
private readonly roomId?: string;
5154
private readonly groupId?: string;
55+
private readonly matrixClient: MatrixClient;
5256

5357
private canceled = false;
5458
private addresses: string[] = [];
@@ -71,6 +75,8 @@ export default class MultiInviter {
7175
this.roomId = targetId;
7276
this.groupId = null;
7377
}
78+
79+
this.matrixClient = MatrixClientPeg.get();
7480
}
7581

7682
public get fatal() {
@@ -83,9 +89,10 @@ export default class MultiInviter {
8389
*
8490
* @param {array} addresses Array of addresses to invite
8591
* @param {string} reason Reason for inviting (optional)
92+
* @param {boolean} sendSharedHistoryKeys whether to share e2ee keys with the invitees if applicable.
8693
* @returns {Promise} Resolved when all invitations in the queue are complete
8794
*/
88-
public invite(addresses, reason?: string): Promise<CompletionStates> {
95+
public invite(addresses, reason?: string, sendSharedHistoryKeys = false): Promise<CompletionStates> {
8996
if (this.addresses.length > 0) {
9097
throw new Error("Already inviting/invited");
9198
}
@@ -104,7 +111,30 @@ export default class MultiInviter {
104111
this.deferred = defer<CompletionStates>();
105112
this.inviteMore(0);
106113

107-
return this.deferred.promise;
114+
if (!sendSharedHistoryKeys || !this.roomId || !this.matrixClient.isRoomEncrypted(this.roomId)) {
115+
return this.deferred.promise;
116+
}
117+
118+
const room = this.matrixClient.getRoom(this.roomId);
119+
const visibilityEvent = room?.currentState.getStateEvents(EventType.RoomHistoryVisibility, "");
120+
const visibility = visibilityEvent?.getContent().history_visibility;
121+
122+
if (visibility !== HistoryVisibility.WorldReadable && visibility !== HistoryVisibility.Shared) {
123+
return this.deferred.promise;
124+
}
125+
126+
return this.deferred.promise.then(async states => {
127+
const invitedUsers = [];
128+
for (const [addr, state] of Object.entries(states)) {
129+
if (state === InviteState.Invited && getAddressType(addr) === AddressType.MatrixUserId) {
130+
invitedUsers.push(addr);
131+
}
132+
}
133+
logger.log("Sharing history with", invitedUsers);
134+
await this.matrixClient.sendSharedHistoryKeys(this.roomId, invitedUsers);
135+
136+
return states;
137+
});
108138
}
109139

110140
/**
@@ -129,9 +159,9 @@ export default class MultiInviter {
129159
const addrType = getAddressType(addr);
130160

131161
if (addrType === AddressType.Email) {
132-
return MatrixClientPeg.get().inviteByEmail(roomId, addr);
162+
return this.matrixClient.inviteByEmail(roomId, addr);
133163
} else if (addrType === AddressType.MatrixUserId) {
134-
const room = MatrixClientPeg.get().getRoom(roomId);
164+
const room = this.matrixClient.getRoom(roomId);
135165
if (!room) throw new Error("Room not found");
136166

137167
const member = room.getMember(addr);
@@ -148,14 +178,14 @@ export default class MultiInviter {
148178
}
149179

150180
if (!ignoreProfile && SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
151-
const profile = await MatrixClientPeg.get().getProfileInfo(addr);
181+
const profile = await this.matrixClient.getProfileInfo(addr);
152182
if (!profile) {
153183
// noinspection ExceptionCaughtLocallyJS
154184
throw new Error("User has no profile");
155185
}
156186
}
157187

158-
return MatrixClientPeg.get().invite(roomId, addr, undefined, this.reason);
188+
return this.matrixClient.invite(roomId, addr, undefined, this.reason);
159189
} else {
160190
throw new Error('Unsupported address');
161191
}

src/utils/RoomUpgrade.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export async function upgradeRoom(
117117

118118
if (toInvite.length > 0) {
119119
// Errors are handled internally to this function
120-
await inviteUsersToRoom(newRoomId, toInvite, () => {
120+
await inviteUsersToRoom(newRoomId, toInvite, false, () => {
121121
progress.inviteUsersProgress++;
122122
progressCallback?.(progress);
123123
});

0 commit comments

Comments
 (0)