object storage + full permission system + testing

Object storage now works fully, with the permission system. It still
needs additional external endpoints for updating and deleting objects
from the API, but it is otherwise complete. Further tasks include
writing an S3 adapter.
This commit is contained in:
DecDuck
2024-10-09 14:43:06 +11:00
parent de388a937a
commit 435551c207
20 changed files with 376 additions and 63 deletions

View File

@ -1,32 +1,60 @@
import { AuthMec } from "@prisma/client";
import { Readable } from "stream";
import prisma from "~/server/internal/db/database";
import { createHash } from "~/server/internal/security/simple";
import { v4 as uuidv4 } from "uuid";
export default defineEventHandler(async (h3) => {
const body = await readBody(h3);
const body = await readBody(h3);
const username = body.username;
const password = body.password;
if (username === undefined || password === undefined)
throw createError({ statusCode: 403, statusMessage: "Username or password missing from request." });
const existing = await prisma.user.count({ where: { username: username } });
if (existing > 0) throw createError({ statusCode: 400, statusMessage: "Username already taken." })
const user = await prisma.user.create({
data: {
username,
}
const username = body.username;
const password = body.password;
if (username === undefined || password === undefined)
throw createError({
statusCode: 403,
statusMessage: "Username or password missing from request.",
});
const hash = await createHash(password);
const authMek = await prisma.linkedAuthMec.create({
data: {
mec: AuthMec.Simple,
credentials: [username, hash],
userId: user.id
}
const existing = await prisma.user.count({ where: { username: username } });
if (existing > 0)
throw createError({
statusCode: 400,
statusMessage: "Username already taken.",
});
return user;
})
const userId = uuidv4();
const profilePictureObject = await h3.context.objects.createFromSource(
() =>
$fetch<Readable>("https://avatars.githubusercontent.com/u/64579723?v=4", {
responseType: "stream",
}),
{},
[`anonymous:read`, `${userId}:write`]
);
if (!profilePictureObject)
throw createError({
statusCode: 500,
statusMessage: "Unable to import profile picture",
});
const user = await prisma.user.create({
data: {
username,
displayName: "",
email: "",
profilePicture: profilePictureObject,
},
});
const hash = await createHash(password);
await prisma.linkedAuthMec.create({
data: {
mec: AuthMec.Simple,
credentials: [username, hash],
userId: user.id,
},
});
return user;
});

View File

@ -1,5 +1,4 @@
import clientHandler from "~/server/internal/clients/handler";
import { useGlobalCertificateAuthority } from "~/server/plugins/ca";
export default defineEventHandler(async (h3) => {
const body = await readBody(h3);
@ -28,7 +27,7 @@ export default defineEventHandler(async (h3) => {
statusMessage: "Invalid token",
});
const ca = useGlobalCertificateAuthority();
const ca = h3.context.ca;
const bundle = await ca.generateClientCertificate(
clientId,
metadata.data.name

View File

@ -0,0 +1,13 @@
export default defineEventHandler(async (h3) => {
const id = getRouterParam(h3, "id");
if (!id) throw createError({ statusCode: 400, statusMessage: "Invalid ID" });
const userId = await h3.context.session.getUserId(h3);
const object = await h3.context.objects.fetchWithPermissions(id, userId);
if (!object)
throw createError({ statusCode: 404, statusMessage: "Object not found" });
setHeader(h3, "Content-Type", object.mime);
return object.data;
});

View File

@ -0,0 +1,4 @@
export default defineEventHandler(async (h3) => {
const user = await h3.context.session.getUser(h3);
return user ?? null; // Need to specifically return null
});

View File

@ -1,4 +0,0 @@
export default defineEventHandler(async (h3) => {
const user = await h3.context.session.getUser(h3);
return user ?? null;
});