From 0fca896cc21b7c946e5d43284c33c51c2ead87fe Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Sat, 27 Sep 2025 22:54:15 +0200 Subject: [PATCH] Refactor API key validation: streamline error handling and enforce API key presence in routes --- backend/routes/api.js | 11 ------ backend/routes/apiV2.js | 88 ++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 55 deletions(-) diff --git a/backend/routes/api.js b/backend/routes/api.js index 4b35f53..05c6536 100644 --- a/backend/routes/api.js +++ b/backend/routes/api.js @@ -341,17 +341,6 @@ router.get("/apiKeys", authenticate, async (req, res) => { return res.status(500).json({ message: "Failed to fetch API keys" }); }); -router.get("/apiKeys/apiV2/:id", authenticate, async (req, res) => { - if (req.params.id !== process.env.ADMIN_ID) { - return res.status(403).json({ message: "Access denied" }); - } - const result = await getAPIkey(); - if (result.success) { - return res.status(200).json(result.data); - } - return res.status(500).json({ message: "Failed to fetch API keys" }); -}); - router.delete("/deleteAPKey/:id", authenticate, async (req, res) => { const apiKeyId = req.params.id; const result = await deleteAPKey(apiKeyId); diff --git a/backend/routes/apiV2.js b/backend/routes/apiV2.js index bf78ea7..15f994d 100644 --- a/backend/routes/apiV2.js +++ b/backend/routes/apiV2.js @@ -15,32 +15,40 @@ const router = express.Router(); async function validateAPIKey(apiKey) { try { + if (!apiKey) return false; const result = await getAPIkey(); - if (!result.success || !Array.isArray(result.data)) return false; - - return result.data.some((row) => { - const val = String(row?.apiKey ?? row?.key ?? row?.api_key); - return val === String(apiKey); - }); + if (!result?.success || !Array.isArray(result.data)) return false; + return result.data.some((row) => String(row.apiKey) === String(apiKey)); } catch (err) { console.error("validateAPIKey error:", err); return false; } } -async function ensureValidApiKey(req, res) { - const isValid = await validateAPIKey(req.params.key); - if (!isValid) { - res.status(403).json({ message: "Access denied" }); - return false; +// Add a guard that returns Access Denied instead of hanging +const apiKeyGuard = async (req, res, next) => { + try { + const key = req.params.key; + if (!key) { + return res + .status(401) + .json({ message: "Access denied: missing API key" }); + } + const ok = await validateAPIKey(key); + if (!ok) { + return res + .status(401) + .json({ message: "Access denied: invalid API key" }); + } + next(); + } catch (e) { + console.error("apiKeyGuard error:", e); + res.status(500).json({ message: "Internal server error" }); } - return true; -} +}; // Route for API to get ALL items from the database -router.get("/items/:key", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.get("/items/:key", apiKeyGuard, async (req, res) => { const result = await getItemsFromDatabaseV2(); if (result.success) { res.status(200).json({ data: result.data }); @@ -50,28 +58,28 @@ router.get("/items/:key", async (req, res) => { }); // Route for API to control the position of an item -router.post("/controlInSafe/:key/:itemId/:state", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; +router.post( + "/controlInSafe/:key/:itemId/:state", + apiKeyGuard, + async (req, res) => { + const itemId = req.params.itemId; + const state = req.params.state; - const itemId = req.params.itemId; - const state = req.params.state; - - if (state === "1" || state === "0") { - const result = await changeInSafeStateV2(itemId, state); - if (result.success) { - res.status(200).json({ data: result.data }); + if (state === "1" || state === "0") { + const result = await changeInSafeStateV2(itemId, state); + if (result.success) { + res.status(200).json({ data: result.data }); + } else { + res.status(500).json({ message: "Failed to update item state" }); + } } else { - res.status(500).json({ message: "Failed to update item state" }); + res.status(400).json({ message: "Invalid state value" }); } - } else { - res.status(400).json({ message: "Invalid state value" }); } -}); +); // Route for API to get a loan by its code -router.get("/getLoanByCode/:key/:loan_code", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.get("/getLoanByCode/:key/:loan_code", apiKeyGuard, async (req, res) => { const loan_code = req.params.loan_code; const result = await getLoanByCodeV2(loan_code); if (result.success) { @@ -82,9 +90,7 @@ router.get("/getLoanByCode/:key/:loan_code", async (req, res) => { }); // Route for API to set the return date by the loan code -router.post("/setReturnDate/:key/:loan_code", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.post("/setReturnDate/:key/:loan_code", apiKeyGuard, async (req, res) => { const loanCode = req.params.loan_code; const result = await setReturnDateV2(loanCode); if (result.success) { @@ -95,9 +101,7 @@ router.post("/setReturnDate/:key/:loan_code", async (req, res) => { }); // Route for API to set the take away date by the loan code -router.post("/setTakeDate/:key/:loan_code", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.post("/setTakeDate/:key/:loan_code", apiKeyGuard, async (req, res) => { const loanCode = req.params.loan_code; const result = await setTakeDateV2(loanCode); if (result.success) { @@ -108,9 +112,7 @@ router.post("/setTakeDate/:key/:loan_code", async (req, res) => { }); // Route for API to get ALL loans from the database without sensitive info -router.get("/allLoans/:key", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.get("/allLoans/:key", apiKeyGuard, async (req, res) => { const result = await getAllLoansV2(); if (result.success) { return res.status(200).json(result.data); @@ -119,9 +121,7 @@ router.get("/allLoans/:key", async (req, res) => { }); // Route for API to get ALL items form the database -router.get("/allItems/:key", async (req, res) => { - if (!(await ensureValidApiKey(req, res))) return; - +router.get("/allItems/:key", apiKeyGuard, async (req, res) => { const result = await getItemsFromDatabaseV2(); if (result.success) { res.status(200).json(result.data);