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

OIDC: use delegated auth account URL from OidcClientStore #11723

Merged
merged 103 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
2607997
test persistCredentials without a pickle key
Jul 11, 2023
3506c06
Merge branch 'develop' into kerry/25708/test-persist-credentials
Jul 12, 2023
609f790
test setLoggedIn with pickle key
Jul 12, 2023
f3092c7
lint
Jul 12, 2023
fad7f33
type error
Jul 12, 2023
32d5fb0
extract token persisting code into function, persist refresh token
Jul 12, 2023
e6529f1
store has_refresh_token too
Jul 12, 2023
66d57e5
pass refreshToken from oidcAuthGrant into credentials
Jul 12, 2023
b33e347
rest restore session with pickle key
Jul 13, 2023
823ba2e
Merge branch 'kerry/25708/test-persist-credentials' into kerry/25708/…
Jul 13, 2023
e91bbf4
retreive stored refresh token and add to credentials
Jul 13, 2023
b7e0603
Merge branch 'develop' into kerry/25708/test-persist-credentials
Jul 13, 2023
b8b0c86
Merge branch 'kerry/25708/test-persist-credentials' into kerry/25708/…
Jul 13, 2023
3ed9cc1
Merge branch 'develop' into kerry/25708/restore-refresh-token
Jul 13, 2023
221d306
extract token decryption into function
Jul 13, 2023
64dbc94
remove TODO
Jul 13, 2023
f059642
Merge branch 'develop' into kerry/25708/test-persist-credentials
Jul 16, 2023
9272110
Merge branch 'kerry/25708/test-persist-credentials' into kerry/25708/…
Jul 17, 2023
0f5fc31
Merge branch 'develop' into kerry/25708/restore-refresh-token
Jul 17, 2023
1708bef
very messy poc
Jul 17, 2023
1b76c18
Merge branch 'develop' into kerry/token-refresh-poc
Jul 18, 2023
d24fbd0
Merge branch 'develop' into kerry/25708/save-refresh-token
Jul 19, 2023
880c258
Merge branch 'kerry/25708/save-refresh-token' of https://github.com/m…
Jul 19, 2023
65c0734
Merge branch 'develop' into kerry/25708/save-refresh-token
Jul 19, 2023
2bab36b
utils to persist clientId and issuer after oidc authentication
Jul 19, 2023
66dc9fb
add dep oidc-client-ts
Jul 19, 2023
a5c0a51
persist issuer and clientId after successful oidc auth
Jul 19, 2023
50f3fe4
add OidcClientStore
Jul 20, 2023
3681b2e
comments and tidy
Jul 20, 2023
978109a
Merge branch 'develop' into kerry/25710/oidc-client-store
Jul 20, 2023
05d6252
Merge branch 'kerry/25708/restore-refresh-token' into kerry/25709/rev…
Jul 20, 2023
880671c
expose getters for stored refresh and access tokens in Lifecycle
Jul 20, 2023
97a9c89
revoke tokens with oidc provider
Jul 20, 2023
b75ad17
test logout action in MatrixChat
Jul 20, 2023
70ddb4a
comments
Jul 20, 2023
22329b9
Merge branch 'kerry/25708/save-refresh-token' into kerry/25708/restor…
Jul 20, 2023
56441dc
Merge branch 'develop' into kerry/25708/save-refresh-token
Jul 20, 2023
af481b2
prettier
Jul 20, 2023
976ec8c
Merge branch 'kerry/25708/save-refresh-token' into kerry/25708/restor…
Jul 20, 2023
70b7ca2
Merge branch 'kerry/25708/restore-refresh-token' into kerry/25709/rev…
Jul 20, 2023
07195c0
test OidcClientStore.revokeTokens
Jul 21, 2023
31822a5
Merge branch 'kerry/25710/test-logout' into kerry/25709/revoke-tokens
Jul 21, 2023
4f1bb4e
put pickle key destruction back
Jul 21, 2023
ae80087
Merge branch 'kerry/25708/restore-refresh-token' into kerry/token-ref…
Jul 21, 2023
ddd8ed7
Merge branch 'develop' into kerry/25708/restore-refresh-token
Sep 25, 2023
8cd5823
comment pedantry
Sep 25, 2023
ca24f0a
Merge branch 'kerry/25708/restore-refresh-token' into kerry/token-ref…
Sep 25, 2023
1fa7809
Merge branch 'develop' into kerry/token-refresh-poc
Oct 1, 2023
97fad4d
working refresh without persistence
Oct 1, 2023
e3673ee
extract token persistence functions to utils
Oct 2, 2023
41a4eb3
Merge branch 'kerry/25392/extract-token-functions' into kerry/token-r…
Oct 2, 2023
1c8e8cb
add sugar
Oct 2, 2023
0d558d7
Merge branch 'kerry/25392/extract-token-functions' into kerry/token-r…
Oct 2, 2023
5986b6c
implement TokenRefresher class with persistence
Oct 2, 2023
7db7291
tidying
Oct 2, 2023
dcd3026
persist idTokenClaims
Oct 2, 2023
4921e78
persist idTokenClaims
Oct 2, 2023
6ba08a2
tests
Oct 2, 2023
c962ca1
remove unused cde
Oct 2, 2023
0b4c4d8
Merge branch 'develop' into kerry/25392/persist-oidc-token-claims
Oct 2, 2023
3590f9c
Merge branch 'develop' into kerry/25392/persist-oidc-token-claims
Oct 2, 2023
87eb820
Merge branch 'kerry/25392/persist-oidc-token-claims' into kerry/token…
Oct 2, 2023
153ec78
create token refresher during doSetLoggedIn
Oct 2, 2023
ebdf0d5
tidying
Oct 2, 2023
2b1e73c
also tidying
Oct 2, 2023
b9b5411
Merge branch 'develop' into kerry/25709/revoke-tokens
Oct 3, 2023
e578107
Merge branch 'kerry/token-refresh-poc' into kerry/25709/revoke-tokens
Oct 4, 2023
f345a09
OidcClientStore.initClient use stored issuer when client well known u…
Oct 4, 2023
83de914
test Lifecycle.logout
Oct 4, 2023
7e081d4
update Lifecycle test replaceUsingCreds calls
Oct 4, 2023
7048c03
Merge branch 'develop' into kerry/25709/revoke-tokens
Oct 4, 2023
80dfd23
Merge branch 'kerry/25709/revoke-tokens' of https://github.com/matrix…
Oct 4, 2023
69b3cab
Merge branch 'kerry/token-refresh-poc' into kerry/25709/revoke-tokens
Oct 5, 2023
b2a3cd1
fix test
Oct 5, 2023
dabbee6
Merge branch 'develop' into kerry/25709/revoke-tokens
Oct 8, 2023
0a1c66e
add sdkContext to UserSettingsDialog
Oct 8, 2023
40b065f
use sdkContext and oidcClientStore in session manager
Oct 8, 2023
cbd9c88
use sdkContext and OidcClientStore in generalusersettingstab
Oct 8, 2023
d302374
Merge branch 'develop' into kerry/token-refresh-poc
Oct 10, 2023
df70f53
tidy
Oct 10, 2023
0b0bb61
test tokenrefresher creation in login flow
Oct 10, 2023
8a47e6e
test token refresher
Oct 10, 2023
a32ca16
Update src/utils/oidc/TokenRefresher.ts
Oct 11, 2023
5370474
use literal value for m.authentication
Oct 11, 2023
7f40f86
improve comments
Oct 11, 2023
ead0aae
Merge branch 'kerry/token-refresh-poc' of https://github.com/matrix-o…
Oct 11, 2023
9c0fdf9
Merge branch 'develop' into kerry/token-refresh-poc
Oct 11, 2023
6953b45
Merge branch 'develop' into kerry/token-refresh-poc
Oct 11, 2023
541a6e6
Merge branch 'develop' into kerry/token-refresh-poc
Oct 11, 2023
ec3421a
Merge branch 'kerry/token-refresh-poc' into kerry/25709/revoke-tokens
Oct 11, 2023
866296d
fix test mock, comment
Oct 11, 2023
1a232b7
typo
Oct 12, 2023
fc10e64
add sdkContext to SoftLogout, pass oidcClientStore to logout
Oct 12, 2023
1f7dd1b
fullstops
Oct 12, 2023
f1fdd13
comments
Oct 12, 2023
d43c620
Merge branch 'kerry/25709/revoke-tokens' into kerry/26305/fix-oidc-ac…
Oct 12, 2023
09b8d13
fussy comment formatting
Oct 12, 2023
3c43304
Merge branch 'kerry/25709/revoke-tokens' into kerry/26305/fix-oidc-ac…
Oct 12, 2023
a3c50ad
Merge branch 'develop' into kerry/25709/revoke-tokens
Oct 12, 2023
c43ad79
Merge branch 'kerry/25709/revoke-tokens' into kerry/26305/fix-oidc-ac…
Oct 12, 2023
ba2a561
Merge branch 'develop' into kerry/25709/revoke-tokens
Oct 12, 2023
f522c7e
Merge branch 'kerry/25709/revoke-tokens' into kerry/26305/fix-oidc-ac…
Oct 12, 2023
836b655
Merge branch 'develop' into kerry/26305/fix-oidc-acc-man-url
Oct 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const tabPayload = payload as OpenToTabPayload;
Modal.createDialog(
UserSettingsDialog,
{ initialTabId: tabPayload.initialTabId as UserTab },
{ initialTabId: tabPayload.initialTabId as UserTab, sdkContext: this.stores },
/*className=*/ undefined,
/*isPriority=*/ false,
/*isStatic=*/ true,
Expand Down
35 changes: 21 additions & 14 deletions src/components/views/dialogs/UserSettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsT
import SessionManagerTab from "../settings/tabs/user/SessionManagerTab";
import { UserTab } from "./UserTab";
import { NonEmptyArray } from "../../../@types/common";
import { SDKContext, SdkContextClass } from "../../../contexts/SDKContext";

interface IProps {
initialTabId?: UserTab;
sdkContext: SdkContextClass;
onFinished(): void;
}

Expand Down Expand Up @@ -197,20 +199,25 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>

public render(): React.ReactNode {
return (
<BaseDialog
className="mx_UserSettingsDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("common|settings")}
>
<div className="mx_SettingsDialog_content">
<TabbedView
tabs={this.getTabs()}
initialTabId={this.props.initialTabId}
screenName="UserSettings"
/>
</div>
</BaseDialog>
// XXX: SDKContext is provided within the LoggedInView subtree.
// Modals function outside the MatrixChat React tree, so sdkContext is reprovided here to simulate that.
// The longer term solution is to move our ModalManager into the React tree to inherit contexts properly.
<SDKContext.Provider value={this.props.sdkContext}>
<BaseDialog
className="mx_UserSettingsDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("common|settings")}
>
<div className="mx_SettingsDialog_content">
<TabbedView
tabs={this.getTabs()}
initialTabId={this.props.initialTabId}
screenName="UserSettings"
/>
</div>
</BaseDialog>
</SDKContext.Provider>
);
}
}
5 changes: 3 additions & 2 deletions src/components/views/settings/devices/useOwnDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ import { VerificationRequest } from "matrix-js-sdk/src/crypto-api";
import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";

import MatrixClientContext from "../../../../contexts/MatrixClientContext";
import { _t } from "../../../../languageHandler";
import { getDeviceClientInformation, pruneClientInformation } from "../../../../utils/device/clientInformation";
import { DevicesDictionary, ExtendedDevice, ExtendedDeviceAppInfo } from "./types";
import { useEventEmitter } from "../../../../hooks/useEventEmitter";
import { parseUserAgent } from "../../../../utils/device/parseUserAgent";
import { isDeviceVerified } from "../../../../utils/device/isDeviceVerified";
import { SDKContext } from "../../../../contexts/SDKContext";

const parseDeviceExtendedInformation = (matrixClient: MatrixClient, device: IMyDevice): ExtendedDeviceAppInfo => {
const { name, version, url } = getDeviceClientInformation(matrixClient, device.device_id);
Expand Down Expand Up @@ -90,7 +90,8 @@ export type DevicesState = {
supportsMSC3881?: boolean | undefined;
};
export const useOwnDevices = (): DevicesState => {
const matrixClient = useContext(MatrixClientContext);
const sdkContext = useContext(SDKContext);
const matrixClient = sdkContext.client!;

const currentDeviceId = matrixClient.getDeviceId()!;
const userId = matrixClient.getSafeUserId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ import SettingsSubsection, { SettingsSubsectionText } from "../../shared/Setting
import { SettingsSubsectionHeading } from "../../shared/SettingsSubsectionHeading";
import Heading from "../../../typography/Heading";
import InlineSpinner from "../../../elements/InlineSpinner";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
import { ThirdPartyIdentifier } from "../../../../../AddThreepid";
import { getDelegatedAuthAccountUrl } from "../../../../../utils/oidc/getDelegatedAuthAccountUrl";
import { SDKContext } from "../../../../../contexts/SDKContext";

interface IProps {
closeSettingsFn: () => void;
Expand Down Expand Up @@ -94,20 +93,22 @@ interface IState {
}

export default class GeneralUserSettingsTab extends React.Component<IProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public static contextType = SDKContext;
public context!: React.ContextType<typeof SDKContext>;

private readonly dispatcherRef: string;

public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
super(props);
this.context = context;

const cli = this.context.client!;

this.state = {
language: languageHandler.getCurrentLanguage(),
spellCheckEnabled: false,
spellCheckLanguages: [],
haveIdServer: Boolean(this.context.getIdentityServerUrl()),
haveIdServer: Boolean(cli.getIdentityServerUrl()),
idServerHasUnsignedTerms: false,
requiredPolicyInfo: {
// This object is passed along to a component for handling
Expand Down Expand Up @@ -150,7 +151,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta

private onAction = (payload: ActionPayload): void => {
if (payload.action === "id_server_changed") {
this.setState({ haveIdServer: Boolean(this.context.getIdentityServerUrl()) });
this.setState({ haveIdServer: Boolean(this.context.client!.getIdentityServerUrl()) });
this.getThreepidState();
}
};
Expand All @@ -164,7 +165,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
};

private async getCapabilities(): Promise<void> {
const cli = this.context;
const cli = this.context.client!;

const capabilities = await cli.getCapabilities(); // this is cached
const changePasswordCap = capabilities["m.change_password"];
Expand All @@ -174,7 +175,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
// the enabled flag value.
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;

const externalAccountManagementUrl = getDelegatedAuthAccountUrl(cli.getClientWellKnown());
const externalAccountManagementUrl = this.context.oidcClientStore.accountManagementEndpoint;
// https://spec.matrix.org/v1.7/client-server-api/#m3pid_changes-capability
// We support as far back as v1.1 which doesn't have m.3pid_changes
// so the behaviour for when it is missing has to be assume true
Expand All @@ -184,7 +185,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
}

private async getThreepidState(): Promise<void> {
const cli = this.context;
const cli = this.context.client!;

// Check to see if terms need accepting
this.checkTerms();
Expand All @@ -195,7 +196,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
try {
threepids = await getThreepidsWithBindStatus(cli);
} catch (e) {
const idServerUrl = this.context.getIdentityServerUrl();
const idServerUrl = cli.getIdentityServerUrl();
logger.warn(
`Unable to reach identity server at ${idServerUrl} to check ` + `for 3PIDs bindings in Settings`,
);
Expand All @@ -211,7 +212,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private async checkTerms(): Promise<void> {
// By starting the terms flow we get the logic for checking which terms the user has signed
// for free. So we might as well use that for our own purposes.
const idServerUrl = this.context.getIdentityServerUrl();
const idServerUrl = this.context.client!.getIdentityServerUrl();
if (!this.state.haveIdServer || !idServerUrl) {
this.setState({ idServerHasUnsignedTerms: false });
return;
Expand All @@ -221,7 +222,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
try {
const idAccessToken = await authClient.getAccessToken({ check: false });
await startTermsFlow(
this.context,
this.context.client!,
[new Service(SERVICE_TYPES.IS, idServerUrl, idAccessToken!)],
(policiesAndServices, agreedUrls, extraClassNames) => {
return new Promise((resolve, reject) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";

import { _t } from "../../../../../languageHandler";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
import Modal from "../../../../../Modal";
import SettingsSubsection from "../../shared/SettingsSubsection";
import SetupEncryptionDialog from "../../../dialogs/security/SetupEncryptionDialog";
Expand All @@ -39,8 +38,8 @@ import QuestionDialog from "../../../dialogs/QuestionDialog";
import { FilterVariation } from "../../devices/filter";
import { OtherSessionsSectionHeading } from "../../devices/OtherSessionsSectionHeading";
import { SettingsSection } from "../../shared/SettingsSection";
import { getDelegatedAuthAccountUrl } from "../../../../../utils/oidc/getDelegatedAuthAccountUrl";
import { OidcLogoutDialog } from "../../../dialogs/oidc/OidcLogoutDialog";
import { SDKContext } from "../../../../../contexts/SDKContext";

const confirmSignOut = async (sessionsToSignOutCount: number): Promise<boolean> => {
const { finished } = Modal.createDialog(QuestionDialog, {
Expand Down Expand Up @@ -167,13 +166,14 @@ const SessionManagerTab: React.FC = () => {
const filteredDeviceListRef = useRef<HTMLDivElement>(null);
const scrollIntoViewTimeoutRef = useRef<number>();

const matrixClient = useContext(MatrixClientContext);
const sdkContext = useContext(SDKContext);
const matrixClient = sdkContext.client!;
/**
* If we have a delegated auth account management URL, all sessions but the current session need to be managed in the
* delegated auth provider.
* See https://github.com/matrix-org/matrix-spec-proposals/pull/3824
*/
const delegatedAuthAccountUrl = getDelegatedAuthAccountUrl(matrixClient.getClientWellKnown());
const delegatedAuthAccountUrl = sdkContext.oidcClientStore.accountManagementEndpoint;
const disableMultipleSignout = !!delegatedAuthAccountUrl;

const userId = matrixClient?.getUserId();
Expand Down
27 changes: 0 additions & 27 deletions src/utils/oidc/getDelegatedAuthAccountUrl.ts

This file was deleted.

18 changes: 12 additions & 6 deletions test/components/views/dialogs/UserSettingsDialog-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ limitations under the License.

import React, { ReactElement } from "react";
import { render } from "@testing-library/react";
import { mocked } from "jest-mock";
import { mocked, MockedObject } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import SettingsStore, { CallbackFn } from "../../../../src/settings/SettingsStore";
import SdkConfig from "../../../../src/SdkConfig";
Expand All @@ -30,6 +31,7 @@ import {
} from "../../../test-utils";
import { UIFeature } from "../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import { SdkContextClass } from "../../../../src/contexts/SDKContext";

mockPlatformPeg({
supportsSpellCheckSettings: jest.fn().mockReturnValue(false),
Expand All @@ -55,18 +57,22 @@ describe("<UserSettingsDialog />", () => {
const userId = "@alice:server.org";
const mockSettingsStore = mocked(SettingsStore);
const mockSdkConfig = mocked(SdkConfig);
getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
...mockClientMethodsServer(),
});
let mockClient!: MockedObject<MatrixClient>;

let sdkContext: SdkContextClass;
const defaultProps = { onFinished: jest.fn() };
const getComponent = (props: Partial<typeof defaultProps & { initialTabId?: UserTab }> = {}): ReactElement => (
<UserSettingsDialog {...defaultProps} {...props} />
<UserSettingsDialog sdkContext={sdkContext} {...defaultProps} {...props} />
);

beforeEach(() => {
jest.clearAllMocks();
mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
...mockClientMethodsServer(),
});
sdkContext = new SdkContextClass();
sdkContext.client = mockClient;
mockSettingsStore.getValue.mockReturnValue(false);
mockSettingsStore.getFeatureSettingNames.mockReturnValue([]);
mockSdkConfig.get.mockReturnValue({ brand: "Test" });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ limitations under the License.

import { fireEvent, render, screen, within } from "@testing-library/react";
import React from "react";
import { M_AUTHENTICATION, ThreepidMedium } from "matrix-js-sdk/src/matrix";
import { ThreepidMedium } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";

import GeneralUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/GeneralUserSettingsTab";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
import { SdkContextClass, SDKContext } from "../../../../../../src/contexts/SDKContext";
import SettingsStore from "../../../../../../src/settings/SettingsStore";
import {
getMockClientWithEventEmitter,
Expand All @@ -28,6 +28,7 @@ import {
} from "../../../../../test-utils";
import { UIFeature } from "../../../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
import { OidcClientStore } from "../../../../../../src/stores/oidc/OidcClientStore";

describe("<GeneralUserSettingsTab />", () => {
const defaultProps = {
Expand All @@ -44,19 +45,18 @@ describe("<GeneralUserSettingsTab />", () => {
deleteThreePid: jest.fn(),
});

let stores: SdkContextClass;

const getComponent = () => (
<MatrixClientContext.Provider value={mockClient}>
<SDKContext.Provider value={stores}>
<GeneralUserSettingsTab {...defaultProps} />
</MatrixClientContext.Provider>
</SDKContext.Provider>
);

const clientWellKnownSpy = jest.spyOn(mockClient, "getClientWellKnown");

beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
mockPlatformPeg();
jest.clearAllMocks();
clientWellKnownSpy.mockReturnValue({});
jest.spyOn(SettingsStore, "getValue").mockRestore();
jest.spyOn(logger, "error").mockRestore();

Expand All @@ -67,6 +67,12 @@ describe("<GeneralUserSettingsTab />", () => {
mockClient.deleteThreePid.mockResolvedValue({
id_server_unbind_result: "success",
});

stores = new SdkContextClass();
stores.client = mockClient;
// stub out this store completely to avoid mocking initialisation
const mockOidcClientStore = {} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
});

it("does not show account management link when not available", () => {
Expand All @@ -78,12 +84,11 @@ describe("<GeneralUserSettingsTab />", () => {

it("show account management link in expected format", async () => {
const accountManagementLink = "https://id.server.org/my-account";
clientWellKnownSpy.mockReturnValue({
[M_AUTHENTICATION.name]: {
issuer: "https://id.server.org",
account: accountManagementLink,
},
});
const mockOidcClientStore = {
accountManagementEndpoint: accountManagementLink,
} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);

const { getByTestId } = render(getComponent());

// wait for well-known call to settle
Expand Down Expand Up @@ -167,12 +172,11 @@ describe("<GeneralUserSettingsTab />", () => {
(settingName) => settingName === UIFeature.Deactivate,
);
// account is managed externally when we have delegated auth configured
mockClient.getClientWellKnown.mockReturnValue({
[M_AUTHENTICATION.name]: {
issuer: "https://issuer.org",
account: "https://issuer.org/account",
},
});
const accountManagementLink = "https://id.server.org/my-account";
const mockOidcClientStore = {
accountManagementEndpoint: accountManagementLink,
} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
render(getComponent());

await flushPromises();
Expand Down
Loading
Loading