import { Alert, Button, Input, Space, Spin, Collapse } from 'antd'; import React, { FC, useState } from 'react'; import dynamic from 'next/dynamic'; import styles from './FediAuthModal.module.scss'; import { validateAccount } from '../../../utils/validators'; const { Panel } = Collapse; // Lazy loaded components const CheckCircleOutlined = dynamic(() => import('@ant-design/icons/CheckCircleOutlined'), { ssr: false, }); export type FediAuthModalProps = { authenticated: boolean; displayName: string; accessToken: string; }; export const FediAuthModal: FC = ({ authenticated, displayName, accessToken, }) => { const [errorMessage, setErrorMessage] = useState(null); const [loading, setLoading] = useState(false); const [valid, setValid] = useState(false); const [account, setAccount] = useState(''); const [code, setCode] = useState(''); const [verifyingCode, setVerifyingCode] = useState(false); const message = !authenticated ? ( Receive a direct message on the Fediverse to link your account to{' '} {displayName}, or login as a previously linked chat user. ) : ( You are already authenticated. However, you can add other domains or log in as a different user. ); let errorMessageText = errorMessage; if (errorMessageText) { if (errorMessageText.includes('url does not support indieauth')) { errorMessageText = 'The provided URL is either invalid or does not support IndieAuth.'; } } const validate = (acct: string) => { setValid(validateAccount(acct)); }; const onInput = (e: React.ChangeEvent) => { setAccount(e.target.value); validate(e.target.value); }; const makeRequest = async (url, data) => { const rawResponse = await fetch(url, { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); const content = await rawResponse.json(); if (content.message) { setErrorMessage(content.message); setLoading(false); } }; const submitCodePressed = async () => { setLoading(true); const url = `/api/auth/fediverse/verify?accessToken=${accessToken}`; const data = { code }; try { await makeRequest(url, data); // Success. Reload the page. window.location.href = '/'; } catch (e) { console.error(e); setErrorMessage(e); } setLoading(false); }; const submitAccountPressed = async () => { if (!valid) { return; } setLoading(true); setErrorMessage(null); const url = `/api/auth/fediverse?accessToken=${accessToken}`; const normalizedAccount = account.replace(/^@+/, ''); const data = { account: normalizedAccount }; try { await makeRequest(url, data); setVerifyingCode(true); } catch (e) { console.error(e); setErrorMessage(e); } setLoading(false); }; const inputCodeStep = (
Paste in the code that was sent to your Fediverse account. If you did not receive a code, make sure you can accept direct messages.
setCode(e.target.value)} className={styles.codeInput} placeholder="123456" maxLength={6} />
); const inputAccountStep = ( <>
Your Fediverse Account
0 ? 'error' : undefined} onSearch={submitAccountPressed} enterButton={ } /> ); return ( {message} {errorMessageText && ( )} {verifyingCode ? inputCodeStep : inputAccountStep}

You can link your chat identity with your Fediverse identity. Next time you want to use this chat identity you can again go through the Fediverse authentication.

Note: This is for authentication purposes only, and no personal information will be accessed or stored.
); };