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