summaryrefslogtreecommitdiffstats
path: root/server/api
diff options
context:
space:
mode:
authorJannik Schönartz2019-12-01 16:03:55 +0100
committerJannik Schönartz2019-12-01 16:03:55 +0100
commitdc25bd7de72aa574767876341e5792733c2ee0e0 (patch)
tree4086f19a6df107773a3990c422fe1160f8959147 /server/api
parent[configloader] bugfixes in the beta configloader: (diff)
downloadbas-dc25bd7de72aa574767876341e5792733c2ee0e0.tar.gz
bas-dc25bd7de72aa574767876341e5792733c2ee0e0.tar.xz
bas-dc25bd7de72aa574767876341e5792733c2ee0e0.zip
[server/log] Add logging to all modules
Logging with snapshots: Client: create / edit / delete / added to group / removed from group Group: create / edit / delete / added to group / removed from group Logging without snapshot: Wake-on-lan: wakup Ipxe-Builder: build / clear / cancel / script save IP-Ranges: create / edit / delete Logging: with info in description: User: create / edit / delete / grant role / revoke role Event: create / edit / delete Permission-Manager-Role: create / edit / delete Registration-Hook: create / delete / edit / change order Ipxe Configuration: create / delete / edit Backend: create / edit / delete
Diffstat (limited to 'server/api')
-rw-r--r--server/api/backends.js109
-rw-r--r--server/api/clients.js78
-rw-r--r--server/api/events.js99
-rw-r--r--server/api/groups.js282
-rw-r--r--server/api/ipranges.js62
-rw-r--r--server/api/ipxe.js44
-rw-r--r--server/api/ipxeconfigs.js135
-rw-r--r--server/api/registration.js73
-rw-r--r--server/api/roles.js78
-rw-r--r--server/api/systemlog.js2
-rw-r--r--server/api/users.js251
-rw-r--r--server/api/wakerequests.js6
12 files changed, 1153 insertions, 66 deletions
diff --git a/server/api/backends.js b/server/api/backends.js
index 32c7cc7..b75634f 100644
--- a/server/api/backends.js
+++ b/server/api/backends.js
@@ -6,6 +6,8 @@ var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
var noAuthRouter = decorateApp(express.Router())
+const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// GET requests.
@@ -384,8 +386,31 @@ router.postAsync('/:id/connection', async (req, res) => {
const b = new ExternalBackends()
const instance = b.getInstance(backend.type)
const response = await instance.checkConnection(backend.credentials)
- if (response.error) return res.status(500).send(response)
- else if (response) res.status(200).send()
+
+ if (response.error) {
+ console.log(response)
+ log({
+ category: 'ERROR_BACKEND_CHECKCONNECTION',
+ description: '[' + backend.id + '] ' + backend.name + ': Connection error. [' + response.error + ']\n' +
+ 'ID: ' + backend.id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type + '\n' +
+ 'Error: ' + response.error + '\n' +
+ 'Message: ' + response.message,
+ userId: req.user.id
+ })
+ return res.status(500).send(response)
+ } else if (response) {
+ log({
+ category: 'BACKEND_CHECKCONNECTION',
+ description: '[' + backend.id + '] ' + backend.name + ': Connection successfull.\n' +
+ 'ID: ' + backend.id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type,
+ userId: req.user.id
+ })
+ res.status(200).send()
+ }
})
// PUT requests
@@ -408,6 +433,14 @@ router.putAsync('/:id', async (req, res) => {
// Insert new backend in the db.
const credentialString = JSON.stringify(backend.credentials)
db.backend.create({ name: backend.name, type: backend.type, credentials: credentialString })
+ log({
+ category: 'BACKEND_CREATE',
+ description: '[' + id + '] ' + backend.name + ': Backend successfully created.\n' +
+ 'ID: ' + id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type,
+ userId: req.user.id
+ })
} else {
const backendDb = await db.backend.findOne({ where: { id: id } })
if (!backendDb) return res.status(404).send({ error: 'BACKEND_NOT_FOUND', message: 'No backend was found with the provided backend id.' })
@@ -426,6 +459,14 @@ router.putAsync('/:id', async (req, res) => {
// Update an existing backend in the db.
db.backend.update({ name: backend.name, type: backend.type, credentials: JSON.stringify(credentials) }, { where: { id: id } })
+ log({
+ category: 'BACKEND_EDIT',
+ description: '[' + id + '] ' + backend.name + ': Backend successfully edited.\n' +
+ 'ID: ' + id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type,
+ userId: req.user.id
+ })
}
res.status(200).send('success')
@@ -446,6 +487,16 @@ router.put('/:id/syncsettings', (req, res) => {
const sync = req.body.sync
db.backend.findOne({ where: { id: id } }).then(backend => {
db.backend.update({ groupTypes: groups, clientTypes: clients, sync: sync }, { where: { id: id } }).then(() => {
+ log({
+ category: 'BACKEND_SYNCSETTINGS_EDIT',
+ description: '[' + backend.id + '] ' + backend.name + ': Sync settings successfully edited.\n' +
+ 'ID: ' + backend.id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type + '\n' +
+ 'Groups: ' + req.body.groups + '\n' +
+ 'Clients: ' + req.body.clients,
+ userId: req.user.id
+ })
res.status(200).send()
})
})
@@ -458,10 +509,58 @@ router.put('/:id/syncsettings', (req, res) => {
* Deletes the backend to the given id.
*/
router.postAsync('/delete', async (req, res) => {
- const backendIds = req.body.id
+ req.body.ids = req.body.id
+ // await db.backend.destroy({ where: { id: backendIds } })
+ // res.status(200).send('success')
+
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+ // Only need to log batch request if there is more than one backend to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'BACKEND_BATCH_DELETE',
+ description: 'Batch deletion of ' + req.body.ids.length + ' backends initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
- await db.backend.destroy({ where: { id: backendIds } })
- res.status(200).send('success')
+ let deletionCounter = 0
+ // Delete every backend on its own, to get a better log
+ for (let index in req.body.ids) {
+ const backend = await db.backend.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.backend.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_BACKEND_DELETE',
+ description: '[' + backend.id + '] ' + backend.name + ': Backend could not be deleted.\n' +
+ 'ID: ' + backend.id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type,
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'BACKEND_DELETE',
+ description: '[' + backend.id + '] ' + backend.name + ': Backend successfully deleted.\n' +
+ 'ID: ' + backend.id + '\n' +
+ 'Name: ' + backend.name + '\n' +
+ 'Type: ' + backend.type,
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'BACKEND_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' backends successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+ HttpResponse.successBatch('deleted', 'backend', deletionCounter).send(res)
})
module.exports.router = router
diff --git a/server/api/clients.js b/server/api/clients.js
index d72207b..15e3b8d 100644
--- a/server/api/clients.js
+++ b/server/api/clients.js
@@ -7,6 +7,7 @@ var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// ############################################################################
// ########################### GET requests #################################
@@ -30,8 +31,51 @@ router.postAsync(['', '/:id'], async (req, res) => {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res)
await backendHelper.deleteClients(req.body.ids, req.body.backendIds)
- const count = await db.client.destroy({ where: { id: req.body.ids } })
- HttpResponse.successBatch('deleted', 'client', count).send(res)
+
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+ // Only need to log batch request if there is more than one client to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'CLIENT_BATCH_DELETE',
+ description: 'Batch deletion of ' + req.body.ids.length + ' clients initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ // Delete every client on its own, to get a better log
+ for (let index in req.body.ids) {
+ const client = await db.client.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.client.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_CLIENT_DELETE',
+ description: 'Client could not be deleted.',
+ client,
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'CLIENT_DELETE',
+ description: 'Client successfully deleted.',
+ client,
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'CLIENT_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' clients successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+ HttpResponse.successBatch('deleted', 'client', deletionCounter).send(res)
} else {
let client
let action = 'updated'
@@ -51,6 +95,12 @@ router.postAsync(['', '/:id'], async (req, res) => {
client = await db.client.create(req.body.data)
action = 'created'
io.in('broadcast newClient').emit('notifications newAlert', { type: 'info', text: 'New client!' })
+ log({
+ category: 'CLIENT_CREATE',
+ description: 'Client successfully created.',
+ clientId: client.id,
+ userId: req.user.id
+ })
// Add client to the backends
backendClient.id = client.id
@@ -58,7 +108,15 @@ router.postAsync(['', '/:id'], async (req, res) => {
} else if (req.params.id > 0) {
client = await db.client.findOne({ where: { id: req.params.id } })
if (!client) return HttpResponse.notFound(req.params.id).send(res)
- else await client.update(req.body.data)
+ else {
+ await client.update(req.body.data)
+ log({
+ category: 'CLIENT_EDIT',
+ description: 'Client successfully edited.',
+ clientId: client.id,
+ userId: req.user.id
+ })
+ }
backendHelper.updateClient(backendClient)
} else {
return HttpResponse.invalidId().send(res)
@@ -71,10 +129,18 @@ router.postAsync(['', '/:id'], async (req, res) => {
// ############################################################################
// ########################## DELETE requests ###############################
-router.delete('/:id', async (req, res) => {
+router.deleteAsync('/:id', async (req, res) => {
+ const client = db.client.findOne({ where: { id: req.params.id } })
const count = await db.client.destroy({ where: { id: req.params.id } })
- if (count) HttpResponse.success('deleted', 'client', req.params.id).send(res)
- else HttpResponse.notFound(req.params.id).send(res)
+ if (count) {
+ log({
+ category: 'CLIENT_DELETE',
+ description: 'Client successfully deleted.',
+ client,
+ userId: req.user.id
+ })
+ HttpResponse.success('deleted', 'client', req.params.id).send(res)
+ } else HttpResponse.notFound(req.params.id).send(res)
})
// ############################################################################
diff --git a/server/api/events.js b/server/api/events.js
index 6ec37c4..7e330e5 100644
--- a/server/api/events.js
+++ b/server/api/events.js
@@ -8,6 +8,8 @@ var router = decorateApp(express.Router())
const zmq = require('zeromq')
const socket = zmq.socket('push')
socket.connect('ipc:///tmp/bas_zeromq_events')
+const log = require(path.join(__appdir, 'lib', 'log'))
+const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
// ############################################################################
// ########################### GET requests #################################
@@ -47,7 +49,65 @@ router.postAsync('/blacklist', async (req, res) => {
// Create, Update or Delete POST
router.postAsync(['', '/:id'], async (req, res) => {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- await db.event.destroy({ where: { id: req.params.id || req.body.ids } }).then(count => { res.send({ count }) })
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+
+ // Only need to log batch request if there is more than one event to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'EVENT_BATCH_DELETE',
+ description: 'Event batch deletion of ' + req.body.ids.length + ' events initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ // Delete every event on its own, to get a better log
+ for (let index in req.body.ids) {
+ const event = await db.event.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.event.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_EVENT_DELETE',
+ description: '[' + event.id + '] ' + event.name + ': Event could not be deleted.\n' +
+ 'ID: ' + event.id + '\n' +
+ 'Name: ' + event.name + '\n' +
+ 'Description: ' + event.description + '\n' +
+ 'Times: ' + event.times + '\n' +
+ 'Important: ' + event.important + '\n' +
+ 'Wake-on-Lan: ' + event.wakeonlan + '\n' +
+ 'Config ID: ' + event.configId,
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'EVENT_DELETE',
+ description: '[' + event.id + '] ' + event.name + ': Event successfully deleted.\n' +
+ 'ID: ' + event.id + '\n' +
+ 'Name: ' + event.name + '\n' +
+ 'Description: ' + event.description + '\n' +
+ 'Times: ' + event.times + '\n' +
+ 'Important: ' + event.important + '\n' +
+ 'Wake-on-Lan: ' + event.wakeonlan + '\n' +
+ 'Config ID: ' + event.configId,
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'EVENT_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' events successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+ HttpResponse.successBatch('deleted', 'event', deletionCounter).send(res)
+
+ await db.event.destroy({ where: { id: req.body.ids } }).then(count => { res.send({ count }) })
req.body.ids.forEach(id => {
socket.send(id)
})
@@ -58,7 +118,7 @@ router.postAsync(['', '/:id'], async (req, res) => {
if (req.body.config.length !== 1) req.body.config = null
if (req.body.times.length === 0) req.body.times = null
if (req.params.id > 0) {
- // Update existing role
+ // Update existing event
eventDb = await db.event.findOne({ where: { id: req.params.id } })
if (eventDb !== null) {
promises.push(eventDb.update({ name: req.body.name, description: req.body.description, times: req.body.times, important: req.body.important, wakeonlan: req.body.wakeonlan, configId: req.body.config || null }))
@@ -68,13 +128,30 @@ router.postAsync(['', '/:id'], async (req, res) => {
promisesBlacklist.push(eventDb.addGroups(req.body.blacklistGroups, { through: { blacklist: 1 } }))
promisesBlacklist.push(eventDb.addClients(req.body.blacklistClients, { through: { blacklist: 1 } }))
await Promise.all(promisesBlacklist)
+ log({
+ category: 'EVENT_EDIT',
+ description: '[' + eventDb.id + '] ' + eventDb.name + ': Event successfully edited.\n' +
+ 'ID: ' + eventDb.id + '\n' +
+ 'Name: ' + eventDb.name + '\n' +
+ 'Description: ' + eventDb.description + '\n' +
+ 'Times: ' + eventDb.times + '\n' +
+ 'Important: ' + eventDb.important + '\n' +
+ 'Wake-on-Lan: ' + eventDb.wakeonlan + '\n' +
+ 'Config ID: ' + eventDb.configId + '\n' +
+ 'Groups: ' + req.body.groups + '\n' +
+ 'Clients: ' + req.body.clients + '\n' +
+ 'Blacklist-Groups: ' + req.body.blacklistGroups + '\n' +
+ 'Blacklist-Clients: ' + req.body.blacklistClients,
+ userId: req.user.id
+ })
+
socket.send(eventDb.id)
res.send({ id: req.params.id })
} else {
res.status(404).end()
}
} else if (req.params.id === undefined) {
- // Create new role
+ // Create new event
eventDb = await db.event.create({ name: req.body.name, description: req.body.description, times: req.body.times, important: req.body.important, wakeonlan: req.body.wakeonlan, configId: req.body.config || null })
promises.push(eventDb.setGroups(req.body.groups, { through: { blacklist: 0 } }))
promises.push(eventDb.setClients(req.body.clients, { through: { blacklist: 0 } }))
@@ -82,6 +159,22 @@ router.postAsync(['', '/:id'], async (req, res) => {
promisesBlacklist.push(eventDb.addGroups(req.body.blacklistGroups, { through: { blacklist: 1 } }))
promisesBlacklist.push(eventDb.addClients(req.body.blacklistClients, { through: { blacklist: 1 } }))
await Promise.all(promisesBlacklist)
+ log({
+ category: 'EVENT_CREATE',
+ description: '[' + eventDb.id + '] ' + eventDb.name + ': Event successfully created.\n' +
+ 'ID: ' + eventDb.id + '\n' +
+ 'Name: ' + eventDb.name + '\n' +
+ 'Description: ' + eventDb.description + '\n' +
+ 'Times: ' + eventDb.times + '\n' +
+ 'Important: ' + eventDb.important + '\n' +
+ 'Wake-on-Lan: ' + eventDb.wakeonlan + '\n' +
+ 'Config ID: ' + eventDb.configId + '\n' +
+ 'Groups: ' + req.body.groups + '\n' +
+ 'Clients: ' + req.body.clients + '\n' +
+ 'Blacklist-Groups: ' + req.body.blacklistGroups + '\n' +
+ 'Blacklist-Clients: ' + req.body.blacklistClients,
+ userId: req.user.id
+ })
socket.send(eventDb.id)
res.send({ id: req.body.id })
}
diff --git a/server/api/groups.js b/server/api/groups.js
index 633b63d..bdc560b 100644
--- a/server/api/groups.js
+++ b/server/api/groups.js
@@ -8,6 +8,7 @@ const { decorateApp } = require('@awaitjs/express')
const router = decorateApp(express.Router())
const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
const backendHelper = require(path.join(__appdir, 'lib', 'external-backends', 'backendhelper'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// ############################################################################
// ########################### GET requests #################################
@@ -49,18 +50,74 @@ router.getAsync('/:id', async (req, res) => {
router.postAsync(['', '/:id'], async (req, res) => {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res)
- const count = await db.group.destroy({ where: { id: req.body.ids } })
- HttpResponse.successBatch('deleted', 'group', count).send(res)
+
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+ // Only need to log batch request if there is more than one client to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'GROUP_BATCH_DELETE',
+ description: 'Batch deletion of ' + req.body.ids.length + ' groups initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+ let deletionCounter = 0
+ // Delete every group on its own, to get a better log
+ for (let index in req.body.ids) {
+ const group = await db.group.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.group.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_GROUP_DELETE',
+ description: 'Group could not be deleted.',
+ group,
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'GROUP_DELETE',
+ description: 'Group successfully deleted.',
+ group,
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'GROUP_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' groups successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+ HttpResponse.successBatch('deleted', 'group', deletionCounter).send(res)
} else {
let group
let action = 'updated'
if (req.params.id === undefined) {
group = await db.group.create(req.body.data)
action = 'created'
+ log({
+ category: 'GROUP_CREATE',
+ description: 'Group successfully created.',
+ groupId: group.id,
+ userId: req.user.id
+ })
} else if (req.params.id > 0) {
group = await db.group.findOne({ where: { id: req.params.id }, include: ['ipranges'] })
if (!group) return HttpResponse.notFound(req.params.id).send(res)
- else await group.update(req.body.data)
+ else {
+ await group.update(req.body.data)
+ log({
+ category: 'GROUP_EDIT',
+ description: 'Group successfully edited.',
+ groupId: group.id,
+ userId: req.user.id
+ })
+ }
} else {
return HttpResponse.invalidId().send(res)
}
@@ -104,13 +161,107 @@ router.postAsync(['', '/:id'], async (req, res) => {
router.postAsync('/:id/subgroups', async (req, res) => {
if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
const group = await db.group.findOne({ where: { id: req.params.id } })
+
if (group) {
+ let deletionCounter = 0
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- const count = await group.removeSubgroups(req.body.ids)
- HttpResponse.successBatch('removed', 'subgroup', count).send(res)
+ // Remove method for subgroups
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'GROUP_BATCH_REMOVE_SUBGROUP',
+ description: 'Group batch removal of ' + req.body.ids.length + ' subgroups initiated by user.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+
+ for (let index in req.body.ids) {
+ const count = await group.removeSubgroups(req.body.ids[index])
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_GROUP_REMOVE_SUBGROUP',
+ description: 'Subgroup [' + req.body.ids[index] + '] could not be removed from group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ } else {
+ await log({
+ category: 'GROUP_REMOVE_SUBGROUP',
+ description: 'Subgroup [' + req.body.ids[index] + '] successfully removed from group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ deletionCounter++
+ }
+ }
+
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'GROUP_BATCH_REMOVE_SUBGROUP',
+ description: deletionCounter + '/' + req.body.ids.length + ' subgroups successfully removed.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+ HttpResponse.successBatch('removed', 'subgroup', deletionCounter).send(res)
} else {
- const count = await group.addSubgroups(req.body.ids)
- HttpResponse.successBatch('added', 'subgroup', count).send(res)
+ // Add method for subgroups
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'GROUP_BATCH_ADD_SUBGROUP',
+ description: 'Group batch addition of ' + req.body.ids.length + ' subgroups initiated by user.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+
+ for (let index in req.body.ids) {
+ const count = await group.addSubgroups(req.body.ids[index])
+ if (count.length !== 1) {
+ await log({
+ category: 'ERROR_GROUP_ADD_SUBGROUP',
+ description: 'Subgroup [' + req.body.ids[index] + '] could not be added to group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ } else {
+ await log({
+ category: 'GROUP_ADD_SUBGROUP',
+ description: 'Subgroup [' + req.body.ids[index] + '] successfully added to group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ deletionCounter++
+ }
+ }
+
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'GROUP_BATCH_ADD_SUBGROUP',
+ description: deletionCounter + '/' + req.body.ids.length + ' subgroups successfully added.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+ HttpResponse.successBatch('added', 'subgroup', deletionCounter).send(res)
}
} else {
HttpResponse.notFound(req.params.id).send(res)
@@ -121,13 +272,108 @@ router.postAsync('/:id/clients', async (req, res) => {
if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
const group = await db.group.findOne({ where: { id: req.params.id } })
if (group) {
+ let deletionCounter = 0
+ const user = await db.user.findOne({ where: { id: req.user.id } })
let groupid = null
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- const count = await group.removeClients(req.body.ids)
- HttpResponse.successBatch('removed', 'client', count).send(res)
+ // Remove method for clients to groups
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'GROUP_BATCH_REMOVE_CLIENT',
+ description: 'Group batch removal of ' + req.body.ids.length + ' clients initiated by user.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+
+ for (let index in req.body.ids) {
+ const count = await group.removeClients(req.body.ids[index])
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_GROUP_REMOVE_CLIENT',
+ description: 'Client [' + req.body.ids[index] + '] could not be removed from group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ } else {
+ await log({
+ category: 'GROUP_REMOVE_CLIENT',
+ description: 'Client [' + req.body.ids[index] + '] successfully removed from group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id,
+ clientId: req.body.ids[index]
+ })
+ deletionCounter++
+ }
+ }
+
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'GROUP_BATCH_REMOVE_CLIENT',
+ description: deletionCounter + '/' + req.body.ids.length + ' clients successfully deleted.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+ HttpResponse.successBatch('removed', 'client', deletionCounter).send(res)
} else {
- const count = await group.addClients(req.body.ids)
- HttpResponse.successBatch('added', 'client', count).send(res)
+ // Add method for clients to groups
+
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'GROUP_BATCH_ADD_CLIENT',
+ description: 'Group batch addition of ' + req.body.ids.length + ' clients initiated by user.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+
+ for (let index in req.body.ids) {
+ const count = await group.addClients(req.body.ids[index])
+ if (count.length !== 1) {
+ await log({
+ category: 'ERROR_GROUP_ADD_CLIENT',
+ description: 'Client [' + req.body.ids[index] + '] could not be added to group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ } else {
+ await log({
+ category: 'GROUP_ADD_CLIENT',
+ description: 'Client [' + req.body.ids[index] + '] successfully added to group [' + group.id + '] ' + group.name,
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id,
+ clientId: req.body.ids[index]
+ })
+ deletionCounter++
+ }
+ }
+
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'GROUP_BATCH_ADD_CLIENT',
+ description: deletionCounter + '/' + req.body.ids.length + ' clients successfully added.',
+ user,
+ userId: req.user.id,
+ group,
+ groupId: group.id
+ })
+ }
+ HttpResponse.successBatch('added', 'client', deletionCounter).send(res)
groupid = group.id
}
@@ -144,11 +390,19 @@ router.postAsync('/:id/clients', async (req, res) => {
// ############################################################################
// ########################## DELETE requests ###############################
-router.delete('/:id', async (req, res) => {
+router.deleteAsync('/:id', async (req, res) => {
if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
+ const group = db.group.findOne({ where: { id: req.params.id } })
const count = await db.group.destroy({ where: { id: req.params.id } })
- if (count) HttpResponse.success('deleted', 'group', req.params.id).send(res)
- else HttpResponse.notFound(req.params.id).send(res)
+ if (count) {
+ log({
+ category: 'GROUP_DELETE',
+ description: 'Group successfully deleted.',
+ group,
+ userId: req.user.id
+ })
+ HttpResponse.success('deleted', 'group', req.params.id).send(res)
+ } else HttpResponse.notFound(req.params.id).send(res)
})
// ############################################################################
diff --git a/server/api/ipranges.js b/server/api/ipranges.js
index 2a40763..fe66fd5 100644
--- a/server/api/ipranges.js
+++ b/server/api/ipranges.js
@@ -6,6 +6,7 @@ const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
const iphelper = require(path.join(__appdir, 'lib', 'iphelper'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// ############################################################################
// ########################### GET requests #################################
@@ -35,8 +36,51 @@ router.getAsync('/:id', async (req, res) => {
router.postAsync(['', '/:id'], async (req, res) => {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res)
- const count = await db.iprange.destroy({ where: { id: req.body.ids } })
- return HttpResponse.successBatch('deleted', 'client', count).send(res)
+
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+
+ // Only need to log batch request if there is more than one client to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'IPRANGE_BATCH_DELETE',
+ description: 'IP range batch deletion of ' + req.body.ids.length + ' ip ranges initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ // Delete every iprange on its own, to get a better log
+ for (let index in req.body.ids) {
+ const iprange = await db.iprange.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.iprange.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_IPRANGE_DELETE',
+ description: '[' + iprange.id + '] IP range from ' + iphelper.toIPv4(iprange.startIp) + ' to ' + iphelper.toIPv4(iprange.endIp) + ' could not be deleted.',
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'IPRANGE_DELETE',
+ description: '[' + iprange.id + '] IP range from ' + iphelper.toIPv4(iprange.startIp) + ' to ' + iphelper.toIPv4(iprange.endIp) + ' successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'IPRANGE_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' ip ranges successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ return HttpResponse.successBatch('deleted', 'client', deletionCounter).send(res)
}
let iprange
let action = 'updated'
@@ -44,11 +88,23 @@ router.postAsync(['', '/:id'], async (req, res) => {
req.body.endIp = iphelper.toDecimal(req.body.endIp)
if (req.params.id === undefined) {
iprange = await db.iprange.create(req.body)
+ await log({
+ category: 'IPRANGE_CREATE',
+ description: 'IP range from ' + iphelper.toIPv4(req.body.startIp) + ' to ' + iphelper.toIPv4(req.body.endIp) + ' successfully created',
+ userId: req.user.id
+ })
action = 'created'
} else if (req.params.id > 0) {
iprange = await db.iprange.findOne({ where: { id: req.params.id } })
if (!iprange) return HttpResponse.notFound(req.params.id).send(res)
- else await iprange.update(req.body)
+ else {
+ await iprange.update(req.body)
+ await log({
+ category: 'IPRANGE_EDIT',
+ description: '[' + iprange.id + '] IP range successfully edited from ' + iphelper.toIPv4(req.body.startIp) + ' to ' + iphelper.toIPv4(req.body.endIp),
+ userId: req.user.id
+ })
+ }
} else {
return HttpResponse.invalidId().send(res)
}
diff --git a/server/api/ipxe.js b/server/api/ipxe.js
index 7b5ad85..b7e1970 100644
--- a/server/api/ipxe.js
+++ b/server/api/ipxe.js
@@ -5,6 +5,7 @@ var shell = require(path.join(__appdir, 'lib', 'shell'))
var express = require('express')
var router = express.Router()
var noAuthRouter = express.Router()
+const log = require(path.join(__appdir, 'lib', 'log'))
// GET requests.
router.get('/script', (req, res) => {
@@ -72,22 +73,45 @@ router.post('/config', (req, res) => {
router.put('/:filename', (req, res) => {
var filepath = null
+ let filename = ''
+
// Set the file path
if (req.params.filename === 'script') {
filepath = path.join(__appdir, 'ipxe', 'embedded.ipxe')
+ filename = 'embedded.ipxe'
} else if (req.params.filename === 'console' || req.params.filename === 'general') {
filepath = path.join(__appdir, 'ipxe', req.params.filename + '.h')
+ filename = req.params.filename + '.h'
} else if (req.params.filename === 'certificate') {
filepath = path.join(__appdir, 'bin', 'fullchain.pem')
+ filename = 'fullchain.pem'
} else {
+ log({
+ category: 'ERROR_IPXEBUILDER_SAVE',
+ description: filename + ' cannot be saved. Filename unknown',
+ userId: req.user.id
+ })
res.status(500).send({ status: 'UNKNOWN_FILENAME', error: 'The provided filename is unknown' })
return
}
// Write File
fs.writeFile(filepath, req.body.data, err => {
- if (err) res.status(500).send({ status: 'WRITE_FILE_ERROR', error: err })
- else res.status(200).send({ status: 'SUCCESS' })
+ if (err) {
+ log({
+ category: 'ERROR_IPXEBUILDER_SAVE',
+ description: 'Error while saving ' + filename + '. ' + err,
+ userId: req.user.id
+ })
+ res.status(500).send({ status: 'WRITE_FILE_ERROR', error: err })
+ } else {
+ log({
+ category: 'IPXEBUILDER_SAVE',
+ description: 'User has saved ' + filename,
+ userId: req.user.id
+ })
+ res.status(200).send({ status: 'SUCCESS' })
+ }
})
})
@@ -95,6 +119,12 @@ router.put('/:filename', (req, res) => {
* @return: Rebuild the ipxe.
*/
router.get('/build', async (req, res) => {
+ log({
+ category: 'IPXEBUILDER_BUILD',
+ description: 'User initiated the ipxe building process.',
+ userId: req.user.id
+ })
+
delete require.cache[require.resolve(path.join(__appdir, 'config', 'ipxe'))]
const config = require(path.join(__appdir, 'config', 'ipxe'))
const build = await shell.buildIpxe(config.targets.build.join(' '), config.repository, config.branch)
@@ -102,11 +132,21 @@ router.get('/build', async (req, res) => {
})
router.get('/cancel', async (req, res) => {
+ log({
+ category: 'IPXEBUILDER_CANCEL',
+ description: 'User canceled the ipxe building process.',
+ userId: req.user.id
+ })
const result = await shell.cancelBuilding(req, res)
res.send(result)
})
router.get('/clean', async (req, res) => {
+ log({
+ category: 'IPXEBUILDER_CLEAN',
+ description: 'User initiated ipxe cleaning process.',
+ userId: req.user.id
+ })
const result = await shell.clean()
res.send(result)
})
diff --git a/server/api/ipxeconfigs.js b/server/api/ipxeconfigs.js
index 64f2c37..3c6f6eb 100644
--- a/server/api/ipxeconfigs.js
+++ b/server/api/ipxeconfigs.js
@@ -6,6 +6,7 @@ var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// ############################################################################
// ########################### GET requests #################################
@@ -62,18 +63,96 @@ router.getAsync('/:id/clients', async (req, res) => {
router.postAsync(['', '/:id'], async (req, res) => {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res)
- const count = await db.config.destroy({ where: { id: req.body.ids } })
- HttpResponse.successBatch('deleted', 'ipxe config', count).send(res)
+
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+ // Only need to log batch request if there is more than one ipxeconfig to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'IPXECONFIG_BATCH_DELETE',
+ description: 'Batch deletion of ' + req.body.ids.length + ' ipxe configs initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ // Delete every config on its own, to get a better log
+ for (let index in req.body.ids) {
+ const config = await db.config.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.config.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_IPXECONFIG_DELETE',
+ description: '[' + config.id + '] ' + config.name + ': Ipxe config could not be deleted.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault,
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'IPXECONFIG_DELETE',
+ description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully deleted.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault,
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'IPXECONFIG_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' ipxe configs successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ HttpResponse.successBatch('deleted', 'ipxe config', deletionCounter).send(res)
} else {
let config
let action = 'updated'
if (req.params.id === undefined) {
config = await db.config.create(req.body.data)
+ log({
+ category: 'IPXECONFIG_CREATE',
+ description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully created.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault,
+ userId: req.user.id
+ })
action = 'created'
} else if (req.params.id > 0) {
config = await db.config.findOne({ where: { id: req.params.id } })
if (!config) return HttpResponse.notFound(req.params.id).send(res)
- else await config.update(req.body.data)
+ else {
+ await config.update(req.body.data)
+ log({
+ category: 'IPXECONFIG_EDIT',
+ description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully edited.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault,
+ userId: req.user.id
+ })
+ }
} else {
return HttpResponse.invalidId().send(res)
}
@@ -99,6 +178,18 @@ router.putAsync('/:id/groups', async (req, res) => {
if (config) {
await config.setGroups(req.body.ids)
HttpResponse.success('set', 'clients of ipxe config', config.id).send(res)
+ log({
+ category: 'IPXECONFIG_SET_GROUPS',
+ description: '[' + config.id + '] ' + config.name + ': ' + req.body.ids.length + ' groups successfully set.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault + '\n' +
+ 'Groups: ' + req.body.ids,
+ userId: req.user.id
+ })
} else {
HttpResponse.notFound(req.params.id).send(res)
}
@@ -110,6 +201,18 @@ router.putAsync('/:id/clients', async (req, res) => {
const config = await db.config.findOne({ where: { id: req.params.id } })
if (config) {
await config.setClients(req.body.ids)
+ log({
+ category: 'IPXECONFIG_SET_CLIENTS',
+ description: '[' + config.id + '] ' + config.name + ': ' + req.body.ids.length + ' clients successfully set.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault + '\n' +
+ 'Clients: ' + req.body.ids,
+ userId: req.user.id
+ })
HttpResponse.success('set', 'clients of ipxe config', config.id).send(res)
} else {
HttpResponse.notFound(req.params.id).send(res)
@@ -119,9 +222,17 @@ router.putAsync('/:id/clients', async (req, res) => {
router.putAsync('/:id/default', async (req, res) => {
if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
const config = await db.config.findOne({ where: { id: req.params.id } })
+ const oldDefault = await db.config.findOne({ where: { isDefault: true } })
if (config) {
await db.config.update({ isDefault: false }, { where: { isDefault: true } })
await config.update({ isDefault: true })
+ log({
+ category: 'IPXECONFIG_SET_DEFAULT',
+ description: '[' + config.id + '] ' + config.name + ': Config successfully set as default.\n' +
+ 'Old Default: [' + oldDefault.id + '] ' + oldDefault.name + '\n' +
+ 'New Default: [' + config.id + '] ' + config.name,
+ userId: req.user.id
+ })
HttpResponse.success('set as default:', 'config', config.id).send(res)
} else {
HttpResponse.notFound(req.params.id).send(res)
@@ -133,9 +244,23 @@ router.putAsync('/:id/default', async (req, res) => {
router.deleteAsync('/:id', async (req, res) => {
if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
+ const config = await db.config.findOne({ where: { id: req.params.id } })
const count = await db.config.destroy({ where: { id: req.params.id } })
- if (count) res.status(200).end()
- else HttpResponse.notFound(req.params.id).send(res)
+
+ if (count) {
+ log({
+ category: 'IPXECONFIG_DELETE',
+ description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully deleted.\n' +
+ 'ID: ' + config.id + '\n' +
+ 'Name: ' + config.name + '\n' +
+ 'Description: ' + config.description + '\n' +
+ 'Default Entry: ' + config.defaultEntry + '\n' +
+ 'Timeout: ' + config.timeout + '\n' +
+ 'Default Config: ' + config.isDefault,
+ userId: req.user.id
+ })
+ HttpResponse.success('deleted', 'config', req.params.id).send(res)
+ } else HttpResponse.notFound(req.params.id).send(res)
})
// ############################################################################
diff --git a/server/api/registration.js b/server/api/registration.js
index 202d836..5744369 100644
--- a/server/api/registration.js
+++ b/server/api/registration.js
@@ -11,6 +11,7 @@ const config = require(path.join(__appdir, 'config', 'config'))
// Ipxe needs the url without the port because ipxe can't handle port requests
const url = config.https.host // + ':' + config.https.port
const log = require(path.join(__appdir, 'lib', 'log'))
+const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
// GET requests.
@@ -36,11 +37,19 @@ router.postAsync('/hookorder', async (req, res) => {
idSortvalueMap[id] = index
})
var hooks = await db.registrationhook.findAll()
+ const oldOrder = hooks.sort((a, b) => (a.sortvalue > b.sortvalue))
var promises = []
hooks.forEach(hook => {
promises.push(hook.update({ sortvalue: idSortvalueMap[hook.id] }))
})
await Promise.all(promises)
+ log({
+ category: 'REGISTATIONHOOK_EDIT_ORDER',
+ description: 'Registration hook order successfully edited.\n' +
+ 'Old-Order: ' + '\n\t' + oldOrder.map(x => { return '[' + x.id + '] ' + x.name }).toString().replace(/,/g, '\n\t') + '\n' +
+ 'New-Order: ' + '\n\t' + req.body.ids.map(x => { return '[' + x + '] ' + oldOrder.filter(y => y.id === x)[0].name }).toString().replace(/,/g, '\n\t')
+ })
+
res.end()
})
@@ -54,11 +63,35 @@ router.postAsync(['/hooks', '/hooks/:id'], async (req, res) => {
var hook = null
if (req.params.id > 0) {
hook = await db.registrationhook.findOne({ where: { id: req.params.id } })
- if (hook) await hook.update(item)
+ if (hook) {
+ await hook.update(item)
+ log({
+ category: 'REGISTATIONHOOK_EDIT',
+ description: '[' + hook.id + '] ' + hook.name + ': Registration hook successfully edited.\n' +
+ 'ID: ' + hook.id + '\n' +
+ 'Name: ' + hook.name + '\n' +
+ 'Type: ' + hook.type + '\n' +
+ 'Description: ' + hook.description + '\n' +
+ 'Sortvalue: ' + hook.sortvalue + '\n' +
+ 'Groups: ' + req.body.groups,
+ userId: req.user.id
+ })
+ }
} else {
var maxSortvalue = await db.registrationhook.max('sortvalue')
item.sortvalue = maxSortvalue ? maxSortvalue + 1 : 1
hook = await db.registrationhook.create(item)
+ log({
+ category: 'REGISTATIONHOOK_CREATE',
+ description: '[' + hook.id + '] ' + hook.name + ': Registration hook successfully created.\n' +
+ 'ID: ' + hook.id + '\n' +
+ 'Name: ' + hook.name + '\n' +
+ 'Type: ' + hook.type + '\n' +
+ 'Description: ' + hook.description + '\n' +
+ 'Sortvalue: ' + hook.sortvalue + '\n' +
+ 'Groups: ' + req.body.groups,
+ userId: req.user.id
+ })
}
if (hook) {
hook.setGroups(req.body.groups)
@@ -67,12 +100,31 @@ router.postAsync(['/hooks', '/hooks/:id'], async (req, res) => {
res.end()
})
-// DELETE requests.
-
-router.delete(['/hooks', '/hooks/:id'], (req, res) => {
- db.registrationhook.destroy({ where: { id: req.params.id || req.body.ids } }).then(count => { res.send({ count }) })
+// ############################################################################
+// ########################## DELETE requests ###############################
+
+router.deleteAsync('/hooks/:id', async (req, res) => {
+ if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res)
+ const hook = await db.registrationhook.findOne({ where: { id: req.params.id } })
+ const count = await db.registrationhook.destroy({ where: { id: req.params.id } })
+
+ if (count) {
+ log({
+ category: 'REGISTATIONHOOK_DELETE',
+ description: 'Registration hook successfully deleted.\n' +
+ 'ID: ' + hook.id + '\n' +
+ 'Name: ' + hook.name + '\n' +
+ 'Type: ' + hook.type + '\n' +
+ 'Sortvalue: ' + hook.sortvalue,
+ userId: req.user.id
+ })
+ HttpResponse.success('deleted', 'hook', req.params.id).send(res)
+ } else HttpResponse.notFound(req.params.id).send(res)
})
+// ############################################################################
+// ############################################################################
+
module.exports.router = router
// GET requests.
@@ -164,7 +216,10 @@ noAuthRouter.postAsync('/clients', async (req, res) => {
// Client ip set successfully
client.networks[0].ip = setIp.ip
} else {
- log({ category: 'ERROR_DHCP', description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}` })
+ log({
+ category: 'ERROR_DHCP',
+ description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}`
+ })
}
}
}
@@ -227,7 +282,11 @@ noAuthRouter.postAsync('/clients', async (req, res) => {
// Add groups to the client.
if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.networks[0].ip)
client.parents.forEach(pid => { newClient.addGroup(pid) })
- log({ category: 'REGISTRATION', description: 'Client added successfully.', clientId: newClient.id })
+ log({
+ category: 'REGISTRATION',
+ description: 'Client added successfully.',
+ clientId: newClient.id
+ })
// Add the client to the backends.
const result = backendHelper.addClient(client)
diff --git a/server/api/roles.js b/server/api/roles.js
index f4803cf..5b878f0 100644
--- a/server/api/roles.js
+++ b/server/api/roles.js
@@ -4,6 +4,8 @@ var db = require(path.join(__appdir, 'lib', 'sequelize'))
var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
+const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
+const log = require(path.join(__appdir, 'lib', 'log'))
/*
* /<ROLE_ID>
@@ -44,8 +46,58 @@ router.postAsync(['', '/:id'], async (req, res) => {
// ?delete Delete the roles
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- await db.role.destroy({ where: { id: req.body.ids } })
- res.status(200).send('success')
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+
+ // Only need to log batch request if there is more than one event to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'ROLE_BATCH_DELETE',
+ description: 'Role batch deletion of ' + req.body.ids.length + ' roles initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ // Delete every event on its own, to get a better log
+ for (let index in req.body.ids) {
+ const role = await db.role.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.role.destroy({ where: { id: req.body.ids[index] } })
+
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_ROLE_DELETE',
+ description: '[' + role.id + '] ' + role.name + ': Role could not be deleted.\n' +
+ 'ID: ' + role.id + '\n' +
+ 'Name: ' + role.name + '\n' +
+ 'Description: ' + role.descr + '\n',
+ user,
+ userId: req.user.id
+ })
+ } else {
+ await log({
+ category: 'ROLE_DELETE',
+ description: '[' + role.id + '] ' + role.name + ': Role successfully deleted.\n' +
+ 'ID: ' + role.id + '\n' +
+ 'Name: ' + role.name + '\n' +
+ 'Description: ' + role.descr + '\n',
+ user,
+ userId: req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'ROLE_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' roles successfully deleted.',
+ user,
+ userId: req.user.id
+ })
+ }
+ HttpResponse.successBatch('deleted', 'role', deletionCounter).send(res)
+
+ // res.status(200).send('success')
} else {
var promises = []
var roleDb
@@ -56,6 +108,17 @@ router.postAsync(['', '/:id'], async (req, res) => {
promises.push(roleDb.addGroups(req.body.groups, { through: { blacklist: 0 } }))
promises.push(roleDb.addGroups(req.body.blacklist, { through: { blacklist: 1 } }))
await Promise.all(promises)
+ log({
+ category: 'ROLE_CREATE',
+ description: '[' + roleDb.id + '] ' + roleDb.name + ': Event successfully created.\n' +
+ 'ID: ' + roleDb.id + '\n' +
+ 'Name: ' + roleDb.name + '\n' +
+ 'Description: ' + roleDb.descr + '\n' +
+ 'Permissions: ' + req.body.permissions + '\n' +
+ 'Groups: ' + req.body.groups + '\n' +
+ 'Blacklist: ' + req.body.blacklist,
+ userId: req.user.id
+ })
res.send({ id: req.body.id })
} else if (req.params.id > 0) {
// Update existing role
@@ -66,6 +129,17 @@ router.postAsync(['', '/:id'], async (req, res) => {
promises.push(roleDb.setGroups(req.body.groups, { through: { blacklist: 0 } }))
promises.push(roleDb.addGroups(req.body.blacklist, { through: { blacklist: 1 } }))
await Promise.all(promises)
+ log({
+ category: 'ROLE_EDIT',
+ description: '[' + roleDb.id + '] ' + roleDb.name + ': Role successfully edited.\n' +
+ 'ID: ' + roleDb.id + '\n' +
+ 'Name: ' + roleDb.name + '\n' +
+ 'Description: ' + roleDb.descr + '\n' +
+ 'Permissions: ' + req.body.permissions + '\n' +
+ 'Groups: ' + req.body.groups + '\n' +
+ 'Blacklist: ' + req.body.blacklist,
+ userId: req.user.id
+ })
res.send({ id: req.params.id })
} else {
res.status(404).end()
diff --git a/server/api/systemlog.js b/server/api/systemlog.js
index d2bd10c..4d7a69a 100644
--- a/server/api/systemlog.js
+++ b/server/api/systemlog.js
@@ -19,7 +19,7 @@ router.getAsync('', async (req, res) => {
if (req.query.clients) where.clientId = req.query.clients.split(',')
if (req.query.groups) where.groupId = req.query.groups.split(',')
if (req.query.users) where.userId = req.query.users.split(',')
- const log = await db.log.findAll({ where, include: ['client', 'group', 'user'], order: [['timestamp', 'DESC']] })
+ const log = await db.log.findAll({ where, include: ['client', 'group', 'user'], order: [['id', 'DESC']] })
log.forEach(entry => {
if (entry.clientSnapshot) entry.clientSnapshot = JSON.parse(entry.clientSnapshot)
if (entry.groupSnapshot) entry.groupSnapshot = JSON.parse(entry.groupSnapshot)
diff --git a/server/api/users.js b/server/api/users.js
index 33ad3d3..d69c776 100644
--- a/server/api/users.js
+++ b/server/api/users.js
@@ -5,6 +5,7 @@ var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
var authentication = require(path.join(__appdir, 'lib', 'authentication'))
+const log = require(path.join(__appdir, 'lib', 'log'))
// ############################################################################
// ########################### GET requests #################################
@@ -39,12 +40,44 @@ router.postAsync('/roles', async (req, res) => {
const userIds = req.body.users
const roleIds = req.body.roles
- const users = await db.user.findAll({ where: { id: userIds } })
+ const users = await db.user.findAll({ where: { id: userIds }, include: ['roles'] })
+ const userDb = await db.user.findOne({ where: { id: req.user.id } })
if (users) {
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- users.forEach(user => { user.removeRoles(roleIds) })
+ for (let index in users) {
+ const user = users[index]
+ const roles = user.roles
+ const count = await user.removeRoles(roleIds)
+ let roleString = 'role'
+ if (count > 1) roleString += 's'
+ log({
+ category: 'USER_REVOKE_ROLE',
+ description: '[' + user.id + '] ' + user.name + ': Successfully removed ' + count + ' ' + roleString + '.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'Removed Roles: ' + roleIds.filter(y => { return roles.map(x => x.id).includes(y) }),
+ userDb,
+ userId: req.user.id
+ })
+ }
} else {
- users.forEach(user => { user.addRoles(roleIds) })
+ for (let index in users) {
+ const user = users[index]
+ const count = await user.addRoles(roleIds)
+ if (count.length > 0) {
+ let roleString = 'role'
+ if (count[0].length > 1) roleString += 's'
+ log({
+ category: 'USER_GRANT_ROLE',
+ description: '[' + user.id + '] ' + user.name + ': Successfully added ' + count[0].length + ' ' + roleString + '.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'Added Roles: ' + count[0].map(x => x.roleId),
+ userDb,
+ userId: req.user.id
+ })
+ }
+ }
}
res.status(200).end()
} else {
@@ -59,24 +92,116 @@ router.postAsync(['/', '/:id'], async (req, res) => {
// TODO: Check for permission to delete / create / update user
}
+ // Delete request
if (req.query.delete !== undefined && req.query.delete !== 'false') {
- const count = await db.user.destroy({ where: { id: body.ids } })
- return res.send({ count })
+ const user = await db.user.findOne({ where: { id: req.user.id } })
+
+ // Only need to log batch request if there is more than one user to delete.
+ if (req.body.ids.length > 1) {
+ await log({
+ category: 'USER_BATCH_DELETE',
+ description: 'User batch deletion of ' + req.body.ids.length + ' users initiated by user.',
+ user,
+ userId: req.user.id
+ })
+ }
+
+ let deletionCounter = 0
+ let selfdeletion = false
+
+ // Delete every user on its own, to get a better log
+ for (let index in req.body.ids) {
+ // We can't set the userId in the log if we delete ourselfs.
+ if (req.body.ids[index] === req.user.id) selfdeletion = true
+ const userDb = await db.user.findOne({ where: { id: req.body.ids[index] } })
+ const count = await db.user.destroy({ where: { id: req.body.ids[index] } })
+ if (count !== 1) {
+ await log({
+ category: 'ERROR_USER_DELETE',
+ description: '[' + userDb.id + '] ' + userDb.username + ': User could not be deleted.\n' +
+ 'ID: ' + userDb.id + '\n' +
+ 'Username: ' + userDb.username + '\n' +
+ 'Name: ' + userDb.name + '\n' +
+ 'E-Mail: ' + userDb.email + '\n',
+ user,
+ userId: selfdeletion ? undefined : req.user.id
+ })
+ } else {
+ await log({
+ category: 'USER_DELETE',
+ description: '[' + userDb.id + '] ' + userDb.username + ': User successfully deleted.\n' +
+ 'ID: ' + userDb.id + '\n' +
+ 'Username: ' + userDb.username + '\n' +
+ 'Name: ' + userDb.name + '\n' +
+ 'E-Mail: ' + userDb.email + '\n',
+ user,
+ userId: selfdeletion ? undefined : req.user.id
+ })
+ deletionCounter++
+ }
+ }
+ if (req.body.ids.length > 1) {
+ log({
+ category: 'USER_BATCH_DELETE',
+ description: deletionCounter + '/' + req.body.ids.length + ' users successfully deleted.',
+ user,
+ userId: selfdeletion ? undefined : req.user.id
+ })
+ }
+
+ return res.send({ deletionCounter })
}
if (req.params.id === undefined) {
const result = await authentication.signup(body)
const code = result.code
+ const user = await db.user.findOne({ where: { id: result.id } })
+
+ // Create a log entry for the user creation
+ if (code === 200) {
+ log({
+ category: 'USER_CREATE',
+ description: '[' + user.id + '] ' + user.username + ': User successfully created.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ } else {
+ log({
+ category: 'ERROR_USER_CREATE',
+ description: '[' + code + '][' + result.error + '] ' + result.message + '\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ }
+
delete result.code
return res.status(code).send(result)
} else {
const id = req.params.id === 'current' ? req.user.id : req.params.id
+ let user = await db.user.findOne({ where: { id: id } })
let email = req.body.email
- if (!authentication.validateEmail(req.body.email)) return res.status(500).send({ error: 'EMAIL_INVALID', message: 'The provided email is invalid.' })
-
- let user
- user = await db.user.findOne({ where: { id: id } })
+ if (!authentication.validateEmail(req.body.email)) {
+ log({
+ category: 'ERROR_USER_EDIT',
+ description: '[' + user.id + '] ' + user.username + ': User could not be updated. The E-Mail is invalid.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ return res.status(500).send({
+ error: 'EMAIL_INVALID',
+ message: 'The provided email is invalid.'
+ })
+ }
if (user) {
let userinfo = {
@@ -87,20 +212,74 @@ router.postAsync(['/', '/:id'], async (req, res) => {
// Check if the username is set and if it's valid.
let username = body.username
if (username && req.params.id !== 'current') {
- if (!authentication.validateUsername(username)) return res.status(400).send({ error: 'INVALID_USERNAME', message: 'Username does not fullfill the requirements. (No whitespaces)' })
+ if (!authentication.validateUsername(username)) {
+ log({
+ category: 'ERROR_USER_EDIT',
+ description: '[' + user.id + '] ' + user.username + ': User could not be updated. The username does not fullfull the requirements. (No whitespaces)\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ return res.status(400).send({ error: 'INVALID_USERNAME', message: 'Username does not fullfill the requirements. (No whitespaces)' })
+ }
// Check if the username already exists.
let userDb = await db.user.findOne({ where: { username: username, id: { [db.Op.not]: id } } })
- if (userDb) return res.status(400).send({ error: 'USER_ALREADY_EXISTS', message: 'The provided username already exists.' })
+ if (userDb) {
+ log({
+ category: 'ERROR_USER_EDIT',
+ description: '[' + user.id + '] ' + user.username + ': User could not be updated. The username already exists.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ return res.status(400).send({ error: 'USER_ALREADY_EXISTS', message: 'The provided username already exists.' })
+ }
userinfo.username = username
}
// Update the user.
await user.update(userinfo)
+ log({
+ category: 'USER_EDIT',
+ description: '[' + user.id + '] ' + user.username + ': User successfully updated.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
if (body.password) {
const result = await authentication.changePassword(id, body.password, body.passwordCurrent)
const code = result.code
delete result.code
+
+ if (code === 200) {
+ log({
+ category: 'USER_EDIT_PASSWORD',
+ description: '[' + user.id + '] ' + user.username + ': Password successfully updated.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ } else {
+ log({
+ category: 'ERROR_USER_EDIT_PASSWORD',
+ description: '[' + user.id + '] ' + user.username + ': Password could not be updated. Code ' + code + '\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ userId: req.user.id
+ })
+ }
+
res.status(code).send(result)
}
}
@@ -118,22 +297,58 @@ router.postAsync('/:id/password', async (req, res) => {
const result = await authentication.changePassword(id, body.password, body.passwordCurrent)
const code = result.code
delete result.code
+
+ if (code === 200) {
+ log({
+ category: 'USER_EDIT_PASSWORD',
+ description: '[' + id + '] Password changed.',
+ userId: req.user.id
+ })
+ } else {
+ log({
+ category: 'ERROR_USER_EDIT_PASSWORD',
+ description: '[' + id + '] Password could not be changed. Code ' + code,
+ userId: req.user.id
+ })
+ }
res.status(code).send(result)
} else res.status(400).send({ error: 'PASSWORD_MISSING', message: 'This service requires the current and the new password.' })
})
// Function for deleting a single user
-router.delete('/:id/', (req, res) => {
- // Check if the user has the permission for chaning those userdata. Else return.
+router.deleteAsync('/:id/', async (req, res) => {
if (req.params.id !== 'current') {
- return res.status(500).end()
+ // Check if the user has the permission for changing those userdata. Else return.
+ // return res.status(500).end()
}
const id = req.params.id === 'current' ? req.user.id : req.params.id
-
+ const user = await db.user.findOne({ where: { id: id } })
// Every user can delete his own account.
- db.user.destroy({ where: { id } }).then(() => {
- res.status(200).end()
- })
+ const count = await db.user.destroy({ where: { id } })
+ if (count !== 1) {
+ log({
+ category: 'ERROR_USER_DELETE',
+ description: '[' + user.id + '] ' + user.username + ': User could not be deleted.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ user,
+ userId: req.user.id
+ })
+ } else {
+ log({
+ category: 'USER_DELETE',
+ description: '[' + user.id + '] ' + user.username + ': User successfully deleted.\n' +
+ 'ID: ' + user.id + '\n' +
+ 'Username: ' + user.username + '\n' +
+ 'Name: ' + user.name + '\n' +
+ 'E-Mail: ' + user.email + '\n',
+ user,
+ userId: req.params.id === 'current' ? undefined : req.user.id
+ })
+ }
+ res.status(200).end()
})
// ############################################################################
diff --git a/server/api/wakerequests.js b/server/api/wakerequests.js
index 9791d41..811fea9 100644
--- a/server/api/wakerequests.js
+++ b/server/api/wakerequests.js
@@ -5,9 +5,15 @@ const wolHelper = require(path.join(__appdir, 'lib', 'wolhelper'))
var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
+const log = require(path.join(__appdir, 'lib', 'log'))
router.postAsync('', async (req, res) => {
const clients = await db.client.findAll({ where: { id: req.body.clients } })
+ await log({
+ category: 'WAKE_ON_LAN',
+ description: 'Wake on Lan signal to ' + clients.length + ' clients initiated by user.',
+ userId: req.user.id
+ })
wolHelper.wakeUp(clients)
res.status(200).end()
})