Eliminate the use of MatrixClientPeg in utils (#10910)

This commit is contained in:
Michael Telatynski 2023-05-23 16:24:12 +01:00 committed by GitHub
parent a0c2676c38
commit 30429df948
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 409 additions and 325 deletions

View file

@ -436,15 +436,18 @@ export default class ContentMessages {
} }
} }
promBefore = doMaybeLocalRoomAction(roomId, (actualRoomId) => promBefore = doMaybeLocalRoomAction(
this.sendContentToRoom( roomId,
file, (actualRoomId) =>
actualRoomId, this.sendContentToRoom(
relation, file,
matrixClient, actualRoomId,
replyToEvent ?? undefined, relation,
loopPromiseBefore, matrixClient,
), replyToEvent ?? undefined,
loopPromiseBefore,
),
matrixClient,
); );
} }

View file

@ -301,7 +301,7 @@ export default class DeviceListener {
} else { } else {
// No cross-signing or key backup on account (set up encryption) // No cross-signing or key backup on account (set up encryption)
await cli.waitForClientWellKnown(); await cli.waitForClientWellKnown();
if (isSecureBackupRequired() && isLoggedIn()) { if (isSecureBackupRequired(cli) && isLoggedIn()) {
// If we're meant to set up, and Secure Backup is required, // If we're meant to set up, and Secure Backup is required,
// trigger the flow directly without a toast once logged in. // trigger the flow directly without a toast once logged in.
hideSetupEncryptionToast(); hideSetupEncryptionToast();

View file

@ -133,8 +133,8 @@ export default class IdentityAuthClient {
if ( if (
!this.tempClient && !this.tempClient &&
!doesAccountDataHaveIdentityServer() && !doesAccountDataHaveIdentityServer(this.matrixClient) &&
!(await doesIdentityServerHaveTerms(identityServerUrl)) !(await doesIdentityServerHaveTerms(this.matrixClient, identityServerUrl))
) { ) {
const { finished } = Modal.createDialog(QuestionDialog, { const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Identity server has no terms of service"), title: _t("Identity server has no terms of service"),
@ -158,7 +158,7 @@ export default class IdentityAuthClient {
}); });
const [confirmed] = await finished; const [confirmed] = await finished;
if (confirmed) { if (confirmed) {
setToDefaultIdentityServer(); setToDefaultIdentityServer(this.matrixClient);
} else { } else {
throw new AbortedIdentityActionError("User aborted identity server action without terms"); throw new AbortedIdentityActionError("User aborted identity server action without terms");
} }

View file

@ -1209,7 +1209,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
try { try {
await WidgetUtils.addJitsiWidget(roomId, type, "Jitsi", false); await WidgetUtils.addJitsiWidget(client, roomId, type, "Jitsi", false);
logger.log("Jitsi widget added"); logger.log("Jitsi widget added");
} catch (e) { } catch (e) {
if (e instanceof MatrixError && e.errcode === "M_FORBIDDEN") { if (e instanceof MatrixError && e.errcode === "M_FORBIDDEN") {

View file

@ -636,7 +636,7 @@ async function doSetLoggedIn(credentials: IMatrixClientCreds, clearStorageEnable
} }
dis.fire(Action.OnLoggedIn); dis.fire(Action.OnLoggedIn);
await startMatrixClient(/*startSyncing=*/ !softLogout); await startMatrixClient(client, /*startSyncing=*/ !softLogout);
return client; return client;
} }
@ -780,10 +780,11 @@ export function isLoggingOut(): boolean {
/** /**
* Starts the matrix client and all other react-sdk services that * Starts the matrix client and all other react-sdk services that
* listen for events while a session is logged in. * listen for events while a session is logged in.
* @param client the matrix client to start
* @param {boolean} startSyncing True (default) to actually start * @param {boolean} startSyncing True (default) to actually start
* syncing the client. * syncing the client.
*/ */
async function startMatrixClient(startSyncing = true): Promise<void> { async function startMatrixClient(client: MatrixClient, startSyncing = true): Promise<void> {
logger.log(`Lifecycle: Starting MatrixClient`); logger.log(`Lifecycle: Starting MatrixClient`);
// dispatch this before starting the matrix client: it's used // dispatch this before starting the matrix client: it's used
@ -796,10 +797,10 @@ async function startMatrixClient(startSyncing = true): Promise<void> {
SdkContextClass.instance.typingStore.reset(); SdkContextClass.instance.typingStore.reset();
ToastStore.sharedInstance().reset(); ToastStore.sharedInstance().reset();
DialogOpener.instance.prepare(); DialogOpener.instance.prepare(client);
Notifier.start(); Notifier.start();
UserActivity.sharedInstance().start(); UserActivity.sharedInstance().start();
DMRoomMap.makeShared().start(); DMRoomMap.makeShared(client).start();
IntegrationManagers.sharedInstance().startWatching(); IntegrationManagers.sharedInstance().startWatching();
ActiveWidgetStore.instance.start(); ActiveWidgetStore.instance.start();
LegacyCallHandler.instance.start(); LegacyCallHandler.instance.start();

View file

@ -20,6 +20,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User } from "matrix-js-sdk/src/models/user"; import { User } from "matrix-js-sdk/src/models/user";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "./MatrixClientPeg"; import { MatrixClientPeg } from "./MatrixClientPeg";
import MultiInviter, { CompletionStates } from "./utils/MultiInviter"; import MultiInviter, { CompletionStates } from "./utils/MultiInviter";
@ -49,12 +50,13 @@ export interface IInviteResult {
* @returns {Promise} Promise * @returns {Promise} Promise
*/ */
export function inviteMultipleToRoom( export function inviteMultipleToRoom(
client: MatrixClient,
roomId: string, roomId: string,
addresses: string[], addresses: string[],
sendSharedHistoryKeys = false, sendSharedHistoryKeys = false,
progressCallback?: () => void, progressCallback?: () => void,
): Promise<IInviteResult> { ): Promise<IInviteResult> {
const inviter = new MultiInviter(roomId, progressCallback); const inviter = new MultiInviter(client, roomId, progressCallback);
return inviter return inviter
.invite(addresses, undefined, sendSharedHistoryKeys) .invite(addresses, undefined, sendSharedHistoryKeys)
.then((states) => Promise.resolve({ states, inviter })); .then((states) => Promise.resolve({ states, inviter }));
@ -105,12 +107,13 @@ export function isValid3pidInvite(event: MatrixEvent): boolean {
} }
export function inviteUsersToRoom( export function inviteUsersToRoom(
client: MatrixClient,
roomId: string, roomId: string,
userIds: string[], userIds: string[],
sendSharedHistoryKeys = false, sendSharedHistoryKeys = false,
progressCallback?: () => void, progressCallback?: () => void,
): Promise<void> { ): Promise<void> {
return inviteMultipleToRoom(roomId, userIds, sendSharedHistoryKeys, progressCallback) return inviteMultipleToRoom(client, roomId, userIds, sendSharedHistoryKeys, progressCallback)
.then((result) => { .then((result) => {
const room = MatrixClientPeg.get().getRoom(roomId)!; const room = MatrixClientPeg.get().getRoom(roomId)!;
showAnyInviteErrors(result.states, room, result.inviter); showAnyInviteErrors(result.states, room, result.inviter);

View file

@ -411,6 +411,7 @@ function kickUser(event: MessageEvent<any>, roomId: string, userId: string): voi
} }
function setWidget(event: MessageEvent<any>, roomId: string | null): void { function setWidget(event: MessageEvent<any>, roomId: string | null): void {
const client = MatrixClientPeg.get();
const widgetId = event.data.widget_id; const widgetId = event.data.widget_id;
let widgetType = event.data.type; let widgetType = event.data.type;
const widgetUrl = event.data.url; const widgetUrl = event.data.url;
@ -458,7 +459,7 @@ function setWidget(event: MessageEvent<any>, roomId: string | null): void {
widgetType = WidgetType.fromString(widgetType); widgetType = WidgetType.fromString(widgetType);
if (userWidget) { if (userWidget) {
WidgetUtils.setUserWidget(widgetId, widgetType, widgetUrl, widgetName, widgetData) WidgetUtils.setUserWidget(client, widgetId, widgetType, widgetUrl, widgetName, widgetData)
.then(() => { .then(() => {
sendResponse(event, { sendResponse(event, {
success: true, success: true,
@ -476,6 +477,7 @@ function setWidget(event: MessageEvent<any>, roomId: string | null): void {
return; return;
} }
WidgetUtils.setRoomWidget( WidgetUtils.setRoomWidget(
client,
roomId, roomId,
widgetId, widgetId,
widgetType, widgetType,
@ -516,7 +518,7 @@ function getWidgets(event: MessageEvent<any>, roomId: string | null): void {
} }
// Add user widgets (not linked to a specific room) // Add user widgets (not linked to a specific room)
const userWidgets = WidgetUtils.getUserWidgetsArray(); const userWidgets = WidgetUtils.getUserWidgetsArray(client);
widgetStateEvents = widgetStateEvents.concat(userWidgets); widgetStateEvents = widgetStateEvents.concat(userWidgets);
sendResponse(event, widgetStateEvents); sendResponse(event, widgetStateEvents);

View file

@ -344,7 +344,7 @@ export async function accessSecretStorage(func = async (): Promise<void> => {},
onBeforeClose: async (reason): Promise<boolean> => { onBeforeClose: async (reason): Promise<boolean> => {
// If Secure Backup is required, you cannot leave the modal. // If Secure Backup is required, you cannot leave the modal.
if (reason === "backgroundClick") { if (reason === "backgroundClick") {
return !isSecureBackupRequired(); return !isSecureBackupRequired(cli);
} }
return true; return true;
}, },

View file

@ -576,7 +576,7 @@ export const Commands = [
prom = finished.then(([useDefault]) => { prom = finished.then(([useDefault]) => {
if (useDefault) { if (useDefault) {
setToDefaultIdentityServer(); setToDefaultIdentityServer(MatrixClientPeg.get());
return; return;
} }
throw new UserFriendlyError( throw new UserFriendlyError(
@ -589,7 +589,7 @@ export const Commands = [
); );
} }
} }
const inviter = new MultiInviter(roomId); const inviter = new MultiInviter(MatrixClientPeg.get(), roomId);
return success( return success(
prom prom
.then(() => { .then(() => {
@ -765,7 +765,7 @@ export const Commands = [
} }
if (!targetRoomId) targetRoomId = roomId; if (!targetRoomId) targetRoomId = roomId;
return success(leaveRoomBehaviour(targetRoomId)); return success(leaveRoomBehaviour(cli, targetRoomId));
}, },
category: CommandCategories.actions, category: CommandCategories.actions,
renderingTypes: [TimelineRenderingType.Room], renderingTypes: [TimelineRenderingType.Room],
@ -1018,7 +1018,7 @@ export const Commands = [
if (!widgetUrl.startsWith("https://") && !widgetUrl.startsWith("http://")) { if (!widgetUrl.startsWith("https://") && !widgetUrl.startsWith("http://")) {
return reject(new UserFriendlyError("Please supply a https:// or http:// widget URL")); return reject(new UserFriendlyError("Please supply a https:// or http:// widget URL"));
} }
if (WidgetUtils.canUserModifyWidgets(roomId)) { if (WidgetUtils.canUserModifyWidgets(MatrixClientPeg.get(), roomId)) {
const userId = MatrixClientPeg.get().getUserId(); const userId = MatrixClientPeg.get().getUserId();
const nowMs = new Date().getTime(); const nowMs = new Date().getTime();
const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`); const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`);
@ -1036,7 +1036,9 @@ export const Commands = [
widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl(); widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl();
} }
return success(WidgetUtils.setRoomWidget(roomId, widgetId, type, widgetUrl, name, data)); return success(
WidgetUtils.setRoomWidget(MatrixClientPeg.get(), roomId, widgetId, type, widgetUrl, name, data),
);
} else { } else {
return reject(new UserFriendlyError("You cannot modify widgets in this room.")); return reject(new UserFriendlyError("You cannot modify widgets in this room."));
} }

View file

@ -110,8 +110,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
let passPhraseKeySelected; const cli = MatrixClientPeg.get();
const setupMethods = getSecureBackupSetupMethods();
let passPhraseKeySelected: SecureBackupSetupMethod;
const setupMethods = getSecureBackupSetupMethods(cli);
if (setupMethods.includes(SecureBackupSetupMethod.Key)) { if (setupMethods.includes(SecureBackupSetupMethod.Key)) {
passPhraseKeySelected = SecureBackupSetupMethod.Key; passPhraseKeySelected = SecureBackupSetupMethod.Key;
} else { } else {
@ -143,13 +145,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
// does the server offer a UI auth flow with just m.login.password // does the server offer a UI auth flow with just m.login.password
// for /keys/device_signing/upload? // for /keys/device_signing/upload?
accountPasswordCorrect: null, accountPasswordCorrect: null,
canSkip: !isSecureBackupRequired(), canSkip: !isSecureBackupRequired(cli),
canUploadKeysWithPasswordOnly, canUploadKeysWithPasswordOnly,
passPhraseKeySelected, passPhraseKeySelected,
accountPassword, accountPassword,
}; };
MatrixClientPeg.get().on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange); cli.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);
this.getInitialPhase(); this.getInitialPhase();
} }
@ -542,7 +544,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
} }
private renderPhaseChooseKeyPassphrase(): JSX.Element { private renderPhaseChooseKeyPassphrase(): JSX.Element {
const setupMethods = getSecureBackupSetupMethods(); const setupMethods = getSecureBackupSetupMethods(MatrixClientPeg.get());
const optionKey = setupMethods.includes(SecureBackupSetupMethod.Key) ? this.renderOptionKey() : null; const optionKey = setupMethods.includes(SecureBackupSetupMethod.Key) ? this.renderOptionKey() : null;
const optionPassphrase = setupMethods.includes(SecureBackupSetupMethod.Passphrase) const optionPassphrase = setupMethods.includes(SecureBackupSetupMethod.Passphrase)
? this.renderOptionPassphrase() ? this.renderOptionPassphrase()

View file

@ -57,7 +57,7 @@ function matcherObject(
export default class RoomProvider extends AutocompleteProvider { export default class RoomProvider extends AutocompleteProvider {
protected matcher: QueryMatcher<ReturnType<typeof matcherObject>>; protected matcher: QueryMatcher<ReturnType<typeof matcherObject>>;
public constructor(room: Room, renderingType?: TimelineRenderingType) { public constructor(private readonly room: Room, renderingType?: TimelineRenderingType) {
super({ commandRegex: ROOM_REGEX, renderingType }); super({ commandRegex: ROOM_REGEX, renderingType });
this.matcher = new QueryMatcher<ReturnType<typeof matcherObject>>([], { this.matcher = new QueryMatcher<ReturnType<typeof matcherObject>>([], {
keys: ["displayedAlias", "matchName"], keys: ["displayedAlias", "matchName"],
@ -119,7 +119,7 @@ export default class RoomProvider extends AutocompleteProvider {
completionId: room.room.roomId, completionId: room.room.roomId,
type: "room", type: "room",
suffix: " ", suffix: " ",
href: makeRoomPermalink(room.displayedAlias), href: makeRoomPermalink(this.room.client, room.displayedAlias),
component: ( component: (
<PillCompletion title={room.room.name} description={room.displayedAlias}> <PillCompletion title={room.room.name} description={room.displayedAlias}>
<RoomAvatar width={24} height={24} room={room.room} /> <RoomAvatar width={24} height={24} room={room.room} />

View file

@ -28,7 +28,7 @@ import { OwnProfileStore } from "../../stores/OwnProfileStore";
import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
import { UPDATE_EVENT } from "../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore";
import { useEventEmitter } from "../../hooks/useEventEmitter"; import { useEventEmitter } from "../../hooks/useEventEmitter";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext, { useMatrixClientContext } from "../../contexts/MatrixClientContext";
import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader"; import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import EmbeddedPage from "./EmbeddedPage"; import EmbeddedPage from "./EmbeddedPage";
@ -97,8 +97,9 @@ const UserWelcomeTop: React.FC = () => {
}; };
const HomePage: React.FC<IProps> = ({ justRegistered = false }) => { const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
const cli = useMatrixClientContext();
const config = SdkConfig.get(); const config = SdkConfig.get();
const pageUrl = getHomePageUrl(config); const pageUrl = getHomePageUrl(config, cli);
if (pageUrl) { if (pageUrl) {
return <EmbeddedPage className="mx_HomePage" url={pageUrl} scrollbar={true} />; return <EmbeddedPage className="mx_HomePage" url={pageUrl} scrollbar={true} />;

View file

@ -1154,7 +1154,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
private leaveRoom(roomId: string): void { private leaveRoom(roomId: string): void {
const roomToLeave = MatrixClientPeg.get().getRoom(roomId); const cli = MatrixClientPeg.get();
const roomToLeave = cli.getRoom(roomId);
const warnings = this.leaveRoomWarnings(roomId); const warnings = this.leaveRoomWarnings(roomId);
const isSpace = roomToLeave?.isSpaceRoom(); const isSpace = roomToLeave?.isSpaceRoom();
@ -1173,9 +1174,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
</span> </span>
), ),
button: _t("Leave"), button: _t("Leave"),
onFinished: (shouldLeave) => { onFinished: async (shouldLeave) => {
if (shouldLeave) { if (shouldLeave) {
leaveRoomBehaviour(roomId); await leaveRoomBehaviour(cli, roomId);
dis.dispatch<AfterLeaveRoomPayload>({ dis.dispatch<AfterLeaveRoomPayload>({
action: Action.AfterLeaveRoom, action: Action.AfterLeaveRoom,
@ -1211,7 +1212,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
private async copyRoom(roomId: string): Promise<void> { private async copyRoom(roomId: string): Promise<void> {
const roomLink = makeRoomPermalink(roomId); const roomLink = makeRoomPermalink(MatrixClientPeg.get(), roomId);
const success = await copyPlaintext(roomLink); const success = await copyPlaintext(roomLink);
if (!success) { if (!success) {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {

View file

@ -743,7 +743,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
lastInSection = lastInSection =
willWantDateSeparator || willWantDateSeparator ||
mxEv.getSender() !== nextEv.getSender() || mxEv.getSender() !== nextEv.getSender() ||
getEventDisplayInfo(nextEv, this.showHiddenEvents).isInfoMessage || getEventDisplayInfo(MatrixClientPeg.get(), nextEv, this.showHiddenEvents).isInfoMessage ||
!shouldFormContinuation(mxEv, nextEv, this.showHiddenEvents, this.context.timelineRenderingType); !shouldFormContinuation(mxEv, nextEv, this.showHiddenEvents, this.context.timelineRenderingType);
} }

View file

@ -561,7 +561,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
createdByCurrentUserTs - lastCreatedByOtherTs < PREVENT_MULTIPLE_JITSI_WITHIN createdByCurrentUserTs - lastCreatedByOtherTs < PREVENT_MULTIPLE_JITSI_WITHIN
) { ) {
// more than one Jitsi widget with the last one from the current user → remove it // more than one Jitsi widget with the last one from the current user → remove it
WidgetUtils.setRoomWidget(this.state.roomId, createdByCurrentUser.id); WidgetUtils.setRoomWidget(this.context.client, this.state.roomId, createdByCurrentUser.id);
} }
} }

View file

@ -549,7 +549,7 @@ const SpaceSetupPrivateInvite: React.FC<{
setBusy(true); setBusy(true);
const targetIds = emailAddresses.map((name) => name.trim()).filter(Boolean); const targetIds = emailAddresses.map((name) => name.trim()).filter(Boolean);
try { try {
const result = await inviteMultipleToRoom(space.roomId, targetIds); const result = await inviteMultipleToRoom(space.client, space.roomId, targetIds);
const failedUsers = Object.keys(result.states).filter((a) => result.states[a] === "error"); const failedUsers = Object.keys(result.states).filter((a) => result.states[a] === "error");
if (failedUsers.length > 0) { if (failedUsers.length > 0) {

View file

@ -110,7 +110,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
} }
private get hasHomePage(): boolean { private get hasHomePage(): boolean {
return !!getHomePageUrl(SdkConfig.get()); return !!getHomePageUrl(SdkConfig.get(), this.context.client!);
} }
private onCurrentVoiceBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null): void => { private onCurrentVoiceBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null): void => {

View file

@ -153,7 +153,9 @@ export default class ViewSource extends React.Component<IProps, IState> {
const isEditing = this.state.isEditing; const isEditing = this.state.isEditing;
const roomId = mxEvent.getRoomId()!; const roomId = mxEvent.getRoomId()!;
const eventId = mxEvent.getId()!; const eventId = mxEvent.getId()!;
const canEdit = mxEvent.isState() ? this.canSendStateEvent(mxEvent) : canEditContent(this.props.mxEvent); const canEdit = mxEvent.isState()
? this.canSendStateEvent(mxEvent)
: canEditContent(MatrixClientPeg.get(), this.props.mxEvent);
return ( return (
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t("View Source")}> <BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t("View Source")}>
<div className="mx_ViewSource_header"> <div className="mx_ViewSource_header">

View file

@ -22,6 +22,7 @@ import SdkConfig from "../../../SdkConfig";
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
import { _t, _td } from "../../../languageHandler"; import { _t, _td } from "../../../languageHandler";
import Field, { IInputProps } from "../elements/Field"; import Field, { IInputProps } from "../elements/Field";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface IProps extends Omit<IInputProps, "onValidate" | "element"> { interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
autoFocus?: boolean; autoFocus?: boolean;
@ -56,7 +57,7 @@ class PassphraseField extends PureComponent<IProps> {
deriveData: async ({ value }): Promise<zxcvbn.ZXCVBNResult | null> => { deriveData: async ({ value }): Promise<zxcvbn.ZXCVBNResult | null> => {
if (!value) return null; if (!value) return null;
const { scorePassword } = await import("../../../utils/PasswordScorer"); const { scorePassword } = await import("../../../utils/PasswordScorer");
return scorePassword(value); return scorePassword(MatrixClientPeg.get(), value);
}, },
rules: [ rules: [
{ {

View file

@ -165,7 +165,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
if (otherUserId && this.props.room.getJoinedMemberCount() === 2) { if (otherUserId && this.props.room.getJoinedMemberCount() === 2) {
// Track presence, if available // Track presence, if available
if (isPresenceEnabled()) { if (isPresenceEnabled(this.props.room.client)) {
this.dmUser = MatrixClientPeg.get().getUser(otherUserId); this.dmUser = MatrixClientPeg.get().getUser(otherUserId);
icon = this.getPresenceIcon(); icon = this.getPresenceIcon();
} }

View file

@ -317,7 +317,12 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
}; };
private onEditClick = (): void => { private onEditClick = (): void => {
editEvent(this.props.mxEvent, this.context.timelineRenderingType, this.props.getRelationsForEvent); editEvent(
MatrixClientPeg.get(),
this.props.mxEvent,
this.context.timelineRenderingType,
this.props.getRelationsForEvent,
);
this.closeMenu(); this.closeMenu();
}; };
@ -617,7 +622,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
} }
let editButton: JSX.Element | undefined; let editButton: JSX.Element | undefined;
if (rightClick && canEditContent(mxEvent)) { if (rightClick && canEditContent(cli, mxEvent)) {
editButton = ( editButton = (
<IconizedContextMenuOption <IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconEdit" iconClassName="mx_MessageContextMenu_iconEdit"

View file

@ -61,7 +61,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
const { room, roomId } = useContext(RoomContext); const { room, roomId } = useContext(RoomContext);
const widgetMessaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(app)); const widgetMessaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(app));
const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId); const canModify = userWidget || WidgetUtils.canUserModifyWidgets(cli, roomId);
let streamAudioStreamButton: JSX.Element | undefined; let streamAudioStreamButton: JSX.Element | undefined;
if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) { if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
@ -138,7 +138,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
button: _t("Delete widget"), button: _t("Delete widget"),
onFinished: (confirmed) => { onFinished: (confirmed) => {
if (!confirmed) return; if (!confirmed) return;
WidgetUtils.setRoomWidget(roomId, app.id); WidgetUtils.setRoomWidget(cli, roomId, app.id);
}, },
}); });
} }

View file

@ -75,9 +75,10 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
joinRule = JoinRule.Restricted; joinRule = JoinRule.Restricted;
} }
const cli = MatrixClientPeg.get();
this.state = { this.state = {
isPublic: this.props.defaultPublic || false, isPublic: this.props.defaultPublic || false,
isEncrypted: this.props.defaultEncrypted ?? privateShouldBeEncrypted(), isEncrypted: this.props.defaultEncrypted ?? privateShouldBeEncrypted(cli),
joinRule, joinRule,
name: this.props.defaultName || "", name: this.props.defaultName || "",
topic: "", topic: "",
@ -88,9 +89,9 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
canChangeEncryption: true, canChangeEncryption: true,
}; };
MatrixClientPeg.get() cli.doesServerForceEncryptionForPreset(Preset.PrivateChat).then((isForced) =>
.doesServerForceEncryptionForPreset(Preset.PrivateChat) this.setState({ canChangeEncryption: !isForced }),
.then((isForced) => this.setState({ canChangeEncryption: !isForced })); );
} }
private roomCreateOptions(): IOpts { private roomCreateOptions(): IOpts {
@ -284,7 +285,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
let e2eeSection: JSX.Element | undefined; let e2eeSection: JSX.Element | undefined;
if (this.state.joinRule !== JoinRule.Public) { if (this.state.joinRule !== JoinRule.Public) {
let microcopy: string; let microcopy: string;
if (privateShouldBeEncrypted()) { if (privateShouldBeEncrypted(MatrixClientPeg.get())) {
if (this.state.canChangeEncryption) { if (this.state.canChangeEncryption) {
microcopy = isVideoRoom microcopy = isVideoRoom
? _t("You can't disable this later. The room will be encrypted but the embedded call will not.") ? _t("You can't disable this later. The room will be encrypted but the embedded call will not.")

View file

@ -407,7 +407,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
} }
public componentDidMount(): void { public componentDidMount(): void {
this.encryptionByDefault = privateShouldBeEncrypted(); this.encryptionByDefault = privateShouldBeEncrypted(MatrixClientPeg.get());
if (this.props.initialText) { if (this.props.initialText) {
this.updateSuggestions(this.props.initialText); this.updateSuggestions(this.props.initialText);
@ -613,7 +613,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
} }
try { try {
const result = await inviteMultipleToRoom(this.props.roomId, targetIds, true); const result = await inviteMultipleToRoom(cli, this.props.roomId, targetIds, true);
if (!this.shouldAbortAfterInviteError(result, room)) { if (!this.shouldAbortAfterInviteError(result, room)) {
// handles setting error message too // handles setting error message too
this.props.onFinished(true); this.props.onFinished(true);
@ -986,7 +986,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
// Update the IS in account data. Actually using it may trigger terms. // Update the IS in account data. Actually using it may trigger terms.
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
setToDefaultIdentityServer(); setToDefaultIdentityServer(MatrixClientPeg.get());
this.setState({ canUseIdentityServer: true, tryingIdentityServer: false }); this.setState({ canUseIdentityServer: true, tryingIdentityServer: false });
}; };
@ -1395,7 +1395,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
</a> </a>
), ),
a: (sub) => ( a: (sub) => (
<a href={makeRoomPermalink(roomId)} rel="noreferrer noopener" target="_blank"> <a href={makeRoomPermalink(cli, roomId)} rel="noreferrer noopener" target="_blank">
{sub} {sub}
</a> </a>
), ),

View file

@ -76,7 +76,7 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
try { try {
this.map = new maplibregl.Map({ this.map = new maplibregl.Map({
container: "mx_LocationPicker_map", container: "mx_LocationPicker_map",
style: findMapStyleUrl(), style: findMapStyleUrl(this.context),
center: [0, 0], center: [0, 0],
zoom: 1, zoom: 1,
}); });

View file

@ -101,7 +101,7 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
private pillifyLinks(): void { private pillifyLinks(): void {
// not present for redacted events // not present for redacted events
if (this.content.current) { if (this.content.current) {
pillifyLinks(this.content.current.children, this.props.mxEvent, this.pills); pillifyLinks(MatrixClientPeg.get(), this.content.current.children, this.props.mxEvent, this.pills);
} }
} }

View file

@ -114,16 +114,18 @@ export default class MKeyVerificationConclusion extends React.Component<IProps>
if (request.done) { if (request.done) {
title = _t("You verified %(name)s", { title = _t("You verified %(name)s", {
name: getNameForEventRoom(request.otherUserId, mxEvent.getRoomId()!), name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!),
}); });
} else if (request.cancelled) { } else if (request.cancelled) {
const userId = request.cancellingUserId; const userId = request.cancellingUserId;
if (userId === myUserId) { if (userId === myUserId) {
title = _t("You cancelled verifying %(name)s", { title = _t("You cancelled verifying %(name)s", {
name: getNameForEventRoom(request.otherUserId, mxEvent.getRoomId()!), name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!),
}); });
} else if (userId) { } else if (userId) {
title = _t("%(name)s cancelled verifying", { name: getNameForEventRoom(userId, mxEvent.getRoomId()!) }); title = _t("%(name)s cancelled verifying", {
name: getNameForEventRoom(client, userId, mxEvent.getRoomId()!),
});
} }
} }
@ -135,7 +137,7 @@ export default class MKeyVerificationConclusion extends React.Component<IProps>
<EventTileBubble <EventTileBubble
className={classes} className={classes}
title={title} title={title}
subtitle={userLabelForEventRoom(request.otherUserId, mxEvent.getRoomId()!)} subtitle={userLabelForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!)}
timestamp={this.props.timestamp} timestamp={this.props.timestamp}
/> />
); );

View file

@ -93,7 +93,9 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
if (userId === myUserId) { if (userId === myUserId) {
return _t("You accepted"); return _t("You accepted");
} else { } else {
return _t("%(name)s accepted", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); return _t("%(name)s accepted", {
name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!),
});
} }
} }
@ -110,14 +112,19 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
} }
} else { } else {
if (declined) { if (declined) {
return _t("%(name)s declined", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); return _t("%(name)s declined", {
name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!),
});
} else { } else {
return _t("%(name)s cancelled", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); return _t("%(name)s cancelled", {
name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!),
});
} }
} }
} }
public render(): React.ReactNode { public render(): React.ReactNode {
const client = MatrixClientPeg.get();
const { mxEvent } = this.props; const { mxEvent } = this.props;
const request = mxEvent.verificationRequest; const request = mxEvent.verificationRequest;
@ -149,9 +156,9 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
} }
if (!request.initiatedByMe) { if (!request.initiatedByMe) {
const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId()!); const name = getNameForEventRoom(client, request.requestingUserId, mxEvent.getRoomId()!);
title = _t("%(name)s wants to verify", { name }); title = _t("%(name)s wants to verify", { name });
subtitle = userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId()!); subtitle = userLabelForEventRoom(client, request.requestingUserId, mxEvent.getRoomId()!);
if (request.canAccept) { if (request.canAccept) {
stateNode = ( stateNode = (
<div className="mx_cryptoEvent_buttons"> <div className="mx_cryptoEvent_buttons">
@ -167,7 +174,7 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
} else { } else {
// request sent by us // request sent by us
title = _t("You sent a verification request"); title = _t("You sent a verification request");
subtitle = userLabelForEventRoom(request.receivingUserId, mxEvent.getRoomId()!); subtitle = userLabelForEventRoom(client, request.receivingUserId, mxEvent.getRoomId()!);
} }
if (title) { if (title) {

View file

@ -363,7 +363,12 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
editEvent(this.props.mxEvent, this.context.timelineRenderingType, this.props.getRelationsForEvent); editEvent(
MatrixClientPeg.get(),
this.props.mxEvent,
this.context.timelineRenderingType,
this.props.getRelationsForEvent,
);
}; };
private readonly forbiddenThreadHeadMsgType = [MsgType.KeyVerificationRequest]; private readonly forbiddenThreadHeadMsgType = [MsgType.KeyVerificationRequest];
@ -424,7 +429,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
public render(): React.ReactNode { public render(): React.ReactNode {
const toolbarOpts: JSX.Element[] = []; const toolbarOpts: JSX.Element[] = [];
if (canEditContent(this.props.mxEvent)) { if (canEditContent(MatrixClientPeg.get(), this.props.mxEvent)) {
toolbarOpts.push( toolbarOpts.push(
<RovingAccessibleTooltipButton <RovingAccessibleTooltipButton
className="mx_MessageActionBar_iconButton" className="mx_MessageActionBar_iconButton"

View file

@ -48,6 +48,7 @@ import { options as linkifyOpts } from "../../../linkify-matrix";
import { getParentEventId } from "../../../utils/Reply"; import { getParentEventId } from "../../../utils/Reply";
import { EditWysiwygComposer } from "../rooms/wysiwyg_composer"; import { EditWysiwygComposer } from "../rooms/wysiwyg_composer";
import { IEventTileOps } from "../rooms/EventTile"; import { IEventTileOps } from "../rooms/EventTile";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
const MAX_HIGHLIGHT_LENGTH = 4096; const MAX_HIGHLIGHT_LENGTH = 4096;
@ -92,7 +93,7 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
this.activateSpoilers([content]); this.activateSpoilers([content]);
HtmlUtils.linkifyElement(content); HtmlUtils.linkifyElement(content);
pillifyLinks([content], this.props.mxEvent, this.pills); pillifyLinks(MatrixClientPeg.get(), [content], this.props.mxEvent, this.pills);
this.calculateUrlPreview(); this.calculateUrlPreview();

View file

@ -108,8 +108,8 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
const [canModifyWidget, setCanModifyWidget] = useState<boolean>(); const [canModifyWidget, setCanModifyWidget] = useState<boolean>();
useEffect(() => { useEffect(() => {
setCanModifyWidget(WidgetUtils.canUserModifyWidgets(room.roomId)); setCanModifyWidget(WidgetUtils.canUserModifyWidgets(room.client, room.roomId));
}, [room.roomId]); }, [room.client, room.roomId]);
const onOpenWidgetClick = (): void => { const onOpenWidgetClick = (): void => {
RightPanelStore.instance.pushCard({ RightPanelStore.instance.pushCard({

View file

@ -456,7 +456,7 @@ export const UserOptionsSection: React.FC<{
const onInviteUserButton = async (ev: ButtonEvent): Promise<void> => { const onInviteUserButton = async (ev: ButtonEvent): Promise<void> => {
try { try {
// We use a MultiInviter to re-use the invite logic, even though we're only inviting one user. // We use a MultiInviter to re-use the invite logic, even though we're only inviting one user.
const inviter = new MultiInviter(roomId || ""); const inviter = new MultiInviter(cli, roomId || "");
await inviter.invite([member.userId]).then(() => { await inviter.invite([member.userId]).then(() => {
if (inviter.getCompletionState(member.userId) !== "invited") { if (inviter.getCompletionState(member.userId) !== "invited") {
const errorStringFromInviterUtility = inviter.getErrorText(member.userId); const errorStringFromInviterUtility = inviter.getErrorText(member.userId);

View file

@ -50,6 +50,7 @@ import { editorRoomKey, editorStateKey } from "../../../Editing";
import DocumentOffset from "../../../editor/offset"; import DocumentOffset from "../../../editor/offset";
import { attachMentions, attachRelation } from "./SendMessageComposer"; import { attachMentions, attachRelation } from "./SendMessageComposer";
import { filterBoolean } from "../../../utils/arrays"; import { filterBoolean } from "../../../utils/arrays";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
function getHtmlReplyFallback(mxEvent: MatrixEvent): string { function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
const html = mxEvent.getContent().formatted_body; const html = mxEvent.getContent().formatted_body;
@ -184,6 +185,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
events: this.events, events: this.events,
isForward: false, isForward: false,
fromEventId: this.props.editState.getEvent().getId(), fromEventId: this.props.editState.getEvent().getId(),
matrixClient: MatrixClientPeg.get(),
}); });
if (previousEvent) { if (previousEvent) {
dis.dispatch({ dis.dispatch({
@ -203,6 +205,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
events: this.events, events: this.events,
isForward: true, isForward: true,
fromEventId: this.props.editState.getEvent().getId(), fromEventId: this.props.editState.getEvent().getId(),
matrixClient: MatrixClientPeg.get(),
}); });
if (nextEvent) { if (nextEvent) {
dis.dispatch({ dis.dispatch({

View file

@ -34,7 +34,6 @@ import dis from "../../../dispatcher/dispatcher";
import { Layout } from "../../../settings/enums/Layout"; import { Layout } from "../../../settings/enums/Layout";
import { formatTime } from "../../../DateUtils"; import { formatTime } from "../../../DateUtils";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { DecryptionFailureBody } from "../messages/DecryptionFailureBody"; import { DecryptionFailureBody } from "../messages/DecryptionFailureBody";
import { E2EState } from "./E2EIcon"; import { E2EState } from "./E2EIcon";
import RoomAvatar from "../avatars/RoomAvatar"; import RoomAvatar from "../avatars/RoomAvatar";
@ -267,7 +266,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
private unmounted = false; private unmounted = false;
public constructor(props: EventTileProps, context: React.ContextType<typeof MatrixClientContext>) { public constructor(props: EventTileProps, context: React.ContextType<typeof RoomContext>) {
super(props, context); super(props, context);
const thread = this.thread; const thread = this.thread;
@ -904,7 +903,12 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
isLeftAlignedBubbleMessage, isLeftAlignedBubbleMessage,
noBubbleEvent, noBubbleEvent,
isSeeingThroughMessageHiddenForModeration, isSeeingThroughMessageHiddenForModeration,
} = getEventDisplayInfo(this.props.mxEvent, this.context.showHiddenEvents, this.shouldHideEvent()); } = getEventDisplayInfo(
MatrixClientPeg.get(),
this.props.mxEvent,
this.context.showHiddenEvents,
this.shouldHideEvent(),
);
const { isQuoteExpanded } = this.state; const { isQuoteExpanded } = this.state;
// This shouldn't happen: the caller should check we support this type // This shouldn't happen: the caller should check we support this type
// before trying to instantiate us // before trying to instantiate us

View file

@ -527,7 +527,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
const continuesLink = replacementRoomId ? ( const continuesLink = replacementRoomId ? (
<a <a
href={makeRoomPermalink(replacementRoomId)} href={makeRoomPermalink(MatrixClientPeg.get(), replacementRoomId)}
className="mx_MessageComposer_roomReplaced_link" className="mx_MessageComposer_roomReplaced_link"
onClick={this.onTombstoneClick} onClick={this.onTombstoneClick}
> >

View file

@ -44,7 +44,7 @@ import { shouldEncryptRoomWithSingle3rdPartyInvite } from "../../../utils/room/s
function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): boolean { function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): boolean {
const isEncrypted: boolean = matrixClient.isRoomEncrypted(room.roomId); const isEncrypted: boolean = matrixClient.isRoomEncrypted(room.roomId);
const isPublic: boolean = room.getJoinRule() === "public"; const isPublic: boolean = room.getJoinRule() === "public";
return isPublic || !privateShouldBeEncrypted() || isEncrypted; return isPublic || !privateShouldBeEncrypted(matrixClient) || isEncrypted;
} }
const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): string => { const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): string => {

View file

@ -34,6 +34,7 @@ import MVoiceMessageBody from "../messages/MVoiceMessageBody";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { renderReplyTile } from "../../../events/EventTileFactory"; import { renderReplyTile } from "../../../events/EventTileFactory";
import { GetRelationsForEvent } from "../rooms/EventTile"; import { GetRelationsForEvent } from "../rooms/EventTile";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
@ -110,6 +111,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
const evType = mxEvent.getType(); const evType = mxEvent.getType();
const { hasRenderer, isInfoMessage, isSeeingThroughMessageHiddenForModeration } = getEventDisplayInfo( const { hasRenderer, isInfoMessage, isSeeingThroughMessageHiddenForModeration } = getEventDisplayInfo(
MatrixClientPeg.get(),
mxEvent, mxEvent,
false /* Replies are never hidden, so this should be fine */, false /* Replies are never hidden, so this should be fine */,
); );

View file

@ -335,6 +335,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
? findEditableEvent({ ? findEditableEvent({
events, events,
isForward: false, isForward: false,
matrixClient: MatrixClientPeg.get(),
}) })
: undefined; : undefined;
if (editEvent) { if (editEvent) {

View file

@ -123,7 +123,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
} }
this.props.setStickerPickerOpen(false); this.props.setStickerPickerOpen(false);
WidgetUtils.removeStickerpickerWidgets() WidgetUtils.removeStickerpickerWidgets(this.props.room.client)
.then(() => { .then(() => {
this.forceUpdate(); this.forceUpdate();
}) })
@ -169,7 +169,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
} }
private updateWidget = (): void => { private updateWidget = (): void => {
const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets()[0]; const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets(this.props.room.client)[0];
if (!stickerpickerWidget) { if (!stickerpickerWidget) {
Stickerpicker.currentWidget = undefined; Stickerpicker.currentWidget = undefined;
this.setState({ stickerpickerWidget: null, widgetId: null }); this.setState({ stickerpickerWidget: null, widgetId: null });

View file

@ -146,8 +146,10 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
}); });
} }
doMaybeLocalRoomAction(this.props.room.roomId, (actualRoomId: string) => doMaybeLocalRoomAction(
MatrixClientPeg.get().sendMessage(actualRoomId, content), this.props.room.roomId,
(actualRoomId: string) => MatrixClientPeg.get().sendMessage(actualRoomId, content),
this.props.room.client,
); );
} catch (e) { } catch (e) {
logger.error("Error sending voice message:", e); logger.error("Error sending voice message:", e);

View file

@ -185,6 +185,7 @@ function dispatchEditEvent(
events: foundEvents, events: foundEvents,
isForward, isForward,
fromEventId: editorStateTransfer?.getEvent().getId(), fromEventId: editorStateTransfer?.getEvent().getId(),
matrixClient: mxClient,
}); });
if (newEvent) { if (newEvent) {
dis.dispatch({ dis.dispatch({

View file

@ -419,7 +419,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
</AccessibleButton>, </AccessibleButton>,
); );
if (!isSecureBackupRequired()) { if (!isSecureBackupRequired(MatrixClientPeg.get())) {
actions.push( actions.push(
<AccessibleButton key="delete" kind="danger" onClick={this.deleteBackup}> <AccessibleButton key="delete" kind="danger" onClick={this.deleteBackup}>
{_t("Delete Backup")} {_t("Delete Backup")}

View file

@ -179,7 +179,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
let save = true; let save = true;
// Double check that the identity server even has terms of service. // Double check that the identity server even has terms of service.
const hasTerms = await doesIdentityServerHaveTerms(fullUrl); const hasTerms = await doesIdentityServerHaveTerms(MatrixClientPeg.get(), fullUrl);
if (!hasTerms) { if (!hasTerms) {
const [confirmed] = await this.showNoTermsWarning(fullUrl); const [confirmed] = await this.showNoTermsWarning(fullUrl);
save = !!confirmed; save = !!confirmed;

View file

@ -316,7 +316,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
); );
let warning; let warning;
if (!privateShouldBeEncrypted()) { if (!privateShouldBeEncrypted(MatrixClientPeg.get())) {
warning = ( warning = (
<div className="mx_SecurityUserSettingsTab_warning"> <div className="mx_SecurityUserSettingsTab_warning">
{_t( {_t(

View file

@ -165,7 +165,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
} else { } else {
const userId = request.otherUserId; const userId = request.otherUserId;
const roomId = request.channel.roomId; const roomId = request.channel.roomId;
description = roomId ? userLabelForEventRoom(userId, roomId) : userId; description = roomId ? userLabelForEventRoom(MatrixClientPeg.get(), userId, roomId) : userId;
// for legacy to_device verification requests // for legacy to_device verification requests
if (description === userId) { if (description === userId) {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();

View file

@ -30,6 +30,7 @@ import EmbeddedPage from "../../structures/EmbeddedPage";
import HomePage from "../../structures/HomePage"; import HomePage from "../../structures/HomePage";
import { UserOnboardingHeader } from "./UserOnboardingHeader"; import { UserOnboardingHeader } from "./UserOnboardingHeader";
import { UserOnboardingList } from "./UserOnboardingList"; import { UserOnboardingList } from "./UserOnboardingList";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
interface Props { interface Props {
justRegistered?: boolean; justRegistered?: boolean;
@ -44,8 +45,9 @@ export function showUserOnboardingPage(useCase: UseCase | null): boolean {
const ANIMATION_DURATION = 2800; const ANIMATION_DURATION = 2800;
export function UserOnboardingPage({ justRegistered = false }: Props): JSX.Element { export function UserOnboardingPage({ justRegistered = false }: Props): JSX.Element {
const cli = useMatrixClientContext();
const config = SdkConfig.get(); const config = SdkConfig.get();
const pageUrl = getHomePageUrl(config); const pageUrl = getHomePageUrl(config, cli);
const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection"); const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection");
const context = useUserOnboardingContext(); const context = useUserOnboardingContext();

View file

@ -36,7 +36,7 @@ export interface MatrixClientProps {
mxClient: MatrixClient; mxClient: MatrixClient;
} }
export function useMatrixClientContext(): MatrixClient | undefined { export function useMatrixClientContext(): MatrixClient {
return useContext(MatrixClientContext); return useContext(MatrixClientContext);
} }

View file

@ -462,7 +462,7 @@ export async function ensureDMExists(client: MatrixClient, userId: string): Prom
roomId = existingDMRoom.roomId; roomId = existingDMRoom.roomId;
} else { } else {
let encryption: boolean | undefined; let encryption: boolean | undefined;
if (privateShouldBeEncrypted()) { if (privateShouldBeEncrypted(client)) {
encryption = await canEncryptToAllUsers(client, [userId]); encryption = await canEncryptToAllUsers(client, [userId]);
} }

View file

@ -115,7 +115,7 @@ export class IntegrationManagers {
private setupAccountManagers(): void { private setupAccountManagers(): void {
if (!this.client || !this.client.getUserId()) return; // not logged in if (!this.client || !this.client.getUserId()) return; // not logged in
const widgets = WidgetUtils.getIntegrationManagerWidgets(); const widgets = WidgetUtils.getIntegrationManagerWidgets(this.client);
widgets.forEach((w) => { widgets.forEach((w) => {
const data = w.content["data"]; const data = w.content["data"];
if (!data) return; if (!data) return;
@ -180,14 +180,6 @@ export class IntegrationManagers {
Modal.createDialog(IntegrationsDisabledDialog); Modal.createDialog(IntegrationsDisabledDialog);
} }
public async overwriteManagerOnAccount(manager: IntegrationManagerInstance): Promise<void> {
// TODO: TravisR - We should be logging out of scalar clients.
await WidgetUtils.removeIntegrationManagerWidgets();
// TODO: TravisR - We should actually be carrying over the discovery response verbatim.
await WidgetUtils.addIntegrationManagerWidget(manager.name, manager.uiUrl, manager.apiUrl);
}
/** /**
* Attempts to discover an integration manager using only its name. This will not validate that * Attempts to discover an integration manager using only its name. This will not validate that
* the integration manager is functional - that is the caller's responsibility. * the integration manager is functional - that is the caller's responsibility.

View file

@ -30,6 +30,7 @@ import dis from "./dispatcher/dispatcher";
import { Action } from "./dispatcher/actions"; import { Action } from "./dispatcher/actions";
import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload"; import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload";
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
import { MatrixClientPeg } from "./MatrixClientPeg";
export enum Type { export enum Type {
URL = "url", URL = "url",
@ -196,7 +197,7 @@ export const options: Opts = {
case Type.RoomAlias: case Type.RoomAlias:
case Type.UserId: case Type.UserId:
default: { default: {
return tryTransformEntityToPermalink(href) ?? ""; return tryTransformEntityToPermalink(MatrixClientPeg.get(), href) ?? "";
} }
} }
}, },

View file

@ -342,7 +342,7 @@ export class JitsiCall extends Call {
} }
public static async create(room: Room): Promise<void> { public static async create(room: Room): Promise<void> {
await WidgetUtils.addJitsiWidget(room.roomId, CallType.Video, "Group call", true, room.name); await WidgetUtils.addJitsiWidget(room.client, room.roomId, CallType.Video, "Group call", true, room.name);
} }
private updateParticipants(): void { private updateParticipants(): void {

View file

@ -22,7 +22,6 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Optional } from "matrix-events-sdk"; import { Optional } from "matrix-events-sdk";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { filterValidMDirect } from "./dm/filterValidMDirect"; import { filterValidMDirect } from "./dm/filterValidMDirect";
/** /**
@ -53,8 +52,8 @@ export default class DMRoomMap {
* Makes and returns a new shared instance that can then be accessed * Makes and returns a new shared instance that can then be accessed
* with shared(). This returned instance is not automatically started. * with shared(). This returned instance is not automatically started.
*/ */
public static makeShared(): DMRoomMap { public static makeShared(matrixClient: MatrixClient): DMRoomMap {
DMRoomMap.sharedInstance = new DMRoomMap(MatrixClientPeg.get()); DMRoomMap.sharedInstance = new DMRoomMap(matrixClient);
return DMRoomMap.sharedInstance; return DMRoomMap.sharedInstance;
} }
@ -175,7 +174,7 @@ export default class DMRoomMap {
} }
const joinedRooms = commonRooms const joinedRooms = commonRooms
.map((r) => MatrixClientPeg.get().getRoom(r)) .map((r) => this.matrixClient.getRoom(r))
.filter((r) => r && r.getMyMembership() === "join"); .filter((r) => r && r.getMyMembership() === "join");
return joinedRooms[0]; return joinedRooms[0];

View file

@ -16,13 +16,13 @@ limitations under the License.
import classnames from "classnames"; import classnames from "classnames";
import { ComponentProps } from "react"; import { ComponentProps } from "react";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import defaultDispatcher from "../dispatcher/dispatcher"; import defaultDispatcher from "../dispatcher/dispatcher";
import { ActionPayload } from "../dispatcher/payloads"; import { ActionPayload } from "../dispatcher/payloads";
import Modal from "../Modal"; import Modal from "../Modal";
import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog";
import ForwardDialog from "../components/views/dialogs/ForwardDialog"; import ForwardDialog from "../components/views/dialogs/ForwardDialog";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { Action } from "../dispatcher/actions"; import { Action } from "../dispatcher/actions";
import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; import ReportEventDialog from "../components/views/dialogs/ReportEventDialog";
import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog"; import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog";
@ -43,18 +43,21 @@ export class DialogOpener {
public static readonly instance = new DialogOpener(); public static readonly instance = new DialogOpener();
private isRegistered = false; private isRegistered = false;
private matrixClient?: MatrixClient;
private constructor() {} private constructor() {}
// We could do this in the constructor, but then we wouldn't have // We could do this in the constructor, but then we wouldn't have
// a function to call from Lifecycle to capture the class. // a function to call from Lifecycle to capture the class.
public prepare(): void { public prepare(matrixClient: MatrixClient): void {
this.matrixClient = matrixClient;
if (this.isRegistered) return; if (this.isRegistered) return;
defaultDispatcher.register(this.onDispatch); defaultDispatcher.register(this.onDispatch);
this.isRegistered = true; this.isRegistered = true;
} }
private onDispatch = (payload: ActionPayload): void => { private onDispatch = (payload: ActionPayload): void => {
if (!this.matrixClient) return;
switch (payload.action) { switch (payload.action) {
case "open_room_settings": case "open_room_settings":
Modal.createDialog( Modal.createDialog(
@ -70,7 +73,7 @@ export class DialogOpener {
break; break;
case Action.OpenForwardDialog: case Action.OpenForwardDialog:
Modal.createDialog(ForwardDialog, { Modal.createDialog(ForwardDialog, {
matrixClient: MatrixClientPeg.get(), matrixClient: this.matrixClient,
event: payload.event, event: payload.event,
permalinkCreator: payload.permalinkCreator, permalinkCreator: payload.permalinkCreator,
}); });

View file

@ -18,11 +18,10 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls"; import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon"; import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { IContent } from "matrix-js-sdk/src/matrix"; import { IContent, MatrixClient } from "matrix-js-sdk/src/matrix";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory"; import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { getMessageModerationState, isLocationEvent, MessageModerationState } from "./EventUtils"; import { getMessageModerationState, isLocationEvent, MessageModerationState } from "./EventUtils";
import { ElementCall } from "../models/Call"; import { ElementCall } from "../models/Call";
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../voice-broadcast"; import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../voice-broadcast";
@ -48,6 +47,7 @@ const calcIsInfoMessage = (
}; };
export function getEventDisplayInfo( export function getEventDisplayInfo(
matrixClient: MatrixClient,
mxEvent: MatrixEvent, mxEvent: MatrixEvent,
showHiddenEvents: boolean, showHiddenEvents: boolean,
hideEvent?: boolean, hideEvent?: boolean,
@ -65,7 +65,7 @@ export function getEventDisplayInfo(
let isSeeingThroughMessageHiddenForModeration = false; let isSeeingThroughMessageHiddenForModeration = false;
if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) {
switch (getMessageModerationState(mxEvent)) { switch (getMessageModerationState(mxEvent, matrixClient)) {
case MessageModerationState.VISIBLE_FOR_ALL: case MessageModerationState.VISIBLE_FOR_ALL:
case MessageModerationState.HIDDEN_TO_CURRENT_USER: case MessageModerationState.HIDDEN_TO_CURRENT_USER:
// Nothing specific to do here // Nothing specific to do here
@ -77,8 +77,7 @@ export function getEventDisplayInfo(
} }
} }
// TODO: Thread a MatrixClient through to here let factory = pickFactory(mxEvent, matrixClient, showHiddenEvents);
let factory = pickFactory(mxEvent, MatrixClientPeg.get(), showHiddenEvents);
// Info messages are basically information about commands processed on a room // Info messages are basically information about commands processed on a room
let isBubbleMessage = let isBubbleMessage =
@ -103,10 +102,8 @@ export function getEventDisplayInfo(
// replace relations (which otherwise would display as a confusing // replace relations (which otherwise would display as a confusing
// duplicate of the thing they are replacing). // duplicate of the thing they are replacing).
if (hideEvent || !haveRendererForEvent(mxEvent, showHiddenEvents)) { if (hideEvent || !haveRendererForEvent(mxEvent, showHiddenEvents)) {
// forcefully ask for a factory for a hidden event (hidden event // forcefully ask for a factory for a hidden event (hidden event setting is checked internally)
// setting is checked internally) factory = pickFactory(mxEvent, matrixClient, showHiddenEvents, true);
// TODO: Thread a MatrixClient through to here
factory = pickFactory(mxEvent, MatrixClientPeg.get(), showHiddenEvents, true);
if (factory === JSONEventFactory) { if (factory === JSONEventFactory) {
isBubbleMessage = false; isBubbleMessage = false;
// Reuse info message avatar and sender profile styling // Reuse info message avatar and sender profile styling

View file

@ -23,7 +23,6 @@ import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon"; import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
import { MatrixClientPeg } from "../MatrixClientPeg";
import shouldHideEvent from "../shouldHideEvent"; import shouldHideEvent from "../shouldHideEvent";
import { GetRelationsForEvent } from "../components/views/rooms/EventTile"; import { GetRelationsForEvent } from "../components/views/rooms/EventTile";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
@ -69,7 +68,7 @@ export function isContentActionable(mxEvent: MatrixEvent): boolean {
return false; return false;
} }
export function canEditContent(mxEvent: MatrixEvent): boolean { export function canEditContent(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean {
const isCancellable = mxEvent.getType() === EventType.RoomMessage || M_POLL_START.matches(mxEvent.getType()); const isCancellable = mxEvent.getType() === EventType.RoomMessage || M_POLL_START.matches(mxEvent.getType());
if ( if (
@ -77,7 +76,7 @@ export function canEditContent(mxEvent: MatrixEvent): boolean {
mxEvent.status === EventStatus.CANCELLED || mxEvent.status === EventStatus.CANCELLED ||
mxEvent.isRedacted() || mxEvent.isRedacted() ||
mxEvent.isRelation(RelationType.Replace) || mxEvent.isRelation(RelationType.Replace) ||
mxEvent.getSender() !== MatrixClientPeg.get().getUserId() mxEvent.getSender() !== matrixClient.getUserId()
) { ) {
return false; return false;
} }
@ -89,22 +88,24 @@ export function canEditContent(mxEvent: MatrixEvent): boolean {
); );
} }
export function canEditOwnEvent(mxEvent: MatrixEvent): boolean { export function canEditOwnEvent(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean {
// for now we only allow editing // for now we only allow editing
// your own events. So this just call through // your own events. So this just call through
// In the future though, moderators will be able to // In the future though, moderators will be able to
// edit other people's messages as well but we don't // edit other people's messages as well but we don't
// want findEditableEvent to return other people's events // want findEditableEvent to return other people's events
// hence this method. // hence this method.
return canEditContent(mxEvent); return canEditContent(matrixClient, mxEvent);
} }
const MAX_JUMP_DISTANCE = 100; const MAX_JUMP_DISTANCE = 100;
export function findEditableEvent({ export function findEditableEvent({
matrixClient,
events, events,
isForward, isForward,
fromEventId, fromEventId,
}: { }: {
matrixClient: MatrixClient;
events: MatrixEvent[]; events: MatrixEvent[];
isForward: boolean; isForward: boolean;
fromEventId?: string; fromEventId?: string;
@ -126,7 +127,7 @@ export function findEditableEvent({
// don't look further than MAX_JUMP_DISTANCE events from `fromEventId` // don't look further than MAX_JUMP_DISTANCE events from `fromEventId`
// to not iterate potentially 1000nds of events on key up/down // to not iterate potentially 1000nds of events on key up/down
endIdx = Math.min(Math.max(0, i + inc * MAX_JUMP_DISTANCE), maxIdx); endIdx = Math.min(Math.max(0, i + inc * MAX_JUMP_DISTANCE), maxIdx);
} else if (foundFromEventId && !shouldHideEvent(e) && canEditOwnEvent(e)) { } else if (foundFromEventId && !shouldHideEvent(e) && canEditOwnEvent(matrixClient, e)) {
// otherwise look for editable event // otherwise look for editable event
return e; return e;
} }
@ -170,9 +171,7 @@ const getMsc3531Enabled = (): boolean => {
* If MSC3531 is deactivated in settings, all messages are considered visible * If MSC3531 is deactivated in settings, all messages are considered visible
* to all. * to all.
*/ */
export function getMessageModerationState(mxEvent: MatrixEvent, client?: MatrixClient): MessageModerationState { export function getMessageModerationState(mxEvent: MatrixEvent, client: MatrixClient): MessageModerationState {
client = client ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing
if (!getMsc3531Enabled()) { if (!getMsc3531Enabled()) {
return MessageModerationState.VISIBLE_FOR_ALL; return MessageModerationState.VISIBLE_FOR_ALL;
} }
@ -246,11 +245,12 @@ export async function fetchInitialEvent(
} }
export function editEvent( export function editEvent(
matrixClient: MatrixClient,
mxEvent: MatrixEvent, mxEvent: MatrixEvent,
timelineRenderingType: TimelineRenderingType, timelineRenderingType: TimelineRenderingType,
getRelationsForEvent?: GetRelationsForEvent, getRelationsForEvent?: GetRelationsForEvent,
): void { ): void {
if (!canEditContent(mxEvent)) return; if (!canEditContent(matrixClient, mxEvent)) return;
if (M_POLL_START.matches(mxEvent.getType())) { if (M_POLL_START.matches(mxEvent.getType())) {
launchPollEditor(mxEvent, getRelationsForEvent); launchPollEditor(mxEvent, getRelationsForEvent);

View file

@ -17,27 +17,27 @@ limitations under the License.
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { HTTPError } from "matrix-js-sdk/src/http-api"; import { HTTPError } from "matrix-js-sdk/src/http-api";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import SdkConfig from "../SdkConfig"; import SdkConfig from "../SdkConfig";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { Policies } from "../Terms"; import { Policies } from "../Terms";
export function getDefaultIdentityServerUrl(): string | undefined { export function getDefaultIdentityServerUrl(): string | undefined {
return SdkConfig.get("validated_server_config")?.isUrl; return SdkConfig.get("validated_server_config")?.isUrl;
} }
export function setToDefaultIdentityServer(): void { export function setToDefaultIdentityServer(matrixClient: MatrixClient): void {
const url = getDefaultIdentityServerUrl(); const url = getDefaultIdentityServerUrl();
// Account data change will update localstorage, client, etc through dispatcher // Account data change will update localstorage, client, etc through dispatcher
MatrixClientPeg.get().setAccountData("m.identity_server", { matrixClient.setAccountData("m.identity_server", {
base_url: url, base_url: url,
}); });
} }
export async function doesIdentityServerHaveTerms(fullUrl: string): Promise<boolean> { export async function doesIdentityServerHaveTerms(matrixClient: MatrixClient, fullUrl: string): Promise<boolean> {
let terms: { policies?: Policies } | null; let terms: { policies?: Policies } | null;
try { try {
terms = await MatrixClientPeg.get().getTerms(SERVICE_TYPES.IS, fullUrl); terms = await matrixClient.getTerms(SERVICE_TYPES.IS, fullUrl);
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);
if (e.cors === "rejected" || (e instanceof HTTPError && e.httpStatus === 404)) { if (e.cors === "rejected" || (e instanceof HTTPError && e.httpStatus === 404)) {
@ -50,7 +50,7 @@ export async function doesIdentityServerHaveTerms(fullUrl: string): Promise<bool
return !!terms?.["policies"] && Object.keys(terms["policies"]).length > 0; return !!terms?.["policies"] && Object.keys(terms["policies"]).length > 0;
} }
export function doesAccountDataHaveIdentityServer(): boolean { export function doesAccountDataHaveIdentityServer(matrixClient: MatrixClient): boolean {
const event = MatrixClientPeg.get().getAccountData("m.identity_server"); const event = matrixClient.getAccountData("m.identity_server");
return event && event.getContent() && event.getContent()["base_url"]; return event?.getContent()["base_url"];
} }

View file

@ -14,18 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { MatrixClientPeg } from "../MatrixClientPeg"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { _t } from "../languageHandler"; import { _t } from "../languageHandler";
export function getNameForEventRoom(userId: string, roomId: string): string { export function getNameForEventRoom(matrixClient: MatrixClient, userId: string, roomId: string): string {
const client = MatrixClientPeg.get(); const room = matrixClient.getRoom(roomId);
const room = client.getRoom(roomId);
const member = room && room.getMember(userId); const member = room && room.getMember(userId);
return member ? member.name : userId; return member ? member.name : userId;
} }
export function userLabelForEventRoom(userId: string, roomId: string): string { export function userLabelForEventRoom(matrixClient: MatrixClient, userId: string, roomId: string): string {
const name = getNameForEventRoom(userId, roomId); const name = getNameForEventRoom(matrixClient, userId, roomId);
if (name !== userId) { if (name !== userId) {
return _t("%(name)s (%(userId)s)", { name, userId }); return _t("%(name)s (%(userId)s)", { name, userId });
} else { } else {

View file

@ -21,7 +21,6 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { HistoryVisibility } from "matrix-js-sdk/src/@types/partials"; import { HistoryVisibility } from "matrix-js-sdk/src/@types/partials";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { AddressType, getAddressType } from "../UserAddress"; import { AddressType, getAddressType } from "../UserAddress";
import { _t } from "../languageHandler"; import { _t } from "../languageHandler";
import Modal from "../Modal"; import Modal from "../Modal";
@ -54,8 +53,6 @@ const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED";
* Invites multiple addresses to a room, handling rate limiting from the server * Invites multiple addresses to a room, handling rate limiting from the server
*/ */
export default class MultiInviter { export default class MultiInviter {
private readonly matrixClient: MatrixClient;
private canceled = false; private canceled = false;
private addresses: string[] = []; private addresses: string[] = [];
private busy = false; private busy = false;
@ -66,12 +63,15 @@ export default class MultiInviter {
private reason: string | undefined; private reason: string | undefined;
/** /**
* @param matrixClient the client of the logged in user
* @param {string} roomId The ID of the room to invite to * @param {string} roomId The ID of the room to invite to
* @param {function} progressCallback optional callback, fired after each invite. * @param {function} progressCallback optional callback, fired after each invite.
*/ */
public constructor(private roomId: string, private readonly progressCallback?: () => void) { public constructor(
this.matrixClient = MatrixClientPeg.get(); private readonly matrixClient: MatrixClient,
} private roomId: string,
private readonly progressCallback?: () => void,
) {}
public get fatal(): boolean { public get fatal(): boolean {
return this._fatal; return this._fatal;

View file

@ -15,8 +15,8 @@ limitations under the License.
*/ */
import zxcvbn, { ZXCVBNFeedbackWarning } from "zxcvbn"; import zxcvbn, { ZXCVBNFeedbackWarning } from "zxcvbn";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { _t, _td } from "../languageHandler"; import { _t, _td } from "../languageHandler";
const ZXCVBN_USER_INPUTS = ["riot", "matrix"]; const ZXCVBN_USER_INPUTS = ["riot", "matrix"];
@ -58,14 +58,15 @@ _td("Short keyboard patterns are easy to guess");
* (obviously) which is large. * (obviously) which is large.
* *
* @param {string} password Password to score * @param {string} password Password to score
* @param matrixClient the client of the logged in user, if any
* @returns {object} Score result with `score` and `feedback` properties * @returns {object} Score result with `score` and `feedback` properties
*/ */
export function scorePassword(password: string): zxcvbn.ZXCVBNResult | null { export function scorePassword(matrixClient: MatrixClient | undefined, password: string): zxcvbn.ZXCVBNResult | null {
if (password.length === 0) return null; if (password.length === 0) return null;
const userInputs = ZXCVBN_USER_INPUTS.slice(); const userInputs = ZXCVBN_USER_INPUTS.slice();
if (MatrixClientPeg.get()) { if (matrixClient) {
userInputs.push(MatrixClientPeg.get().getUserIdLocalpart()!); userInputs.push(matrixClient.getUserIdLocalpart()!);
} }
let zxcvbnResult = zxcvbn(password, userInputs); let zxcvbnResult = zxcvbn(password, userInputs);

View file

@ -118,7 +118,7 @@ export async function upgradeRoom(
if (toInvite.length > 0) { if (toInvite.length > 0) {
// Errors are handled internally to this function // Errors are handled internally to this function
await inviteUsersToRoom(newRoomId, toInvite, false, () => { await inviteUsersToRoom(cli, newRoomId, toInvite, false, () => {
progress.inviteUsersProgress!++; progress.inviteUsersProgress!++;
progressCallback?.(progress); progressCallback?.(progress);
}); });

View file

@ -14,11 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { IClientWellKnown } from "matrix-js-sdk/src/client"; import { IClientWellKnown, MatrixClient } from "matrix-js-sdk/src/client";
import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue"; import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue";
import { MatrixClientPeg } from "../MatrixClientPeg";
const CALL_BEHAVIOUR_WK_KEY = "io.element.call_behaviour"; const CALL_BEHAVIOUR_WK_KEY = "io.element.call_behaviour";
const E2EE_WK_KEY = "io.element.e2ee"; const E2EE_WK_KEY = "io.element.e2ee";
const E2EE_WK_KEY_DEPRECATED = "im.vector.riot.e2ee"; const E2EE_WK_KEY_DEPRECATED = "im.vector.riot.e2ee";
@ -45,13 +43,13 @@ export interface IEmbeddedPagesWellKnown {
} }
/* eslint-enable camelcase */ /* eslint-enable camelcase */
export function getCallBehaviourWellKnown(): ICallBehaviourWellKnown { export function getCallBehaviourWellKnown(matrixClient: MatrixClient): ICallBehaviourWellKnown {
const clientWellKnown = MatrixClientPeg.get().getClientWellKnown(); const clientWellKnown = matrixClient.getClientWellKnown();
return clientWellKnown?.[CALL_BEHAVIOUR_WK_KEY]; return clientWellKnown?.[CALL_BEHAVIOUR_WK_KEY];
} }
export function getE2EEWellKnown(): IE2EEWellKnown | null { export function getE2EEWellKnown(matrixClient: MatrixClient): IE2EEWellKnown | null {
const clientWellKnown = MatrixClientPeg.get().getClientWellKnown(); const clientWellKnown = matrixClient.getClientWellKnown();
if (clientWellKnown?.[E2EE_WK_KEY]) { if (clientWellKnown?.[E2EE_WK_KEY]) {
return clientWellKnown[E2EE_WK_KEY]; return clientWellKnown[E2EE_WK_KEY];
} }
@ -61,24 +59,24 @@ export function getE2EEWellKnown(): IE2EEWellKnown | null {
return null; return null;
} }
export function getTileServerWellKnown(): ITileServerWellKnown | undefined { export function getTileServerWellKnown(matrixClient: MatrixClient): ITileServerWellKnown | undefined {
return tileServerFromWellKnown(MatrixClientPeg.get().getClientWellKnown()); return tileServerFromWellKnown(matrixClient.getClientWellKnown());
} }
export function tileServerFromWellKnown(clientWellKnown?: IClientWellKnown | undefined): ITileServerWellKnown { export function tileServerFromWellKnown(clientWellKnown?: IClientWellKnown | undefined): ITileServerWellKnown {
return clientWellKnown?.[TILE_SERVER_WK_KEY.name] ?? clientWellKnown?.[TILE_SERVER_WK_KEY.altName]; return clientWellKnown?.[TILE_SERVER_WK_KEY.name] ?? clientWellKnown?.[TILE_SERVER_WK_KEY.altName];
} }
export function getEmbeddedPagesWellKnown(): IEmbeddedPagesWellKnown | undefined { export function getEmbeddedPagesWellKnown(matrixClient: MatrixClient | undefined): IEmbeddedPagesWellKnown | undefined {
return embeddedPagesFromWellKnown(MatrixClientPeg.get()?.getClientWellKnown()); return embeddedPagesFromWellKnown(matrixClient?.getClientWellKnown());
} }
export function embeddedPagesFromWellKnown(clientWellKnown?: IClientWellKnown): IEmbeddedPagesWellKnown { export function embeddedPagesFromWellKnown(clientWellKnown?: IClientWellKnown): IEmbeddedPagesWellKnown {
return clientWellKnown?.[EMBEDDED_PAGES_WK_PROPERTY]; return clientWellKnown?.[EMBEDDED_PAGES_WK_PROPERTY];
} }
export function isSecureBackupRequired(): boolean { export function isSecureBackupRequired(matrixClient: MatrixClient): boolean {
return getE2EEWellKnown()?.["secure_backup_required"] === true; return getE2EEWellKnown(matrixClient)?.["secure_backup_required"] === true;
} }
export enum SecureBackupSetupMethod { export enum SecureBackupSetupMethod {
@ -86,8 +84,8 @@ export enum SecureBackupSetupMethod {
Passphrase = "passphrase", Passphrase = "passphrase",
} }
export function getSecureBackupSetupMethods(): SecureBackupSetupMethod[] { export function getSecureBackupSetupMethods(matrixClient: MatrixClient): SecureBackupSetupMethod[] {
const wellKnown = getE2EEWellKnown(); const wellKnown = getE2EEWellKnown(matrixClient);
if ( if (
!wellKnown || !wellKnown ||
!wellKnown["secure_backup_setup_methods"] || !wellKnown["secure_backup_setup_methods"] ||

View file

@ -20,11 +20,10 @@ import { IWidget, IWidgetData } from "matrix-widget-api";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { ClientEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { ClientEvent, MatrixClient, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { CallType } from "matrix-js-sdk/src/webrtc/call"; import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { randomString, randomLowercaseString, randomUppercaseString } from "matrix-js-sdk/src/randomstring"; import { randomString, randomLowercaseString, randomUppercaseString } from "matrix-js-sdk/src/randomstring";
import { MatrixClientPeg } from "../MatrixClientPeg";
import PlatformPeg from "../PlatformPeg"; import PlatformPeg from "../PlatformPeg";
import SdkConfig from "../SdkConfig"; import SdkConfig from "../SdkConfig";
import dis from "../dispatcher/dispatcher"; import dis from "../dispatcher/dispatcher";
@ -55,19 +54,20 @@ export interface UserWidget extends Omit<IWidgetEvent, "content"> {
} }
export default class WidgetUtils { export default class WidgetUtils {
/* Returns true if user is able to send state events to modify widgets in this room /**
* Returns true if user is able to send state events to modify widgets in this room
* (Does not apply to non-room-based / user widgets) * (Does not apply to non-room-based / user widgets)
* @param client The matrix client of the logged-in user
* @param roomId -- The ID of the room to check * @param roomId -- The ID of the room to check
* @return Boolean -- true if the user can modify widgets in this room * @return Boolean -- true if the user can modify widgets in this room
* @throws Error -- specifies the error reason * @throws Error -- specifies the error reason
*/ */
public static canUserModifyWidgets(roomId?: string): boolean { public static canUserModifyWidgets(client: MatrixClient, roomId?: string): boolean {
if (!roomId) { if (!roomId) {
logger.warn("No room ID specified"); logger.warn("No room ID specified");
return false; return false;
} }
const client = MatrixClientPeg.get();
if (!client) { if (!client) {
logger.warn("User must be be logged in"); logger.warn("User must be be logged in");
return false; return false;
@ -79,7 +79,7 @@ export default class WidgetUtils {
return false; return false;
} }
const me = client.credentials.userId; const me = client.getUserId();
if (!me) { if (!me) {
logger.warn("Failed to get user ID"); logger.warn("Failed to get user ID");
return false; return false;
@ -97,6 +97,7 @@ export default class WidgetUtils {
// TODO: Generify the name of this function. It's not just scalar. // TODO: Generify the name of this function. It's not just scalar.
/** /**
* Returns true if specified url is a scalar URL, typically https://scalar.vector.im/api * Returns true if specified url is a scalar URL, typically https://scalar.vector.im/api
* @param matrixClient The matrix client of the logged-in user
* @param {[type]} testUrlString URL to check * @param {[type]} testUrlString URL to check
* @return {Boolean} True if specified URL is a scalar URL * @return {Boolean} True if specified URL is a scalar URL
*/ */
@ -138,13 +139,14 @@ export default class WidgetUtils {
* ID has been added as a user widget (ie. the accountData event * ID has been added as a user widget (ie. the accountData event
* arrives) or rejects after a timeout * arrives) or rejects after a timeout
* *
* @param {string} widgetId The ID of the widget to wait for * @param client The matrix client of the logged-in user
* @param {boolean} add True to wait for the widget to be added, * @param widgetId The ID of the widget to wait for
* @param add True to wait for the widget to be added,
* false to wait for it to be deleted. * false to wait for it to be deleted.
* @returns {Promise} that resolves when the widget is in the * @returns {Promise} that resolves when the widget is in the
* requested state according to the `add` param * requested state according to the `add` param
*/ */
public static waitForUserWidget(widgetId: string, add: boolean): Promise<void> { public static waitForUserWidget(client: MatrixClient, widgetId: string, add: boolean): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Tests an account data event, returning true if it's in the state // Tests an account data event, returning true if it's in the state
// we're waiting for it to be in // we're waiting for it to be in
@ -157,25 +159,25 @@ export default class WidgetUtils {
} }
} }
const startingAccountDataEvent = MatrixClientPeg.get().getAccountData("m.widgets"); const startingAccountDataEvent = client.getAccountData("m.widgets");
if (eventInIntendedState(startingAccountDataEvent)) { if (eventInIntendedState(startingAccountDataEvent)) {
resolve(); resolve();
return; return;
} }
function onAccountData(ev: MatrixEvent): void { function onAccountData(ev: MatrixEvent): void {
const currentAccountDataEvent = MatrixClientPeg.get().getAccountData("m.widgets"); const currentAccountDataEvent = client.getAccountData("m.widgets");
if (eventInIntendedState(currentAccountDataEvent)) { if (eventInIntendedState(currentAccountDataEvent)) {
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, onAccountData); client.removeListener(ClientEvent.AccountData, onAccountData);
clearTimeout(timerId); clearTimeout(timerId);
resolve(); resolve();
} }
} }
const timerId = window.setTimeout(() => { const timerId = window.setTimeout(() => {
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, onAccountData); client.removeListener(ClientEvent.AccountData, onAccountData);
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear"));
}, WIDGET_WAIT_TIME); }, WIDGET_WAIT_TIME);
MatrixClientPeg.get().on(ClientEvent.AccountData, onAccountData); client.on(ClientEvent.AccountData, onAccountData);
}); });
} }
@ -184,6 +186,7 @@ export default class WidgetUtils {
* ID has been added as a room widget in the given room (ie. the * ID has been added as a room widget in the given room (ie. the
* room state event arrives) or rejects after a timeout * room state event arrives) or rejects after a timeout
* *
* @param client The matrix client of the logged-in user
* @param {string} widgetId The ID of the widget to wait for * @param {string} widgetId The ID of the widget to wait for
* @param {string} roomId The ID of the room to wait for the widget in * @param {string} roomId The ID of the room to wait for the widget in
* @param {boolean} add True to wait for the widget to be added, * @param {boolean} add True to wait for the widget to be added,
@ -191,7 +194,12 @@ export default class WidgetUtils {
* @returns {Promise} that resolves when the widget is in the * @returns {Promise} that resolves when the widget is in the
* requested state according to the `add` param * requested state according to the `add` param
*/ */
public static waitForRoomWidget(widgetId: string, roomId: string, add: boolean): Promise<void> { public static waitForRoomWidget(
client: MatrixClient,
widgetId: string,
roomId: string,
add: boolean,
): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Tests a list of state events, returning true if it's in the state // Tests a list of state events, returning true if it's in the state
// we're waiting for it to be in // we're waiting for it to be in
@ -206,7 +214,7 @@ export default class WidgetUtils {
} }
} }
const room = MatrixClientPeg.get().getRoom(roomId); const room = client.getRoom(roomId);
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
const startingWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets"); const startingWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets");
if (eventsInIntendedState(startingWidgetEvents)) { if (eventsInIntendedState(startingWidgetEvents)) {
@ -221,30 +229,30 @@ export default class WidgetUtils {
const currentWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets"); const currentWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets");
if (eventsInIntendedState(currentWidgetEvents)) { if (eventsInIntendedState(currentWidgetEvents)) {
MatrixClientPeg.get().removeListener(RoomStateEvent.Events, onRoomStateEvents); client.removeListener(RoomStateEvent.Events, onRoomStateEvents);
clearTimeout(timerId); clearTimeout(timerId);
resolve(); resolve();
} }
} }
const timerId = window.setTimeout(() => { const timerId = window.setTimeout(() => {
MatrixClientPeg.get().removeListener(RoomStateEvent.Events, onRoomStateEvents); client.removeListener(RoomStateEvent.Events, onRoomStateEvents);
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear"));
}, WIDGET_WAIT_TIME); }, WIDGET_WAIT_TIME);
MatrixClientPeg.get().on(RoomStateEvent.Events, onRoomStateEvents); client.on(RoomStateEvent.Events, onRoomStateEvents);
}); });
} }
public static setUserWidget( public static setUserWidget(
client: MatrixClient,
widgetId: string, widgetId: string,
widgetType: WidgetType, widgetType: WidgetType,
widgetUrl: string, widgetUrl: string,
widgetName: string, widgetName: string,
widgetData: IWidgetData, widgetData: IWidgetData,
): Promise<void> { ): Promise<void> {
const client = MatrixClientPeg.get();
// Get the current widgets and clone them before we modify them, otherwise // Get the current widgets and clone them before we modify them, otherwise
// we'll modify the content of the old event. // we'll modify the content of the old event.
const userWidgets = objectClone(WidgetUtils.getUserWidgets()); const userWidgets = objectClone(WidgetUtils.getUserWidgets(client));
// Delete existing widget with ID // Delete existing widget with ID
try { try {
@ -284,7 +292,7 @@ export default class WidgetUtils {
return client return client
.setAccountData("m.widgets", userWidgets) .setAccountData("m.widgets", userWidgets)
.then(() => { .then(() => {
return WidgetUtils.waitForUserWidget(widgetId, addingWidget); return WidgetUtils.waitForUserWidget(client, widgetId, addingWidget);
}) })
.then(() => { .then(() => {
dis.dispatch({ action: "user_widget_updated" }); dis.dispatch({ action: "user_widget_updated" });
@ -292,6 +300,7 @@ export default class WidgetUtils {
} }
public static setRoomWidget( public static setRoomWidget(
client: MatrixClient,
roomId: string, roomId: string,
widgetId: string, widgetId: string,
widgetType?: WidgetType, widgetType?: WidgetType,
@ -318,20 +327,24 @@ export default class WidgetUtils {
content = {}; content = {};
} }
return WidgetUtils.setRoomWidgetContent(roomId, widgetId, content as IWidget); return WidgetUtils.setRoomWidgetContent(client, roomId, widgetId, content as IWidget);
} }
public static setRoomWidgetContent(roomId: string, widgetId: string, content: IWidget): Promise<void> { public static setRoomWidgetContent(
client: MatrixClient,
roomId: string,
widgetId: string,
content: IWidget,
): Promise<void> {
const addingWidget = !!content.url; const addingWidget = !!content.url;
WidgetEchoStore.setRoomWidgetEcho(roomId, widgetId, content); WidgetEchoStore.setRoomWidgetEcho(roomId, widgetId, content);
const client = MatrixClientPeg.get();
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
return client return client
.sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId) .sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId)
.then(() => { .then(() => {
return WidgetUtils.waitForRoomWidget(widgetId, roomId, addingWidget); return WidgetUtils.waitForRoomWidget(client, widgetId, roomId, addingWidget);
}) })
.finally(() => { .finally(() => {
WidgetEchoStore.removeRoomWidgetEcho(roomId, widgetId); WidgetEchoStore.removeRoomWidgetEcho(roomId, widgetId);
@ -357,10 +370,10 @@ export default class WidgetUtils {
/** /**
* Get user specific widgets (not linked to a specific room) * Get user specific widgets (not linked to a specific room)
* @param client The matrix client of the logged-in user
* @return {object} Event content object containing current / active user widgets * @return {object} Event content object containing current / active user widgets
*/ */
public static getUserWidgets(): Record<string, UserWidget> { public static getUserWidgets(client: MatrixClient | undefined): Record<string, UserWidget> {
const client = MatrixClientPeg.get();
if (!client) { if (!client) {
throw new Error("User not logged in"); throw new Error("User not logged in");
} }
@ -373,27 +386,30 @@ export default class WidgetUtils {
/** /**
* Get user specific widgets (not linked to a specific room) as an array * Get user specific widgets (not linked to a specific room) as an array
* @param client The matrix client of the logged-in user
* @return {[object]} Array containing current / active user widgets * @return {[object]} Array containing current / active user widgets
*/ */
public static getUserWidgetsArray(): UserWidget[] { public static getUserWidgetsArray(client: MatrixClient | undefined): UserWidget[] {
return Object.values(WidgetUtils.getUserWidgets()); return Object.values(WidgetUtils.getUserWidgets(client));
} }
/** /**
* Get active stickerpicker widgets (stickerpickers are user widgets by nature) * Get active stickerpicker widgets (stickerpickers are user widgets by nature)
* @param client The matrix client of the logged-in user
* @return {[object]} Array containing current / active stickerpicker widgets * @return {[object]} Array containing current / active stickerpicker widgets
*/ */
public static getStickerpickerWidgets(): UserWidget[] { public static getStickerpickerWidgets(client: MatrixClient | undefined): UserWidget[] {
const widgets = WidgetUtils.getUserWidgetsArray(); const widgets = WidgetUtils.getUserWidgetsArray(client);
return widgets.filter((widget) => widget.content?.type === "m.stickerpicker"); return widgets.filter((widget) => widget.content?.type === "m.stickerpicker");
} }
/** /**
* Get all integration manager widgets for this user. * Get all integration manager widgets for this user.
* @param client The matrix client of the logged-in user
* @returns {Object[]} An array of integration manager user widgets. * @returns {Object[]} An array of integration manager user widgets.
*/ */
public static getIntegrationManagerWidgets(): UserWidget[] { public static getIntegrationManagerWidgets(client: MatrixClient | undefined): UserWidget[] {
const widgets = WidgetUtils.getUserWidgetsArray(); const widgets = WidgetUtils.getUserWidgetsArray(client);
return widgets.filter((w) => w.content?.type === "m.integration_manager"); return widgets.filter((w) => w.content?.type === "m.integration_manager");
} }
@ -405,8 +421,7 @@ export default class WidgetUtils {
}); });
} }
public static async removeIntegrationManagerWidgets(): Promise<void> { public static async removeIntegrationManagerWidgets(client: MatrixClient | undefined): Promise<void> {
const client = MatrixClientPeg.get();
if (!client) { if (!client) {
throw new Error("User not logged in"); throw new Error("User not logged in");
} }
@ -421,8 +436,14 @@ export default class WidgetUtils {
await client.setAccountData("m.widgets", userWidgets); await client.setAccountData("m.widgets", userWidgets);
} }
public static addIntegrationManagerWidget(name: string, uiUrl: string, apiUrl: string): Promise<void> { public static addIntegrationManagerWidget(
client: MatrixClient,
name: string,
uiUrl: string,
apiUrl: string,
): Promise<void> {
return WidgetUtils.setUserWidget( return WidgetUtils.setUserWidget(
client,
"integration_manager_" + new Date().getTime(), "integration_manager_" + new Date().getTime(),
WidgetType.INTEGRATION_MANAGER, WidgetType.INTEGRATION_MANAGER,
uiUrl, uiUrl,
@ -433,10 +454,10 @@ export default class WidgetUtils {
/** /**
* Remove all stickerpicker widgets (stickerpickers are user widgets by nature) * Remove all stickerpicker widgets (stickerpickers are user widgets by nature)
* @param client The matrix client of the logged-in user
* @return {Promise} Resolves on account data updated * @return {Promise} Resolves on account data updated
*/ */
public static async removeStickerpickerWidgets(): Promise<void> { public static async removeStickerpickerWidgets(client: MatrixClient | undefined): Promise<void> {
const client = MatrixClientPeg.get();
if (!client) { if (!client) {
throw new Error("User not logged in"); throw new Error("User not logged in");
} }
@ -452,6 +473,7 @@ export default class WidgetUtils {
} }
public static async addJitsiWidget( public static async addJitsiWidget(
client: MatrixClient,
roomId: string, roomId: string,
type: CallType, type: CallType,
name: string, name: string,
@ -462,7 +484,7 @@ export default class WidgetUtils {
const auth = (await Jitsi.getInstance().getJitsiAuth()) ?? undefined; const auth = (await Jitsi.getInstance().getJitsiAuth()) ?? undefined;
const widgetId = randomString(24); // Must be globally unique const widgetId = randomString(24); // Must be globally unique
let confId; let confId: string;
if (auth === "openidtoken-jwt") { if (auth === "openidtoken-jwt") {
// Create conference ID from room ID // Create conference ID from room ID
// For compatibility with Jitsi, use base32 without padding. // For compatibility with Jitsi, use base32 without padding.
@ -479,9 +501,9 @@ export default class WidgetUtils {
widgetUrl.search = ""; // Causes the URL class use searchParams instead widgetUrl.search = ""; // Causes the URL class use searchParams instead
widgetUrl.searchParams.set("confId", confId); widgetUrl.searchParams.set("confId", confId);
await WidgetUtils.setRoomWidget(roomId, widgetId, WidgetType.JITSI, widgetUrl.toString(), name, { await WidgetUtils.setRoomWidget(client, roomId, widgetId, WidgetType.JITSI, widgetUrl.toString(), name, {
conferenceId: confId, conferenceId: confId,
roomName: oobRoomName ?? MatrixClientPeg.get().getRoom(roomId)?.name, roomName: oobRoomName ?? client.getRoom(roomId)?.name,
isAudioOnly: type === CallType.Voice, isAudioOnly: type === CallType.Voice,
isVideoChannel, isVideoChannel,
domain, domain,

View file

@ -51,7 +51,7 @@ export async function startDmOnFirstMessage(client: MatrixClient, targets: Membe
return existingRoom.roomId; return existingRoom.roomId;
} }
if (targets.length === 1 && targets[0] instanceof ThreepidMember && privateShouldBeEncrypted()) { if (targets.length === 1 && targets[0] instanceof ThreepidMember && privateShouldBeEncrypted(client)) {
// Single 3rd-party invite and well-known promotes encryption: // Single 3rd-party invite and well-known promotes encryption:
// Directly create a room and invite the other. // Directly create a room and invite the other.
return await startDm(client, targets); return await startDm(client, targets);
@ -192,7 +192,7 @@ export interface IDMUserTileProps {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
export async function determineCreateRoomEncryptionOption(client: MatrixClient, targets: Member[]): Promise<boolean> { export async function determineCreateRoomEncryptionOption(client: MatrixClient, targets: Member[]): Promise<boolean> {
if (privateShouldBeEncrypted()) { if (privateShouldBeEncrypted(client)) {
// Enable encryption for a single 3rd party invite. // Enable encryption for a single 3rd party invite.
if (targets.length === 1 && targets[0] instanceof ThreepidMember) return true; if (targets.length === 1 && targets[0] instanceof ThreepidMember) return true;

View file

@ -16,13 +16,11 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Direction } from "matrix-js-sdk/src/models/event-timeline"; import { Direction } from "matrix-js-sdk/src/models/event-timeline";
import { saveAs } from "file-saver"; import { saveAs } from "file-saver";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import sanitizeFilename from "sanitize-filename"; import sanitizeFilename from "sanitize-filename";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { ExportType, IExportOptions } from "./exportUtils"; import { ExportType, IExportOptions } from "./exportUtils";
import { decryptFile } from "../DecryptFile"; import { decryptFile } from "../DecryptFile";
import { mediaFromContent } from "../../customisations/Media"; import { mediaFromContent } from "../../customisations/Media";
@ -39,7 +37,6 @@ type BlobFile = {
export default abstract class Exporter { export default abstract class Exporter {
protected files: BlobFile[] = []; protected files: BlobFile[] = [];
protected client: MatrixClient;
protected cancelled = false; protected cancelled = false;
protected constructor( protected constructor(
@ -56,7 +53,6 @@ export default abstract class Exporter {
) { ) {
throw new Error("Invalid export options"); throw new Error("Invalid export options");
} }
this.client = MatrixClientPeg.get();
window.addEventListener("beforeunload", this.onBeforeUnload); window.addEventListener("beforeunload", this.onBeforeUnload);
} }
@ -124,7 +120,7 @@ export default abstract class Exporter {
} }
protected setEventMetadata(event: MatrixEvent): MatrixEvent { protected setEventMetadata(event: MatrixEvent): MatrixEvent {
const roomState = this.client.getRoom(this.room.roomId)?.currentState; const roomState = this.room.currentState;
const sender = event.getSender(); const sender = event.getSender();
event.sender = (!!sender && roomState?.getSentinelMember(sender)) || null; event.sender = (!!sender && roomState?.getSentinelMember(sender)) || null;
if (event.getType() === "m.room.member") { if (event.getType() === "m.room.member") {
@ -151,7 +147,7 @@ export default abstract class Exporter {
} }
protected async getRequiredEvents(): Promise<MatrixEvent[]> { protected async getRequiredEvents(): Promise<MatrixEvent[]> {
const eventMapper = this.client.getEventMapper(); const eventMapper = this.room.client.getEventMapper();
let prevToken: string | null = null; let prevToken: string | null = null;
let limit = this.getLimit(); let limit = this.getLimit();
@ -159,7 +155,7 @@ export default abstract class Exporter {
while (limit) { while (limit) {
const eventsPerCrawl = Math.min(limit, 1000); const eventsPerCrawl = Math.min(limit, 1000);
const res = await this.client.createMessagesRequest( const res = await this.room.client.createMessagesRequest(
this.room.roomId, this.room.roomId,
prevToken, prevToken,
eventsPerCrawl, eventsPerCrawl,
@ -211,7 +207,7 @@ export default abstract class Exporter {
const decryptionPromises = events const decryptionPromises = events
.filter((event) => event.isEncrypted()) .filter((event) => event.isEncrypted())
.map((event) => { .map((event) => {
return this.client.decryptEventIfNeeded(event, { return this.room.client.decryptEventIfNeeded(event, {
isRetry: true, isRetry: true,
emit: false, emit: false,
}); });

View file

@ -94,7 +94,7 @@ export default class HTMLExporter extends Exporter {
const exportDate = formatFullDateNoDayNoTime(new Date()); const exportDate = formatFullDateNoDayNoTime(new Date());
const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender(); const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
const creatorName = (creator ? this.room.getMember(creator)?.rawDisplayName : creator) || creator; const creatorName = (creator ? this.room.getMember(creator)?.rawDisplayName : creator) || creator;
const exporter = this.client.getUserId()!; const exporter = this.room.client.getSafeUserId();
const exporterName = this.room.getMember(exporter)?.rawDisplayName; const exporterName = this.room.getMember(exporter)?.rawDisplayName;
const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || ""; const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || "";
const createdText = _t("%(creatorName)s created this room.", { const createdText = _t("%(creatorName)s created this room.", {
@ -282,7 +282,7 @@ export default class HTMLExporter extends Exporter {
public getEventTile(mxEv: MatrixEvent, continuation: boolean): JSX.Element { public getEventTile(mxEv: MatrixEvent, continuation: boolean): JSX.Element {
return ( return (
<div className="mx_Export_EventWrapper" id={mxEv.getId()}> <div className="mx_Export_EventWrapper" id={mxEv.getId()}>
<MatrixClientContext.Provider value={this.client}> <MatrixClientContext.Provider value={this.room.client}>
<EventTile <EventTile
mxEvent={mxEv} mxEvent={mxEv}
continuation={continuation} continuation={continuation}

View file

@ -47,7 +47,7 @@ export default class JSONExporter extends Exporter {
const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender(); const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
const creatorName = (creator && this.room?.getMember(creator)?.rawDisplayName) || creator; const creatorName = (creator && this.room?.getMember(creator)?.rawDisplayName) || creator;
const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || ""; const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || "";
const exporter = this.client.getUserId()!; const exporter = this.room.client.getUserId()!;
const exporterName = this.room?.getMember(exporter)?.rawDisplayName || exporter; const exporterName = this.room?.getMember(exporter)?.rawDisplayName || exporter;
const jsonObject = { const jsonObject = {
room_name: this.room.name, room_name: this.room.name,

View file

@ -19,11 +19,10 @@ import React, { ReactNode } from "react";
import { EventStatus } from "matrix-js-sdk/src/models/event-status"; import { EventStatus } from "matrix-js-sdk/src/models/event-status";
import { MatrixEventEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixError } from "matrix-js-sdk/src/matrix"; import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import Modal, { IHandle } from "../Modal"; import Modal, { IHandle } from "../Modal";
import Spinner from "../components/views/elements/Spinner"; import Spinner from "../components/views/elements/Spinner";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { _t } from "../languageHandler"; import { _t } from "../languageHandler";
import ErrorDialog from "../components/views/dialogs/ErrorDialog"; import ErrorDialog from "../components/views/dialogs/ErrorDialog";
import { isMetaSpace } from "../stores/spaces"; import { isMetaSpace } from "../stores/spaces";
@ -38,15 +37,19 @@ import { bulkSpaceBehaviour } from "./space";
import { SdkContextClass } from "../contexts/SDKContext"; import { SdkContextClass } from "../contexts/SDKContext";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = true): Promise<void> { export async function leaveRoomBehaviour(
matrixClient: MatrixClient,
roomId: string,
retry = true,
spinner = true,
): Promise<void> {
let spinnerModal: IHandle<any> | undefined; let spinnerModal: IHandle<any> | undefined;
if (spinner) { if (spinner) {
spinnerModal = Modal.createDialog(Spinner, undefined, "mx_Dialog_spinner"); spinnerModal = Modal.createDialog(Spinner, undefined, "mx_Dialog_spinner");
} }
const cli = MatrixClientPeg.get();
let leavingAllVersions = true; let leavingAllVersions = true;
const history = cli.getRoomUpgradeHistory( const history = matrixClient.getRoomUpgradeHistory(
roomId, roomId,
false, false,
SettingsStore.getValue("feature_dynamic_room_predecessors"), SettingsStore.getValue("feature_dynamic_room_predecessors"),
@ -60,7 +63,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
} }
} }
const room = cli.getRoom(roomId); const room = matrixClient.getRoom(roomId);
// should not encounter this // should not encounter this
if (!room) { if (!room) {
@ -97,9 +100,9 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
let results: { [roomId: string]: Error | MatrixError | null } = {}; let results: { [roomId: string]: Error | MatrixError | null } = {};
if (!leavingAllVersions) { if (!leavingAllVersions) {
try { try {
await cli.leave(roomId); await matrixClient.leave(roomId);
} catch (e) { } catch (e) {
if (e?.data?.errcode) { if (e instanceof MatrixError) {
const message = e.data.error || _t("Unexpected server error trying to leave the room"); const message = e.data.error || _t("Unexpected server error trying to leave the room");
results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data }); results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data });
} else { } else {
@ -107,7 +110,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
} }
} }
} else { } else {
results = await cli.leaveRoomChain(roomId, retry); results = await matrixClient.leaveRoomChain(roomId, retry);
} }
if (retry) { if (retry) {
@ -116,7 +119,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
) as MatrixError; ) as MatrixError;
if (limitExceededError) { if (limitExceededError) {
await sleep(limitExceededError.data.retry_after_ms ?? 100); await sleep(limitExceededError.data.retry_after_ms ?? 100);
return leaveRoomBehaviour(roomId, false, false); return leaveRoomBehaviour(matrixClient, roomId, false, false);
} }
} }
@ -186,7 +189,7 @@ export const leaveSpace = (space: Room): void => {
space, space,
onFinished: async (leave: boolean, rooms: Room[]): Promise<void> => { onFinished: async (leave: boolean, rooms: Room[]): Promise<void> => {
if (!leave) return; if (!leave) return;
await bulkSpaceBehaviour(space, rooms, (room) => leaveRoomBehaviour(room.roomId)); await bulkSpaceBehaviour(space, rooms, (room) => leaveRoomBehaviour(space.client, room.roomId));
dis.dispatch<AfterLeaveRoomPayload>({ dis.dispatch<AfterLeaveRoomPayload>({
action: Action.AfterLeaveRoom, action: Action.AfterLeaveRoom,

View file

@ -18,7 +18,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
import defaultDispatcher from "../dispatcher/dispatcher"; import defaultDispatcher from "../dispatcher/dispatcher";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { LocalRoom, LocalRoomState } from "../models/LocalRoom"; import { LocalRoom, LocalRoomState } from "../models/LocalRoom";
import { isLocalRoom } from "./localRoom/isLocalRoom"; import { isLocalRoom } from "./localRoom/isLocalRoom";
import { isRoomReady } from "./localRoom/isRoomReady"; import { isRoomReady } from "./localRoom/isRoomReady";
@ -39,10 +38,9 @@ import { isRoomReady } from "./localRoom/isRoomReady";
export async function doMaybeLocalRoomAction<T>( export async function doMaybeLocalRoomAction<T>(
roomId: string, roomId: string,
fn: (actualRoomId: string) => Promise<T>, fn: (actualRoomId: string) => Promise<T>,
client?: MatrixClient, client: MatrixClient,
): Promise<T> { ): Promise<T> {
if (isLocalRoom(roomId)) { if (isLocalRoom(roomId)) {
client = client ?? MatrixClientPeg.get();
const room = client.getRoom(roomId) as LocalRoom; const room = client.getRoom(roomId) as LocalRoom;
if (room.isCreated) { if (room.isCreated) {

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import SdkConfig from "../../SdkConfig"; import SdkConfig from "../../SdkConfig";
import { getTileServerWellKnown } from "../WellKnownUtils"; import { getTileServerWellKnown } from "../WellKnownUtils";
@ -25,8 +26,8 @@ import { LocationShareError } from "./LocationShareErrors";
* .well-known location, or, failing that, in our local config, or, failing * .well-known location, or, failing that, in our local config, or, failing
* that, defaults to the same tile server listed by matrix.org. * that, defaults to the same tile server listed by matrix.org.
*/ */
export function findMapStyleUrl(): string { export function findMapStyleUrl(matrixClient: MatrixClient): string {
const mapStyleUrl = getTileServerWellKnown()?.map_style_url ?? SdkConfig.get().map_style_url; const mapStyleUrl = getTileServerWellKnown(matrixClient)?.map_style_url ?? SdkConfig.get().map_style_url;
if (!mapStyleUrl) { if (!mapStyleUrl) {
logger.error("'map_style_url' missing from homeserver .well-known area, and missing from from config.json."); logger.error("'map_style_url' missing from homeserver .well-known area, and missing from from config.json.");

View file

@ -15,7 +15,7 @@ limitations under the License.
*/ */
import * as maplibregl from "maplibre-gl"; import * as maplibregl from "maplibre-gl";
import { MatrixEvent } from "matrix-js-sdk/src/matrix"; import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location"; import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
@ -24,9 +24,14 @@ import { parseGeoUri } from "./parseGeoUri";
import { findMapStyleUrl } from "./findMapStyleUrl"; import { findMapStyleUrl } from "./findMapStyleUrl";
import { LocationShareError } from "./LocationShareErrors"; import { LocationShareError } from "./LocationShareErrors";
export const createMap = (interactive: boolean, bodyId: string, onError?: (error: Error) => void): maplibregl.Map => { export const createMap = (
client: MatrixClient,
interactive: boolean,
bodyId: string,
onError?: (error: Error) => void,
): maplibregl.Map => {
try { try {
const styleUrl = findMapStyleUrl(); const styleUrl = findMapStyleUrl(client);
const map = new maplibregl.Map({ const map = new maplibregl.Map({
container: bodyId, container: bodyId,

View file

@ -18,6 +18,7 @@ import { useEffect, useState } from "react";
import { Map as MapLibreMap } from "maplibre-gl"; import { Map as MapLibreMap } from "maplibre-gl";
import { createMap } from "./map"; import { createMap } from "./map";
import { useMatrixClientContext } from "../../contexts/MatrixClientContext";
interface UseMapProps { interface UseMapProps {
bodyId: string; bodyId: string;
@ -32,12 +33,13 @@ interface UseMapProps {
* As map is recreated on changes to it * As map is recreated on changes to it
*/ */
export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => { export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => {
const cli = useMatrixClientContext();
const [map, setMap] = useState<MapLibreMap>(); const [map, setMap] = useState<MapLibreMap>();
useEffect( useEffect(
() => { () => {
try { try {
setMap(createMap(!!interactive, bodyId, onError)); setMap(createMap(cli, !!interactive, bodyId, onError));
} catch (error) { } catch (error) {
onError?.(error); onError?.(error);
} }

View file

@ -15,12 +15,13 @@ limitations under the License.
*/ */
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { IConfigOptions } from "../IConfigOptions"; import { IConfigOptions } from "../IConfigOptions";
import { getEmbeddedPagesWellKnown } from "../utils/WellKnownUtils"; import { getEmbeddedPagesWellKnown } from "../utils/WellKnownUtils";
import { SnakedObject } from "./SnakedObject"; import { SnakedObject } from "./SnakedObject";
export function getHomePageUrl(appConfig: IConfigOptions): string | undefined { export function getHomePageUrl(appConfig: IConfigOptions, matrixClient: MatrixClient): string | undefined {
const config = new SnakedObject(appConfig); const config = new SnakedObject(appConfig);
const pagesConfig = config.get("embedded_pages"); const pagesConfig = config.get("embedded_pages");
@ -40,7 +41,7 @@ export function getHomePageUrl(appConfig: IConfigOptions): string | undefined {
} }
if (!pageUrl) { if (!pageUrl) {
pageUrl = getEmbeddedPagesWellKnown()?.home_url; pageUrl = getEmbeddedPagesWellKnown(matrixClient)?.home_url;
} }
return pageUrl; return pageUrl;

View file

@ -20,8 +20,8 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import MatrixToPermalinkConstructor, { import MatrixToPermalinkConstructor, {
baseUrl as matrixtoBaseUrl, baseUrl as matrixtoBaseUrl,
baseUrlPattern as matrixToBaseUrlPattern, baseUrlPattern as matrixToBaseUrlPattern,
@ -284,7 +284,7 @@ export function makeUserPermalink(userId: string): string {
return getPermalinkConstructor().forUser(userId); return getPermalinkConstructor().forUser(userId);
} }
export function makeRoomPermalink(roomId: string): string { export function makeRoomPermalink(matrixClient: MatrixClient, roomId: string): string {
if (!roomId) { if (!roomId) {
throw new Error("can't permalink a falsy roomId"); throw new Error("can't permalink a falsy roomId");
} }
@ -293,8 +293,7 @@ export function makeRoomPermalink(roomId: string): string {
// Aliases are already routable, and don't need extra information. // Aliases are already routable, and don't need extra information.
if (roomId[0] !== "!") return getPermalinkConstructor().forRoom(roomId, []); if (roomId[0] !== "!") return getPermalinkConstructor().forRoom(roomId, []);
const client = MatrixClientPeg.get(); const room = matrixClient.getRoom(roomId);
const room = client.getRoom(roomId);
if (!room) { if (!room) {
return getPermalinkConstructor().forRoom(roomId, []); return getPermalinkConstructor().forRoom(roomId, []);
} }
@ -317,11 +316,11 @@ export function isPermalinkHost(host: string): boolean {
* @param {string} entity The entity to transform. * @param {string} entity The entity to transform.
* @returns {string|null} The transformed permalink or null if unable. * @returns {string|null} The transformed permalink or null if unable.
*/ */
export function tryTransformEntityToPermalink(entity: string): string | null { export function tryTransformEntityToPermalink(matrixClient: MatrixClient, entity: string): string | null {
if (!entity) return null; if (!entity) return null;
// Check to see if it is a bare entity for starters // Check to see if it is a bare entity for starters
if (entity[0] === "#" || entity[0] === "!") return makeRoomPermalink(entity); if (entity[0] === "#" || entity[0] === "!") return makeRoomPermalink(matrixClient, entity);
if (entity[0] === "@") return makeUserPermalink(entity); if (entity[0] === "@") return makeUserPermalink(entity);
if (entity.slice(0, 7) === "matrix:") { if (entity.slice(0, 7) === "matrix:") {

View file

@ -18,8 +18,8 @@ import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor"; import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../MatrixClientPeg";
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
import { Pill, PillType, pillRoomNotifLen, pillRoomNotifPos } from "../components/views/elements/Pill"; import { Pill, PillType, pillRoomNotifLen, pillRoomNotifPos } from "../components/views/elements/Pill";
import { parsePermalink } from "./permalinks/Permalinks"; import { parsePermalink } from "./permalinks/Permalinks";
@ -51,6 +51,7 @@ const shouldBePillified = (node: Element, href: string, parts: PermalinkParts |
* into pills based on the context of a given room. Returns a list of * into pills based on the context of a given room. Returns a list of
* the resulting React nodes so they can be unmounted rather than leaking. * the resulting React nodes so they can be unmounted rather than leaking.
* *
* @param matrixClient the client of the logged-in user
* @param {Element[]} nodes - a list of sibling DOM nodes to traverse to try * @param {Element[]} nodes - a list of sibling DOM nodes to traverse to try
* to turn into pills. * to turn into pills.
* @param {MatrixEvent} mxEvent - the matrix event which the DOM nodes are * @param {MatrixEvent} mxEvent - the matrix event which the DOM nodes are
@ -59,8 +60,13 @@ const shouldBePillified = (node: Element, href: string, parts: PermalinkParts |
* React components which have been mounted as part of this. * React components which have been mounted as part of this.
* The initial caller should pass in an empty array to seed the accumulator. * The initial caller should pass in an empty array to seed the accumulator.
*/ */
export function pillifyLinks(nodes: ArrayLike<Element>, mxEvent: MatrixEvent, pills: Element[]): void { export function pillifyLinks(
const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()) ?? undefined; matrixClient: MatrixClient,
nodes: ArrayLike<Element>,
mxEvent: MatrixEvent,
pills: Element[],
): void {
const room = matrixClient.getRoom(mxEvent.getRoomId()) ?? undefined;
const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar"); const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar");
let node = nodes[0]; let node = nodes[0];
while (node) { while (node) {
@ -118,7 +124,7 @@ export function pillifyLinks(nodes: ArrayLike<Element>, mxEvent: MatrixEvent, pi
} }
if (roomNotifTextNodes.length > 0) { if (roomNotifTextNodes.length > 0) {
const pushProcessor = new PushProcessor(MatrixClientPeg.get()); const pushProcessor = new PushProcessor(matrixClient);
const atRoomRule = pushProcessor.getPushRuleById(".m.rule.roomnotif"); const atRoomRule = pushProcessor.getPushRuleById(".m.rule.roomnotif");
if (atRoomRule && pushProcessor.ruleMatchesEvent(atRoomRule, mxEvent)) { if (atRoomRule && pushProcessor.ruleMatchesEvent(atRoomRule, mxEvent)) {
// Now replace all those nodes with Pills // Now replace all those nodes with Pills
@ -151,7 +157,7 @@ export function pillifyLinks(nodes: ArrayLike<Element>, mxEvent: MatrixEvent, pi
} }
if (node.childNodes && node.childNodes.length && !pillified) { if (node.childNodes && node.childNodes.length && !pillified) {
pillifyLinks(node.childNodes as NodeListOf<Element>, mxEvent, pills); pillifyLinks(matrixClient, node.childNodes as NodeListOf<Element>, mxEvent, pills);
} }
node = node.nextSibling as Element; node = node.nextSibling as Element;

View file

@ -14,11 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { MatrixClientPeg } from "../MatrixClientPeg"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import SdkConfig from "../SdkConfig"; import SdkConfig from "../SdkConfig";
export function isPresenceEnabled(): boolean { export function isPresenceEnabled(matrixClient: MatrixClient): boolean {
const hsUrl = MatrixClientPeg.get().baseUrl; const hsUrl = matrixClient.baseUrl;
const urls = SdkConfig.get("enable_presence_by_hs_url"); const urls = SdkConfig.get("enable_presence_by_hs_url");
if (!urls) return true; if (!urls) return true;
if (urls[hsUrl] || urls[hsUrl] === undefined) return true; if (urls[hsUrl] || urls[hsUrl] === undefined) return true;

View file

@ -27,7 +27,7 @@ export const shouldEncryptRoomWithSingle3rdPartyInvite = (
room: Room, room: Room,
): { shouldEncrypt: true; inviteEvent: MatrixEvent } | { shouldEncrypt: false; inviteEvent?: undefined } => { ): { shouldEncrypt: true; inviteEvent: MatrixEvent } | { shouldEncrypt: false; inviteEvent?: undefined } => {
// encryption not promoted via .well-known // encryption not promoted via .well-known
if (!privateShouldBeEncrypted()) return { shouldEncrypt: false }; if (!privateShouldBeEncrypted(room.client)) return { shouldEncrypt: false };
// not a DM room // not a DM room
if (!DMRoomMap.shared().getRoomIds().has(room.roomId)) return { shouldEncrypt: false }; if (!DMRoomMap.shared().getRoomIds().has(room.roomId)) return { shouldEncrypt: false };

View file

@ -14,10 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { getE2EEWellKnown } from "./WellKnownUtils"; import { getE2EEWellKnown } from "./WellKnownUtils";
export function privateShouldBeEncrypted(): boolean { export function privateShouldBeEncrypted(client: MatrixClient): boolean {
const e2eeWellKnown = getE2EEWellKnown(); const e2eeWellKnown = getE2EEWellKnown(client);
if (e2eeWellKnown) { if (e2eeWellKnown) {
const defaultDisabled = e2eeWellKnown["default"] === false; const defaultDisabled = e2eeWellKnown["default"] === false;
return !defaultDisabled; return !defaultDisabled;

View file

@ -38,7 +38,7 @@ function getWidgetBuildUrl(): string | undefined {
return SdkConfig.get().widget_build_url; return SdkConfig.get().widget_build_url;
} }
/* eslint-disable-next-line camelcase */ /* eslint-disable-next-line camelcase */
return getCallBehaviourWellKnown()?.widget_build_url; return getCallBehaviourWellKnown(MatrixClientPeg.get())?.widget_build_url;
} }
export function isManagedHybridWidgetEnabled(): boolean { export function isManagedHybridWidgetEnabled(): boolean {
@ -53,7 +53,7 @@ export async function addManagedHybridWidget(roomId: string): Promise<void> {
} }
// Check for permission // Check for permission
if (!WidgetUtils.canUserModifyWidgets(roomId)) { if (!WidgetUtils.canUserModifyWidgets(cli, roomId)) {
logger.error(`User not allowed to modify widgets in ${roomId}`); logger.error(`User not allowed to modify widgets in ${roomId}`);
return; return;
} }
@ -87,7 +87,7 @@ export async function addManagedHybridWidget(roomId: string): Promise<void> {
// Add the widget // Add the widget
try { try {
await WidgetUtils.setRoomWidgetContent(roomId, widgetId, widgetContent); await WidgetUtils.setRoomWidgetContent(cli, roomId, widgetId, widgetContent);
} catch (e) { } catch (e) {
logger.error(`Unable to add managed hybrid widget in room ${roomId}`, e); logger.error(`Unable to add managed hybrid widget in room ${roomId}`, e);
return; return;

View file

@ -112,7 +112,7 @@ describe("MessagePanel", function () {
return arg === "showDisplaynameChanges"; return arg === "showDisplaynameChanges";
}); });
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
}); });
afterEach(function () { afterEach(function () {

View file

@ -91,7 +91,7 @@ describe("PipContainer", () => {
stubClient(); stubClient();
client = mocked(MatrixClientPeg.get()); client = mocked(MatrixClientPeg.get());
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
room = new Room("!1:example.org", client, "@alice:example.org", { room = new Room("!1:example.org", client, "@alice:example.org", {
pendingEventOrdering: PendingEventOrdering.Detached, pendingEventOrdering: PendingEventOrdering.Detached,

View file

@ -48,7 +48,7 @@ describe("RightPanel", () => {
beforeEach(() => { beforeEach(() => {
stubClient(); stubClient();
cli = mocked(MatrixClientPeg.get()); cli = mocked(MatrixClientPeg.get());
DMRoomMap.makeShared(); DMRoomMap.makeShared(cli);
context = new SdkContextClass(); context = new SdkContextClass();
context.client = cli; context.client = cli;
RightPanel = wrapInSdkContext(RightPanelBase, context); RightPanel = wrapInSdkContext(RightPanelBase, context);

View file

@ -83,7 +83,7 @@ describe("RoomView", () => {
room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args)); room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args));
room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args)); room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args));
DMRoomMap.makeShared(); DMRoomMap.makeShared(cli);
stores = new SdkContextClass(); stores = new SdkContextClass();
stores.client = cli; stores.client = cli;
stores.rightPanelStore.useUnitTestClient(cli); stores.rightPanelStore.useUnitTestClient(cli);
@ -457,7 +457,7 @@ describe("RoomView", () => {
}); });
it("the last Jitsi widget should be removed", () => { it("the last Jitsi widget should be removed", () => {
expect(WidgetUtils.setRoomWidget).toHaveBeenCalledWith(room.roomId, widget2Id); expect(WidgetUtils.setRoomWidget).toHaveBeenCalledWith(cli, room.roomId, widget2Id);
}); });
}); });

View file

@ -131,7 +131,7 @@ describe("ThreadView", () => {
rootEvent = res.rootEvent; rootEvent = res.rootEvent;
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(SENDER); jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(SENDER);
}); });

View file

@ -90,7 +90,7 @@ describe("ForwardDialog", () => {
}; };
beforeEach(() => { beforeEach(() => {
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
jest.clearAllMocks(); jest.clearAllMocks();
mockClient.getUserId.mockReturnValue("@bob:example.org"); mockClient.getUserId.mockReturnValue("@bob:example.org");
mockClient.getSafeUserId.mockReturnValue("@bob:example.org"); mockClient.getSafeUserId.mockReturnValue("@bob:example.org");

View file

@ -143,7 +143,7 @@ describe("InviteDialog", () => {
getClientWellKnown: jest.fn().mockResolvedValue({}), getClientWellKnown: jest.fn().mockResolvedValue({}),
}); });
SdkConfig.put({ validated_server_config: {} as ValidatedServerConfig } as IConfigOptions); SdkConfig.put({ validated_server_config: {} as ValidatedServerConfig } as IConfigOptions);
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
jest.clearAllMocks(); jest.clearAllMocks();
room = new Room(roomId, mockClient, mockClient.getSafeUserId()); room = new Room(roomId, mockClient, mockClient.getSafeUserId());

View file

@ -86,7 +86,7 @@ describe("AppTile", () => {
cli.hasLazyLoadMembersEnabled = () => false; cli.hasLazyLoadMembersEnabled = () => false;
// Init misc. startup deps // Init misc. startup deps
DMRoomMap.makeShared(); DMRoomMap.makeShared(cli);
r1 = new Room("r1", cli, "@name:example.com"); r1 = new Room("r1", cli, "@name:example.com");
r2 = new Room("r2", cli, "@name:example.com"); r2 = new Room("r2", cli, "@name:example.com");

View file

@ -75,7 +75,7 @@ describe("<Pill>", () => {
beforeEach(() => { beforeEach(() => {
client = mocked(stubClient()); client = mocked(stubClient());
SdkContextClass.instance.client = client; SdkContextClass.instance.client = client;
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
room1 = new Room(room1Id, client, user1Id); room1 = new Room(room1Id, client, user1Id);
room1.name = "Room 1"; room1.name = "Room 1";
const user1JoinRoom1Event = mkRoomMemberJoinEvent(user1Id, room1Id, { const user1JoinRoom1Event = mkRoomMemberJoinEvent(user1Id, room1Id, {

View file

@ -120,7 +120,7 @@ describe("<TextualBody />", () => {
); );
it("renders m.emote correctly", () => { it("renders m.emote correctly", () => {
DMRoomMap.makeShared(); DMRoomMap.makeShared(defaultMatrixClient);
const ev = mkEvent({ const ev = mkEvent({
type: "m.room.message", type: "m.room.message",
@ -140,7 +140,7 @@ describe("<TextualBody />", () => {
}); });
it("renders m.notice correctly", () => { it("renders m.notice correctly", () => {
DMRoomMap.makeShared(); DMRoomMap.makeShared(defaultMatrixClient);
const ev = mkEvent({ const ev = mkEvent({
type: "m.room.message", type: "m.room.message",
@ -161,7 +161,7 @@ describe("<TextualBody />", () => {
describe("renders plain-text m.text correctly", () => { describe("renders plain-text m.text correctly", () => {
beforeEach(() => { beforeEach(() => {
DMRoomMap.makeShared(); DMRoomMap.makeShared(defaultMatrixClient);
}); });
it("simple message renders as expected", () => { it("simple message renders as expected", () => {
@ -264,7 +264,7 @@ describe("<TextualBody />", () => {
isGuest: () => false, isGuest: () => false,
mxcUrlToHttp: (s: string) => s, mxcUrlToHttp: (s: string) => s,
}); });
DMRoomMap.makeShared(); DMRoomMap.makeShared(defaultMatrixClient);
}); });
it("italics, bold, underline and strikethrough render as expected", () => { it("italics, bold, underline and strikethrough render as expected", () => {
@ -408,7 +408,7 @@ describe("<TextualBody />", () => {
isGuest: () => false, isGuest: () => false,
mxcUrlToHttp: (s: string) => s, mxcUrlToHttp: (s: string) => s,
}); });
DMRoomMap.makeShared(); DMRoomMap.makeShared(defaultMatrixClient);
const ev = mkRoomTextMessage("Visit https://matrix.org/"); const ev = mkRoomTextMessage("Visit https://matrix.org/");
const { container, rerender } = getComponent( const { container, rerender } = getComponent(

View file

@ -71,7 +71,7 @@ describe("<RoomSummaryCard />", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
mockClient.getRoom.mockReturnValue(room); mockClient.getRoom.mockReturnValue(room);
jest.spyOn(room, "isElementVideoRoom").mockRestore(); jest.spyOn(room, "isElementVideoRoom").mockRestore();

View file

@ -97,7 +97,7 @@ describe("<EditMessageComposer/>", () => {
userEvent.setup(); userEvent.setup();
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
jest.spyOn(Autocompleter.prototype, "getCompletions").mockResolvedValue([ jest.spyOn(Autocompleter.prototype, "getCompletions").mockResolvedValue([
{ {

View file

@ -47,7 +47,7 @@ describe("NewRoomIntro", () => {
beforeAll(() => { beforeAll(() => {
client = stubClient(); client = stubClient();
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
}); });
describe("for a DM Room", () => { describe("for a DM Room", () => {

View file

@ -112,7 +112,7 @@ describe("RoomHeader", () => {
[MediaDeviceKindEnum.AudioOutput]: [], [MediaDeviceKindEnum.AudioOutput]: [],
}); });
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(carol.userId); jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(carol.userId);
}); });
@ -761,7 +761,7 @@ function createRoom(info: IRoomCreationInfo) {
}; };
} }
DMRoomMap.makeShared().start(); DMRoomMap.makeShared(client).start();
const room = new Room(roomId, client, userId, { const room = new Room(roomId, client, userId, {
pendingEventOrdering: PendingEventOrdering.Detached, pendingEventOrdering: PendingEventOrdering.Detached,

View file

@ -33,8 +33,9 @@ jest.mock("../../../../src/IdentityAuthClient", () => {
jest.useRealTimers(); jest.useRealTimers();
const createRoom = (roomId: string, userId: string): Room => { const createRoom = (roomId: string, userId: string): Room => {
const newRoom = new Room(roomId, MatrixClientPeg.get(), userId, {}); const cli = MatrixClientPeg.get();
DMRoomMap.makeShared().start(); const newRoom = new Room(roomId, cli, userId, {});
DMRoomMap.makeShared(cli).start();
return newRoom; return newRoom;
}; };

View file

@ -42,7 +42,7 @@ describe("RoomPreviewCard", () => {
stubClient(); stubClient();
client = mocked(MatrixClientPeg.get()); client = mocked(MatrixClientPeg.get());
client.getUserId.mockReturnValue("@alice:example.org"); client.getUserId.mockReturnValue("@alice:example.org");
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
room = new Room("!1:example.org", client, "@alice:example.org", { room = new Room("!1:example.org", client, "@alice:example.org", {
pendingEventOrdering: PendingEventOrdering.Detached, pendingEventOrdering: PendingEventOrdering.Detached,

View file

@ -90,7 +90,7 @@ describe("RoomTile", () => {
client = mocked(stubClient()); client = mocked(stubClient());
sdkContext.client = client; sdkContext.client = client;
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
room = new Room("!1:example.org", client, "@alice:example.org", { room = new Room("!1:example.org", client, "@alice:example.org", {
pendingEventOrdering: PendingEventOrdering.Detached, pendingEventOrdering: PendingEventOrdering.Detached,

View file

@ -159,7 +159,7 @@ describe("<SpacePanel />", () => {
mkStubRoom("!room2:server", "Room 2", mockClient), mkStubRoom("!room2:server", "Room 2", mockClient),
mkStubRoom("!room3:server", "Room 3", mockClient), mkStubRoom("!room3:server", "Room 3", mockClient),
]; ];
DMRoomMap.makeShared(); DMRoomMap.makeShared(mockClient);
jest.useFakeTimers(); jest.useFakeTimers();
const { getByLabelText } = render(<SpacePanel />); const { getByLabelText } = render(<SpacePanel />);

View file

@ -40,7 +40,7 @@ jest.mock("../../../../src/stores/spaces/SpaceStore", () => {
describe("SpaceButton", () => { describe("SpaceButton", () => {
stubClient(); stubClient();
const space = mkRoom(MatrixClientPeg.get(), "!1:example.org"); const space = mkRoom(MatrixClientPeg.get(), "!1:example.org");
DMRoomMap.makeShared(); DMRoomMap.makeShared(MatrixClientPeg.get());
const dispatchSpy = jest.spyOn(defaultDispatcher, "dispatch"); const dispatchSpy = jest.spyOn(defaultDispatcher, "dispatch");

View file

@ -37,7 +37,7 @@ describe("RightPanelStore", () => {
beforeEach(() => { beforeEach(() => {
stubClient(); stubClient();
cli = mocked(MatrixClientPeg.get()); cli = mocked(MatrixClientPeg.get());
DMRoomMap.makeShared(); DMRoomMap.makeShared(cli);
// Make sure we start with a clean store // Make sure we start with a clean store
store.reset(); store.reset();

View file

@ -162,7 +162,7 @@ describe("RoomListStore", () => {
room1.updateMyMembership("join"); room1.updateMyMembership("join");
room2.updateMyMembership("join"); room2.updateMyMembership("join");
room3.updateMyMembership("join"); room3.updateMyMembership("join");
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
const { store } = createStore(); const { store } = createStore();
client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]); client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]);
@ -274,7 +274,7 @@ describe("RoomListStore", () => {
it("Passes the feature flag on to the client when asking for visible rooms", () => { it("Passes the feature flag on to the client when asking for visible rooms", () => {
// Given a store that we can ask for a room list // Given a store that we can ask for a room list
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
const { store } = createStore(); const { store } = createStore();
client.getVisibleRooms = jest.fn().mockReturnValue([]); client.getVisibleRooms = jest.fn().mockReturnValue([]);

View file

@ -41,7 +41,7 @@ describe("Algorithm", () => {
beforeEach(() => { beforeEach(() => {
stubClient(); stubClient();
client = mocked(MatrixClientPeg.get()); client = mocked(MatrixClientPeg.get());
DMRoomMap.makeShared(); DMRoomMap.makeShared(client);
algorithm = new Algorithm(); algorithm = new Algorithm();
algorithm.start(); algorithm.start();

Some files were not shown because too many files have changed in this diff Show more