updated dependencies and updated router auth

This commit is contained in:
lllllllillllllillll 2024-03-31 14:37:00 -07:00
parent 42ca573b51
commit c9d7dea132
7 changed files with 129 additions and 58 deletions

View File

@ -4,7 +4,7 @@
<p align="center">
<a href=""><img src="https://img.shields.io/github/stars/lllllllillllllillll/DweebUI?style=flat"/></a>
<a href="https://github.com/lllllllillllllillll"><img src="https://img.shields.io/github/commit-activity/y/lllllllillllllillll/DweebUI%2Fdev"/></a>
<a href="https://github.com/lllllllillllllillll/DweebUI"><img src="https://img.shields.io/github/last-commit/lllllllillllllillll/DweebUI%2Fdev"/></a>
<a href="https://github.com/lllllllillllllillll/DweebUI%2Fdev"><img src="https://img.shields.io/github/last-commit/lllllllillllllillll/DweebUI%2Fdev"/></a>
<a href="https://hub.docker.com/r/lllllllillllllillll/dweebui"><img src="https://img.shields.io/docker/pulls/lllllllillllllillll/dweebui"/></a>
<a href="https://github.com/lllllllillllllillll/DweebUI/blob/main/LICENSE"><img src="https://img.shields.io/github/license/lllllllillllllillll/DweebUI"/></a>
<a href="https://www.reddit.com/r/dweebui"><img src="https://img.shields.io/badge/reddit-orange"/></a>
@ -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).

View File

@ -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 = `<span class="text-yellow align-items-center lh-1">
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-point-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 7a5 5 0 1 1 -4.995 5.217l-.005 -.217l.005 -.217a5 5 0 0 1 4.995 -4.783z" stroke-width="0" fill="currentColor"></path></svg>

32
package-lock.json generated
View File

@ -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",

View File

@ -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"
}
}

View File

@ -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);

View File

@ -61,6 +61,16 @@
VNC
</a>
</div> -->
<!-- <% if(role == 'admin') { %>
<div class="btn-list">
<a href="#" class="btn text-red">
Admin
</a>
</div>
<% } %> -->
</div>

View File

@ -9,6 +9,7 @@
<link href="/css/tabler.min.css" rel="stylesheet"/>
<link href="/css/meters.css" rel="stylesheet"/>
<script src="/js/htmx.min.js"></script>
<script src="/js/htmx-sse.js"></script>
<style>
@import url('/fonts/inter.css');
:root {
@ -29,7 +30,7 @@
<div class="page-body">
<div class="container-xl">
<div class="row row-deck row-cards">
<div class="row row-deck row-cards" hx-ext="sse" sse-connect="/sse_event">
<div class="col-12">
<div class="row row-cards">
@ -45,7 +46,7 @@
</div>
<!-- HTMX -->
<div class="col" name="CPU" id="green" data-hx-get="" data-hx-trigger="">
<div class="col" name="CPU" id="green" data-hx-get="/stats" data-hx-trigger="load, every 1s">
<div class="font-weight-medium">
<label class="cpu-text mb-1" for="cpu">CPU 0%</label>
</div>
@ -70,7 +71,7 @@
</div>
<!-- HTMX -->
<div class="col" name="RAM" id="blue" data-hx-get="" data-hx-trigger="">
<div class="col" name="RAM" id="blue" data-hx-get="/stats" data-hx-trigger="load, every 2s">
<div class="font-weight-medium">
<label class="ram-text mb-1" for="ram">RAM 0%</label>
</div>
@ -95,7 +96,7 @@
</div>
<!-- HTMX -->
<div class="col" name="NET" id="purple" data-hx-get="" data-hx-trigger="">
<div class="col" name="NET" id="purple" data-hx-get="/stats" data-hx-trigger="load, every 2s">
<div class="font-weight-medium">
<label id="net-text" class="net-text mb-1" for="network">Down: 0MB Up: 0MB</label>
</div>
@ -120,7 +121,7 @@
</div>
<!-- HTMX -->
<div class="col" name="DISK" id="orange" data-hx-get="" data-hx-trigger="">
<div class="col" name="DISK" id="orange" data-hx-get="/stats" data-hx-trigger="load, every 3s">
<div class="font-weight-medium">
<label class="disk-text mb-1" for="disk">DISK 0%</label>
</div>