improvements for multi-user and permissions
This commit is contained in:
parent
66f273e22e
commit
8d9eb9981a
10
README.md
10
README.md
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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> -->
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 -->
|
||||
|
|
Loading…
Reference in New Issue