From 5d146f22bfc324f543010a0907c783849f3dd22b Mon Sep 17 00:00:00 2001 From: Z8MB1E Date: Tue, 28 Jul 2026 14:17:52 -0400 Subject: [PATCH] fix(security): restrict deposit/withdraw to admin/dev, allow transfer/reorganize for users - addResource, removeResource, placeResourceOnGrid, removeGridItem now require admin or developer role (game master operations) - transferResource, moveGridItem, mergeGridStacks, rotateGridItem, splitGridStack, autoArrangeGrid require user, admin, or developer (logistics operations that don't change total inventory) - Guests are excluded from all mutating operations --- .../logistics/structures/actions.ts | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/app/(frontend)/logistics/structures/actions.ts b/src/app/(frontend)/logistics/structures/actions.ts index 41ce7fc..53dbd82 100644 --- a/src/app/(frontend)/logistics/structures/actions.ts +++ b/src/app/(frontend)/logistics/structures/actions.ts @@ -3,6 +3,7 @@ import config from "@payload-config"; import { getPayload } from "payload"; import { GameStructure, Resource, Structure } from "@/payload-types"; +import hasRoles from "@/utils/access-control/hasRoles"; interface ActionResult { success: boolean; @@ -64,7 +65,10 @@ export async function addResource( amount: number, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user)) { + return { success: false, error: "Insufficient permissions. Admin or Developer role required for deposit." }; + } if (amount <= 0) { return { success: false, error: "Amount must be greater than zero." }; @@ -233,7 +237,10 @@ export async function removeResource( amount: number, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user)) { + return { success: false, error: "Insufficient permissions. Admin or Developer role required for withdrawal." }; + } if (amount <= 0) { return { success: false, error: "Amount must be greater than zero." }; @@ -303,7 +310,10 @@ export async function transferResource( amount: number, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required for transfer." }; + } if (amount <= 0) { return { success: false, error: "Amount must be greater than zero." }; @@ -387,7 +397,10 @@ export async function placeResourceOnGrid( rotated: boolean, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user)) { + return { success: false, error: "Insufficient permissions. Admin or Developer role required for placement." }; + } if (amount <= 0) return { success: false, error: "Amount must be greater than zero." }; @@ -479,7 +492,10 @@ export async function moveGridItem( rotated?: boolean, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required." }; + } const structure = await getStructure(payload, structureId); const existing = [...(structure.storedResources ?? [])]; const idx = existing.findIndex((e) => e.id === entryId); @@ -541,7 +557,10 @@ export async function mergeGridStacks( targetId: string, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required." }; + } const structure = await getStructure(payload, structureId); const existing = [...(structure.storedResources ?? [])]; @@ -593,7 +612,10 @@ export async function rotateGridItem( entryId: string, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required." }; + } const structure = await getStructure(payload, structureId); const existing = [...(structure.storedResources ?? [])]; const idx = existing.findIndex((e) => e.id === entryId); @@ -653,7 +675,10 @@ export async function removeGridItem( entryId: string, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user)) { + return { success: false, error: "Insufficient permissions. Admin or Developer role required for removal." }; + } const structure = await getStructure(payload, structureId); const existing = [...(structure.storedResources ?? [])]; const idx = existing.findIndex((e) => e.id === entryId); @@ -676,7 +701,10 @@ export async function splitGridStack( splitAmount: number, ): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required." }; + } if (splitAmount <= 0) return { success: false, error: "Split amount must be positive." }; @@ -755,7 +783,10 @@ export async function splitGridStack( export async function autoArrangeGrid(structureId: number): Promise { try { - const { payload } = await authenticate(); + const { payload, user } = await authenticate(); + if (!hasRoles(["admin"], user) && !hasRoles(["user"], user)) { + return { success: false, error: "Insufficient permissions. User, Admin, or Developer role required." }; + } const structure = await getStructure(payload, structureId); const gridW = structure.type.xSize ?? 0; const gridH = structure.type.ySize ?? 0;