require("dotenv").config(); const express = require("express"); const cors = require("cors"); const fs = require("node:fs"); const wol = require("wol"); const mariadb = require("mariadb"); const bodyParser = require("body-parser"); const pool = mariadb.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASS, connectionLimit: 5, }); function sqlEscape(str) { return str.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, (char) => { switch (char) { case "\0": return "\\0"; case "\x08": return "\\b"; case "\x09": return "\\t"; case "\x1a": return "\\z"; case "\n": return "\\n"; case "\r": return "\\r"; case '"': case "'": case "\\": case "%": return `\\${char}`; // prepends a backslash to backslash, percent, // and double/single quotes default: return char; } }); } // initializing app const app = express(); // initializing cors middleware for all routes const corsOptions = { origin: "*", credentials: true, }; app.use(cors(corsOptions)); app.use(bodyParser.json()); app.get("/trigger/api/personalData", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.personalData;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.patch("/trigger/api/personalData", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.personalData SET firstName = '${sqlEscape(req.body.firstName)}', lastName = '${sqlEscape(req.body.lastName)}', email = '${sqlEscape(req.body.email)}', physicalAddress = '${sqlEscape(req.body.physicalAddress)}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/messages", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.messages;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/messages", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.messages (message) VALUES ('${sqlEscape(req.body.message)}');`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/messages", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.messages SET message = '${sqlEscape(req.body.message)}' WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/messages", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.messages WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/apps", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.apps;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/apps", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.apps (name, url, icon, baseUrl, filterName) VALUES ('${sqlEscape(req.body.name)}', '${sqlEscape(req.body.url)}', '${sqlEscape(req.body.icon)}', '${sqlEscape(req.body.baseUrl)}', '${sqlEscape(req.body.filterName)}');`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/apps", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.apps SET name = '${sqlEscape(req.body.name)}', url = '${sqlEscape(req.body.url)}', icon = '${sqlEscape(req.body.icon)}', baseUrl = '${sqlEscape(req.body.baseUrl)}', filterName = '${sqlEscape(req.body.filterName)}' WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/apps", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.apps WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/appCategories", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT filterName FROM trigger_database.apps UNION SELECT filterName FROM trigger_database.linkCategories;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.get("/trigger/api/links", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.links;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/links", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.links (name, url, category, \`index\`) VALUES ('${sqlEscape(req.body.name)}', '${sqlEscape(req.body.url)}', '${sqlEscape(req.body.category)}', ${req.body.index});`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/links", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.links SET name = '${sqlEscape(req.body.name)}', url = '${sqlEscape(req.body.url)}', category = '${sqlEscape(req.body.category)}' WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/links", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.links WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/providers", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.providers;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/providers", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.providers (name, url, prefix) VALUES ('${sqlEscape(req.body.name)}', '${req.body.url}', '${req.body.prefix}')`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/providers", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.providers SET name = '${sqlEscape(req.body.name)}', url = '${sqlEscape(req.body.url)}', prefix = '${sqlEscape(req.body.prefix)}' WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/providers", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.providers WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/themes", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.themes;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/themes", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.themes (name, backgroundImage, backgroundColor, searchColor, primaryColor, accentColor, borderColor) VALUES ('${sqlEscape(req.body.name)}','${sqlEscape(req.body.backgroundImage)}','${req.body.backgroundColor}','${req.body.searchColor}','${req.body.primaryColor}','${req.body.accentColor}','${req.body.borderColor}')`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/themes", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.themes SET name = '${sqlEscape(req.body.name)}', backgroundImage = '${sqlEscape(req.body.backgroundImage)}', backgroundColor = '${req.body.backgroundColor}', searchColor = '${req.body.searchColor}', primaryColor = '${req.body.primaryColor}', accentColor = '${req.body.accentColor}', borderColor = '${req.body.borderColor}', randomEnabled = '${req.body.randomEnabled ? 1 : 0}' WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/themes", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.themes WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/backgrounds", async (req, res) => { fs.readdir("../TriggerFrontend/dist/backgrounds", (err, files) => { res.status(200).send(files); }); }); app.get("/trigger/api/themePlaylists", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.themePlaylists;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/themePlaylists", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.themePlaylists (name, themeList) VALUES ('${sqlEscape(req.body.name)}','${sqlEscape(req.body.themeList)}');`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/themePlaylists", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.themePlaylists SET name = '${sqlEscape(req.body.name)}', themeList = '${req.body.themeList}' WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/themePlaylists", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.themePlaylists WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.get("/trigger/api/categories", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * from trigger_database.linkCategories;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/categories", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.linkCategories (categoryName, categoryIndex, filterName) VALUES ('${sqlEscape(req.body.categoryName)}','${req.body.categoryIndex || 0}','${sqlEscape(req.body.filterName)}')`; conn.query(query).then((rows) => { res.status(200).send({ status: "success" }); }); conn.end(); }); app.patch("/trigger/api/categories", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.linkCategories SET categoryName = '${sqlEscape(req.body.categoryName)}', filterName = '${sqlEscape(req.body.filterName)}' WHERE id = '${req.body.id}';`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/categories", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.linkCategories WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/categoryOrder", async (req, res) => { const conn = await pool.getConnection(); req.body.map((category) => { conn .query( "UPDATE trigger_database.linkCategories SET categoryIndex = ? where id IN (?)", [category.index, category.id], ) .then((rows) => { res.status(200); }); }); res.send({ status: "success" }); conn.end(); }); app.patch("/trigger/api/linkOrder", async (req, res) => { const conn = await pool.getConnection(); req.body.map((link) => { conn .query("UPDATE trigger_database.links SET `index` = ? where id IN (?)", [ link.index, link.id, ]) .then((rows) => { res.status(200); }); }); res.send({ status: "success" }); conn.end(); }); app.get("/trigger/api/wolClients", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * from trigger_database.wolClients;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/wolClients", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.wolClients (hostname, macAddress) VALUES ('${sqlEscape(req.body.hostname)}', '${sqlEscape(req.body.macAddress)}')`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { console.log(err); res.status(500).send({ error: err }); }); conn.end(); }); app.patch("/trigger/api/wolClients", async (req, res) => { const conn = await pool.getConnection(); const query = `UPDATE trigger_database.wolClients SET hostname = '${sqlEscape(req.body.hostname)}', macAddress = '${sqlEscape(req.body.macAddress)}' WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { console.log(err); res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/wolClients", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.wolClients WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.post("/trigger/api/wakeClient", async (req, res) => { wol.wake(req.body.macAddress, () => { res.status(200).send({ status: "success" }); }); }); app.get("/trigger/api/searchHistory", async (req, res) => { const conn = await pool.getConnection(); const query = "SELECT * FROM trigger_database.searchHistory ORDER BY dateTimeStamp DESC;"; conn.query(query).then((rows) => { res.status(200).send(rows); }); conn.end(); }); app.post("/trigger/api/searchHistory", async (req, res) => { const conn = await pool.getConnection(); const query = `INSERT INTO trigger_database.searchHistory (prefix, provider, searchTerm) VALUES ('${sqlEscape(req.body.prefix)}', '${sqlEscape(req.body.provider)}', '${sqlEscape(req.body.searchTerm)}')`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); app.delete("/trigger/api/searchHistory", async (req, res) => { const conn = await pool.getConnection(); const query = `DELETE FROM trigger_database.searchHistory WHERE id = '${req.body.id}'`; conn .query(query) .then((rows) => { res.status(200).send({ status: "success" }); }) .catch((err) => { res.status(500).send({ error: err }); }); conn.end(); }); // app is listening on port 5000 app.listen(5000, "0.0.0.0", () => {});