mirror of
https://github.com/diced/zipline.git
synced 2026-01-26 03:05:03 -08:00
106 lines
2.9 KiB
TypeScript
Executable File
106 lines
2.9 KiB
TypeScript
Executable File
import { config } from '@/lib/config';
|
|
import { createToken, hashPassword } from '@/lib/crypto';
|
|
import { prisma } from '@/lib/db';
|
|
import { User, userSelect } from '@/lib/db/models/user';
|
|
import { log } from '@/lib/logger';
|
|
import { secondlyRatelimit } from '@/lib/ratelimits';
|
|
import { getSession, saveSession } from '@/server/session';
|
|
import typedPlugin from '@/server/typedPlugin';
|
|
import z from 'zod';
|
|
import { ApiLoginResponse } from './login';
|
|
|
|
export type ApiAuthRegisterResponse = ApiLoginResponse;
|
|
|
|
const logger = log('api').c('auth').c('register');
|
|
|
|
export const PATH = '/api/auth/register';
|
|
export default typedPlugin(
|
|
async (server) => {
|
|
server.post(
|
|
PATH,
|
|
{
|
|
schema: {
|
|
body: z.object({
|
|
username: z.string().min(1),
|
|
password: z.string().min(1),
|
|
code: z.string().min(1).optional(),
|
|
}),
|
|
},
|
|
...secondlyRatelimit(5),
|
|
},
|
|
async (req, res) => {
|
|
const session = await getSession(req, res);
|
|
|
|
const { username, password, code } = req.body;
|
|
|
|
if (code && !config.invites.enabled) return res.badRequest("Invites aren't enabled");
|
|
if (!code && !config.features.userRegistration)
|
|
return res.badRequest('User registration is disabled');
|
|
|
|
const oUser = await prisma.user.findUnique({
|
|
where: {
|
|
username,
|
|
},
|
|
});
|
|
if (oUser) return res.badRequest('Username is taken');
|
|
|
|
if (code) {
|
|
const invite = await prisma.invite.findFirst({
|
|
where: {
|
|
OR: [{ id: code }, { code }],
|
|
},
|
|
});
|
|
|
|
if (!invite) return res.badRequest('Invalid invite code');
|
|
if (invite.expiresAt && new Date(invite.expiresAt) < new Date())
|
|
return res.badRequest('Invalid invite code');
|
|
if (invite.maxUses && invite.uses >= invite.maxUses) return res.badRequest('Invalid invite code');
|
|
|
|
await prisma.invite.update({
|
|
where: {
|
|
id: invite.id,
|
|
},
|
|
data: {
|
|
uses: invite.uses + 1,
|
|
},
|
|
});
|
|
|
|
logger.info('invite used', {
|
|
user: username,
|
|
invite: invite.id,
|
|
});
|
|
}
|
|
|
|
const user = await prisma.user.create({
|
|
data: {
|
|
username,
|
|
password: await hashPassword(password),
|
|
role: 'USER',
|
|
token: createToken(),
|
|
},
|
|
select: {
|
|
...userSelect,
|
|
password: true,
|
|
token: true,
|
|
},
|
|
});
|
|
|
|
await saveSession(session, <User>user);
|
|
|
|
delete (user as any).password;
|
|
|
|
logger.info('user registered successfully', {
|
|
username,
|
|
ip: req.ip ?? 'unknown',
|
|
ua: req.headers['user-agent'],
|
|
});
|
|
|
|
return res.send({
|
|
user,
|
|
});
|
|
},
|
|
);
|
|
},
|
|
{ name: PATH },
|
|
);
|