import { h, Component } from '/js/web_modules/preact.js'; import htm from '/js/web_modules/htm.js'; const html = htm.bind(h); export default class FediverseAuth extends Component { constructor(props) { super(props); this.submitButtonPressed = this.submitButtonPressed.bind(this); this.state = { account: '', code: '', errorMessage: null, loading: false, verifying: false, valid: false, }; } async makeRequest(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) { this.setState({ errorMessage: content.message, loading: false }); return; } } switchToCodeVerify() { this.setState({ verifying: true, loading: false }); } async validateCodeButtonPressed() { const { accessToken } = this.props; const { code } = this.state; this.setState({ loading: true, errorMessage: null }); const url = `/api/auth/fediverse/verify?accessToken=${accessToken}`; const data = { code: code }; try { await this.makeRequest(url, data); // Success. Reload the page. window.location = '/'; } catch (e) { console.error(e); this.setState({ errorMessage: e, loading: false }); } } async registerAccountButtonPressed() { const { accessToken } = this.props; const { account, valid } = this.state; if (!valid) { return; } const url = `/api/auth/fediverse?accessToken=${accessToken}`; const normalizedAccount = account.replace(/^@+/, ''); const data = { account: normalizedAccount }; this.setState({ loading: true, errorMessage: null }); try { await this.makeRequest(url, data); this.switchToCodeVerify(); } catch (e) { console.error(e); this.setState({ errorMessage: e, loading: false }); } } async submitButtonPressed() { const { verifying } = this.state; if (verifying) { this.validateCodeButtonPressed(); } else { this.registerAccountButtonPressed(); } } onInput = (e) => { const { value } = e.target; const { verifying } = this.state; if (verifying) { this.setState({ code: value }); return; } const valid = validateAccount(value); this.setState({ account: value, valid }); }; render() { const { errorMessage, account, code, valid, loading, verifying } = this.state; const { authenticated, username } = this.props; const buttonState = valid ? '' : 'cursor-not-allowed opacity-50'; const loaderStyle = loading ? 'flex' : 'none'; const message = verifying ? '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.' : !authenticated ? html`Receive a direct message from on the Fediverse to ${' '} link your account to ${' '} ${username}, or login as a previously linked chat user.` : html`You are already authenticated. However, you can add other accounts or log in as a different user.`; const label = verifying ? 'Code' : 'Your fediverse account'; const placeholder = verifying ? '123456' : 'youraccount@fediverse.server'; const buttonText = verifying ? 'Verify' : 'Authenticate with Fediverse'; const error = errorMessage ? html`
${message}
${error}
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.
Learn more about using the Fediverse to authenticate with chat.
Authenticating.
Please wait...