import { env } from '$env/dynamic/private'; import { Changesets } from '$lib/server/changesets.js'; import { Users } from '$lib/server/users/index.js'; import { emailRegex, passwordRegex, usernameRegex } from '$lib/validators.js'; import { error, fail, redirect } from '@sveltejs/kit'; import { RateLimiter } from 'sveltekit-rate-limiter/server'; interface RegisterData { username: string; displayName: string; email: string; password: string; } const fields: (keyof RegisterData)[] = ['username', 'displayName', 'email', 'password']; const limiter = new RateLimiter({ IP: [6, 'm'] }); export const actions = { default: async (event) => { const { request, locals } = event; if (await limiter.isLimited(event)) throw error(429); // Logged in users cannot make more accounts if (locals.session.data?.user || env.REGISTRATIONS === 'false') { return redirect(303, '/'); } const body = await request.formData(); const changes = Changesets.take(fields, body); const { username, displayName, email, password } = changes; // Each field must be present if (!username || !displayName || !email || !password) { return fail(400, { username, displayName, email, errors: ['required'], fields: fields.reduce( (missing, field) => (!changes[field] ? [...missing, field] : missing), [] ) }); } if (!usernameRegex.test(username)) { return fail(400, { username, displayName, email, errors: ['invalidUsername'], fields: ['username'] }); } if (displayName.length < 3 || displayName.length > 32) { return fail(400, { username, displayName, email, errors: ['invalidDisplayName'], fields: ['displayName'] }); } if (!emailRegex.test(email)) { return fail(400, { username, displayName, email, errors: ['invalidEmail'], fields: ['email'] }); } if (!passwordRegex.test(password)) { return fail(400, { username, displayName, email, errors: ['invalidPassword'], fields: ['password'] }); } if (!(await Users.checkRegistration(username, email))) { return fail(400, { username, displayName, email, errors: ['existingRegistration'], fields: ['username', 'email'] }); } // TODO: check for registration token const newUser = await Users.register({ username, displayName, password, email }); return { success: newUser.activated ? 'userCreated' : 'emailSent' }; } }; export const load = ({ locals }) => { if (locals.session.data?.user) { return redirect(301, '/'); } return { enabled: env.REGISTRATIONS === 'true' }; };