diff --git a/server/api/v1/admin/game/image/index.delete.ts b/server/api/v1/admin/game/image/index.delete.ts index a0149f2..3d3440e 100644 --- a/server/api/v1/admin/game/image/index.delete.ts +++ b/server/api/v1/admin/game/image/index.delete.ts @@ -35,7 +35,7 @@ export default defineEventHandler(async (h3) => { throw createError({ statusCode: 400, statusMessage: "Image not found" }); game.mImageLibrary.splice(imageIndex, 1); - await objectHandler.deleteWithPermission(imageId); + await objectHandler.deleteAsServer(imageId); if (game.mBannerId === imageId) { game.mBannerId = game.mImageLibrary[0]; diff --git a/server/api/v1/auth/signup/simple.post.ts b/server/api/v1/auth/signup/simple.post.ts index 1d909f3..757fc78 100644 --- a/server/api/v1/auth/signup/simple.post.ts +++ b/server/api/v1/auth/signup/simple.post.ts @@ -5,7 +5,6 @@ import * as jdenticon from "jdenticon"; import objectHandler from "~/server/internal/objects"; import { type } from "arktype"; import { randomUUID } from "node:crypto"; -import { writeNonLiteralDefaultMessage } from "arktype/internal/parser/shift/operator/default.ts"; const userValidator = type({ username: "string >= 5", @@ -64,7 +63,7 @@ export default defineEventHandler(async (h3) => { profilePictureId, async () => jdenticon.toPng(user.username, 256), {}, - [`internal:read`, `${userId}:delete`] + [`internal:read`, `${userId}:read`] ); const [linkMec] = await prisma.$transaction([ prisma.linkedAuthMec.create({ diff --git a/server/internal/news/index.ts b/server/internal/news/index.ts index 96e2c31..603a077 100644 --- a/server/internal/news/index.ts +++ b/server/internal/news/index.ts @@ -129,7 +129,7 @@ class NewsManager { where: { id }, }); if (article.image) { - return await objectHandler.deleteWithPermission(article.image); + return await objectHandler.deleteAsServer(article.image); } return true; } diff --git a/server/internal/objects/objectHandler.ts b/server/internal/objects/objectHandler.ts index c5d5fdb..21defce 100644 --- a/server/internal/objects/objectHandler.ts +++ b/server/internal/objects/objectHandler.ts @@ -122,8 +122,8 @@ export class ObjectHandler { /** * Fetches object, but also checks if user has perms to access it - * @param id - * @param userId + * @param id object id + * @param userId user to check, or act as anon user * @returns */ async fetchWithPermissions(id: ObjectReference, userId?: string) { @@ -154,6 +154,12 @@ export class ObjectHandler { return object; } + /** + * Fetch object hash, but also checks if user has perms to access it + * @param id object id + * @param userId user to check, or act as anon user + * @returns + */ async fetchHashWithWithPermissions(id: ObjectReference, userId?: string) { const metadata = await this.backend.fetchMetadata(id); if (!metadata) return; @@ -176,11 +182,18 @@ export class ObjectHandler { return await this.backend.fetchHash(id); } - // If we need to fetch a remote resource, it doesn't make sense - // to immediately fetch the object, *then* check permissions. - // Instead the caller can pass a simple anonymous funciton, like - // () => $dropFetch('/my-image'); - // And if we actually have permission to write, it fetches it then. + /** + * + * @param id object id + * @param sourceFetcher callback used to provide image + * @param userId user to check, or act as anon user + * @returns + * @description If we need to fetch a remote resource, it doesn't make sense + * to immediately fetch the object, *then* check permissions. + * Instead the caller can pass a simple anonymous funciton, like + * () => $dropFetch('/my-image'); + * And if we actually have permission to write, it fetches it then. + */ async writeWithPermissions( id: ObjectReference, sourceFetcher: () => Promise, @@ -213,6 +226,12 @@ export class ObjectHandler { return result; } + /** + * + * @param id object id + * @param userId user to check, or act as anon user + * @returns + */ async deleteWithPermission(id: ObjectReference, userId?: string) { const metadata = await this.backend.fetchMetadata(id); if (!metadata) return false; @@ -238,4 +257,13 @@ export class ObjectHandler { const result = await this.backend.delete(id); return result; } + + /** + * Deletes object without checking permission + * @param id + * @returns + */ + async deleteAsServer(id: ObjectReference) { + return await this.backend.delete(id); + } } diff --git a/server/internal/saves/index.ts b/server/internal/saves/index.ts index c76d52b..7401b9b 100644 --- a/server/internal/saves/index.ts +++ b/server/internal/saves/index.ts @@ -62,7 +62,7 @@ class SaveManager { await Promise.all([hashPromise, uploadStream]); if (!hash) { - await objectHandler.deleteWithPermission(newSaveObjectId, userId); + await objectHandler.deleteAsServer(newSaveObjectId); throw createError({ statusCode: 500, statusMessage: "Hash failed to generate",