import React, { useMemo } from 'react'; import { Box, Text, color } from 'folds'; import { Link, useSearchParams } from 'react-router-dom'; import { SSOAction } from 'matrix-js-sdk'; import { useAuthFlows } from '../../../hooks/useAuthFlows'; import { useAuthServer } from '../../../hooks/useAuthServer'; import { useParsedLoginFlows } from '../../../hooks/useParsedLoginFlows'; import { PasswordLoginForm } from './PasswordLoginForm'; import { SSOLogin } from '../SSOLogin'; import { TokenLogin } from './TokenLogin'; import { OidcLogin } from './OidcLogin'; import { useAutoDiscoveryInfo } from '../../../hooks/useAutoDiscoveryInfo'; import { getOidcIssuer } from '../../../cs-api'; import { OrDivider } from '../OrDivider'; import { getLoginPath, getRegisterPath, withSearchParam } from '../../pathUtils'; import { usePathWithOrigin } from '../../../hooks/usePathWithOrigin'; import { LoginPathSearchParams } from '../../paths'; import { useClientConfig } from '../../../hooks/useClientConfig'; const getLoginTokenSearchParam = () => { // when using hasRouter query params in existing route // gets ignored by react-router, so we need to read it ourself // we only need to read loginToken as it's the only param that // is provided by external entity. example: SSO login const parmas = new URLSearchParams(window.location.search); const loginToken = parmas.get('loginToken'); return loginToken ?? undefined; }; const useLoginSearchParams = (searchParams: URLSearchParams): LoginPathSearchParams => useMemo( () => ({ username: searchParams.get('username') ?? undefined, email: searchParams.get('email') ?? undefined, loginToken: searchParams.get('loginToken') ?? undefined, }), [searchParams], ); export function Login() { const server = useAuthServer(); const discovery = useAutoDiscoveryInfo(); const { hashRouter } = useClientConfig(); const { loginFlows } = useAuthFlows(); const [searchParams] = useSearchParams(); const loginSearchParams = useLoginSearchParams(searchParams); const ssoRedirectUrl = usePathWithOrigin(getLoginPath(server)); const loginTokenForHashRouter = getLoginTokenSearchParam(); const absoluteLoginPath = usePathWithOrigin(getLoginPath(server)); if (hashRouter?.enabled && loginTokenForHashRouter) { window.location.replace( withSearchParam(absoluteLoginPath, { loginToken: loginTokenForHashRouter, }), ); } const parsedFlows = useParsedLoginFlows(loginFlows.flows); // Next-gen auth (MSC3861/MSC2965): when the server advertises an OIDC issuer in // its `.well-known` discovery, use the native OIDC flow and suppress the // password / legacy-SSO forms (those servers, e.g. MAS, reject `m.login.password`). const oidc = getOidcIssuer(discovery); if (oidc.issuer) { return ( Login Do not have an account? Register ); } return ( Login {parsedFlows.token && loginSearchParams.loginToken && ( )} {parsedFlows.password && ( <> {parsedFlows.sso && } )} {parsedFlows.sso && ( <> )} {!parsedFlows.password && !parsedFlows.sso && ( <> {`This client does not support login on "${server}" homeserver. Password and SSO based login method not found.`} )} Do not have an account? Register ); }