You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-03 00:33:22 +03:00 
			
		
		
		
	Share e2ee keys when using /invite SlashCommand (#7655)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							15276ea3b4
						
					
				
				
					commit
					cbc671b19f
				
			@@ -43,16 +43,19 @@ export interface IInviteResult {
 | 
			
		||||
 *
 | 
			
		||||
 * @param {string} roomId The ID of the room to invite to
 | 
			
		||||
 * @param {string[]} addresses Array of strings of addresses to invite. May be matrix IDs or 3pids.
 | 
			
		||||
 * @param {boolean} sendSharedHistoryKeys whether to share e2ee keys with the invitees if applicable.
 | 
			
		||||
 * @param {function} progressCallback optional callback, fired after each invite.
 | 
			
		||||
 * @returns {Promise} Promise
 | 
			
		||||
 */
 | 
			
		||||
export function inviteMultipleToRoom(
 | 
			
		||||
    roomId: string,
 | 
			
		||||
    addresses: string[],
 | 
			
		||||
    sendSharedHistoryKeys = false,
 | 
			
		||||
    progressCallback?: () => void,
 | 
			
		||||
): Promise<IInviteResult> {
 | 
			
		||||
    const inviter = new MultiInviter(roomId, progressCallback);
 | 
			
		||||
    return inviter.invite(addresses).then(states => Promise.resolve({ states, inviter }));
 | 
			
		||||
    return inviter.invite(addresses, undefined, sendSharedHistoryKeys)
 | 
			
		||||
        .then(states => Promise.resolve({ states, inviter }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function showStartChatInviteDialog(initialText = ""): void {
 | 
			
		||||
@@ -110,8 +113,13 @@ export function isValid3pidInvite(event: MatrixEvent): boolean {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function inviteUsersToRoom(roomId: string, userIds: string[], progressCallback?: () => void): Promise<void> {
 | 
			
		||||
    return inviteMultipleToRoom(roomId, userIds, progressCallback).then((result) => {
 | 
			
		||||
export function inviteUsersToRoom(
 | 
			
		||||
    roomId: string,
 | 
			
		||||
    userIds: string[],
 | 
			
		||||
    sendSharedHistoryKeys = false,
 | 
			
		||||
    progressCallback?: () => void,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    return inviteMultipleToRoom(roomId, userIds, sendSharedHistoryKeys, progressCallback).then((result) => {
 | 
			
		||||
        const room = MatrixClientPeg.get().getRoom(roomId);
 | 
			
		||||
        showAnyInviteErrors(result.states, room, result.inviter);
 | 
			
		||||
    }).catch((err) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ import { linkifyAndSanitizeHtml } from './HtmlUtils';
 | 
			
		||||
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
 | 
			
		||||
import WidgetUtils from "./utils/WidgetUtils";
 | 
			
		||||
import { textToHtmlRainbow } from "./utils/colour";
 | 
			
		||||
import { getAddressType } from './UserAddress';
 | 
			
		||||
import { AddressType, getAddressType } from './UserAddress';
 | 
			
		||||
import { abbreviateUrl } from './utils/UrlUtils';
 | 
			
		||||
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils';
 | 
			
		||||
import { isPermalinkHost, parsePermalink } from "./utils/permalinks/Permalinks";
 | 
			
		||||
@@ -500,7 +500,7 @@ export const Commands = [
 | 
			
		||||
                    // meaningful.
 | 
			
		||||
                    let prom = Promise.resolve();
 | 
			
		||||
                    if (
 | 
			
		||||
                        getAddressType(address) === 'email' &&
 | 
			
		||||
                        getAddressType(address) === AddressType.Email &&
 | 
			
		||||
                        !MatrixClientPeg.get().getIdentityServerUrl()
 | 
			
		||||
                    ) {
 | 
			
		||||
                        const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
 | 
			
		||||
@@ -541,7 +541,7 @@ export const Commands = [
 | 
			
		||||
                    }
 | 
			
		||||
                    const inviter = new MultiInviter(roomId);
 | 
			
		||||
                    return success(prom.then(() => {
 | 
			
		||||
                        return inviter.invite([address], reason);
 | 
			
		||||
                        return inviter.invite([address], reason, true);
 | 
			
		||||
                    }).then(() => {
 | 
			
		||||
                        if (inviter.getCompletionState(address) !== "invited") {
 | 
			
		||||
                            throw new Error(inviter.getErrorText(address));
 | 
			
		||||
 
 | 
			
		||||
@@ -208,7 +208,7 @@ const CreateSpaceFromCommunityDialog: React.FC<IProps> = ({ matrixClient: cli, g
 | 
			
		||||
            setProgress(Progress.InvitingUsers);
 | 
			
		||||
 | 
			
		||||
            const userIds = [...members, ...invitedMembers].map(m => m.userId).filter(m => m !== cli.getUserId());
 | 
			
		||||
            await inviteUsersToRoom(roomId, userIds, () => setProgress(p => p + 1));
 | 
			
		||||
            await inviteUsersToRoom(roomId, userIds, false, () => setProgress(p => p + 1));
 | 
			
		||||
 | 
			
		||||
            // eagerly remove it from the community panel
 | 
			
		||||
            dis.dispatch(TagOrderActions.removeTag(cli, groupId));
 | 
			
		||||
 
 | 
			
		||||
@@ -761,31 +761,11 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await inviteMultipleToRoom(this.props.roomId, targetIds);
 | 
			
		||||
            const result = await inviteMultipleToRoom(this.props.roomId, targetIds, true);
 | 
			
		||||
            CountlyAnalytics.instance.trackSendInvite(startTime, this.props.roomId, targetIds.length);
 | 
			
		||||
            if (!this.shouldAbortAfterInviteError(result, room)) { // handles setting error message too
 | 
			
		||||
                this.props.onFinished();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (cli.isRoomEncrypted(this.props.roomId)) {
 | 
			
		||||
                const visibilityEvent = room.currentState.getStateEvents(
 | 
			
		||||
                    "m.room.history_visibility", "",
 | 
			
		||||
                );
 | 
			
		||||
                const visibility = visibilityEvent && visibilityEvent.getContent() &&
 | 
			
		||||
                    visibilityEvent.getContent().history_visibility;
 | 
			
		||||
                if (visibility == "world_readable" || visibility == "shared") {
 | 
			
		||||
                    const invitedUsers = [];
 | 
			
		||||
                    for (const [addr, state] of Object.entries(result.states)) {
 | 
			
		||||
                        if (state === "invited" && getAddressType(addr) === "mx-user-id") {
 | 
			
		||||
                            invitedUsers.push(addr);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    logger.log("Sharing history with", invitedUsers);
 | 
			
		||||
                    cli.sendSharedHistoryKeys(
 | 
			
		||||
                        this.props.roomId, invitedUsers,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            logger.error(err);
 | 
			
		||||
            this.setState({
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,9 @@ limitations under the License.
 | 
			
		||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
 | 
			
		||||
import { defer, IDeferred } from "matrix-js-sdk/src/utils";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { HistoryVisibility } from "matrix-js-sdk/src/@types/partials";
 | 
			
		||||
 | 
			
		||||
import { MatrixClientPeg } from '../MatrixClientPeg';
 | 
			
		||||
import { AddressType, getAddressType } from '../UserAddress';
 | 
			
		||||
@@ -49,6 +52,7 @@ const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED";
 | 
			
		||||
export default class MultiInviter {
 | 
			
		||||
    private readonly roomId?: string;
 | 
			
		||||
    private readonly groupId?: string;
 | 
			
		||||
    private readonly matrixClient: MatrixClient;
 | 
			
		||||
 | 
			
		||||
    private canceled = false;
 | 
			
		||||
    private addresses: string[] = [];
 | 
			
		||||
@@ -71,6 +75,8 @@ export default class MultiInviter {
 | 
			
		||||
            this.roomId = targetId;
 | 
			
		||||
            this.groupId = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.matrixClient = MatrixClientPeg.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public get fatal() {
 | 
			
		||||
@@ -83,9 +89,10 @@ export default class MultiInviter {
 | 
			
		||||
     *
 | 
			
		||||
     * @param {array} addresses Array of addresses to invite
 | 
			
		||||
     * @param {string} reason Reason for inviting (optional)
 | 
			
		||||
     * @param {boolean} sendSharedHistoryKeys whether to share e2ee keys with the invitees if applicable.
 | 
			
		||||
     * @returns {Promise} Resolved when all invitations in the queue are complete
 | 
			
		||||
     */
 | 
			
		||||
    public invite(addresses, reason?: string): Promise<CompletionStates> {
 | 
			
		||||
    public invite(addresses, reason?: string, sendSharedHistoryKeys = false): Promise<CompletionStates> {
 | 
			
		||||
        if (this.addresses.length > 0) {
 | 
			
		||||
            throw new Error("Already inviting/invited");
 | 
			
		||||
        }
 | 
			
		||||
@@ -104,9 +111,32 @@ export default class MultiInviter {
 | 
			
		||||
        this.deferred = defer<CompletionStates>();
 | 
			
		||||
        this.inviteMore(0);
 | 
			
		||||
 | 
			
		||||
        if (!sendSharedHistoryKeys || !this.roomId || !this.matrixClient.isRoomEncrypted(this.roomId)) {
 | 
			
		||||
            return this.deferred.promise;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const room = this.matrixClient.getRoom(this.roomId);
 | 
			
		||||
        const visibilityEvent = room?.currentState.getStateEvents(EventType.RoomHistoryVisibility, "");
 | 
			
		||||
        const visibility = visibilityEvent?.getContent().history_visibility;
 | 
			
		||||
 | 
			
		||||
        if (visibility !== HistoryVisibility.WorldReadable && visibility !== HistoryVisibility.Shared) {
 | 
			
		||||
            return this.deferred.promise;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.deferred.promise.then(async states => {
 | 
			
		||||
            const invitedUsers = [];
 | 
			
		||||
            for (const [addr, state] of Object.entries(states)) {
 | 
			
		||||
                if (state === InviteState.Invited && getAddressType(addr) === AddressType.MatrixUserId) {
 | 
			
		||||
                    invitedUsers.push(addr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            logger.log("Sharing history with", invitedUsers);
 | 
			
		||||
            await this.matrixClient.sendSharedHistoryKeys(this.roomId, invitedUsers);
 | 
			
		||||
 | 
			
		||||
            return states;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stops inviting. Causes promises returned by invite() to be rejected.
 | 
			
		||||
     */
 | 
			
		||||
@@ -129,9 +159,9 @@ export default class MultiInviter {
 | 
			
		||||
        const addrType = getAddressType(addr);
 | 
			
		||||
 | 
			
		||||
        if (addrType === AddressType.Email) {
 | 
			
		||||
            return MatrixClientPeg.get().inviteByEmail(roomId, addr);
 | 
			
		||||
            return this.matrixClient.inviteByEmail(roomId, addr);
 | 
			
		||||
        } else if (addrType === AddressType.MatrixUserId) {
 | 
			
		||||
            const room = MatrixClientPeg.get().getRoom(roomId);
 | 
			
		||||
            const room = this.matrixClient.getRoom(roomId);
 | 
			
		||||
            if (!room) throw new Error("Room not found");
 | 
			
		||||
 | 
			
		||||
            const member = room.getMember(addr);
 | 
			
		||||
@@ -148,14 +178,14 @@ export default class MultiInviter {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ignoreProfile && SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
 | 
			
		||||
                const profile = await MatrixClientPeg.get().getProfileInfo(addr);
 | 
			
		||||
                const profile = await this.matrixClient.getProfileInfo(addr);
 | 
			
		||||
                if (!profile) {
 | 
			
		||||
                    // noinspection ExceptionCaughtLocallyJS
 | 
			
		||||
                    throw new Error("User has no profile");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return MatrixClientPeg.get().invite(roomId, addr, undefined, this.reason);
 | 
			
		||||
            return this.matrixClient.invite(roomId, addr, undefined, this.reason);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new Error('Unsupported address');
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,7 @@ export async function upgradeRoom(
 | 
			
		||||
 | 
			
		||||
    if (toInvite.length > 0) {
 | 
			
		||||
        // Errors are handled internally to this function
 | 
			
		||||
        await inviteUsersToRoom(newRoomId, toInvite, () => {
 | 
			
		||||
        await inviteUsersToRoom(newRoomId, toInvite, false, () => {
 | 
			
		||||
            progress.inviteUsersProgress++;
 | 
			
		||||
            progressCallback?.(progress);
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user