added helmet. updated readme and changelog.
This commit is contained in:
parent
e99dc8470b
commit
56b18cdbba
16 changed files with 126 additions and 174 deletions
|
@ -1,7 +1,10 @@
|
||||||
## v0.09 (dev)
|
## v0.09 (dev)
|
||||||
* Added authentication middleware to router.
|
* Added authentication middleware to router.
|
||||||
* Added gzip compression.
|
* Added gzip compression.
|
||||||
* Added PM2 to dockerfile.
|
* Added PM2.
|
||||||
|
* Added Helmet.
|
||||||
|
* Fixed missing session data.
|
||||||
|
* Reduced sqlite queries.
|
||||||
|
|
||||||
## v0.08 (Dec 15th 2023)
|
## v0.08 (Dec 15th 2023)
|
||||||
* Updates to compose file and instructions from [steveiliop56](https://github.com/steveiliop56)
|
* Updates to compose file and instructions from [steveiliop56](https://github.com/steveiliop56)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# DweebUI
|
# DweebUI
|
||||||
DweebUI is a simple Docker web interface created using Javascript, Node.JS, and Express.
|
DweebUI is a simple Docker web interface created using Javascript, Node.JS, and Express.
|
||||||
|
|
||||||
v0.09
|
Alpha v0.09 ( :fire: Experimental :fire: )
|
||||||
|
|
||||||
[](https://github.com/lllllllillllllillll)
|
[](https://github.com/lllllllillllllillll)
|
||||||
[](https://github.com/lllllllillllllillll)
|
[](https://github.com/lllllllillllllillll)
|
||||||
|
@ -18,13 +18,13 @@ v0.09
|
||||||
* [x] Dashboard provides server metrics, container metrics, and container controls, on a single page.
|
* [x] Dashboard provides server metrics, container metrics, and container controls, on a single page.
|
||||||
* [x] View container logs.
|
* [x] View container logs.
|
||||||
* [ ] Update containers (planned).
|
* [ ] Update containers (planned).
|
||||||
* [ ] Manage your Docker networks, images, and volumes (planned).
|
* [ ] Manage your Docker networks, images, and volumes (in development).
|
||||||
* [x] Light/Dark Mode.
|
* [x] Light/Dark Mode.
|
||||||
* [x] Easy to install app templates.
|
* [x] Easy to install app templates.
|
||||||
* [x] Multi-User built-in.
|
* [x] Multi-User built-in.
|
||||||
* [ ] User pages (planned).
|
* [ ] Permissions system (in development).
|
||||||
* [x] Support for Windows, Linux, and MacOS.
|
* [x] Support for Windows, Linux, and MacOS.
|
||||||
* [ ] Docker compose support (planned).
|
* [ ] Docker compose import (in development).
|
||||||
* [x] Templates.json maintains compatability with Portainer, allowing you to use the template without needing to use DweebUI.
|
* [x] Templates.json maintains compatability with Portainer, allowing you to use the template without needing to use DweebUI.
|
||||||
* [x] Automatically persists data in docker volumes if bind mount isn't used.
|
* [x] Automatically persists data in docker volumes if bind mount isn't used.
|
||||||
* [ ] Preset variables (planned).
|
* [ ] Preset variables (planned).
|
||||||
|
|
14
app.js
14
app.js
|
@ -3,6 +3,7 @@ const express = require("express");
|
||||||
const app = express();
|
const app = express();
|
||||||
const session = require("express-session");
|
const session = require("express-session");
|
||||||
const compression = require('compression');
|
const compression = require('compression');
|
||||||
|
const helmet = require('helmet');
|
||||||
const PORT = process.env.PORT || 8000;
|
const PORT = process.env.PORT || 8000;
|
||||||
|
|
||||||
// Router
|
// Router
|
||||||
|
@ -13,7 +14,7 @@ const { serverStats, containerList, containerStats, containerAction, containerLo
|
||||||
let sentList, clicked;
|
let sentList, clicked;
|
||||||
app.locals.site_list = '';
|
app.locals.site_list = '';
|
||||||
|
|
||||||
const Containers = require('./database/ContainerSettings');
|
const Containers = require('./database/ContainerModel');
|
||||||
|
|
||||||
|
|
||||||
// Configure Session
|
// Configure Session
|
||||||
|
@ -32,6 +33,7 @@ const sessionMiddleware = session({
|
||||||
app.set('view engine', 'ejs');
|
app.set('view engine', 'ejs');
|
||||||
app.use([
|
app.use([
|
||||||
compression(),
|
compression(),
|
||||||
|
helmet(),
|
||||||
express.static("public"),
|
express.static("public"),
|
||||||
express.json(),
|
express.json(),
|
||||||
express.urlencoded({ extended: true }),
|
express.urlencoded({ extended: true }),
|
||||||
|
@ -115,10 +117,14 @@ io.on('connection', (socket) => {
|
||||||
if(!containerExists){
|
if(!containerExists){
|
||||||
const container = await Containers.create({
|
const container = await Containers.create({
|
||||||
name: data.container,
|
name: data.container,
|
||||||
visibility: false
|
visibility: false,
|
||||||
});
|
});
|
||||||
hiddenContainers();
|
hiddenContainers();
|
||||||
console.log(`[Created] Container ${data.container} hidden`)
|
console.log(`[Created] Container ${data.container} hidden`)
|
||||||
|
|
||||||
|
let containerData = await Containers.findOne({ where: {name:data.container}});
|
||||||
|
console.log(containerData);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
containerExists.update({ visibility: false });
|
containerExists.update({ visibility: false });
|
||||||
console.log(`[Updated] Container ${data.container} hidden`)
|
console.log(`[Updated] Container ${data.container} hidden`)
|
||||||
|
|
|
@ -166,6 +166,7 @@ module.exports.dashCard = function dashCard(data) {
|
||||||
<div class="dropdown-menu dropdown-menu-end">
|
<div class="dropdown-menu dropdown-menu-end">
|
||||||
<a class="dropdown-item" onclick="hideContainer(this)" name="${name}" href="#">Hide</a>
|
<a class="dropdown-item" onclick="hideContainer(this)" name="${name}" href="#">Hide</a>
|
||||||
<a class="dropdown-item" onclick="resetView()" name="${name}" href="#">Reset View</a>
|
<a class="dropdown-item" onclick="resetView()" name="${name}" href="#">Reset View</a>
|
||||||
|
<a class="dropdown-item" href="#">Permissions</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,40 +1,7 @@
|
||||||
const User = require('../database/UserModel');
|
|
||||||
|
|
||||||
exports.Images = async function(req, res) {
|
exports.Images = async function(req, res) {
|
||||||
|
|
||||||
let user_list = `
|
|
||||||
<tr>
|
|
||||||
<th><input class="form-check-input" type="checkbox"></th>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Avatar</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>UUID</th>
|
|
||||||
<th>Role</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
let users = await User.findAll();
|
|
||||||
users.forEach((account) => {
|
|
||||||
full_name = account.first_name + ' ' + account.last_name;
|
|
||||||
user_info = `
|
|
||||||
<tr>
|
|
||||||
<td><input class="form-check-input" type="checkbox"></td>
|
|
||||||
<td>${user.id}</td>
|
|
||||||
<td><span class="avatar me-2">${account.avatar}</span></td>
|
|
||||||
<td>${full_name}</td>
|
|
||||||
<td>${account.username}</td>
|
|
||||||
<td>${account.email}</td>
|
|
||||||
<td>${account.UUID}</td>
|
|
||||||
<td>${account.role}</td>
|
|
||||||
<td><span class="badge badge-outline text-green">Active</span></td>
|
|
||||||
<td><a href="#" class="btn">Edit</a></td>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
user_list += user_info;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render the home page
|
// Render the home page
|
||||||
res.render("pages/images", {
|
res.render("pages/images", {
|
||||||
|
@ -42,7 +9,6 @@ exports.Images = async function(req, res) {
|
||||||
role: req.session.role,
|
role: req.session.role,
|
||||||
avatar: req.session.avatar,
|
avatar: req.session.avatar,
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
user_list: user_list
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,39 +2,6 @@ const User = require('../database/UserModel');
|
||||||
|
|
||||||
exports.Networks = async function(req, res) {
|
exports.Networks = async function(req, res) {
|
||||||
|
|
||||||
let user_list = `
|
|
||||||
<tr>
|
|
||||||
<th><input class="form-check-input" type="checkbox"></th>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Avatar</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>UUID</th>
|
|
||||||
<th>Role</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
let users = await User.findAll();
|
|
||||||
users.forEach((account) => {
|
|
||||||
full_name = account.first_name + ' ' + account.last_name;
|
|
||||||
user_info = `
|
|
||||||
<tr>
|
|
||||||
<td><input class="form-check-input" type="checkbox"></td>
|
|
||||||
<td>${user.id}</td>
|
|
||||||
<td><span class="avatar me-2">${account.avatar}</span></td>
|
|
||||||
<td>${full_name}</td>
|
|
||||||
<td>${account.username}</td>
|
|
||||||
<td>${account.email}</td>
|
|
||||||
<td>${account.UUID}</td>
|
|
||||||
<td>${account.role}</td>
|
|
||||||
<td><span class="badge badge-outline text-green">Active</span></td>
|
|
||||||
<td><a href="#" class="btn">Edit</a></td>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
user_list += user_info;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render the home page
|
// Render the home page
|
||||||
res.render("pages/users", {
|
res.render("pages/users", {
|
||||||
|
@ -42,7 +9,6 @@ exports.Networks = async function(req, res) {
|
||||||
role: req.session.role,
|
role: req.session.role,
|
||||||
avatar: req.session.avatar,
|
avatar: req.session.avatar,
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
user_list: user_list
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
const User = require('../database/UserModel.js');
|
const User = require('../database/UserModel.js');
|
||||||
const Server = require('../database/ServerSettings.js');
|
const Server = require('../database/ServerModel.js');
|
||||||
|
|
||||||
exports.Settings = async function(req, res) {
|
exports.Settings = async function(req, res) {
|
||||||
|
|
||||||
|
|
|
@ -3,39 +3,6 @@ const User = require('../database/UserModel');
|
||||||
exports.Volumes = async function(req, res) {
|
exports.Volumes = async function(req, res) {
|
||||||
|
|
||||||
|
|
||||||
let user_list = `
|
|
||||||
<tr>
|
|
||||||
<th><input class="form-check-input" type="checkbox"></th>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Avatar</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>UUID</th>
|
|
||||||
<th>Role</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
let users = await User.findAll();
|
|
||||||
users.forEach((account) => {
|
|
||||||
full_name = account.first_name + ' ' + account.last_name;
|
|
||||||
user_info = `
|
|
||||||
<tr>
|
|
||||||
<td><input class="form-check-input" type="checkbox"></td>
|
|
||||||
<td>${user.id}</td>
|
|
||||||
<td><span class="avatar me-2">${account.avatar}</span></td>
|
|
||||||
<td>${full_name}</td>
|
|
||||||
<td>${account.username}</td>
|
|
||||||
<td>${account.email}</td>
|
|
||||||
<td>${account.UUID}</td>
|
|
||||||
<td>${account.role}</td>
|
|
||||||
<td><span class="badge badge-outline text-green">Active</span></td>
|
|
||||||
<td><a href="#" class="btn">Edit</a></td>
|
|
||||||
</tr>`
|
|
||||||
|
|
||||||
user_list += user_info;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render the home page
|
// Render the home page
|
||||||
res.render("pages/volumes", {
|
res.render("pages/volumes", {
|
||||||
|
@ -43,7 +10,6 @@ exports.Volumes = async function(req, res) {
|
||||||
role: req.session.role,
|
role: req.session.role,
|
||||||
avatar: req.session.avatar,
|
avatar: req.session.avatar,
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
user_list: user_list
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
|
@ -30,10 +30,35 @@ const Containers = sequelize.define('Containers', {
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
// allowNull defaults to true
|
// allowNull defaults to true
|
||||||
},
|
},
|
||||||
permissions: {
|
start: {
|
||||||
type: DataTypes.STRING
|
type: DataTypes.JSON
|
||||||
// allowNull defaults to true
|
// allowNull defaults to true
|
||||||
}
|
},
|
||||||
|
stop: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
pause: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
restart: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
logs: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
type: DataTypes.JSON
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function syncModel() {
|
async function syncModel() {
|
|
@ -28,7 +28,11 @@ const Server = sequelize.define('Server', {
|
||||||
puid: {
|
puid: {
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
// allowNull defaults to true
|
// allowNull defaults to true
|
||||||
}
|
},
|
||||||
|
caddy: {
|
||||||
|
type: DataTypes.STRING
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
async function syncModel() {
|
async function syncModel() {
|
|
@ -2,9 +2,9 @@ version: "3.9"
|
||||||
services:
|
services:
|
||||||
dweebui:
|
dweebui:
|
||||||
container_name: dweebui
|
container_name: dweebui
|
||||||
image: lllllllillllllillll/dweebui:v0.09-dev
|
# image: lllllllillllllillll/dweebui:v0.09-dev
|
||||||
# build:
|
build:
|
||||||
# context: .
|
context: .
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
PORT: 8000
|
PORT: 8000
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
const { currentLoad, mem, networkStats, fsSize, dockerContainerStats, dockerImages, networkInterfaces } = require('systeminformation');
|
const { currentLoad, mem, networkStats, fsSize, dockerContainerStats, dockerImages, networkInterfaces, dockerInfo } = require('systeminformation');
|
||||||
var Docker = require('dockerode');
|
var Docker = require('dockerode');
|
||||||
var docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
var docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||||
const { dashCard } = require('../components/dashCard');
|
const { dashCard } = require('../components/dashCard');
|
||||||
const { Readable } = require('stream');
|
const { Readable } = require('stream');
|
||||||
|
|
||||||
const Containers = require('../database/ContainerSettings');
|
const Containers = require('../database/ContainerModel');
|
||||||
|
|
||||||
// export docker
|
// export docker
|
||||||
module.exports.docker = docker;
|
module.exports.docker = docker;
|
||||||
|
@ -318,14 +318,20 @@ module.exports.containerLogs = function (data) {
|
||||||
|
|
||||||
module.exports.dockerImages = async function () {
|
module.exports.dockerImages = async function () {
|
||||||
|
|
||||||
const data = await dockerImages({ all: true });
|
// get the names, tags, status, created date, and size of all images
|
||||||
|
|
||||||
for ( i = 0; i < data.length; i++) {
|
const data1 = await dockerImages({ all: true });
|
||||||
console.log(`Image ${i}:`)
|
|
||||||
console.log(`repoTags: ${data[i].repoTags}`)
|
|
||||||
// console.log(`repoDigest: ${data[i].repoDigests}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const data2 = await docker.listImages({ all: true });
|
||||||
|
|
||||||
|
// for ( i = 0; i < data.length; i++) {
|
||||||
|
// console.log(`Image ${i}:`)
|
||||||
|
// console.log(`repoTags: ${data[i].repoTags}`)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// console.log(data1);
|
||||||
|
|
||||||
|
console.log(data2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
package-lock.json
generated
9
package-lock.json
generated
|
@ -17,6 +17,7 @@
|
||||||
"ejs": "^3.1.9",
|
"ejs": "^3.1.9",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
|
"helmet": "^7.1.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"sequelize": "^6.35.2",
|
"sequelize": "^6.35.2",
|
||||||
"socket.io": "^4.6.1",
|
"socket.io": "^4.6.1",
|
||||||
|
@ -1182,6 +1183,14 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/helmet": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/http-cache-semantics": {
|
"node_modules/http-cache-semantics": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"ejs": "^3.1.9",
|
"ejs": "^3.1.9",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
|
"helmet": "^7.1.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"sequelize": "^6.35.2",
|
"sequelize": "^6.35.2",
|
||||||
"socket.io": "^4.6.1",
|
"socket.io": "^4.6.1",
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
<table class="table table-vcenter table-mobile-md card-table">
|
<table class="table table-vcenter table-mobile-md card-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
<%- user_list %>
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<table class="table table-vcenter table-mobile-md card-table">
|
<table class="table table-vcenter table-mobile-md card-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
<%- user_list %>
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Add table
Reference in a new issue