use zod for register verification

This commit is contained in:
bytedream 2024-10-19 15:27:29 +02:00
parent 18135a0816
commit aa91eaf82a
5 changed files with 58 additions and 47 deletions

13
package-lock.json generated

@ -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"
}
}
}
}

@ -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": {

@ -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
});

@ -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<void>(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<void> | null = null;
@ -248,7 +246,7 @@
class="modal"
on:close={() => {
clearInterval(rulesModalTimer);
rulesModalTimer = null;
rulesModalTimer = undefined;
}}
bind:this={rulesModal}
>

@ -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'])
});