bugfix permissions

This commit is contained in:
2026-04-28 15:35:20 +02:00
parent 061188a3c0
commit c98089e359
14 changed files with 47 additions and 125 deletions

View File

@@ -1,4 +0,0 @@
© 2025 Grünflächenamt | Manuel Sowada
Diese Software ist ausschließlich für den internen dienstlichen Gebrauch durch Mitarbeiter des Grünflächenamtes vorgesehen.
Weitergabe, Veröffentlichung oder private Nutzung ist ohne ausdrückliche Genehmigung untersagt.

View File

@@ -36,7 +36,7 @@
{{#each items}}
{{#ifSingle this.menu.items}}
{{#if this.authorized}}
<li class="start-item {{#unless ../this.active}}unload{{/unless}}" data-active="{{#equaler ../this.active "&&" this.authorized}}true{{else}}false{{/equaler}}" data-appname="{{../this.name}}" data-appview="{{this.view}}" data-viewlabel="{{this.label}}">
<li class="start-item {{#unless ../this.active}}unload{{/unless}}" {{#if ../this.description}}data-tooltip="{{../this.description}}"{{/if}} data-active="{{#equaler ../this.active "&&" this.authorized}}true{{else}}false{{/equaler}}" data-appname="{{../this.name}}" data-appview="{{this.view}}" data-viewlabel="{{this.label}}">
{{#if this.icon}}
<img src="{{#if ../this.pluginPath}}/{{../this.name}}{{/if}}/images/{{this.icon}}" class="start-icon" />
{{else}}
@@ -47,7 +47,7 @@
{{else}}
<li class="start-item has-submenu">
<img src="{{#if ../this.pluginPath}}/{{../this.name}}{{/if}}/images/folder.png" class="start-icon" style="position:absolute;left:12px;"/>
<span class="menu-label">{{this.menu.label}}</span>
<span {{#if this.description}}data-tooltip="{{this.description}}"{{/if}} class="menu-label">{{this.menu.label}}</span>
{{!-- {{#if this.version}}<small>v{{this.version}}</small>{{/if}} --}}
<ul class="submenu">

View File

@@ -15,7 +15,7 @@
<script>
fetch('/api/getConfig', { method: 'POST' })
fetch('/api/config/get', { method: 'POST' })
.then(res => res.json())
.then(json => {
const tree = createJsonTree({
@@ -24,7 +24,7 @@
expandInitially: true,
onSave: json => {
console.log(JSON.stringify(tree.getChanges()));
fetch('/config', {
fetch('/api/config/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(tree.getChanges(), null, 2)

View File

@@ -46,7 +46,7 @@
});
};
fetch('/api/getServerInfo', { method: 'POST' })
fetch('/api/serverInfo/get', { method: 'POST' })
.then(res => res.json())
.then(json => {

View File

@@ -10,7 +10,7 @@
</div>
<script>
fetch('/api/getStyles', { method: 'POST' })
fetch('/api/styles/get', { method: 'POST' })
.then(res => res.json())
.then(json => {
const tree = createJsonTree({
@@ -18,7 +18,7 @@
data: json,
expandInitially: true,
onSave: json => {
fetch('/style', {
fetch('/api/styles/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(tree.getChanges(), null, 2)

View File

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Role Based Access Control</title>
</head>
<body>
<div class="container static" style="height: 100vh;">
<div class="card static" style="overflow-y:auto;flex: 1 1 auto;" >
</div>
</div>
</body>
</html>

View File

@@ -114,7 +114,7 @@ const server = https.createServer(httpsOptions, app);
databaseModel.set('roleModel', require(`@models/roleModel`)(service.get('sqlManager').getInstance('main')));
databaseModel.set('rolePermissionsModel', require(`@models/rolePermissionsModel`)(service.get('sqlManager').getInstance('main')));
service.set('rbacManager', new RBACManager(databaseModel));
service.set('rbacManager', new RBACManager(databaseModel, runtimeFile.configuration.live.integration.token.secret));
service.set('authenticationManager', new AuthenticationManager(databaseModel.get('authentication'), runtimeFile.configuration.live.integration.token.secret));
service.set('activeDirectoryManager', new ActiveDirectory(runtimeFile.configuration.live.integration.activedirectory))
@@ -128,13 +128,11 @@ const server = https.createServer(httpsOptions, app);
//#endregion
//#region Service-Registration/Middleware/Utils/Helpers
require(`${localPath.root}/utils.js`);
let helpers = service.get('fileSystemManager').loadAllFiles(`${localPath.public}/helpers`, '.js');
exports.helpers = helpers;
// app.use(service.get('vaultifyManager').createMiddleware());
app.use(service.get('rbacManager').requirePermissionMiddleware());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
@@ -145,7 +143,9 @@ const server = https.createServer(httpsOptions, app);
app.use(express.static(localPath.public));
app.use(express.static(localPath.source));
//#region Service-Registration/Middleware/Utils/Helpers
app.use(service.get('rbacManager').authenticate());
app.use(service.get('rbacManager').requirePermissionMiddleware());
app.use(function(request, response, next) {
if (!request.secure) {
@@ -200,14 +200,13 @@ const server = https.createServer(httpsOptions, app);
});
//#endregion
//#region Implement routes
require(`${localPath.source}/routes/loginRoutes.js`).route(app, service); // #1 - no token security! important: first!!!
require(`${localPath.source}/routes/indexRoutes.js`).route(app, service); // #2 - token security enabled at this point
require(`${localPath.source}/routes/adminRoutes.js`).route(app, service); // #3 - token security always enabled
//#endregion
app.use(service.get('rbacManager').authenticate());
//#region Implements sockets
require(`${localPath.source}/sockets/mainSocket.js`)(

View File

@@ -15,8 +15,7 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
},
{
"label": "Configs",
@@ -31,8 +30,7 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
},
{
"label": "RBAC",
@@ -48,15 +46,9 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": "800px",
"height": "600px"
}
},
{
@@ -70,8 +62,8 @@
"label": "EventLog",
"view": "eventlog",
"defaultSize": {
"width": "1200px",
"height": "1200px"
"width": "800px",
"height": "600px"
},
"icon": "eventlog.ico",
"permissions": [
@@ -79,15 +71,9 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": "1200px",
"height": "1200px"
}
},
{
@@ -110,15 +96,9 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": "900px",
"height": "800px"
}
},
{
@@ -141,15 +121,9 @@
"scope": "SYSTEM",
"action": "Administration"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": "900px",
"height": "500px"
}
},
{
@@ -172,15 +146,9 @@
"scope": "SYSTEM",
"action": "Default_Access"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": "460px",
"height": "515px"
}
},
{
@@ -199,15 +167,9 @@
"scope": "SYSTEM",
"action": "Default_Access"
}
],
"authorized": true
]
}
]
},
"onlyAdministration": false,
"defaultSize": {
"width": 800,
"height": 600
}
}
]

View File

@@ -4,20 +4,20 @@ const path = require('path');
const { localPath, cache, runtimeFile } = require('@root/globalize.js');
const configurationFile = path.join(require('@root/server.js').path.source, 'models', 'configuration.json');
const stylesheetFile = path.join(require('@root/server.js').path.source, 'models', 'stylesheet.json');
const serverInfoFile = path.join(require('@root/server.js').path.root, 'package.json');
module.exports = {
route(app, service) {
// JSON configuration abrufen
app.post('/api/getConfig', (req, res) => {
app.post('/api/config/get', (req, res) => {
res.status(200).send(runtimeFile.configuration.live);
});
// JSON stylesheet speichern
app.post('/api/styles/get', (req, res) => {
res.status(200).send(runtimeFile.stylesheet.live);
});
// JSON configuration speichern
app.post('/config', (req, res) => {
app.post('/api/config/save', (req, res) => {
try {
runtimeFile.configuration.save(req.body);
res.status(200).send({ status: 'ok' });
@@ -27,7 +27,7 @@ module.exports = {
});
// JSON stylesheet abrufen
app.post('/api/getStyles', (req, res) => {
app.post('/api/styles/save', (req, res) => {
try {
runtimeFile.stylesheet.save(req.body);
res.status(200).send({ status: 'ok' });
@@ -35,30 +35,12 @@ module.exports = {
return res.status(500).send(err)
}
});
// JSON stylesheet speichern
app.post('/style', (req, res) => {
fs.writeFile(runtimeFile.stylesheet.live, JSON.stringify(req.body, null, 2), (err) => {
if (err) return res.status(500).send(err);
res.status(200).send({ status: 'ok' });
});
});
// JSON package.json abrufen
app.post('/api/getServerInfo', (req, res) => {
app.post('/api/serverInfo/get', (req, res) => {
res.status(200).send({ package: runtimeFile.package.live, pid: process.pid, releaseNotes: runtimeFile.releaseNotes.live });
});
// JSON package.json speichern
app.post('/serverinfo', (req, res) => {
fs.writeFile(runtimeFile.package.live, JSON.stringify(req.body, null, 2), (err) => {
if (err) return res.status(500).send(err);
res.status(200).send({ status: 'ok' });
});
});
app.post('/api/eventlog/clearlog', (req, res) => {
service.get('eventManager').clear();
res.status(200).send({ status: 'ok' })
@@ -119,7 +101,7 @@ module.exports = {
app.post('/api/plugins/integrated', async (req, res) => {
try {
res.status(200).json(cached.startMenuItems.live);
res.status(200).json(runtimeFile.startMenuItems.live);
} catch (error) {
res.status(500).json({ error: error.message });
}

View File

@@ -21,7 +21,7 @@ module.exports = {
let context = fs.existsSync(pluginPath)
? service.get('fileSystemManager').loadJSON(pluginPath)
: runtimeFile.startMenuItems.live.find(item => item.name == name);
: cache.startMenuItems.find(item => item.name == name);
context.defaultSize =
context.menu.items.find(item => item.label == viewLabel)?.defaultSize ||

View File

@@ -1,4 +1,4 @@
const { verify } = require("jsonwebtoken");
const { localPath, cache, runtimeFile } = require('@root/globalize.js');
module.exports = {
@@ -71,7 +71,7 @@ module.exports = {
res.clearCookie('sAMAccountName');
res.clearCookie('ObjectGUID');
res.render('login', { layout: false, title: app.locals.configuration.server.name })
res.render('login', { layout: false, title: runtimeFile.configuration.live.server.name })
// setTimeout(() => res.render('login', { layout: false, title: app.locals.configuration.server.name }), 3000);
// res.json({ message: 'Logout erfolgreich' });
});

View File

@@ -101,7 +101,7 @@ class EventManager {
const stackLine = err.stack.split('\n')[2]; // calls trace-line
const trace = stackLine.match(/\/.*\d+/)[0].replace(localPath.root, ''); // path:line:column
const message = `${this.EventLog.tableName} cleared successfully`;
const message = `${this.EventLog.tableName} geleert`;
await this.EventLog.destroy({
where: {},
truncate: true,

View File

@@ -1,8 +1,9 @@
// rbac/RbacService.js
const jwt = require('jsonwebtoken');
class RBACManager {
constructor(databaseModel) {
constructor(databaseModel, SECRET_KEY) {
this.db = databaseModel;
this.SECRET_KEY = SECRET_KEY;
}
async resolvePermissions(objectGuid) {
@@ -128,8 +129,6 @@ class RBACManager {
return next(); // oder 401 wenn du streng sein willst
}
const rbac = this.rbac;
const permissions = req.user.permissions || [];
const isSuperAdmin = req.user.isSuperAdmin || false;
@@ -137,16 +136,12 @@ class RBACManager {
permissions,
isSuperAdmin,
hasPermission: (required) =>
rbac.hasPermission(permissions, required, isSuperAdmin)
this.hasPermission(permissions, required, isSuperAdmin)
};
return next();
next();
} catch (err) {
console.error('[RBAC MIDDLEWARE ERROR]', err);
return res.status(500).json({ message: 'RBAC Fehler' });
return res.status(500).json('[RBAC MIDDLEWARE ERROR]', err);
}
};
}
@@ -168,7 +163,11 @@ class RBACManager {
const publicRoutes = [
'/login',
'/public'
'/public',
'/css',
'/js',
'/images',
'/favicon.ico'
];
const isPublicRoute = publicRoutes.some(route =>
@@ -216,7 +215,6 @@ class RBACManager {
permissions: normalized,
isSuperAdmin
};
next();
} catch (err) {

View File

@@ -21,8 +21,7 @@ module.exports = startMenuItems = async function (app, objectGuid) {
// =========================
// Load menu sources
// =========================
const integratedStartmenuItems = runtimeFile.startMenuItems.live;
const integratedStartmenuItems = safeClone(runtimeFile.startMenuItems.live);
const plugins = service
.get('pluginManager')
.getStatus()