mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-10 04:22:09 +10:00
121 lines
3.1 KiB
TypeScript
121 lines
3.1 KiB
TypeScript
import { AuthMec, Invitation } from "@prisma/client";
|
|
import prisma from "~/server/internal/db/database";
|
|
import { createHash } from "~/server/internal/security/simple";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
import * as jdenticon from "jdenticon";
|
|
import objectHandler from "~/server/internal/objects";
|
|
|
|
// Only really a simple test, in case people mistype their emails
|
|
const mailRegex = /^\S+@\S+\.\S+$/;
|
|
|
|
export default defineEventHandler(async (h3) => {
|
|
const body = await readBody(h3);
|
|
|
|
const invitationId = body.invitation;
|
|
if (!invitationId)
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: "Invalid or expired invitation.",
|
|
});
|
|
|
|
const invitation = await prisma.invitation.findUnique({
|
|
where: { id: invitationId },
|
|
});
|
|
if (!invitation)
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: "Invalid or expired invitation.",
|
|
});
|
|
|
|
const useInvitationOrBodyRequirement = (
|
|
field: keyof Invitation,
|
|
check: (v: string) => boolean
|
|
) => {
|
|
if (invitation[field]) {
|
|
return invitation[field].toString();
|
|
}
|
|
|
|
const v: string = body[field]?.toString();
|
|
const valid = check(v);
|
|
return valid ? v : undefined;
|
|
};
|
|
|
|
const username = useInvitationOrBodyRequirement(
|
|
"username",
|
|
(e) => e.length >= 5
|
|
);
|
|
const email = useInvitationOrBodyRequirement("email", (e) =>
|
|
mailRegex.test(e)
|
|
);
|
|
const password = body.password;
|
|
const displayName = body.displayName || username;
|
|
|
|
if (username === undefined)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Username is invalid. Must be more than 5 characters.",
|
|
});
|
|
if (username.toLowerCase() != username)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Username must be all lowercase",
|
|
});
|
|
|
|
if (email === undefined)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Invalid email. Must follow the format you@example.com",
|
|
});
|
|
|
|
if (!password)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Password empty or missing.",
|
|
});
|
|
|
|
if (password.length < 14)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Password must be 14 or more characters.",
|
|
});
|
|
|
|
const existing = await prisma.user.count({ where: { username: username } });
|
|
if (existing > 0)
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Username already taken.",
|
|
});
|
|
|
|
const userId = uuidv4();
|
|
|
|
const profilePictureId = uuidv4();
|
|
await objectHandler.createFromSource(
|
|
profilePictureId,
|
|
async () => jdenticon.toPng(username, 256),
|
|
{},
|
|
[`anonymous:read`, `${userId}:write`]
|
|
);
|
|
const user = await prisma.user.create({
|
|
data: {
|
|
username,
|
|
displayName,
|
|
email,
|
|
profilePicture: profilePictureId,
|
|
admin: invitation.isAdmin,
|
|
},
|
|
});
|
|
|
|
const hash = await createHash(password);
|
|
await prisma.linkedAuthMec.create({
|
|
data: {
|
|
mec: AuthMec.Simple,
|
|
credentials: [username, hash],
|
|
userId: user.id,
|
|
},
|
|
});
|
|
|
|
await prisma.invitation.delete({ where: { id: invitationId } });
|
|
|
|
return user;
|
|
});
|