Skip to content

Commit

Permalink
Merge branch 'refs/heads/develop' into florianduros/tooltip-update
Browse files Browse the repository at this point in the history
  • Loading branch information
florianduros committed Apr 15, 2024
2 parents 5354e6e + 6392759 commit 79cbfaf
Show file tree
Hide file tree
Showing 23 changed files with 628 additions and 77 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"@matrix-org/emojibase-bindings": "^1.1.2",
"@matrix-org/matrix-wysiwyg": "2.17.0",
"@matrix-org/olm": "3.2.15",
"@matrix-org/react-sdk-module-api": "^2.3.0",
"@matrix-org/react-sdk-module-api": "^2.4.0",
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^7.0.0",
"@testing-library/react-hooks": "^8.0.1",
Expand Down
4 changes: 2 additions & 2 deletions src/Lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { QueryDict } from "matrix-js-sdk/src/utils";
import { logger } from "matrix-js-sdk/src/logger";

import { IMatrixClientCreds, MatrixClientPeg } from "./MatrixClientPeg";
import SecurityCustomisations from "./customisations/Security";
import { ModuleRunner } from "./modules/ModuleRunner";
import EventIndexPeg from "./indexing/EventIndexPeg";
import createMatrixClient from "./utils/createMatrixClient";
import Notifier from "./Notifier";
Expand Down Expand Up @@ -863,7 +863,7 @@ async function persistCredentials(credentials: IMatrixClientCreds): Promise<void
localStorage.setItem("mx_device_id", credentials.deviceId);
}

SecurityCustomisations.persistCredentials?.(credentials);
ModuleRunner.instance.extensions.cryptoSetup?.persistCredentials(credentials);

logger.log(`Session persisted for ${credentials.userId}`);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
import { logger } from "matrix-js-sdk/src/logger";

import { IMatrixClientCreds } from "./MatrixClientPeg";
import SecurityCustomisations from "./customisations/Security";
import { ModuleRunner } from "./modules/ModuleRunner";
import { getOidcClientId } from "./utils/oidc/registerClient";
import { IConfigOptions } from "./IConfigOptions";
import SdkConfig from "./SdkConfig";
Expand Down Expand Up @@ -291,7 +291,7 @@ export async function sendLoginRequest(
accessToken: data.access_token,
};

SecurityCustomisations.examineLoginResponse?.(data, creds);
ModuleRunner.instance.extensions.cryptoSetup.examineLoginResponse(data, creds);

return creds;
}
7 changes: 4 additions & 3 deletions src/MatrixClientPeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientB
import * as StorageManager from "./utils/StorageManager";
import IdentityAuthClient from "./IdentityAuthClient";
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from "./SecurityManager";
import SecurityCustomisations from "./customisations/Security";
import { ModuleRunner } from "./modules/ModuleRunner";
import { SlidingSyncManager } from "./SlidingSyncManager";
import CryptoStoreTooNewDialog from "./components/views/dialogs/CryptoStoreTooNewDialog";
import { _t, UserFriendlyError } from "./languageHandler";
Expand Down Expand Up @@ -463,8 +463,9 @@ class MatrixClientPegClass implements IMatrixClientPeg {
},
};

if (SecurityCustomisations.getDehydrationKey) {
opts.cryptoCallbacks!.getDehydrationKey = SecurityCustomisations.getDehydrationKey;
const dehydrationKeyCallback = ModuleRunner.instance.extensions.cryptoSetup.getDehydrationKeyCallback();
if (dehydrationKeyCallback) {
opts.cryptoCallbacks!.getDehydrationKey = dehydrationKeyCallback;
}

this.matrixClient = createMatrixClient(opts);
Expand Down
12 changes: 6 additions & 6 deletions src/SecurityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { isSecureBackupRequired } from "./utils/WellKnownUtils";
import AccessSecretStorageDialog, { KeyParams } from "./components/views/dialogs/security/AccessSecretStorageDialog";
import RestoreKeyBackupDialog from "./components/views/dialogs/security/RestoreKeyBackupDialog";
import SettingsStore from "./settings/SettingsStore";
import SecurityCustomisations from "./customisations/Security";
import { ModuleRunner } from "./modules/ModuleRunner";
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog";

Expand Down Expand Up @@ -137,9 +137,9 @@ async function getSecretStorageKey({
}
}

const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.getSecretStorageKey();
if (keyFromCustomisations) {
logger.log("Using key from security customisations (secret storage)");
logger.log("CryptoSetupExtension: Using key from extension (secret storage)");
cacheSecretStorageKey(keyId, keyInfo, keyFromCustomisations);
return [keyId, keyFromCustomisations];
}
Expand Down Expand Up @@ -187,9 +187,9 @@ export async function getDehydrationKey(
keyInfo: SecretStorage.SecretStorageKeyDescription,
checkFunc: (data: Uint8Array) => void,
): Promise<Uint8Array> {
const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.getSecretStorageKey();
if (keyFromCustomisations) {
logger.log("Using key from security customisations (dehydration)");
logger.log("CryptoSetupExtension: Using key from extension (dehydration)");
return keyFromCustomisations;
}

Expand Down Expand Up @@ -430,7 +430,7 @@ async function doAccessSecretStorage(func: () => Promise<void>, forceReset: bool
// inner operation completes.
return await func();
} catch (e) {
SecurityCustomisations.catchAccessSecretStorageError?.(e);
ModuleRunner.instance.extensions.cryptoSetup.catchAccessSecretStorageError(e as Error);
logger.error(e);
// Re-throw so that higher level logic can abort as needed
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
isSecureBackupRequired,
SecureBackupSetupMethod,
} from "../../../../utils/WellKnownUtils";
import SecurityCustomisations from "../../../../customisations/Security";
import { ModuleRunner } from "../../../../modules/ModuleRunner";
import Field from "../../../../components/views/elements/Field";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import Spinner from "../../../../components/views/elements/Spinner";
Expand Down Expand Up @@ -180,9 +180,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
}

private getInitialPhase(): void {
const keyFromCustomisations = SecurityCustomisations.createSecretStorageKey?.();
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
if (keyFromCustomisations) {
logger.log("Created key via customisations, jumping to bootstrap step");
logger.log("CryptoSetupExtension: Created key via extension, jumping to bootstrap step");
this.recoveryKey = {
privateKey: keyFromCustomisations,
};
Expand Down
6 changes: 4 additions & 2 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ import { showToast as showMobileGuideToast } from "../../toasts/MobileGuideToast
import { shouldUseLoginForWelcome } from "../../utils/pages";
import RoomListStore from "../../stores/room-list/RoomListStore";
import { RoomUpdateCause } from "../../stores/room-list/models";
import SecurityCustomisations from "../../customisations/Security";
import { ModuleRunner } from "../../modules/ModuleRunner";
import Spinner from "../views/elements/Spinner";
import QuestionDialog from "../views/dialogs/QuestionDialog";
import UserSettingsDialog from "../views/dialogs/UserSettingsDialog";
Expand Down Expand Up @@ -441,7 +441,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (crossSigningIsSetUp) {
// if the user has previously set up cross-signing, verify this device so we can fetch the
// private keys.
if (SecurityCustomisations.SHOW_ENCRYPTION_SETUP_UI === false) {

const cryptoExtension = ModuleRunner.instance.extensions.cryptoSetup;
if (cryptoExtension.SHOW_ENCRYPTION_SETUP_UI == false) {
this.onLoggedIn();
} else {
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export const CallGuestLinkButton: React.FC<{ room: Room }> = ({ room }) => {
// If the user cannot invite the Knocking is not given as an option.
canInvite,
}).finished.then(() => {
// we need to use the function here because the callback got called before the state was updated.
if (isRoomJoinable()) showLinkModal();
});
}
Expand Down
70 changes: 35 additions & 35 deletions src/components/views/settings/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { Caption } from "../typography/Caption";
import { SettingsSubsectionHeading } from "./shared/SettingsSubsectionHeading";
import SettingsSubsection from "./shared/SettingsSubsection";
import { doesRoomHaveUnreadMessages } from "../../../Unread";
import SettingsFlag from "../elements/SettingsFlag";

// TODO: this "view" component still has far too much application logic in it,
// which should be factored out to other files.
Expand Down Expand Up @@ -200,6 +201,18 @@ const maximumVectorState = (
return vectorState;
};

const NotificationActivitySettings = (): JSX.Element => {
return (
<div>
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</div>
);
};

/**
* The old, deprecated notifications tab view, only displayed if the user has the labs flag disabled.
*/
export default class Notifications extends React.PureComponent<IProps, IState> {
private settingWatchers: string[];

Expand Down Expand Up @@ -731,43 +744,10 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
}

private renderCategory(category: RuleClass): ReactNode {
if (category !== RuleClass.VectorOther && this.isInhibited) {
if (this.isInhibited) {
return null; // nothing to show for the section
}

let clearNotifsButton: JSX.Element | undefined;
if (
category === RuleClass.VectorOther &&
MatrixClientPeg.safeGet()
.getRooms()
.some((r) => doesRoomHaveUnreadMessages(r, true))
) {
clearNotifsButton = (
<AccessibleButton
onClick={this.onClearNotificationsClicked}
disabled={this.state.clearingNotifications}
kind="danger"
className="mx_UserNotifSettings_clearNotifsButton"
data-testid="clear-notifications"
>
{_t("notifications|mark_all_read")}
</AccessibleButton>
);
}

if (category === RuleClass.VectorOther && this.isInhibited) {
// only render the utility buttons (if needed)
if (clearNotifsButton) {
return (
<div className="mx_UserNotifSettings_floatingSection">
<div>{_t("notifications|class_other")}</div>
{clearNotifsButton}
</div>
);
}
return null;
}

let keywordComposer: JSX.Element | undefined;
if (category === RuleClass.VectorMentions) {
const tags = filterBoolean<string>(this.state.vectorKeywordRuleInfo?.rules.map((r) => r.pattern) || []);
Expand Down Expand Up @@ -842,7 +822,6 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
<span className="mx_UserNotifSettings_gridColumnLabel">{VectorStateToLabel[VectorState.Loud]}</span>
{fieldsetRows}
</div>
{clearNotifsButton}
{keywordComposer}
</div>
);
Expand Down Expand Up @@ -878,13 +857,34 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
return <p data-testid="error-message">{_t("settings|notifications|error_loading")}</p>;
}

let clearNotifsButton: JSX.Element | undefined;
if (
MatrixClientPeg.safeGet()
.getRooms()
.some((r) => doesRoomHaveUnreadMessages(r, true))
) {
clearNotifsButton = (
<AccessibleButton
onClick={this.onClearNotificationsClicked}
disabled={this.state.clearingNotifications}
kind="danger"
className="mx_UserNotifSettings_clearNotifsButton"
data-testid="clear-notifications"
>
{_t("notifications|mark_all_read")}
</AccessibleButton>
);
}

return (
<>
{this.renderTopSection()}
{this.renderCategory(RuleClass.VectorGlobal)}
{this.renderCategory(RuleClass.VectorMentions)}
{this.renderCategory(RuleClass.VectorOther)}
{this.renderTargets()}
<NotificationActivitySettings />
{clearNotifsButton}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { SettingsBanner } from "../shared/SettingsBanner";
import { SettingsSection } from "../shared/SettingsSection";
import SettingsSubsection from "../shared/SettingsSubsection";
import { NotificationPusherSettings } from "./NotificationPusherSettings";
import SettingsFlag from "../../elements/SettingsFlag";

enum NotificationDefaultLevels {
AllMessages = "all_messages",
Expand Down Expand Up @@ -71,6 +72,9 @@ function useHasUnreadNotifications(): boolean {
return cli.getRooms().some((room) => room.getUnreadNotificationCount() > 0);
}

/**
* The new notification settings tab view, only displayed if the user has Features.NotificationSettings2 enabled
*/
export default function NotificationSettings2(): JSX.Element {
const cli = useMatrixClientContext();

Expand Down Expand Up @@ -352,6 +356,9 @@ export default function NotificationSettings2(): JSX.Element {
label={_t("notifications|keyword")}
placeholder={_t("notifications|keyword_new")}
/>

<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</SettingsSubsection>
<NotificationPusherSettings />
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ type Result = {
*/
export function useUnreadThreadRooms(forceComputation: boolean): Result {
const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors");
const settingTACOnlyNotifs = useSettingValue<boolean>("Notifications.tac_only_notifications");
const mxClient = useMatrixClientContext();

const [result, setResult] = useState<Result>({ greatestNotificationLevel: NotificationLevel.None, rooms: [] });

const doUpdate = useCallback(() => {
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor));
}, [mxClient, msc3946ProcessDynamicPredecessor]);
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs));
}, [mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs]);

// The exhautive deps lint rule can't compute dependencies here since it's not a plain inline func.
// We make this as simple as possible so its only dep is doUpdate itself.
Expand Down Expand Up @@ -83,7 +84,11 @@ export function useUnreadThreadRooms(forceComputation: boolean): Result {
* @param mxClient - MatrixClient
* @param msc3946ProcessDynamicPredecessor
*/
function computeUnreadThreadRooms(mxClient: MatrixClient, msc3946ProcessDynamicPredecessor: boolean): Result {
function computeUnreadThreadRooms(
mxClient: MatrixClient,
msc3946ProcessDynamicPredecessor: boolean,
settingTACOnlyNotifs: boolean,
): Result {
// Only count visible rooms to not torment the user with notification counts in rooms they can't see.
// This will include highlights from the previous version of the room internally
const visibleRooms = mxClient.getVisibleRooms(msc3946ProcessDynamicPredecessor);
Expand All @@ -98,7 +103,7 @@ function computeUnreadThreadRooms(mxClient: MatrixClient, msc3946ProcessDynamicP
const notificationLevel = getThreadNotificationLevel(room);

// If the room has an activity notification or less, we ignore it
if (notificationLevel <= NotificationLevel.Activity) {
if (settingTACOnlyNotifs && notificationLevel <= NotificationLevel.Activity) {
continue;
}

Expand Down
7 changes: 5 additions & 2 deletions src/hooks/room/useGuestAccessInformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export const useGuestAccessInformation = (room: Room): GuestAccessInformation =>
[canChangeJoinRule, isRoomJoinable, guestSpaUrl],
);

const isRoomJoinableFunction = (): boolean =>
room.getJoinRule() === JoinRule.Public || (joinRule === JoinRule.Knock && room.canInvite(room.myUserId));
const isRoomJoinableFunction = (): boolean => {
const join = room.getJoinRule();
return join === JoinRule.Public || (join === JoinRule.Knock && room.canInvite(room.myUserId));
};

return { canInviteGuests, guestSpaUrl, isRoomJoinable: isRoomJoinableFunction, canInvite };
};
2 changes: 2 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2846,6 +2846,7 @@
"show_redaction_placeholder": "Show a placeholder for removed messages",
"show_stickers_button": "Show stickers button",
"show_typing_notifications": "Show typing notifications",
"showbold": "Show all activity in the room list (dots or number of unread messages)",
"sidebar": {
"metaspaces_favourites_description": "Group all your favourite rooms and people in one place.",
"metaspaces_home_all_rooms": "Show all rooms",
Expand All @@ -2862,6 +2863,7 @@
"title": "Sidebar"
},
"start_automatically": "Start automatically after system login",
"tac_only_notifications": "Only show notifications in the thread activity centre",
"use_12_hour_format": "Show timestamps in 12 hour format (e.g. 2:30pm)",
"use_command_enter_send_message": "Use Command + Enter to send a message",
"use_command_f_search": "Use Command + F to search timeline",
Expand Down
Loading

0 comments on commit 79cbfaf

Please sign in to comment.