/* Copyright 2024 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import React from "react"; import { chunk } from "lodash"; import classNames from "classnames"; import { MatrixClient, IdentityProviderBrand, SSOFlow, SSOAction, IIdentityProvider, DELEGATED_OIDC_COMPATIBILITY, } from "matrix-js-sdk/src/matrix"; import { Signup } from "@matrix-org/analytics-events/types/typescript/Signup"; import PlatformPeg from "../../../PlatformPeg"; import AccessibleButton from "./AccessibleButton"; import { _t } from "../../../languageHandler"; import { mediaFromMxc } from "../../../customisations/Media"; import { PosthogAnalytics } from "../../../PosthogAnalytics"; interface ISSOButtonProps extends IProps { idp?: IIdentityProvider; mini?: boolean; action?: SSOAction; } const getIcon = (brand: IdentityProviderBrand | string): string | null => { switch (brand) { /* eslint-disable @typescript-eslint/no-require-imports */ case IdentityProviderBrand.Apple: return require(`../../../../res/img/element-icons/brands/apple.svg`).default; case IdentityProviderBrand.Facebook: return require(`../../../../res/img/element-icons/brands/facebook.svg`).default; case IdentityProviderBrand.Github: return require(`../../../../res/img/element-icons/brands/github.svg`).default; case IdentityProviderBrand.Gitlab: return require(`../../../../res/img/element-icons/brands/gitlab.svg`).default; case IdentityProviderBrand.Google: return require(`../../../../res/img/element-icons/brands/google.svg`).default; case IdentityProviderBrand.Twitter: return require(`../../../../res/img/element-icons/brands/twitter.svg`).default; default: return null; /* eslint-enable @typescript-eslint/no-require-imports */ } }; const getAuthenticationType = (brand: IdentityProviderBrand | string): Signup["authenticationType"] => { switch (brand) { case IdentityProviderBrand.Apple: return "Apple"; case IdentityProviderBrand.Facebook: return "Facebook"; case IdentityProviderBrand.Github: return "GitHub"; case IdentityProviderBrand.Gitlab: return "GitLab"; case IdentityProviderBrand.Google: return "Google"; // Not supported on the analytics SDK at the moment. // case IdentityProviderBrand.Twitter: // return "Twitter"; default: return "SSO"; } }; const SSOButton: React.FC = ({ matrixClient, loginType, fragmentAfterLogin, idp, primary, mini, action, flow, ...props }) => { let label: string; if (idp) { label = _t("auth|continue_with_idp", { provider: idp.name }); } else if (DELEGATED_OIDC_COMPATIBILITY.findIn(flow)) { label = _t("action|continue"); } else { label = _t("auth|sign_in_with_sso"); } const onClick = (): void => { const authenticationType = getAuthenticationType(idp?.brand ?? ""); PosthogAnalytics.instance.setAuthenticationType(authenticationType); PlatformPeg.get()?.startSingleSignOn(matrixClient, loginType, fragmentAfterLogin, idp?.id, action); }; let icon: JSX.Element | undefined; let brandClass: string | undefined; const brandIcon = idp?.brand ? getIcon(idp.brand) : null; if (idp?.brand && brandIcon) { const brandName = idp.brand.split(".").pop(); brandClass = `mx_SSOButton_brand_${brandName}`; icon = {brandName}; } else if (typeof idp?.icon === "string" && idp.icon.startsWith("mxc://")) { const src = mediaFromMxc(idp.icon, matrixClient).getSquareThumbnailHttp(24) ?? undefined; icon = {idp.name}; } const brandPart = brandClass ? { [brandClass]: brandClass } : undefined; const classes = classNames( "mx_SSOButton", { mx_SSOButton_mini: mini, mx_SSOButton_default: !idp, mx_SSOButton_primary: primary, }, brandPart, ); if (mini) { // TODO fallback icon return ( {icon} ); } return ( {icon} {label} ); }; interface IProps { matrixClient: MatrixClient; flow: SSOFlow; loginType: "sso" | "cas"; fragmentAfterLogin?: string; primary?: boolean; action?: SSOAction; disabled?: boolean; } const MAX_PER_ROW = 6; const SSOButtons: React.FC = ({ matrixClient, flow, loginType, fragmentAfterLogin, primary, action, disabled, }) => { const providers = flow.identity_providers || []; if (providers.length < 2) { return (
); } const rows = Math.ceil(providers.length / MAX_PER_ROW); const size = Math.ceil(providers.length / rows); return (
{chunk(providers, size).map((chunk) => (
{chunk.map((idp) => ( ))}
))}
); }; export default SSOButtons;