From c9d7dea13262809b187e6faa0276828824ea5b1e Mon Sep 17 00:00:00 2001 From: lllllllillllllillll Date: Sun, 31 Mar 2024 14:37:00 -0700 Subject: [PATCH] updated dependencies and updated router auth --- README.md | 4 +-- controllers/portal.js | 70 ++++++++++++++++++++++++++++++++++++-- package-lock.json | 32 +++++++---------- package.json | 4 +-- router/index.js | 56 ++++++++++++++++-------------- views/partials/navbar.html | 10 ++++++ views/portal.html | 11 +++--- 7 files changed, 129 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 688d1a1..46a4f33 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- + @@ -27,7 +27,7 @@ * [x] Light/Dark Mode. * [x] Mobile Friendly. * [x] Easy to install app templates. -* [x] Multi-User built-in. +* [x] Multiple Users. * [ ] Permissions system (in development). * [x] Support for Windows, Linux, and MacOS. * [ ] Docker compose (in development). diff --git a/controllers/portal.js b/controllers/portal.js index 4725440..48102e0 100644 --- a/controllers/portal.js +++ b/controllers/portal.js @@ -3,7 +3,6 @@ import { Permission, Container, User } from '../database/models.js'; import { docker } from '../server.js'; import { dockerContainerStats } from 'systeminformation'; import { readFileSync } from 'fs'; -import { currentLoad, mem, networkStats, fsSize } from 'systeminformation'; let hidden = ''; @@ -21,6 +20,7 @@ export const Portal = (req, res) => { }); } + async function containerInfo (containerName) { let container = docker.getContainer(containerName); let info = await container.inspect(); @@ -126,6 +126,72 @@ export async function addCard (name, state) { + +// HTMX server-side events +export const SSE = (req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); + + let eventCheck = setInterval(async () => { + // builds array of containers and their states + containersArray = []; + await docker.listContainers({ all: true }).then(containers => { + containers.forEach(container => { + let name = container.Names[0].replace('/', ''); + if (!hidden.includes(name)) { // if not hidden + containersArray.push({ container: name, state: container.State }); + } + }); + }); + + if ((JSON.stringify(containersArray) !== JSON.stringify(sentArray))) { + cardList = ''; + newCards = ''; + containersArray.forEach(container => { + const { container: containerName, state } = container; + const existingContainer = sentArray.find(c => c.container === containerName); + if (!existingContainer) { + containerInfo(containerName).then(details => { + createCard(details).then(card => { + newCards += card; + }); + }); + res.write(`event: update\n`); + res.write(`data: 'update cards'\n\n`); + } else if (existingContainer.state !== state) { + updatesArray.push(containerName); + } + containerInfo(containerName).then(details => { + createCard(details).then(card => { + cardList += card; + }); + }); + }); + + sentArray.forEach(container => { + const { container: containerName } = container; + const existingContainer = containersArray.find(c => c.container === containerName); + if (!existingContainer) { + updatesArray.push(containerName); + } + }); + + for (let i = 0; i < updatesArray.length; i++) { + res.write(`event: ${updatesArray[i]}\n`); + res.write(`data: 'update cards'\n\n`); + } + updatesArray = []; + sentArray = containersArray.slice(); + } + + }, 500); + + + req.on('close', () => { + clearInterval(eventCheck); + }); +}; + + export const updateCards = async (req, res) => { console.log('updateCards called'); res.send(newCards); @@ -152,8 +218,6 @@ export const Card = async (req, res) => { } - - function status (state) { let status = ` diff --git a/package-lock.json b/package-lock.json index b63ebc0..118047b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,13 +13,13 @@ "dockerode": "^4.0.2", "dockerode-compose": "^1.4.0", "ejs": "^3.1.9", - "express": "^4.18.3", + "express": "^4.19.2", "express-session": "^1.18.0", "js-yaml": "^4.1.0", "memorystore": "^1.6.7", "sequelize": "^6.37.1", "sqlite3": "^5.1.7", - "systeminformation": "^5.22.0" + "systeminformation": "^5.22.6" } }, "node_modules/@balena/dockerignore": { @@ -525,9 +525,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -810,16 +810,16 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -868,14 +868,6 @@ "node": ">= 0.8.0" } }, - "node_modules/express-session/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express-session/node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", @@ -2514,9 +2506,9 @@ } }, "node_modules/systeminformation": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.22.0.tgz", - "integrity": "sha512-oAP80ymt8ssrAzjX8k3frbL7ys6AotqC35oikG6/SG15wBw+tG9nCk4oPaXIhEaAOAZ8XngxUv3ORq2IuR3r4Q==", + "version": "5.22.6", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.22.6.tgz", + "integrity": "sha512-hUTQX+bRgIFbv1T/z251NtwGwNIeSyWURnT2BGnsYu6dQNbkiBl4oAwk50acVfITFq1Zvb8KDNgibQK9uGlUGg==", "os": [ "darwin", "linux", diff --git a/package.json b/package.json index 0bc7c8b..18cc4d7 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "dockerode": "^4.0.2", "dockerode-compose": "^1.4.0", "ejs": "^3.1.9", - "express": "^4.18.3", + "express": "^4.19.2", "express-session": "^1.18.0", "js-yaml": "^4.1.0", "memorystore": "^1.6.7", "sequelize": "^6.37.1", "sqlite3": "^5.1.7", - "systeminformation": "^5.22.0" + "systeminformation": "^5.22.6" } } diff --git a/router/index.js b/router/index.js index f299b54..736fbbb 100644 --- a/router/index.js +++ b/router/index.js @@ -22,51 +22,55 @@ import { Portal } from "../controllers/portal.js" // Auth middleware const auth = async (req, res, next) => { if (!req.session.user) { res.redirect('/login'); return; } + if (req.session.role == "admin") { next(); } let user = req.session.user; let role = req.session.role; let action = req.path.split("/")[2]; let trigger = req.header('hx-trigger-name'); + // console.log("Auth: ", user, role, action, trigger); - if (role == "admin") { - next(); - } - else if (action == "start" || action == "stop" || action == "pause" || action == "restart") { - let permission = await Permission.findOne({ where: { containerName: trigger, user: user }, attributes: [`${action}`] }); + + // if (action == "start" || action == "stop" || action == "pause" || action == "restart") { + // let permission = await Permission.findOne({ where: { containerName: trigger, user: user }, attributes: [`${action}`] }); - if (permission) { - if (permission[action] == true) { - console.log(`User ${user} has permission to ${action} ${trigger}`); - next(); - } - else { - console.log(`User ${user} does not have permission to ${action} ${trigger}`); - } - } else { - console.log(`No entry found for ${user} in ${trigger} permissions`); - } - } - else { - res.redirect('/portal'); - } + // if (permission) { + // if (permission[action] == true) { + // console.log(`User ${user} has permission to ${action} ${trigger}`); + // next(); + // } + // else { + // console.log(`User ${user} does not have permission to ${action} ${trigger}`); + // } + // } else { + // console.log(`No entry found for ${user} in ${trigger} permissions`); + // } + // } + // else { + // res.redirect('/portal'); + // } + + res.redirect('/portal'); } + + + // Admin routes router.get("/", auth, Dashboard); router.post("/action/:action", auth, Action); router.post("/updatePermissions", auth, UpdatePermissions); -router.get("/logs", Logs); - -router.get("/modals", Modals); +router.get("/logs", auth, Logs); +router.get("/modals", auth, Modals); router.get("/stats", auth, Stats); router.get("/chart", auth, Chart); router.get("/sse_event", auth, SSE); -router.get("/containers", Containers); -router.get("/card", Card); -router.get("/new_cards", updateCards); +router.get("/containers", auth, Containers); +router.get("/card", auth, Card); +router.get("/new_cards", auth, updateCards); router.get("/images", auth, Images); diff --git a/views/partials/navbar.html b/views/partials/navbar.html index a23beb6..94c94b9 100644 --- a/views/partials/navbar.html +++ b/views/partials/navbar.html @@ -61,6 +61,16 @@ VNC --> + + + + diff --git a/views/portal.html b/views/portal.html index 5a12f81..1101ff0 100644 --- a/views/portal.html +++ b/views/portal.html @@ -9,6 +9,7 @@ +