diff --git a/apps/app/env.example b/apps/app/env.example index 7b7bc86..81c601e 100644 --- a/apps/app/env.example +++ b/apps/app/env.example @@ -1,4 +1,9 @@ GOOGLE_CLIENT_ID="" GOOGLE_CLIENT_SECRET="" -GOOGLE_CALLBACK_URI="http://localhost:5173/login/google/callback" -DB_ADAPTER="" \ No newline at end of file +GOOGLE_CALLBACK_URI="http://localhost:3000/login/google/callback" +DB_ADAPTER="http://localhost:5237" +CF_ACCESS_CLIENT_SECRET="" +CF_ACCESS_CLIENT_ID="" +NODE_ENV="development" +PORT="3000" +HOST="0.0.0.0" \ No newline at end of file diff --git a/apps/app/src/lib/api/client.ts b/apps/app/src/lib/api/client.ts new file mode 100644 index 0000000..b900090 --- /dev/null +++ b/apps/app/src/lib/api/client.ts @@ -0,0 +1,10 @@ +import createClient from "openapi-fetch"; +import type { paths } from "$lib/api/api.gen"; // generated by openapi-typescript +import { DB_ADAPTER, CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRET } from '$env/static/private'; + +export const client = createClient({ + baseUrl: DB_ADAPTER || "http://localhost:5237", headers: { + "CF-Access-Client-Secret": CF_ACCESS_CLIENT_SECRET || "", + "CF-Access-Client-Id": CF_ACCESS_CLIENT_ID || "", + } +}); \ No newline at end of file diff --git a/apps/app/src/lib/server/session.ts b/apps/app/src/lib/server/session.ts index cb7b12e..333757e 100644 --- a/apps/app/src/lib/server/session.ts +++ b/apps/app/src/lib/server/session.ts @@ -13,7 +13,6 @@ export async function validateSessionToken( ): Promise { const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token))); const session: Session | null = await sessions.get(sessionId, { type: 'json' }); - if (!session) { return null; } @@ -21,6 +20,7 @@ export async function validateSessionToken( if (Date.now() >= session.expiresAt.getTime() - 1000 * 60 * 60 * 24 * 15) { await sessions.put(sessionId, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL }); } + return session; } @@ -64,7 +64,7 @@ export function generateSessionToken(): string { export async function createSession( token: string, - userId: string, + userId: number, sessions: KVNamespace ): Promise { const sessionId = `${userId}:${encodeHexLowerCase(sha256(new TextEncoder().encode(token)))}`; @@ -80,7 +80,7 @@ export async function createSession( export interface Session { id: string; expiresAt: Date; - userId: string; + userId: number; } type SessionValidationResult = Session | null; diff --git a/apps/app/src/routes/+page.server.ts b/apps/app/src/routes/+page.server.ts index 8da8db8..2ff99c3 100644 --- a/apps/app/src/routes/+page.server.ts +++ b/apps/app/src/routes/+page.server.ts @@ -1,14 +1,31 @@ import { fail, redirect } from '@sveltejs/kit'; import { deleteSessionTokenCookie, invalidateSession } from '$lib/server/session'; +import { client } from '$lib/api/client'; import type { Actions, RequestEvent } from './$types'; +import { browser } from '$app/environment'; export async function load(event: RequestEvent) { if (event.locals.session === null /*|| event.locals.familytree === nul*/) { return redirect(302, '/login'); } - return { - // TODO - Add Family Graph - }; + + //prevent loading in developer mode, due to some issues with universal load, even if this is a server only ts,it will still run on client in dev mode idk + if (browser) { + return {}; + } + + client.GET('/family-tree-with-spouses', { + params: { + header: { "X-User-ID": event.locals.session }, + } + }).then((response) => { + + if (response.response.status === 200) { + return response.data; + } else { + return fail(response.response.status, { message: response.error?.msg || 'An error occurred' }); + } + }); } export const actions: Actions = { diff --git a/apps/app/src/routes/+page.svelte b/apps/app/src/routes/+page.svelte index 9156953..f67aaf2 100644 --- a/apps/app/src/routes/+page.svelte +++ b/apps/app/src/routes/+page.svelte @@ -1,5 +1,6 @@ diff --git a/apps/app/src/routes/login/google/callback/+page.server.ts b/apps/app/src/routes/login/google/callback/+page.server.ts index fb2cd82..50353cf 100644 --- a/apps/app/src/routes/login/google/callback/+page.server.ts +++ b/apps/app/src/routes/login/google/callback/+page.server.ts @@ -1,9 +1,8 @@ import { google } from '$lib/server/oauth'; import { ObjectParser } from '@pilcrowjs/object-parser'; -import { createUser, getUserFromGoogleId } from '$lib/server/user'; -import { DB } from '$lib/server/db'; import { browser } from '$app/environment'; -import { Date as neoDate } from 'neo4j-driver'; +import { client } from '$lib/api/client'; +import { type components } from '$lib/api/api.gen'; import { createSession, generateSessionToken, setSessionTokenCookie } from '$lib/server/session'; import { decodeIdToken } from 'arctic'; import { @@ -48,10 +47,6 @@ export const load: PageServerLoad = async (event: RequestEvent) => { return error(400, { message: 'Failed to validate authorization code with ' + e }); } - // if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) { - // return error(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" }); - // } - const claims = decodeIdToken(tokens.idToken()); const claimsParser = new ObjectParser(claims); @@ -60,27 +55,44 @@ export const load: PageServerLoad = async (event: RequestEvent) => { const first_name = claimsParser.getString('given_name'); const email = claimsParser.getString('email'); - const dbSession = DB.session(); - const existingUser = await getUserFromGoogleId(dbSession, sub); - dbSession.close(); + client.GET('/person/google/{google_id}', + { + params: { + path: { google_id: sub }, + }, + } + ).then((response) => { + if (response.response.status !== 200) { + return error(500, { + message: "Failed to get user from Google ID: " + response.error?.msg + }); + } - let eUser = existingUser.records.pop(); - if (eUser !== null && eUser?.get('elementId') !== undefined) { - const sessionToken = generateSessionToken(); - // const session = await createSession(sessionToken, eUser.get('elementId'), event.platform.env.GH_SESSIONS); - // setSessionTokenCookie(event, sessionToken, session.expiresAt); + if (response.data?.Id) { + if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) { + return error(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" }); + } - return redirect(302, '/'); - } + const sessionToken = generateSessionToken(); + createSession(sessionToken, response.data.Id, event.platform.env.GH_SESSIONS).then((session) => { + if (session === null) { + return error(500, { + message: 'Failed to create session' + }); + } + + setSessionTokenCookie(event, sessionToken, session.expiresAt); + + return redirect(302, '/'); + }); + } + }) let personP: PersonProperties = { google_id: sub, first_name: first_name, last_name: family_name, email: email, - allow_admin_access: false, - limit: StorageLimit, - verified: false }; return { @@ -94,9 +106,10 @@ export const actions: Actions = { async function register(event: RequestEvent) { const data = await event.request.formData(); - // if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) { - // return fail(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" }); - // } + if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) { + return fail(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" }); + } + const google_id = data.get('google_id'); if (google_id === null) { return fail(400, { @@ -156,35 +169,63 @@ async function register(event: RequestEvent) { const parsed_date = new Date(birth_date as string); - let personP: PersonProperties = { - google_id: google_id as string, + let personP: components['schemas']['PersonRegistration'] = { first_name: first_name_f as string, last_name: last_name_f as string, email: email as string, - born: new neoDate( - parsed_date.getFullYear(), - parsed_date.getUTCMonth(), - parsed_date.getUTCDate() - ), + born: parsed_date.toISOString(), mothers_first_name: mothers_first_name_f as string, mothers_last_name: mothers_last_name_f as string, - allow_admin_access: false, limit: StorageLimit, - verified: false }; - const dbSession = DB.session(); - const user = (await createUser(dbSession, personP)).records.pop(); - if (user === null || user === undefined) { - dbSession.close(); + client.POST('/person/google/{google_id}', + { + params: { + path: { google_id: google_id.toString() }, + }, + body: personP + } + ).then((response) => { + if (response.response.status !== 200) { + return fail(400, { + message: failed_to_create_user({ + error: response.error?.msg + }) + }); + } - return fail(500, { message: failed_to_create_user() }); - } - dbSession.close(); + const sessionToken = generateSessionToken(); + if (!response.data?.Id) { + return fail(400, { + message: failed_to_create_user({ + error: 'No user ID returned' + }) + }); + } - const sessionToken = generateSessionToken(); - // const session = await createSession(sessionToken, user.get('elementId'), event.platform.env.GH_SESSIONS); - // setSessionTokenCookie(event, sessionToken, session.expiresAt); + if (!event.platform) { + return fail(500, { + message: 'Server configuration error. GH_SESSIONS KeyValue store missing' + }); + } - return redirect(302, '/'); + const session = createSession(sessionToken, response.data.Id, event.platform.env.GH_SESSIONS).then((session) => { + if (session === null) { + return fail(500, { + message: 'Failed to create session' + }); + } + + setSessionTokenCookie(event, sessionToken, session.expiresAt); + + return redirect(302, '/'); + }); + }).catch((error) => { + return fail(500, { + message: failed_to_create_user({ + error: error.message + }) + }); + }) } diff --git a/apps/app/src/routes/login/google/callback/+page.svelte b/apps/app/src/routes/login/google/callback/+page.svelte index 6a42cac..22fe9c9 100644 --- a/apps/app/src/routes/login/google/callback/+page.svelte +++ b/apps/app/src/routes/login/google/callback/+page.svelte @@ -67,13 +67,13 @@ {/if} - + - -