From 5d414996a0d2192fc2ad4e20eacc03ef3aa622b5 Mon Sep 17 00:00:00 2001 From: aumetra Date: Mon, 12 Aug 2024 10:19:57 +0200 Subject: [PATCH] oauth progress --- flake.nix | 2 + kitsune-fe/package-lock.json | 1 + kitsune-fe/src/client.ts | 24 +++---- kitsune-fe/src/lib/oauth/auth.svelte.ts | 12 ++++ kitsune-fe/src/lib/oauth/client.svelte.ts | 76 +++++++++++++++++++++++ 5 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 kitsune-fe/src/lib/oauth/auth.svelte.ts create mode 100644 kitsune-fe/src/lib/oauth/client.svelte.ts diff --git a/flake.nix b/flake.nix index 4239b5a18..65c51252d 100644 --- a/flake.nix +++ b/flake.nix @@ -105,6 +105,8 @@ packages = rec { default = main; + devenv-up = self.devShells.${system}.default.config.procfileScript; + cli = craneLib.buildPackage ( commonArgs // { diff --git a/kitsune-fe/package-lock.json b/kitsune-fe/package-lock.json index b0a79ddfa..234d88b4a 100644 --- a/kitsune-fe/package-lock.json +++ b/kitsune-fe/package-lock.json @@ -373,6 +373,7 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/kitsune-fe/src/client.ts b/kitsune-fe/src/client.ts index 2cb2e522b..f39e63907 100644 --- a/kitsune-fe/src/client.ts +++ b/kitsune-fe/src/client.ts @@ -1,15 +1,15 @@ -import { HoudiniClient } from '$houdini'; +import { HoudiniClient, getClientSession } from '$houdini'; +import { houdiniPlugin as authPlugin } from '$lib/oauth/auth.svelte'; export default new HoudiniClient({ - url: `${import.meta.env.VITE_BACKEND_URL ?? ''}/graphql` - - // uncomment this to configure the network call (for things like authentication) - // for more information, please visit here: https://www.houdinigraphql.com/guides/authentication - // fetchParams({ session }) { - // return { - // headers: { - // Authentication: `Bearer ${session.token}`, - // } - // } - // } + url: `${import.meta.env.VITE_BACKEND_URL ?? ''}/graphql`, + plugins: [authPlugin], + fetchParams(wha) { + const session = getClientSession(); + return { + headers: { + ...session.headers + } + }; + } }); diff --git a/kitsune-fe/src/lib/oauth/auth.svelte.ts b/kitsune-fe/src/lib/oauth/auth.svelte.ts new file mode 100644 index 000000000..28c64b842 --- /dev/null +++ b/kitsune-fe/src/lib/oauth/auth.svelte.ts @@ -0,0 +1,12 @@ +import { setClientSession, type ClientPlugin } from '$houdini'; + +const houdiniPlugin: ClientPlugin = () => { + return { + async start(ctx, { next }) { + setClientSession({ headers: { owo: 'uwu' } }); + next(ctx); + } + }; +}; + +export { houdiniPlugin }; diff --git a/kitsune-fe/src/lib/oauth/client.svelte.ts b/kitsune-fe/src/lib/oauth/client.svelte.ts new file mode 100644 index 000000000..e8281eabc --- /dev/null +++ b/kitsune-fe/src/lib/oauth/client.svelte.ts @@ -0,0 +1,76 @@ +import { RegisterOAuthAppStore } from '$houdini'; + +import { readable, type Readable } from 'svelte/store'; +import { z } from 'zod'; + +const OAUTH_STORAGE_KEY = 'oauth_app'; +const OAUTH_APP_SCHEMA = z.object({ + id: z.string().min(1), + secret: z.string().min(1) +}); + +const REGISTER_APP = new RegisterOAuthAppStore(); + +type OAuthApplicationTy = z.infer; + +async function registerOAuthApp(): Promise { + const redirectUri = `${window.location.origin}/oauth-callback`; + + try { + const response = await REGISTER_APP.mutate({ + redirectUri + }); + + if (response.errors) { + throw new Error(response.errors.map((error) => error.message).join('\n')); + } + + // If we don't have any errors, we can assume the data is well formed. + // And if the data isn't well formed, then we're fucked anyways. + + return response.data!.registerOauthApplication; + } catch (error) { + console.error(`Failed to register OAuth app: ${error}`); + throw error; + } +} + +async function registerAndStore(): Promise { + const oauthApp = await registerOAuthApp(); + localStorage.setItem(OAUTH_STORAGE_KEY, JSON.stringify(oauthApp)); +} + +async function loadOAuthApp(): Promise { + const rawApp = localStorage.getItem(OAUTH_STORAGE_KEY); + + if (rawApp) { + try { + return OAUTH_APP_SCHEMA.parseAsync(JSON.parse(rawApp)); + } catch (error) { + console.error(`Failed to load OAuth app. Error: ${error}`); + console.error(`Registering new..`); + + await registerAndStore(); + return await loadOAuthApp(); + } + } else { + await registerAndStore(); + return await loadOAuthApp(); + } +} + +class OAuthApplication { + #data = $state(); + + get data() { + return this.#data; + } + + constructor() { + loadOAuthApp() + .then((loadedApp) => (this.#data = loadedApp)) + .catch(console.error); + } +} + +export { OAuthApplication };