Link device account management with OIDC (#2390)

* load auth metadata configs on startup

* deep-link cross-signing reset button with oidc

* deep-link manage devices and delete device with oidc

* fix import typo
This commit is contained in:
Ajay Bura 2025-07-15 18:10:16 +05:30 committed by GitHub
parent c30c142653
commit c462a3b8d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 185 additions and 52 deletions

View file

@ -11,6 +11,10 @@ import { useUIAMatrixError } from '../../../hooks/useUIAFlows';
import { DeviceVerificationStatus } from '../../../components/DeviceVerificationStatus';
import { VerifyOtherDeviceTile } from './Verification';
import { VerificationStatus } from '../../../hooks/useDeviceVerificationStatus';
import { useAuthMetadata } from '../../../hooks/useAuthMetadata';
import { withSearchParam } from '../../../pages/pathUtils';
import { useAccountManagementActions } from '../../../hooks/useAccountManagement';
import { SettingTile } from '../../../components/setting-tile';
type OtherDevicesProps = {
devices: IMyDevice[];
@ -20,8 +24,39 @@ type OtherDevicesProps = {
export function OtherDevices({ devices, refreshDeviceList, showVerification }: OtherDevicesProps) {
const mx = useMatrixClient();
const crypto = mx.getCrypto();
const authMetadata = useAuthMetadata();
const accountManagementActions = useAccountManagementActions();
const [deleted, setDeleted] = useState<Set<string>>(new Set());
const handleDashboardOIDC = useCallback(() => {
const authUrl = authMetadata?.account_management_uri ?? authMetadata?.issuer;
if (!authUrl) return;
window.open(
withSearchParam(authUrl, {
action: accountManagementActions.sessionsList,
}),
'_blank'
);
}, [authMetadata, accountManagementActions]);
const handleDeleteOIDC = useCallback(
(deviceId: string) => {
const authUrl = authMetadata?.account_management_uri ?? authMetadata?.issuer;
if (!authUrl) return;
window.open(
withSearchParam(authUrl, {
action: accountManagementActions.sessionEnd,
device_id: deviceId,
}),
'_blank'
);
},
[authMetadata, accountManagementActions]
);
const handleToggleDelete = useCallback((deviceId: string) => {
setDeleted((deviceIds) => {
const newIds = new Set(deviceIds);
@ -70,6 +105,31 @@ export function OtherDevices({ devices, refreshDeviceList, showVerification }: O
<>
<Box direction="Column" gap="100">
<Text size="L400">Others</Text>
{authMetadata && (
<SequenceCard
className={SequenceCardStyle}
variant="SurfaceVariant"
direction="Column"
gap="400"
>
<SettingTile
title="Device Dashboard"
description="Manage your devices on OIDC dashboard."
after={
<Button
size="300"
variant="Secondary"
fill="Soft"
radii="300"
outlined
onClick={handleDashboardOIDC}
>
<Text size="B300">Open</Text>
</Button>
}
/>
</SequenceCard>
)}
{devices
.sort((d1, d2) => {
if (!d1.last_seen_ts || !d2.last_seen_ts) return 0;
@ -89,12 +149,20 @@ export function OtherDevices({ devices, refreshDeviceList, showVerification }: O
refreshDeviceList={refreshDeviceList}
disabled={deleting}
options={
<DeviceDeleteBtn
deviceId={device.device_id}
deleted={deleted.has(device.device_id)}
onDeleteToggle={handleToggleDelete}
disabled={deleting}
/>
authMetadata ? (
<DeviceDeleteBtn
deviceId={device.device_id}
deleted={false}
onDeleteToggle={handleDeleteOIDC}
/>
) : (
<DeviceDeleteBtn
deviceId={device.device_id}
deleted={deleted.has(device.device_id)}
onDeleteToggle={handleToggleDelete}
disabled={deleting}
/>
)
}
/>
{showVerification && crypto && (

View file

@ -32,6 +32,9 @@ import {
DeviceVerificationSetup,
} from '../../../components/DeviceVerificationSetup';
import { stopPropagation } from '../../../utils/keyboard';
import { useAuthMetadata } from '../../../hooks/useAuthMetadata';
import { withSearchParam } from '../../../pages/pathUtils';
import { useAccountManagementActions } from '../../../hooks/useAccountManagement';
type VerificationStatusBadgeProps = {
verificationStatus: VerificationStatus;
@ -252,6 +255,8 @@ export function EnableVerification({ visible }: EnableVerificationProps) {
export function DeviceVerificationOptions() {
const [menuCords, setMenuCords] = useState<RectCords>();
const authMetadata = useAuthMetadata();
const accountManagementActions = useAccountManagementActions();
const [reset, setReset] = useState(false);
@ -265,6 +270,18 @@ export function DeviceVerificationOptions() {
const handleReset = () => {
setMenuCords(undefined);
if (authMetadata) {
const authUrl = authMetadata.account_management_uri ?? authMetadata.issuer;
window.open(
withSearchParam(authUrl, {
action: accountManagementActions.crossSigningReset,
}),
'_blank'
);
return;
}
setReset(true);
};