mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 14:30:29 +03:00 
			
		
		
		
	fix sso login without identity providers (#1934)
This commit is contained in:
		
							parent
							
								
									c6a8fb1117
								
							
						
					
					
						commit
						09444f9e08
					
				
					 4 changed files with 72 additions and 63 deletions
				
			
		| 
						 | 
				
			
			@ -1,16 +1,10 @@
 | 
			
		|||
import { useMemo } from 'react';
 | 
			
		||||
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[]): Required_SSOFlow | undefined =>
 | 
			
		||||
  loginFlows.find(
 | 
			
		||||
    (flow) =>
 | 
			
		||||
      (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 getSSOFlow = (loginFlows: LoginFlow[]): ISSOFlow | undefined =>
 | 
			
		||||
  loginFlows.find((flow) => flow.type === 'm.login.sso' || flow.type === 'm.login.cas') as
 | 
			
		||||
    | ISSOFlow
 | 
			
		||||
    | undefined;
 | 
			
		||||
 | 
			
		||||
export const getPasswordFlow = (loginFlows: LoginFlow[]): IPasswordFlow | undefined =>
 | 
			
		||||
  loginFlows.find((flow) => flow.type === 'm.login.password') as IPasswordFlow;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +16,7 @@ export const getTokenFlow = (loginFlows: LoginFlow[]): LoginFlow | undefined =>
 | 
			
		|||
export type ParsedLoginFlows = {
 | 
			
		||||
  password?: LoginFlow;
 | 
			
		||||
  token?: LoginFlow;
 | 
			
		||||
  sso?: Required_SSOFlow;
 | 
			
		||||
  sso?: ISSOFlow;
 | 
			
		||||
};
 | 
			
		||||
export const useParsedLoginFlows = (loginFlows: LoginFlow[]) => {
 | 
			
		||||
  const parsedFlow: ParsedLoginFlows = useMemo<ParsedLoginFlows>(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,69 +4,89 @@ import React, { useMemo } from 'react';
 | 
			
		|||
import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
 | 
			
		||||
 | 
			
		||||
type SSOLoginProps = {
 | 
			
		||||
  providers: IIdentityProvider[];
 | 
			
		||||
  asIcons?: boolean;
 | 
			
		||||
  providers?: IIdentityProvider[];
 | 
			
		||||
  redirectUrl: string;
 | 
			
		||||
  saveScreenSpace?: boolean;
 | 
			
		||||
};
 | 
			
		||||
export function SSOLogin({ providers, redirectUrl, asIcons }: SSOLoginProps) {
 | 
			
		||||
export function SSOLogin({ providers, redirectUrl, saveScreenSpace }: SSOLoginProps) {
 | 
			
		||||
  const discovery = useAutoDiscoveryInfo();
 | 
			
		||||
  const baseUrl = discovery['m.homeserver'].base_url;
 | 
			
		||||
  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(
 | 
			
		||||
    (provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false)
 | 
			
		||||
  );
 | 
			
		||||
  const withoutIcon = providers
 | 
			
		||||
    ? providers.find(
 | 
			
		||||
        (provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false)
 | 
			
		||||
      )
 | 
			
		||||
    : true;
 | 
			
		||||
 | 
			
		||||
  const renderAsIcons = withoutIcon ? false : saveScreenSpace && providers && providers.length > 2;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Box justifyContent="Center" gap="600" wrap="Wrap">
 | 
			
		||||
      {providers.map((provider) => {
 | 
			
		||||
        const { id, name, icon } = provider;
 | 
			
		||||
        const iconUrl = icon && mx.mxcUrlToHttp(icon, 96, 96, 'crop', false);
 | 
			
		||||
      {providers ? (
 | 
			
		||||
        providers.map((provider) => {
 | 
			
		||||
          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 (
 | 
			
		||||
            <Avatar
 | 
			
		||||
              style={{ cursor: 'pointer' }}
 | 
			
		||||
            <Button
 | 
			
		||||
              style={{ width: '100%' }}
 | 
			
		||||
              key={id}
 | 
			
		||||
              as="a"
 | 
			
		||||
              href={getSSOIdUrl(id)}
 | 
			
		||||
              aria-label={buttonTitle}
 | 
			
		||||
              size="300"
 | 
			
		||||
              radii="300"
 | 
			
		||||
              size="500"
 | 
			
		||||
              variant="Secondary"
 | 
			
		||||
              fill="Soft"
 | 
			
		||||
              outlined
 | 
			
		||||
              before={
 | 
			
		||||
                iconUrl && (
 | 
			
		||||
                  <Avatar size="200" radii="300">
 | 
			
		||||
                    <AvatarImage src={iconUrl} alt={name} />
 | 
			
		||||
                  </Avatar>
 | 
			
		||||
                )
 | 
			
		||||
              }
 | 
			
		||||
            >
 | 
			
		||||
              <AvatarImage src={iconUrl} alt={name} title={buttonTitle} />
 | 
			
		||||
            </Avatar>
 | 
			
		||||
              <Text align="Center" size="B500" truncate>
 | 
			
		||||
                {buttonTitle}
 | 
			
		||||
              </Text>
 | 
			
		||||
            </Button>
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
          <Button
 | 
			
		||||
            style={{ width: '100%' }}
 | 
			
		||||
            key={id}
 | 
			
		||||
            as="a"
 | 
			
		||||
            href={getSSOIdUrl(id)}
 | 
			
		||||
            size="500"
 | 
			
		||||
            variant="Secondary"
 | 
			
		||||
            fill="Soft"
 | 
			
		||||
            outlined
 | 
			
		||||
            before={
 | 
			
		||||
              iconUrl && (
 | 
			
		||||
                <Avatar size="200" radii="300">
 | 
			
		||||
                  <AvatarImage src={iconUrl} alt={name} />
 | 
			
		||||
                </Avatar>
 | 
			
		||||
              )
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <Text align="Center" size="B500" truncate>
 | 
			
		||||
              {buttonTitle}
 | 
			
		||||
            </Text>
 | 
			
		||||
          </Button>
 | 
			
		||||
        );
 | 
			
		||||
      })}
 | 
			
		||||
        })
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button
 | 
			
		||||
          style={{ width: '100%' }}
 | 
			
		||||
          as="a"
 | 
			
		||||
          href={getSSOIdUrl()}
 | 
			
		||||
          size="500"
 | 
			
		||||
          variant="Secondary"
 | 
			
		||||
          fill="Soft"
 | 
			
		||||
          outlined
 | 
			
		||||
        >
 | 
			
		||||
          <Text align="Center" size="B500" truncate>
 | 
			
		||||
            Continue with SSO
 | 
			
		||||
          </Text>
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
    </Box>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,9 +76,7 @@ export function Login() {
 | 
			
		|||
          <SSOLogin
 | 
			
		||||
            providers={parsedFlows.sso.identity_providers}
 | 
			
		||||
            redirectUrl={ssoRedirectUrl}
 | 
			
		||||
            asIcons={
 | 
			
		||||
              parsedFlows.password !== undefined && parsedFlows.sso.identity_providers.length > 2
 | 
			
		||||
            }
 | 
			
		||||
            saveScreenSpace={parsedFlows.password !== undefined}
 | 
			
		||||
          />
 | 
			
		||||
          <span data-spacing-node />
 | 
			
		||||
        </>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,10 +83,7 @@ export function Register() {
 | 
			
		|||
          <SSOLogin
 | 
			
		||||
            providers={sso.identity_providers}
 | 
			
		||||
            redirectUrl={ssoRedirectUrl}
 | 
			
		||||
            asIcons={
 | 
			
		||||
              registerFlows.status === RegisterFlowStatus.FlowRequired &&
 | 
			
		||||
              sso.identity_providers.length > 2
 | 
			
		||||
            }
 | 
			
		||||
            saveScreenSpace={registerFlows.status === RegisterFlowStatus.FlowRequired}
 | 
			
		||||
          />
 | 
			
		||||
          <span data-spacing-node />
 | 
			
		||||
        </>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue