From 2e1fd83de341f5b7184d7c923182f59ab9eab7c1 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Bajpai Date: Wed, 3 Jun 2026 12:52:31 +0530 Subject: [PATCH] fix(tasks): enforce authenticated task mutations --- backend/controllers/tasks.controller.js | 73 ++++++++++++++++++++++++- backend/routes/tasks.routes.js | 13 +---- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/backend/controllers/tasks.controller.js b/backend/controllers/tasks.controller.js index 6f1c5f9..024ff07 100644 --- a/backend/controllers/tasks.controller.js +++ b/backend/controllers/tasks.controller.js @@ -1,11 +1,43 @@ import supabase from "../config/db.js"; +function getUserId(req) { + return req.user?.id; +} + +function requireUserId(req, res) { + const userId = getUserId(req); + + if (!userId) { + res.status(401).json({ error: "Unauthorized" }); + return null; + } + + return userId; +} + +async function findOwnedTask(taskId, userId) { + const { data, error } = await supabase + .from("tasks") + .select("id") + .eq("id", taskId) + .eq("owner_id", userId) + .maybeSingle(); + + if (error) throw error; + + return data; +} + // Get all tasks export const getTasks = async (req, res) => { try { + const userId = requireUserId(req, res); + if (!userId) return; + const { data, error } = await supabase .from("tasks") .select("*") + .eq("owner_id", userId) .order("position", { ascending: true }); if (error) throw error; @@ -19,7 +51,10 @@ export const getTasks = async (req, res) => { // Create a new task export const createTask = async (req, res) => { try { - const { title, description, status, position } = req.body; + const userId = requireUserId(req, res); + if (!userId) return; + + const { title, description, status, position, project_id } = req.body; // Validate required fields and enforce length limits before any database // operation. Without these checks an authenticated user could insert empty @@ -42,7 +77,7 @@ export const createTask = async (req, res) => { const { data, error } = await supabase .from("tasks") - .insert([{ title, description, status, position }]) + .insert([{ title, description, status, position, project_id, owner_id: userId }]) .select(); if (error) throw error; @@ -63,6 +98,9 @@ export const createTask = async (req, res) => { //update task status export const updateTaskStatus = async (req, res) => { try { + const userId = requireUserId(req, res); + if (!userId) return; + const { id } = req.params; const { status, position } = req.body; @@ -83,10 +121,19 @@ export const updateTaskStatus = async (req, res) => { }); } + const existingTask = await findOwnedTask(id, userId); + + if (!existingTask) { + return res.status(404).json({ + error: "Task not found", + }); + } + const { data, error } = await supabase .from("tasks") .update({ status, position }) .eq("id", id) + .eq("owner_id", userId) .select(); if (error) throw error; @@ -107,6 +154,9 @@ export const updateTaskStatus = async (req, res) => { }; export const updateTask = async (req, res) => { try { + const userId = requireUserId(req, res); + if (!userId) return; + const { id } = req.params; const { title, description, status } = req.body; const updateFields = {}; @@ -128,11 +178,18 @@ export const updateTask = async (req, res) => { return res.status(400).json({ error: "No fields to update" }); } + const existingTask = await findOwnedTask(id, userId); + + if (!existingTask) { + return res.status(404).json({ error: "Task not found" }); + } + // Update task in database const { data, error } = await supabase .from("tasks") .update(updateFields) .eq("id", id) + .eq("owner_id", userId) .select(); if (error) throw error; @@ -161,12 +218,22 @@ export const updateTask = async (req, res) => { // Delete a task export const deleteTask = async (req, res) => { try { + const userId = requireUserId(req, res); + if (!userId) return; + const { id } = req.params; + const existingTask = await findOwnedTask(id, userId); + + if (!existingTask) { + return res.status(404).json({ error: "Task not found" }); + } + const { error } = await supabase .from("tasks") .delete() - .eq("id", id); + .eq("id", id) + .eq("owner_id", userId); if (error) throw error; diff --git a/backend/routes/tasks.routes.js b/backend/routes/tasks.routes.js index c7f11a4..d235ede 100644 --- a/backend/routes/tasks.routes.js +++ b/backend/routes/tasks.routes.js @@ -12,21 +12,14 @@ import { validateTask } from "../middleware/validation.middleware.js"; const router = express.Router(); -router.get("/", getTasks); +router.get("/", authenticateUser, getTasks); -router.post("/", authenticateUser, createTask); +router.post("/", authenticateUser, validateTask, createTask); router.patch("/:id", authenticateUser, updateTaskStatus); router.patch("/:id/edit", authenticateUser, updateTask); router.delete("/:id", authenticateUser, deleteTask); -router.post("/", validateTask, createTask); -router.patch("/:id", validateTask, updateTaskStatus); - -router.patch("/:id/edit", validateTask, updateTask); - -router.delete("/:id", deleteTask); - -export default router; \ No newline at end of file +export default router;