mirror of
https://github.com/vcscsvcscs/GenerationsHeritage.git
synced 2025-08-14 06:49:05 +02:00
add a google registration call back site
This commit is contained in:
177
app/src/routes/login/google/callback/+page.server.ts
Normal file
177
app/src/routes/login/google/callback/+page.server.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
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 { Date as neoDate } from 'neo4j-driver';
|
||||
import { createSession, generateSessionToken, setSessionTokenCookie } from "$lib/server/session";
|
||||
import { decodeIdToken } from "arctic";
|
||||
import { missing_field, last_name, first_name, mothers_first_name, mothers_last_name, born, failed_to_create_user } from "$lib/paraglide/messages";
|
||||
|
||||
import type { PageServerLoad, Actions, RequestEvent, PageData } from "./$types";
|
||||
import type { OAuth2Tokens } from "arctic";
|
||||
import type { PersonProperties } from '$lib/model';
|
||||
import { error, redirect, fail } from "@sveltejs/kit";
|
||||
|
||||
const StorageLimit = 200 * 1024 * 1024;
|
||||
|
||||
export const load: PageServerLoad = async (event: RequestEvent) => {
|
||||
const storedState = event.cookies.get("google_oauth_state") ?? null;
|
||||
const codeVerifier = event.cookies.get("google_code_verifier") ?? null;
|
||||
const code = event.url.searchParams.get("code");
|
||||
const state = event.url.searchParams.get("state");
|
||||
|
||||
if (storedState === null || codeVerifier === null || code === null || state === null) {
|
||||
return error(400, { message: "Please restart the process." })
|
||||
}
|
||||
if (storedState !== state) {
|
||||
return error(400, { message: "Please restart the process." })
|
||||
}
|
||||
|
||||
let tokens: OAuth2Tokens;
|
||||
try {
|
||||
tokens = await google.validateAuthorizationCode(code, codeVerifier);
|
||||
} catch (e) {
|
||||
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);
|
||||
|
||||
const sub = claimsParser.getString("sub");
|
||||
const family_name = claimsParser.getString("family_name");
|
||||
const first_name = claimsParser.getString("given_name");
|
||||
const email = claimsParser.getString("email");
|
||||
|
||||
const dbSession = DB.session();
|
||||
const existingUser = await getUserFromGoogleId(dbSession, sub);
|
||||
dbSession.close();
|
||||
|
||||
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);
|
||||
|
||||
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 {
|
||||
props: personP
|
||||
};
|
||||
}
|
||||
|
||||
export const actions: Actions = {
|
||||
register: register
|
||||
};
|
||||
|
||||
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" });
|
||||
// }
|
||||
const google_id = data.get('google_id')
|
||||
if (google_id === null) {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: "google_id"
|
||||
})
|
||||
});
|
||||
}
|
||||
const first_name_f = data.get('first_name')
|
||||
if (first_name_f === null) {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: first_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
const last_name_f = data.get('last_name')
|
||||
if (last_name_f === null) {
|
||||
return fail(400, {
|
||||
message:
|
||||
missing_field({
|
||||
field: last_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
const email = data.get('email')
|
||||
if (email === null) {
|
||||
return fail(400, {
|
||||
message:
|
||||
missing_field({
|
||||
field: "Email"
|
||||
})
|
||||
});
|
||||
}
|
||||
const birth_date = data.get('birth_date');
|
||||
if (birth_date === null) {
|
||||
return fail(400, {
|
||||
message:
|
||||
missing_field({
|
||||
field: born()
|
||||
})
|
||||
});
|
||||
}
|
||||
const mothers_first_name_f = data.get('mothers_first_name');
|
||||
if (mothers_first_name_f === null) {
|
||||
return fail(400, {
|
||||
message:
|
||||
missing_field({
|
||||
field: mothers_first_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
const mothers_last_name_f = data.get('mothers_last_name');
|
||||
if (mothers_last_name_f === null) {
|
||||
return fail(400, {
|
||||
message:
|
||||
missing_field({
|
||||
field: mothers_last_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const parsed_date = new Date(birth_date as string);
|
||||
|
||||
let personP: PersonProperties = {
|
||||
google_id: google_id as string,
|
||||
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()),
|
||||
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();
|
||||
|
||||
return fail(500, { message: failed_to_create_user() });
|
||||
}
|
||||
dbSession.close();
|
||||
|
||||
const sessionToken = generateSessionToken();
|
||||
// const session = await createSession(sessionToken, user.get('elementId'), event.platform.env.GH_SESSIONS);
|
||||
// setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
return redirect(302, "/");
|
||||
}
|
90
app/src/routes/login/google/callback/+page.svelte
Normal file
90
app/src/routes/login/google/callback/+page.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import type { PageProps } from './$types';
|
||||
import {
|
||||
register,
|
||||
title,
|
||||
family_tree,
|
||||
welcome,
|
||||
site_intro,
|
||||
born,
|
||||
mothers_first_name,
|
||||
mothers_last_name,
|
||||
last_name,
|
||||
first_name,
|
||||
email,
|
||||
allow_family_tree_admin_access,
|
||||
} from '$lib/paraglide/messages';
|
||||
import FamilyTree from '../../highresolution_icon_no_background_croped.png';
|
||||
let { data, form }: PageProps = $props();
|
||||
import Pikaday from 'pikaday';
|
||||
|
||||
let birth_date: HTMLInputElement;
|
||||
$effect(() => {
|
||||
if (birth_date) {
|
||||
const picker = new Pikaday({
|
||||
field: birth_date
|
||||
});
|
||||
return () => picker.destroy();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{title({ page: register() })}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="hero bg-base-200 min-h-screen">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||
<div class="text-center lg:text-left">
|
||||
<figure class="top-margin-10 px-10 pt-10">
|
||||
<img src={FamilyTree} alt={family_tree()} class="rounded-xl" />
|
||||
</figure>
|
||||
<h1 class="text-5xl font-bold">{welcome()}</h1>
|
||||
<p class="py-6">
|
||||
{site_intro()}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card bg-base-100 w-full max-w-sm shrink-0 shadow-2xl">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="/register">
|
||||
<fieldset class="fieldset">
|
||||
{#if form?.message}
|
||||
<div role="alert" class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>{form.message}</span>
|
||||
</div>
|
||||
{/if }
|
||||
<label class="fieldset-label" for="email">Email</label>
|
||||
<input type="email" class="input" placeholder="Email" value="{data.props.email}" />
|
||||
<input type="text" class="hidden" id="google_id" placeholder="Google ID" value="{data.props.google_id}" />
|
||||
<label class="fieldset-label" for="first_name">{first_name()}</label>
|
||||
<input type="text" class="input" id="first_name" placeholder="{first_name()}" value="{data.props.first_name}" />
|
||||
<label class="fieldset-label" for="last_name">{last_name()}</label>
|
||||
<input type="text" class="input" id="last_name" placeholder="{last_name()}" value="{data.props.last_name}" />
|
||||
<label class="fieldset-label" for="allow_admin_access">{allow_family_tree_admin_access()}</label>
|
||||
<input type="checkbox" class="input" id="allow_admin_access" checked="{data.props.allow_admin_access}" />
|
||||
<label class="fieldset-label" for="birth_date">{born()}</label>
|
||||
<input type="text" class="input pika-single" id="birth_date" bind:this={birth_date} value={born()} />
|
||||
<label class="fieldset-label" for="mothers_last_name">{mothers_last_name()}</label>
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
id="mothers_last_name"
|
||||
placeholder={mothers_last_name()}
|
||||
/>
|
||||
<label class="fieldset-label" for="mothers_first_name">{mothers_first_name()}</label>
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
id="mothers_first_name"
|
||||
placeholder={mothers_first_name()}
|
||||
/>
|
||||
<button class="btn btn-neutral mt-4">{register()}</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1,81 +0,0 @@
|
||||
import { fail } from "@sveltejs/kit";
|
||||
import { google } from "$lib/server/oauth";
|
||||
import { ObjectParser } from "@pilcrowjs/object-parser";
|
||||
import { createUser, getUserFromGoogleId } from "$lib/server/user";
|
||||
import { driverInstance } from "$lib/server/db";
|
||||
import { createSession, generateSessionToken, setSessionTokenCookie } from "$lib/server/session";
|
||||
import { decodeIdToken } from "arctic";
|
||||
|
||||
import type { RequestEvent } from "./$types";
|
||||
import type { OAuth2Tokens } from "arctic";
|
||||
import { middle_name } from "$lib/paraglide/messages";
|
||||
|
||||
export async function GET(event: RequestEvent): Promise<Response> {
|
||||
const storedState = event.cookies.get("google_oauth_state") ?? null;
|
||||
const codeVerifier = event.cookies.get("google_code_verifier") ?? null;
|
||||
const code = event.url.searchParams.get("code");
|
||||
const state = event.url.searchParams.get("state");
|
||||
|
||||
if (storedState === null || codeVerifier === null || code === null || state === null) {
|
||||
return new Response("Please restart the process.", {
|
||||
status: 400
|
||||
});
|
||||
}
|
||||
if (storedState !== state) {
|
||||
return new Response("Please restart the process.", {
|
||||
status: 400
|
||||
});
|
||||
}
|
||||
|
||||
let tokens: OAuth2Tokens;
|
||||
try {
|
||||
tokens = await google.validateAuthorizationCode(code, codeVerifier);
|
||||
} catch (e) {
|
||||
return new Response("Please restart the process.", {
|
||||
status: 400
|
||||
});
|
||||
}
|
||||
|
||||
if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
|
||||
return new Response("Server configuration error. GH_SESSIONS KeyValue store missing", {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
const claims = decodeIdToken(tokens.idToken());
|
||||
const claimsParser = new ObjectParser(claims);
|
||||
|
||||
const googleId = claimsParser.getString("sub");
|
||||
const family_name = claimsParser.getString("family_name");
|
||||
const first_name = claimsParser.getString("given_name");
|
||||
const middle_name = claimsParser.getString("middle_name");
|
||||
const picture = claimsParser.getString("picture");
|
||||
const email = claimsParser.getString("email");
|
||||
|
||||
const existingUser = getUserFromGoogleId(googleId);
|
||||
if (existingUser !== null) {
|
||||
const sessionToken = generateSessionToken();
|
||||
const session = await createSession(sessionToken, existingUser.id, event.platform.env.GH_SESSIONS);
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: "/"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const dbSession = driverInstance.session()
|
||||
const user = createUser(dbSession, googleId, email, first_name, family_name, middle_name);
|
||||
dbSession.close();
|
||||
const sessionToken = generateSessionToken();
|
||||
const session = await createSession(sessionToken, user.id, event.platform.env.GH_SESSIONS);
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: "/"
|
||||
}
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user