From 9703e4a0814791cc04c4a22e9754f09a6d20619e Mon Sep 17 00:00:00 2001 From: sagit <36596628+Sagit-chu@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:05:05 +0800 Subject: [PATCH] feat: restrict user permissions and multi-node IP constraints (#262) * feat: restrict user permissions and multi-node IP constraints - Non-admin users cannot set speedId or inPort on forward create/update - Multi-entrance tunnels disable custom listen IP for forwards - Multi-exit tunnels disable custom connect IP - Multi-node hop chains disable custom connect IP per hop - Remove tunnel-first-IP fallback in forward ingress resolution - Add contract tests for non-admin permission restrictions Entire-Checkpoint: 133693290660 * fix: allow non-admin users to submit null speedId and zero inPort - Backend: Check speedId is not nil before rejecting non-admin requests - Backend: Only reject inPort if value > 0 for non-admin users - Frontend: Only include speedId and inPort in payload for admin users - Tests: Add contract tests for null speedId and zero inPort cases * refactor: simplify forward mutation payload construction --- vite-frontend/src/pages/forward.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vite-frontend/src/pages/forward.tsx b/vite-frontend/src/pages/forward.tsx index 085bb7f..9a684ff 100644 --- a/vite-frontend/src/pages/forward.tsx +++ b/vite-frontend/src/pages/forward.tsx @@ -1426,9 +1426,8 @@ export default function ForwardPage() { const speedLimitAutoCleared = isMissingSpeedLimit(form.speedId); if (isEdit) { - const updateData: ForwardMutationPayload = { + const updateData = { id: form.id, - userId: form.userId, name: form.name, tunnelId: form.tunnelId, ...(isAdmin ? { inPort: form.inPort } : {}), @@ -1440,7 +1439,7 @@ export default function ForwardPage() { res = await updateForward(updateData); } else { - const createData: ForwardMutationPayload = { + const createData = { name: form.name, tunnelId: form.tunnelId, ...(isAdmin ? { inPort: form.inPort } : {}),