diff --git a/package-lock.json b/package-lock.json index 272c909..2ca7b58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,8 @@ "tslib": "^2.8.0", "typescript": "^5.6.3", "vite": "^5.4.9", - "vitest": "^2.1.3" + "vitest": "^2.1.3", + "zod": "^3.23.8" } }, "node_modules/@alloc/quick-lru": { @@ -7618,6 +7619,16 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index ba9ad78..8c09738 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "tslib": "^2.8.0", "typescript": "^5.6.3", "vite": "^5.4.9", - "vitest": "^2.1.3" + "vitest": "^2.1.3", + "zod": "^3.23.8" }, "type": "module", "dependencies": { diff --git a/src/routes/register/+server.ts b/src/routes/register/+server.ts index 9b67136..631f388 100644 --- a/src/routes/register/+server.ts +++ b/src/routes/register/+server.ts @@ -1,6 +1,7 @@ import { ApiError, getJavaUuid, getNoAuthUuid, UserNotFoundError } from '$lib/server/minecraft'; import { error, type RequestHandler } from '@sveltejs/kit'; import { Settings, User } from '$lib/server/database'; +import { RegisterSchema } from './schema'; export const POST = (async ({ request }) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -9,48 +10,33 @@ export const POST = (async ({ request }) => { throw error(400, 'Anmeldung geschlossen'); } - const data = await request.formData(); - const firstname = data.get('firstname') as string | null; - const lastname = data.get('lastname') as string | null; - const birthday: number = Date.parse(data.get('birthday') as string); - const telephone = data.get('telephone') as string | null; - const username = data.get('username') as string | null; - const playertype = data.get('playertype') as string | null; - const password = data.get('password') as string | null; - - if ( - firstname == null || - lastname == null || - Number.isNaN(birthday) || - username == null || - playertype == null - ) { + try { + var data = RegisterSchema.parse(await request.json()); + } catch (e) { + console.error(e); throw error(400, 'Ungültige Parameter'); } let uuid: string | null; try { - // available playertypes are 'java', 'bedrock' and 'noauth' - switch (data.get('playertype')) { + switch (data.playertype) { case 'java': - uuid = await getJavaUuid(username); + uuid = await getJavaUuid(data.username); break; case 'bedrock': uuid = null; // uuid = await getBedrockUuid(username); break; case 'noauth': - uuid = getNoAuthUuid(username); + uuid = getNoAuthUuid(data.username); break; - default: - throw new Error(`invalid player type (${playertype})`); } } catch (e) { if (e instanceof UserNotFoundError) { throw error( 400, "Der Spielername '" + - username + + data.username + "' existiert nicht. Hast Du Deinen Spielernamen korrekt geschrieben " + 'und besitzt Du einen Minecraft-Account?\n\nKontaktiere bitte einen Admin, falls Du Dich trotz korrekter ' + 'Angabe nicht registrieren kannst.' @@ -74,9 +60,9 @@ export const POST = (async ({ request }) => { } else if ( await User.findOne({ where: { - firstname: firstname, - lastname: lastname, - birthday: new Date(birthday).toUTCString() + firstname: data.firstname, + lastname: data.lastname, + birthday: data.birthday.toUTCString() } }) ) { @@ -89,13 +75,13 @@ export const POST = (async ({ request }) => { } await User.create({ - firstname: firstname, - lastname: lastname, - birthday: new Date(birthday).toUTCString(), - telephone: telephone, - username: username, - playertype: playertype, - password: password, + firstname: data.firstname, + lastname: data.lastname, + birthday: data.birthday.toUTCString(), + telephone: data.telephone, + username: data.username, + playertype: data.playertype, + password: null, uuid: uuid }); diff --git a/src/routes/register/Register.svelte b/src/routes/register/Register.svelte index 52c047c..bc13153 100644 --- a/src/routes/register/Register.svelte +++ b/src/routes/register/Register.svelte @@ -4,6 +4,7 @@ import { createEventDispatcher, onMount } from 'svelte'; import { env } from '$env/dynamic/public'; import { rulesShort } from '$lib/rules'; + import { RegisterSchema } from './schema'; const dispatch = createEventDispatcher(); @@ -40,21 +41,18 @@ async function sendRegister() { // eslint-disable-next-line no-async-promise-executor registerRequest = new Promise(async (resolve, reject) => { - if ( - (birthdayInput.valueAsDate || new Date()) > - new Date(Date.now() - 1000 * 60 * 60 * 24 * 365 * 6) - ) { - reject( - Error( - 'Bitte gib Deinen vollständigen Geburtstag und die korrekte Jahreszahl an. Du musst mindestens 6 Jahre alt sein.\n' - ) - ); + const parseResult = RegisterSchema.safeParse( + Object.fromEntries(new FormData(document.forms[0])) + ); + + if (!parseResult.success) { + reject(Error(parseResult.error.issues.map((i) => i.message).join('\n\n'))); return; } const response = await fetch(`${env.PUBLIC_BASE_PATH}/register`, { method: 'POST', - body: new FormData(document.forms[0]) + body: JSON.stringify(Object.fromEntries(new FormData(document.forms[0]))) }); if (response.ok) { dispatch('submit', { @@ -80,7 +78,7 @@ let rulesAccepted = false; let rulesModal: HTMLDialogElement; let rulesModalSecondsOpened = 0; - let rulesModalTimer: number | null = null; + let rulesModalTimer: number | NodeJS.Timeout | undefined = undefined; let inputsInvalidMessage: string | null = 'Bitte fülle alle erforderlichen Felder aus'; let registerRequest: Promise | null = null; @@ -248,7 +246,7 @@ class="modal" on:close={() => { clearInterval(rulesModalTimer); - rulesModalTimer = null; + rulesModalTimer = undefined; }} bind:this={rulesModal} > diff --git a/src/routes/register/schema.ts b/src/routes/register/schema.ts new file mode 100644 index 0000000..256b55a --- /dev/null +++ b/src/routes/register/schema.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +export const RegisterSchema = z.object({ + firstname: z.string(), + lastname: z.string(), + birthday: z.coerce + .date() + .max( + new Date(Date.now() - 1000 * 60 * 60 * 24 * 365 * 6), + 'Bitte gib Deinen vollständigen Geburtstag und die korrekte Jahreszahl an. Du musst mindestens 6 Jahre alt sein.' + ), + telephone: z.string().optional(), + username: z.string(), + playertype: z.enum(['java', 'bedrock', 'noauth']) +});