feat(frontend): don't break signup pages on reload
This commit is contained in:
		
							parent
							
								
									32e0c09d06
								
							
						
					
					
						commit
						74800b46ef
					
				
					 13 changed files with 79 additions and 88 deletions
				
			
		|  | @ -94,8 +94,7 @@ public class FediverseAuthController( | |||
|     public async Task<IActionResult> RegisterAsync([FromBody] OauthRegisterRequest req) | ||||
|     { | ||||
|         FediverseTicketData? ticketData = await keyCacheService.GetKeyAsync<FediverseTicketData>( | ||||
|             $"fediverse:{req.Ticket}", | ||||
|             true | ||||
|             $"fediverse:{req.Ticket}" | ||||
|         ); | ||||
|         if (ticketData == null) | ||||
|             throw new ApiError.BadRequest("Invalid ticket", "ticket", req.Ticket); | ||||
|  |  | |||
|  | @ -4,10 +4,12 @@ import type { AddAccountResponse, CallbackResponse } from "$api/models"; | |||
| import { setToken } from "$lib"; | ||||
| import log from "$lib/log"; | ||||
| import { isRedirect, redirect, type ServerLoadEvent } from "@sveltejs/kit"; | ||||
| import type { TicketData } from "../../routes/auth/callback/register/[ticket]/+page.server"; | ||||
| 
 | ||||
| export default function createCallbackLoader( | ||||
| 	callbackType: string, | ||||
| 	bodyFn?: (event: ServerLoadEvent) => Promise<unknown>, | ||||
| 	returnData?: boolean, | ||||
| ) { | ||||
| 	return async (event: ServerLoadEvent) => { | ||||
| 		const { parent, fetch, cookies } = event; | ||||
|  | @ -53,12 +55,23 @@ export default function createCallbackLoader( | |||
| 				redirect(303, `/@${resp.user!.username}`); | ||||
| 			} | ||||
| 
 | ||||
| 			if (returnData) | ||||
| 				return { | ||||
| 				hasAccount: false, | ||||
| 				isLinkRequest: false, | ||||
| 					ticket: resp.ticket!, | ||||
| 					remoteUser: resp.remote_username!, | ||||
| 				}; | ||||
| 
 | ||||
| 			const ticket = btoa( | ||||
| 				JSON.stringify({ | ||||
| 					type: callbackType, | ||||
| 					ticket: resp.ticket!, | ||||
| 					remoteUsername: resp.remote_username!, | ||||
| 				} satisfies TicketData), | ||||
| 			) | ||||
| 				.replaceAll("+", "-") | ||||
| 				.replaceAll("/", "_"); | ||||
| 
 | ||||
| 			redirect(303, "/auth/callback/register/" + ticket); | ||||
| 		} catch (e) { | ||||
| 			if (isRedirect(e)) throw e; | ||||
| 			if (e instanceof ApiError) return { isLinkRequest: false, error: e.obj }; | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ | |||
| 		"remote-fediverse-account-label": "Your Fediverse account", | ||||
| 		"register-username-label": "Username", | ||||
| 		"register-button": "Register account", | ||||
| 		"register-with-mastodon": "Register with a Fediverse account", | ||||
| 		"register-with-fediverse": "Register with a Fediverse account", | ||||
| 		"log-in-with-fediverse-error-blurb": "Is your instance returning an error?", | ||||
| 		"log-in-with-fediverse-force-refresh-button": "Force a refresh on our end", | ||||
| 		"register-with-discord": "Register with a Discord account", | ||||
|  |  | |||
|  | @ -1,8 +1,3 @@ | |||
| import createCallbackLoader from "$lib/actions/callback"; | ||||
| import createRegisterAction from "$lib/actions/register"; | ||||
| 
 | ||||
| export const load = createCallbackLoader("discord"); | ||||
| 
 | ||||
| export const actions = { | ||||
| 	default: createRegisterAction("/auth/discord/register"), | ||||
| }; | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| <script lang="ts"> | ||||
| 	import Error from "$components/Error.svelte"; | ||||
| 	import NewAuthMethod from "$components/settings/NewAuthMethod.svelte"; | ||||
| 	import OauthRegistrationForm from "$components/settings/OauthRegistrationForm.svelte"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import type { ActionData, PageData } from "./$types"; | ||||
| 	import type { PageData } from "./$types"; | ||||
| 
 | ||||
| 	type Props = { data: PageData; form: ActionData }; | ||||
| 	let { data, form }: Props = $props(); | ||||
| 	type Props = { data: PageData }; | ||||
| 	let { data }: Props = $props(); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
|  | @ -17,15 +16,7 @@ | |||
| 	{#if data.error} | ||||
| 		<h1>{$t("auth.register-with-discord")}</h1> | ||||
| 		<Error error={data.error} /> | ||||
| 	{:else if data.isLinkRequest} | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{:else} | ||||
| 		<OauthRegistrationForm | ||||
| 			title={$t("auth.register-with-discord")} | ||||
| 			remoteLabel={$t("auth.remote-discord-account-label")} | ||||
| 			remoteUser={data.remoteUser!} | ||||
| 			ticket={data.ticket!} | ||||
| 			error={form?.error} | ||||
| 		/> | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{/if} | ||||
| </div> | ||||
|  |  | |||
|  | @ -1,8 +1,3 @@ | |||
| import createCallbackLoader from "$lib/actions/callback"; | ||||
| import createRegisterAction from "$lib/actions/register"; | ||||
| 
 | ||||
| export const load = createCallbackLoader("google"); | ||||
| 
 | ||||
| export const actions = { | ||||
| 	default: createRegisterAction("/auth/google/register"), | ||||
| }; | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| <script lang="ts"> | ||||
| 	import Error from "$components/Error.svelte"; | ||||
| 	import NewAuthMethod from "$components/settings/NewAuthMethod.svelte"; | ||||
| 	import OauthRegistrationForm from "$components/settings/OauthRegistrationForm.svelte"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import type { ActionData, PageData } from "./$types"; | ||||
| 	import type { PageData } from "./$types"; | ||||
| 
 | ||||
| 	type Props = { data: PageData; form: ActionData }; | ||||
| 	let { data, form }: Props = $props(); | ||||
| 	type Props = { data: PageData }; | ||||
| 	let { data }: Props = $props(); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
|  | @ -17,15 +16,7 @@ | |||
| 	{#if data.error} | ||||
| 		<h1>{$t("auth.register-with-google")}</h1> | ||||
| 		<Error error={data.error} /> | ||||
| 	{:else if data.isLinkRequest} | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{:else} | ||||
| 		<OauthRegistrationForm | ||||
| 			title={$t("auth.register-with-google")} | ||||
| 			remoteLabel={$t("auth.remote-google-account-label")} | ||||
| 			remoteUser={data.remoteUser!} | ||||
| 			ticket={data.ticket!} | ||||
| 			error={form?.error} | ||||
| 		/> | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{/if} | ||||
| </div> | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| import ApiError, { ErrorCode } from "$api/error"; | ||||
| import createCallbackLoader from "$lib/actions/callback"; | ||||
| import createRegisterAction from "$lib/actions/register"; | ||||
| 
 | ||||
| export const load = createCallbackLoader("fediverse", async ({ params, url }) => { | ||||
| 	const code = url.searchParams.get("code") as string | null; | ||||
|  | @ -10,7 +9,3 @@ export const load = createCallbackLoader("fediverse", async ({ params, url }) => | |||
| 
 | ||||
| 	return { code: code || token, state, instance: params.instance! }; | ||||
| }); | ||||
| 
 | ||||
| export const actions = { | ||||
| 	default: createRegisterAction("/auth/fediverse/register"), | ||||
| }; | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| <script lang="ts"> | ||||
| 	import type { ActionData, PageData } from "./$types"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import Error from "$components/Error.svelte"; | ||||
| 	import OauthRegistrationForm from "$components/settings/OauthRegistrationForm.svelte"; | ||||
| 	import NewAuthMethod from "$components/settings/NewAuthMethod.svelte"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import type { PageData } from "./$types"; | ||||
| 
 | ||||
| 	type Props = { data: PageData; form: ActionData }; | ||||
| 	let { data, form }: Props = $props(); | ||||
| 	type Props = { data: PageData }; | ||||
| 	let { data }: Props = $props(); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
|  | @ -17,15 +16,7 @@ | |||
| 	{#if data.error} | ||||
| 		<h1>{$t("auth.register-with-mastodon")}</h1> | ||||
| 		<Error error={data.error} /> | ||||
| 	{:else if data.isLinkRequest} | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{:else} | ||||
| 		<OauthRegistrationForm | ||||
| 			title={$t("auth.register-with-mastodon")} | ||||
| 			remoteLabel={$t("auth.remote-fediverse-account-label")} | ||||
| 			remoteUser={data.remoteUser!} | ||||
| 			ticket={data.ticket!} | ||||
| 			error={form?.error} | ||||
| 		/> | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{/if} | ||||
| </div> | ||||
|  |  | |||
|  | @ -3,10 +3,23 @@ import ApiError, { ErrorCode, type RawApiError } from "$api/error"; | |||
| import type { AuthResponse } from "$api/models/auth"; | ||||
| import { setToken } from "$lib"; | ||||
| import log from "$lib/log"; | ||||
| import { isRedirect, redirect, type RequestEvent } from "@sveltejs/kit"; | ||||
| import { isRedirect, redirect } from "@sveltejs/kit"; | ||||
| 
 | ||||
| export type TicketData = { | ||||
| 	type: string; | ||||
| 	ticket: string; | ||||
| 	remoteUsername: string; | ||||
| }; | ||||
| 
 | ||||
| export const load = async ({ params }) => { | ||||
| 	const data = JSON.parse(atob(params.ticket)) as TicketData; | ||||
| 	return data; | ||||
| }; | ||||
| 
 | ||||
| export const actions = { | ||||
| 	default: async ({ request, fetch, cookies, params }) => { | ||||
| 		const type = (JSON.parse(atob(params.ticket)) as TicketData).type; | ||||
| 
 | ||||
| export default function createRegisterAction(callbackUrl: string) { | ||||
| 	return async function ({ request, fetch, cookies }: RequestEvent) { | ||||
| 		const data = await request.formData(); | ||||
| 		const username = data.get("username") as string | null; | ||||
| 		const ticket = data.get("ticket") as string | null; | ||||
|  | @ -17,7 +30,7 @@ export default function createRegisterAction(callbackUrl: string) { | |||
| 			}; | ||||
| 
 | ||||
| 		try { | ||||
| 			const resp = await apiRequest<AuthResponse>("POST", callbackUrl, { | ||||
| 			const resp = await apiRequest<AuthResponse>("POST", `/auth/${type}/register`, { | ||||
| 				body: { username, ticket }, | ||||
| 				isInternal: true, | ||||
| 				fetch, | ||||
|  | @ -31,5 +44,5 @@ export default function createRegisterAction(callbackUrl: string) { | |||
| 			if (e instanceof ApiError) return { error: e.obj }; | ||||
| 			throw e; | ||||
| 		} | ||||
| 	}, | ||||
| }; | ||||
| } | ||||
|  | @ -0,0 +1,22 @@ | |||
| <script lang="ts"> | ||||
| 	import OauthRegistrationForm from "$components/settings/OauthRegistrationForm.svelte"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import type { ActionData, PageData } from "./$types"; | ||||
| 
 | ||||
| 	type Props = { data: PageData; form: ActionData }; | ||||
| 	let { data, form }: Props = $props(); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
| 	<title>{$t(`auth.register-with-${data.type}`)} • pronouns.cc</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <div class="container"> | ||||
| 	<OauthRegistrationForm | ||||
| 		title={$t(`auth.register-with-${data.type}`)} | ||||
| 		remoteLabel={$t(`auth.remote-${data.type}-account-label`)} | ||||
| 		remoteUser={data.remoteUsername} | ||||
| 		ticket={data.ticket} | ||||
| 		error={form?.error} | ||||
| 	/> | ||||
| </div> | ||||
|  | @ -1,8 +1,3 @@ | |||
| import createCallbackLoader from "$lib/actions/callback"; | ||||
| import createRegisterAction from "$lib/actions/register"; | ||||
| 
 | ||||
| export const load = createCallbackLoader("tumblr"); | ||||
| 
 | ||||
| export const actions = { | ||||
| 	default: createRegisterAction("/auth/tumblr/register"), | ||||
| }; | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| <script lang="ts"> | ||||
| 	import Error from "$components/Error.svelte"; | ||||
| 	import NewAuthMethod from "$components/settings/NewAuthMethod.svelte"; | ||||
| 	import OauthRegistrationForm from "$components/settings/OauthRegistrationForm.svelte"; | ||||
| 	import { t } from "$lib/i18n"; | ||||
| 	import type { ActionData, PageData } from "./$types"; | ||||
| 	import type { PageData } from "./$types"; | ||||
| 
 | ||||
| 	type Props = { data: PageData; form: ActionData }; | ||||
| 	let { data, form }: Props = $props(); | ||||
| 	type Props = { data: PageData }; | ||||
| 	let { data }: Props = $props(); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
|  | @ -17,15 +16,7 @@ | |||
| 	{#if data.error} | ||||
| 		<h1>{$t("auth.register-with-tumblr")}</h1> | ||||
| 		<Error error={data.error} /> | ||||
| 	{:else if data.isLinkRequest} | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{:else} | ||||
| 		<OauthRegistrationForm | ||||
| 			title={$t("auth.register-with-tumblr")} | ||||
| 			remoteLabel={$t("auth.remote-tumblr-account-label")} | ||||
| 			remoteUser={data.remoteUser!} | ||||
| 			ticket={data.ticket!} | ||||
| 			error={form?.error} | ||||
| 		/> | ||||
| 		<NewAuthMethod method={data.newAuthMethod!} user={data.meUser!} /> | ||||
| 	{/if} | ||||
| </div> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue