improvements for multi-user and permissions

This commit is contained in:
lllllllillllllillll 2024-03-21 23:59:45 -07:00
parent 66f273e22e
commit 8d9eb9981a
11 changed files with 209 additions and 196 deletions

View File

@ -1,8 +1,6 @@
<h3 align="center"><img width="150" src="https://raw.githubusercontent.com/lllllllillllllillll/DweebUI/main/public/images/logo.png"></h3>
<h4 align="center">DweebUI Beta v0.50 ( :fire: Experimental :fire: )</h4>
<h4 align="center">DweebUI Beta v0.50 (:fire: Experimental :fire:)</h4>
<h3 align="center">Free and Open-Source WebUI For Managing Your Containers.</h3>
<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"/></a>
@ -12,13 +10,11 @@
<a href="https://www.reddit.com/r/dweebui"><img src="https://img.shields.io/badge/reddit-orange"/></a>
<a href="https://www.buymeacoffee.com/lllllllillllllillll"><img src="https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee"/></a>
</p>
<h3 align="center"><img width="800" src="https://raw.githubusercontent.com/lllllllillllllillll/DweebUI/main/screenshots/dashboard1.png"></h3>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="screenshot" src="https://raw.githubusercontent.com/lllllllillllllillll/DweebUI/main/screenshots/dashboard1.png"></h3>
<br/>
## About
* I started this as a personal project to get more familiar with Javascript and Node.js. There may be some rough edges and spaghetti code .
* I started this as a personal project to get more familiar with Javascript and Node.js, so there may be some rough edges and spaghetti code.
* I'm open to any contributions but you may want to wait until I reach v1.0 first.
* Please post issues and discussions so I know what bugs and features to focus on.
* DweebUI is a management interface and should not be directly exposed to the internet

View File

@ -1,12 +1,15 @@
import { Readable } from 'stream';
import { Permission, Container } from '../database/models.js';
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 = '';
// The actual page
export const Dashboard = (req, res) => {
res.render("dashboard", {
name: req.session.user,
role: req.session.role,
@ -33,12 +36,15 @@ export const Stats = async (req, res) => {
case 'NET':
let down = 0;
let up = 0;
let percent = 0;
await networkStats().then(data => {
down = Math.round(data[0].rx_bytes / (1024 * 1024));
up = Math.round(data[0].tx_bytes / (1024 * 1024));
// percent of download vs max download if max download was 1GB
percent = Math.round((down / 1000) * 100);
});
let net = `<div class="font-weight-medium">
<label class="cpu-text mb-1">Down:${down} Up:${up}</label>
<label class="cpu-text mb-1">Down:${down}MB Up:${up}MB</label>
</div>
<div class="cpu-bar meter animate ${color}">
<span style="width:20%"><span></span></span>
@ -143,10 +149,6 @@ async function createCard (details) {
let [ cardList, newCards, containersArray, sentArray, updatesArray ] = [ '', '', [], [], [] ];
let hidden = await Container.findAll({ where: {visibility:false}});
hidden = hidden.map((container) => container.name);
export async function addCard (name, state) {
console.log(`Adding card for ${name}: ${state}`);
@ -321,15 +323,195 @@ export const Logs = (req, res) => {
export const Modals = async (req, res) => {
let name = req.header('hx-trigger-name');
let id = req.header('hx-trigger');
let title = name.charAt(0).toUpperCase() + name.slice(1);
if (id == 'permissions') {
let modal = readFileSync('./views/modals/permissions.html', 'utf8');
modal = modal.replace(/AppName/g, name);
// let containerPermissions = await Permission.findAll({ where: {containerName: name}});
let permissions_list = '';
modal = modal.replace(/AppName/g, title);
let users = await User.findAll({ attributes: ['username', 'UUID']});
for (let i = 0; i < users.length; i++) {
// check if user Permission contains an entry for this container for this user. If not, create one.
let exists = await Permission.findOne({ where: {containerName: name, user: users[i].username}});
if (!exists) {
const newPermission = await Permission.create({ containerName: name, user: users[i].username, userID: users[i].UUID});
}
let user_permissions = `
<div class="accordion-item mb-3" style="border: 1px solid grey;">
<h2 class="accordion-header" id="heading-${i}">
<button class="accordion-button collapsed row" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-${i}" aria-expanded="false">
<span class="avatar avatar-sm bg-green-lt col-3 text-start">JD</span>
<div class="col text-end" style="margin-right: 10px;">${users[i].username}</div>
</button>
</h2>
<div id="collapse-${i}" class="accordion-collapse collapse" data-bs-parent="#modal-accordion">
<div class="accordion-body pt-0">
<div class="">
<div class="">
<div class="row mb-3">
<div class="col-9">
<label class="row text-start">
<span class="col">
All
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select" onclick="selectAll('select')">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Uninstall
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Edit
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Upgrade
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Start
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Stop
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Pause
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Restart
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-4">
<div class="col-9">
<label class="row text-start">
<span class="col">
Logs
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<button class="btn" type="submit" formaction="/updatePermissions">Update</button>
</div>
</div>
</div>
</div>
</div>
</div>`;
permissions_list += user_permissions;
}
modal = modal.replace(/PermissionsList/g, permissions_list);
res.send(modal);
return;
}
if (id == 'uninstall') {
let modal = readFileSync('./views/modals/uninstall.html', 'utf8');
modal = modal.replace(/AppName/g, name);

View File

@ -1,4 +1,4 @@
import { User, Syslog } from '../database/models.js';
import { User, Syslog, Permission } from '../database/models.js';
import bcrypt from 'bcrypt';
let SECRET = process.env.SECRET || "MrWiskers"
@ -67,6 +67,11 @@ export const submitRegister = async function(req,res){
req.session.UUID = newUser.UUID;
req.session.role = newUser.role;
const permission = await Permission.create({
user: newUser.username,
userID: newUser.UUID
});
const syslog = await Syslog.create({
user: req.session.user,
email: email,

View File

@ -110,11 +110,9 @@ export const Permission = sequelize.define('Permission', {
},
containerName: {
type: DataTypes.STRING,
allowNull: false
},
containerID: {
type: DataTypes.STRING,
allowNull: false
},
user: {
type: DataTypes.STRING,

View File

@ -22,7 +22,7 @@ const auth = (req, res, next) => {
if (req.session.role == "admin") {
next();
} else {
res.redirect("/login");
res.redirect("/portal");
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 166 KiB

View File

@ -10,6 +10,7 @@ export var docker = new Docker();
const app = express();
const MemoryStore = memorystore(session);
const port = process.env.PORT || 8000;
const connection = process.env.HTTPS || false;
// Session middleware
const sessionMiddleware = session({
@ -18,8 +19,8 @@ const sessionMiddleware = session({
resave: false,
saveUninitialized: false,
cookie:{
secure: process.env.HTTPS || false, // Only set to true if you are using HTTPS.
httpOnly: process.env.HTTPS || false, // Only set to true if you are using HTTPS.
secure: connection,
httpOnly: connection,
maxAge:3600000 * 8 // Session max age in milliseconds. 3600000 = 1 hour.
}
});
@ -29,7 +30,6 @@ app.set('view engine', 'html');
app.engine('html', ejs.renderFile);
app.use([
express.static('public'),
express.json(),
express.urlencoded({ extended: true }),
sessionMiddleware,
router

View File

@ -1,178 +1,12 @@
<div class="modal-dialog modal-sm modal-dialog-centered modal-dialog-scrollables">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Permissions</h5>
<h5 class="modal-title">AppName Permissions</h5>
</div>
<div class="modal-body">
<form action="" id="permissions_modal" method="POST">
<div class="accordion" id="modal-accordion">
<div class="accordion-item mb-3" style="border: 1px solid grey;">
<h2 class="accordion-header" id="heading-1">
<button class="accordion-button collapsed row" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-1" aria-expanded="false">
<span class="avatar avatar-sm bg-green-lt col-3 text-start">JD</span>
<div class="col text-end" style="margin-right: 10px;">Jane Doe</div>
</button>
</h2>
<div id="collapse-1" class="accordion-collapse collapse" data-bs-parent="#modal-accordion">
<div class="accordion-body pt-0">
<div class="">
<div class="">
<div class="row mb-3">
<div class="col-9">
<label class="row text-start">
<span class="col">
All
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select" onclick="selectAll('select')">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Uninstall
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Edit
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Upgrade
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Start
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Stop
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Pause
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<div class="col-9">
<label class="row text-start">
<span class="col">
Restart
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-4">
<div class="col-9">
<label class="row text-start">
<span class="col">
Logs
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="select">
</label>
</div>
</div>
<div class="row mb-2">
<button class="btn" type="submit" formaction="/updatePermissions">Update</button>
</div>
</div>
</div>
</div>
</div>
</div>
PermissionsList
</div>
</form>
</div>

View File

@ -150,7 +150,6 @@
</a>
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<a href="/account" class="dropdown-item">Account</a>
<a href="/variables" class="dropdown-item">Variables</a>
<a href="/settings" class="dropdown-item">Settings</a>
<!-- <div class="dropdown-divider"></div> -->

View File

@ -3,7 +3,6 @@
<h4 class="subheader">Menu</h4>
<div class="list-group list-group-transparent">
<a href="/account" class="list-group-item list-group-item-action d-flex align-items-center">Accounts</a>
<a href="/variables" class="list-group-item list-group-item-action d-flex align-items-center" disabled="">Variables</a>
<a href="/settings" class="list-group-item list-group-item-action d-flex align-items-center">Settings</a>
</div>
<h4 class="subheader mt-4">Other</h4>

View File

@ -21,7 +21,7 @@
<body >
<div class="page">
<!-- Navbar -->
<%- include('navbar.html') %>
<%- include('partials/navbar.html') %>
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
@ -40,7 +40,7 @@
<div class="container-xl">
<div class="card">
<div class="row g-0">
<%- include('sidebar.html') %>
<%- include('partials/sidebar.html') %>
<div class="col d-flex flex-column">
<div class="card-body">
@ -109,7 +109,7 @@
</div>
</div>
<%- include('footer.html') %>
<%- include('partials/footer.html') %>
</div>
</div>
<!-- Libs JS -->