= ({ onClose, alert }) => {
+ return (
+
+
+
+ Neuen API Key erstellen
+
+ Füllen Sie das folgende Formular aus, um einen API Key zu erstellen.
+
+
+
+
+
+ API key
+
+
+
+ Benutzer
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default AddAPIKey;
diff --git a/admin/src/utils/userActions.ts b/admin/src/utils/userActions.ts
index beac000..8cf8e1e 100644
--- a/admin/src/utils/userActions.ts
+++ b/admin/src/utils/userActions.ts
@@ -201,3 +201,44 @@ export const changeSafeState = async (itemId: number) => {
return { success: false };
}
};
+
+export const createAPIentry = async (apiKey: string, user: string) => {
+ try {
+ const response = await fetch(`http://localhost:8002/api/createAPIentry`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${Cookies.get("token")}`,
+ },
+ body: JSON.stringify({ apiKey, user }),
+ });
+ if (!response.ok) {
+ throw new Error("Failed to create API entry");
+ }
+ return { success: true };
+ } catch (error) {
+ console.error("Error creating API entry:", error);
+ return { success: false };
+ }
+};
+
+export const deleteAPKey = async (apiKeyId: number) => {
+ try {
+ const response = await fetch(
+ `http://localhost:8002/api/deleteAPKey/${apiKeyId}`,
+ {
+ method: "DELETE",
+ headers: {
+ Authorization: `Bearer ${Cookies.get("token")}`,
+ },
+ }
+ );
+ if (!response.ok) {
+ throw new Error("Failed to delete API key");
+ }
+ return { success: true };
+ } catch (error) {
+ console.error("Error deleting API key:", error);
+ return { success: false };
+ }
+};
diff --git a/backend/routes/api.js b/backend/routes/api.js
index 2b08eed..4b35f53 100644
--- a/backend/routes/api.js
+++ b/backend/routes/api.js
@@ -22,6 +22,9 @@ import {
changeUserPasswordFRONTEND,
changeInSafeStateV2,
updateItemByID,
+ getAllApiKeys,
+ createAPIentry,
+ deleteAPKey,
} from "../services/database.js";
import { authenticate, generateToken } from "../services/tokenService.js";
const router = express.Router();
@@ -330,4 +333,77 @@ router.put("/changeSafeState/:itemId", authenticate, async (req, res) => {
return res.status(500).json({ message: "Failed to update item safe state" });
});
+router.get("/apiKeys", authenticate, async (req, res) => {
+ const result = await getAllApiKeys();
+ if (result.success) {
+ return res.status(200).json(result.data);
+ }
+ 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);
+ if (result.success) {
+ return res.status(200).json({ message: "API key deleted successfully" });
+ }
+ return res.status(500).json({ message: "Failed to delete API key" });
+});
+
+router.post("/createAPIentry", authenticate, async (req, res) => {
+ const apiKey = req.body.apiKey;
+ const user = req.body.user;
+ if (!apiKey || !user) {
+ return res.status(400).json({ message: "API key and user are required" });
+ }
+
+ // Ensure apiKey is a number
+ const apiKeyNum = Number(apiKey);
+ if (!Number.isFinite(apiKeyNum)) {
+ return res.status(400).json({ message: "API key must be a number" });
+ }
+
+ const result = await createAPIentry(apiKeyNum, user);
+ if (result.success) {
+ return res.status(201).json({ message: "API key created successfully" });
+ }
+ if (result.code === "DUPLICATE") {
+ return res.status(409).json({ message: "API key already exists" });
+ }
+ return res.status(500).json({ message: "Failed to create API key" });
+});
+
+router.get("/apiKeys/validate/:key", async (req, res) => {
+ try {
+ const rawKey = req.params.key;
+ const result = await getAllApiKeys();
+ if (!result.success || !Array.isArray(result.data)) {
+ return res.status(500).json({ valid: false });
+ }
+
+ const isValid = result.data.some((entry) => {
+ const val = String(
+ entry?.key ?? entry?.apiKey ?? entry?.api_key ?? entry
+ );
+ return val === String(rawKey);
+ });
+
+ return res.status(200).json({ valid: isValid });
+ } catch (err) {
+ console.error("validate api key error:", err);
+ return res.status(500).json({ valid: false });
+ }
+});
+
export default router;
diff --git a/backend/routes/apiV2.js b/backend/routes/apiV2.js
index b43c02e..bf78ea7 100644
--- a/backend/routes/apiV2.js
+++ b/backend/routes/apiV2.js
@@ -7,93 +7,110 @@ import {
setTakeDateV2,
getLoanByCodeV2,
getAllLoansV2,
+ getAPIkey,
} from "../services/database.js";
dotenv.config();
const router = express.Router();
+async function validateAPIKey(apiKey) {
+ try {
+ 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);
+ });
+ } 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;
+ }
+ return true;
+}
+
// Route for API to get ALL items from the database
router.get("/items/:key", async (req, res) => {
- if (req.params.key === process.env.ADMIN_ID) {
- const result = await getItemsFromDatabaseV2();
- if (result.success) {
- res.status(200).json({ data: result.data });
- } else {
- res.status(500).json({ message: "Failed to fetch items" });
- }
+ if (!(await ensureValidApiKey(req, res))) return;
+
+ const result = await getItemsFromDatabaseV2();
+ if (result.success) {
+ res.status(200).json({ data: result.data });
} else {
- res.status(403).json({ message: "Access denied" });
+ res.status(500).json({ message: "Failed to fetch items" });
}
});
// Route for API to control the position of an item
router.post("/controlInSafe/:key/:itemId/:state", async (req, res) => {
- if (req.params.key === process.env.ADMIN_ID) {
- 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 });
- } else {
- res.status(500).json({ message: "Failed to update item state" });
- }
+ if (!(await ensureValidApiKey(req, res))) return;
+
+ 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 });
} else {
- res.status(400).json({ message: "Invalid state value" });
+ res.status(500).json({ message: "Failed to update item state" });
}
} else {
- res.status(403).json({ message: "Access denied" });
+ 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 (req.params.key === process.env.ADMIN_ID) {
- const loan_code = req.params.loan_code;
+ if (!(await ensureValidApiKey(req, res))) return;
- const result = await getLoanByCodeV2(loan_code);
- if (result.success) {
- res.status(200).json({ data: result.data });
- } else {
- res.status(404).json({ message: "Loan not found" });
- }
+ const loan_code = req.params.loan_code;
+ const result = await getLoanByCodeV2(loan_code);
+ if (result.success) {
+ res.status(200).json({ data: result.data });
+ } else {
+ res.status(404).json({ message: "Loan not found" });
}
});
// Route for API to set the return date by the loan code
router.post("/setReturnDate/:key/:loan_code", async (req, res) => {
- if (req.params.key === process.env.ADMIN_ID) {
- const loanCode = req.params.loan_code;
+ if (!(await ensureValidApiKey(req, res))) return;
- const result = await setReturnDateV2(loanCode);
- if (result.success) {
- res.status(200).json({ data: result.data });
- } else {
- res.status(500).json({ message: "Failed to set return date" });
- }
+ const loanCode = req.params.loan_code;
+ const result = await setReturnDateV2(loanCode);
+ if (result.success) {
+ res.status(200).json({ data: result.data });
} else {
- res.status(403).json({ message: "Access denied" });
+ res.status(500).json({ message: "Failed to set return date" });
}
});
// Route for API to set the take away date by the loan code
router.post("/setTakeDate/:key/:loan_code", async (req, res) => {
- if (req.params.key === process.env.ADMIN_ID) {
- const loanCode = req.params.loan_code;
+ if (!(await ensureValidApiKey(req, res))) return;
- const result = await setTakeDateV2(loanCode);
- if (result.success) {
- res.status(200).json({ data: result.data });
- } else {
- res.status(500).json({ message: "Failed to set take date" });
- }
+ const loanCode = req.params.loan_code;
+ const result = await setTakeDateV2(loanCode);
+ if (result.success) {
+ res.status(200).json({ data: result.data });
} else {
- res.status(403).json({ message: "Access denied" });
+ res.status(500).json({ message: "Failed to set take date" });
}
});
// Route for API to get ALL loans from the database without sensitive info
-router.get("/allLoans", async (req, res) => {
+router.get("/allLoans/:key", async (req, res) => {
+ if (!(await ensureValidApiKey(req, res))) return;
+
const result = await getAllLoansV2();
if (result.success) {
return res.status(200).json(result.data);
@@ -101,8 +118,10 @@ router.get("/allLoans", async (req, res) => {
return res.status(500).json({ message: "Failed to fetch loans" });
});
-// Route for API to get ALL items form the database without key
-router.get("/allItems", 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;
+
const result = await getItemsFromDatabaseV2();
if (result.success) {
res.status(200).json(result.data);
diff --git a/backend/services/database.js b/backend/services/database.js
index 4e1492a..5ddcc9c 100644
--- a/backend/services/database.js
+++ b/backend/services/database.js
@@ -457,3 +457,36 @@ export const getAllLoansV2 = async () => {
}
return { success: false };
};
+
+export const getAllApiKeys = async () => {
+ const [rows] = await pool.query("SELECT * FROM apiKeys");
+ if (rows.length > 0) {
+ return { success: true, data: rows };
+ }
+ return { success: false };
+};
+
+export const createAPIentry = async (apiKey, user) => {
+ const [result] = await pool.query(
+ "INSERT INTO apiKeys (apiKey, user) VALUES (?, ?)",
+ [apiKey, user]
+ );
+ if (result.affectedRows > 0) return { success: true };
+ return { success: false };
+};
+
+export const deleteAPKey = async (apiKeyId) => {
+ const [result] = await pool.query("DELETE FROM apiKeys WHERE id = ?", [
+ apiKeyId,
+ ]);
+ if (result.affectedRows > 0) return { success: true };
+ return { success: false };
+};
+
+export const getAPIkey = async () => {
+ const [rows] = await pool.query("SELECT apiKey FROM apiKeys");
+ if (rows.length > 0) {
+ return { success: true, data: rows };
+ }
+ return { success: false };
+};