fix sso login without identity providers

This commit is contained in:
Ajay Bura 2024-09-08 14:35:33 +05:30
parent c6a8fb1117
commit 704f8ebc1e
4 changed files with 72 additions and 63 deletions

View file

@ -1,16 +1,10 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ILoginFlow, IPasswordFlow, ISSOFlow, LoginFlow } from 'matrix-js-sdk/lib/@types/auth'; import { ILoginFlow, IPasswordFlow, ISSOFlow, LoginFlow } from 'matrix-js-sdk/lib/@types/auth';
import { WithRequiredProp } from '../../types/utils';
export type Required_SSOFlow = WithRequiredProp<ISSOFlow, 'identity_providers'>; export const getSSOFlow = (loginFlows: LoginFlow[]): ISSOFlow | undefined =>
export const getSSOFlow = (loginFlows: LoginFlow[]): Required_SSOFlow | undefined => loginFlows.find((flow) => flow.type === 'm.login.sso' || flow.type === 'm.login.cas') as
loginFlows.find( | ISSOFlow
(flow) => | undefined;
(flow.type === 'm.login.sso' || flow.type === 'm.login.cas') &&
'identity_providers' in flow &&
Array.isArray(flow.identity_providers) &&
flow.identity_providers.length > 0
) as Required_SSOFlow | undefined;
export const getPasswordFlow = (loginFlows: LoginFlow[]): IPasswordFlow | undefined => export const getPasswordFlow = (loginFlows: LoginFlow[]): IPasswordFlow | undefined =>
loginFlows.find((flow) => flow.type === 'm.login.password') as IPasswordFlow; loginFlows.find((flow) => flow.type === 'm.login.password') as IPasswordFlow;
@ -22,7 +16,7 @@ export const getTokenFlow = (loginFlows: LoginFlow[]): LoginFlow | undefined =>
export type ParsedLoginFlows = { export type ParsedLoginFlows = {
password?: LoginFlow; password?: LoginFlow;
token?: LoginFlow; token?: LoginFlow;
sso?: Required_SSOFlow; sso?: ISSOFlow;
}; };
export const useParsedLoginFlows = (loginFlows: LoginFlow[]) => { export const useParsedLoginFlows = (loginFlows: LoginFlow[]) => {
const parsedFlow: ParsedLoginFlows = useMemo<ParsedLoginFlows>( const parsedFlow: ParsedLoginFlows = useMemo<ParsedLoginFlows>(

View file

@ -4,69 +4,89 @@ import React, { useMemo } from 'react';
import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo'; import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
type SSOLoginProps = { type SSOLoginProps = {
providers: IIdentityProvider[]; providers?: IIdentityProvider[];
asIcons?: boolean;
redirectUrl: string; redirectUrl: string;
saveScreenSpace?: boolean;
}; };
export function SSOLogin({ providers, redirectUrl, asIcons }: SSOLoginProps) { export function SSOLogin({ providers, redirectUrl, saveScreenSpace }: SSOLoginProps) {
const discovery = useAutoDiscoveryInfo(); const discovery = useAutoDiscoveryInfo();
const baseUrl = discovery['m.homeserver'].base_url; const baseUrl = discovery['m.homeserver'].base_url;
const mx = useMemo(() => createClient({ baseUrl }), [baseUrl]); const mx = useMemo(() => createClient({ baseUrl }), [baseUrl]);
const getSSOIdUrl = (ssoId: string): string => mx.getSsoLoginUrl(redirectUrl, 'sso', ssoId); const getSSOIdUrl = (ssoId?: string): string => mx.getSsoLoginUrl(redirectUrl, 'sso', ssoId);
const anyAsBtn = providers.find( const withoutIcon = providers
(provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false) ? providers.find(
); (provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false)
)
: true;
const renderAsIcons = withoutIcon ? false : saveScreenSpace && providers && providers.length > 2;
return ( return (
<Box justifyContent="Center" gap="600" wrap="Wrap"> <Box justifyContent="Center" gap="600" wrap="Wrap">
{providers.map((provider) => { {providers ? (
const { id, name, icon } = provider; providers.map((provider) => {
const iconUrl = icon && mx.mxcUrlToHttp(icon, 96, 96, 'crop', false); const { id, name, icon } = provider;
const iconUrl = icon && mx.mxcUrlToHttp(icon, 96, 96, 'crop', false);
const buttonTitle = `Continue with ${name}`; const buttonTitle = `Continue with ${name}`;
if (renderAsIcons) {
return (
<Avatar
style={{ cursor: 'pointer' }}
key={id}
as="a"
href={getSSOIdUrl(id)}
aria-label={buttonTitle}
size="300"
radii="300"
>
<AvatarImage src={iconUrl!} alt={name} title={buttonTitle} />
</Avatar>
);
}
if (!anyAsBtn && iconUrl && asIcons) {
return ( return (
<Avatar <Button
style={{ cursor: 'pointer' }} style={{ width: '100%' }}
key={id} key={id}
as="a" as="a"
href={getSSOIdUrl(id)} href={getSSOIdUrl(id)}
aria-label={buttonTitle} size="500"
size="300" variant="Secondary"
radii="300" fill="Soft"
outlined
before={
iconUrl && (
<Avatar size="200" radii="300">
<AvatarImage src={iconUrl} alt={name} />
</Avatar>
)
}
> >
<AvatarImage src={iconUrl} alt={name} title={buttonTitle} /> <Text align="Center" size="B500" truncate>
</Avatar> {buttonTitle}
</Text>
</Button>
); );
} })
) : (
return ( <Button
<Button style={{ width: '100%' }}
style={{ width: '100%' }} as="a"
key={id} href={getSSOIdUrl()}
as="a" size="500"
href={getSSOIdUrl(id)} variant="Secondary"
size="500" fill="Soft"
variant="Secondary" outlined
fill="Soft" >
outlined <Text align="Center" size="B500" truncate>
before={ Continue with SSO
iconUrl && ( </Text>
<Avatar size="200" radii="300"> </Button>
<AvatarImage src={iconUrl} alt={name} /> )}
</Avatar>
)
}
>
<Text align="Center" size="B500" truncate>
{buttonTitle}
</Text>
</Button>
);
})}
</Box> </Box>
); );
} }

View file

@ -76,9 +76,7 @@ export function Login() {
<SSOLogin <SSOLogin
providers={parsedFlows.sso.identity_providers} providers={parsedFlows.sso.identity_providers}
redirectUrl={ssoRedirectUrl} redirectUrl={ssoRedirectUrl}
asIcons={ saveScreenSpace={parsedFlows.password !== undefined}
parsedFlows.password !== undefined && parsedFlows.sso.identity_providers.length > 2
}
/> />
<span data-spacing-node /> <span data-spacing-node />
</> </>

View file

@ -83,10 +83,7 @@ export function Register() {
<SSOLogin <SSOLogin
providers={sso.identity_providers} providers={sso.identity_providers}
redirectUrl={ssoRedirectUrl} redirectUrl={ssoRedirectUrl}
asIcons={ saveScreenSpace={registerFlows.status === RegisterFlowStatus.FlowRequired}
registerFlows.status === RegisterFlowStatus.FlowRequired &&
sso.identity_providers.length > 2
}
/> />
<span data-spacing-node /> <span data-spacing-node />
</> </>