summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/api/groups.js14
-rw-r--r--server/api/ipxe.js2
-rw-r--r--server/api/registration.js110
-rw-r--r--server/api/users.js2
-rw-r--r--server/config/config.template.json1
-rw-r--r--server/lib/external-backends/backendhelper.js21
-rw-r--r--server/lib/external-backends/backends/idoit-backend.js4
-rw-r--r--server/lib/ip.js21
-rw-r--r--server/lib/iphelper.js62
-rw-r--r--server/lib/permissions/index.js2
-rw-r--r--server/lib/permissions/permissionutil.js2
-rw-r--r--server/lib/sequelize.js8
-rw-r--r--server/migrations/20190307051433-create-conflict.js19
-rw-r--r--server/migrations/20190307051633-create-conflict_x_object.js25
-rw-r--r--server/models/conflict.js23
15 files changed, 213 insertions, 103 deletions
diff --git a/server/api/groups.js b/server/api/groups.js
index 6dbddc7..9a17c92 100644
--- a/server/api/groups.js
+++ b/server/api/groups.js
@@ -2,7 +2,7 @@
var path = require('path')
var db = require(path.join(__appdir, 'lib', 'sequelize'))
var groupUtil = require(path.join(__appdir, 'lib', 'grouputil'))
-const ip = require(path.join(__appdir, 'lib', 'ip'))
+const ipHelper = require(path.join(__appdir, 'lib', 'iphelper'))
var express = require('express')
const { decorateApp } = require('@awaitjs/express')
var router = decorateApp(express.Router())
@@ -22,8 +22,8 @@ router.getAsync('/:id', async (req, res) => {
if (group) {
// Convert ipranges in readable strings.
group.ipranges.forEach(iprange => {
- iprange.startIp = ip.toString(iprange.startIp)
- iprange.endIp = ip.toString(iprange.endIp)
+ iprange.startIp = ipHelper.toIPv4(iprange.startIp)
+ iprange.endIp = ipHelper.toIPv4(iprange.endIp)
})
if (all) res.status(200).send({ ...group.get({ plain: true }), ...await groupUtil.getAllChildren([group]) })
else res.status(200).send(group)
@@ -68,12 +68,10 @@ router.postAsync(['', '/:id'], async (req, res) => {
}
// Update existing ipranges and create the new ones
req.body.ipranges.forEach(iprange => {
- if (!iprange.startIp || !iprange.endIp) return
-
// Convert valid ip addresses to integer values.
- if (!ip.isIpv4(iprange.startIp) || !ip.isIpv4(iprange.endIp)) return
- iprange.startIp = ip.toInt(iprange.startIp)
- iprange.endIp = ip.toInt(iprange.endIp)
+ if (!ipHelper.isIPv4(iprange.startIp) || !ipHelper.isIPv4(iprange.endIp)) return
+ iprange.startIp = ipHelper.toDecimal(iprange.startIp)
+ iprange.endIp = ipHelper.toDecimal(iprange.endIp)
if (iprange.id) {
if (iprangeIdMap[iprange.id]) {
promises.push(iprangeIdMap[iprange.id].update(iprange))
diff --git a/server/api/ipxe.js b/server/api/ipxe.js
index 3a6270f..6367246 100644
--- a/server/api/ipxe.js
+++ b/server/api/ipxe.js
@@ -31,7 +31,7 @@ router.get('/:version/log', async (req, res) => {
res.setHeader('content-type', 'text/plain')
const filepath = path.join(__appdir, 'ipxe', 'log_' + req.params.version + '.txt')
res.sendFile(filepath, err => {
- if (err) {
+ if (err) {
res.end()
}
})
diff --git a/server/api/registration.js b/server/api/registration.js
index 2da1431..2a26c4f 100644
--- a/server/api/registration.js
+++ b/server/api/registration.js
@@ -1,40 +1,18 @@
/* global __appdir */
var path = require('path')
var express = require('express')
-var router = express.Router()
-var noAuthRouter = express.Router()
+const { decorateApp } = require('@awaitjs/express')
+var router = decorateApp(express.Router())
+var noAuthRouter = decorateApp(express.Router())
var db = require(path.join(__appdir, 'lib', 'sequelize'))
-const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends'))
const backendHelper = require(path.join(__appdir, 'lib', 'external-backends', 'backendhelper'))
+const ipHelper = require(path.join(__appdir, 'lib', 'iphelper'))
+const config = require(path.join(__appdir, 'config', 'config'))
+const url = config.https.host + ':' + config.https.port
// GET requests.
/*
- * TODO: CURRENTLY TEST FUNCTION
- */
-noAuthRouter.get('/', (req, res) => {
- // backendHelper.deleteClients().then(r => {
- // res.send(r)
- // })
-
- /*
- db.backend.findOne({ where: { id: 1 } }).then(result => {
- const b = new ExternalBackends()
- const instance = b.getInstance(result.type)
- instance.getClient(result.credentials, {}).then(result => {
- res.status(200).send(result)
- })
- }) */
- db.backend.findOne({ where: { id: 3 } }).then(result => {
- const b = new ExternalBackends()
- const instance = b.getInstance(result.type)
- instance.uploadTpm(result.credentials, 99696, 'I-123-d12', null).then(result => {
- res.status(200).send(result)
- })
- })
-})
-
-/*
* Returns all registration hooks sorted by sortValue.
*
* @return: List of registration hooks
@@ -50,7 +28,7 @@ router.get('/hooks', (req, res) => {
/*
* Reorders the registration hooks based on an array of hook ids.
*/
-router.post('/hookorder', async (req, res) => {
+router.postAsync('/hookorder', async (req, res) => {
var idSortvalueMap = {}
req.body.ids.forEach((id, index) => {
idSortvalueMap[id] = index
@@ -64,7 +42,7 @@ router.post('/hookorder', async (req, res) => {
res.end()
})
-router.post(['/hooks', '/hooks/:id'], async (req, res) => {
+router.postAsync(['/hooks', '/hooks/:id'], async (req, res) => {
var item = {
name: req.body.name,
description: req.body.description,
@@ -130,7 +108,7 @@ noAuthRouter.post('/group', (req, res) => {
/*
* Adds the client to the database and set parents if a parent was selected. Calls addClient for all external-backends.
*/
-noAuthRouter.post('/add', (req, res) => {
+noAuthRouter.postAsync('/add', async (req, res) => {
const feedback = req.body.feedback
const mac = req.body.mac
const uuid = req.body.uuid
@@ -138,40 +116,44 @@ noAuthRouter.post('/add', (req, res) => {
var name = req.body.name
const parentId = req.body.id
const purpose = req.body.purpose
+ let parentIds = []
if (!name) name = 'Client_' + uuid
- db.client.findOne({ where: { uuid: uuid } }).then(client => {
- if (client) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`)
- else {
- var groupids = []
- if (parentId) groupids = [parentId]
- getNextHookScript(groupids).then(resId => {
- db.client.create({ name: name, description: 'Client', ip: ip, mac: mac, uuid: uuid, registrationState: resId }).then(newClient => {
- if (parentId) {
- newClient.addGroup(parentId)
- }
-
- // Add the client to the backends.
- var c = { title: name, uuid: uuid, network: { mac: mac, ip: ip } }
- if (parentId) c.parentId = parentId
- if (purpose) c.purpose = purpose
- backendHelper.addClient(c).then(result => {
- if (feedback) res.send(result)
- result.forEach(response => {
- // If the object was created we need to make the objectid / external id mapping.
- if (response.success) {
- db.backend.findOne({ where: { id: response.backendId }, include: ['mappedClients'] }).then(backend => {
- backend.addMappedClients(newClient, { through: { externalId: response.id, externalType: response.type } })
- })
- }
- })
- })
- if (!feedback) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`)
- })
- })
+ const client = await db.client.findOne({ where: { uuid: uuid } })
+
+ if (client) return res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`)
+ // Else
+ var groupids = []
+ if (parentId) groupids = [parentId]
+ const resId = await getNextHookScript(groupids)
+ const newClient = await db.client.create({ name: name, description: 'Client', ip: ip, mac: mac, uuid: uuid, registrationState: resId })
+ if (parentId) {
+ newClient.addGroup(parentId)
+ parentIds.push(parentId)
+ } else {
+ // Filtered list with all group we will add the client
+ parentIds = await ipHelper.getGroups(ip)
+ parentIds.forEach(pid => { newClient.addGroup(pid) })
+ // TODO: check if there are multiple groups which are mapped to a backend if so --> merge conflict
+ }
+
+ // Add the client to the backends.
+ var c = { title: name, uuid: uuid, network: { mac: mac, ip: ip } }
+ if (parentIds.length > 0) c.parents = parentIds
+ // if (parentId) c.parentId = parentId
+ if (purpose) c.purpose = purpose
+ const result = await backendHelper.addClient(c)
+ if (feedback) res.send(result)
+
+ for (let response of result) {
+ // If the object was created we need to make the objectid / external id mapping.
+ if (response.success) {
+ const backend = await db.backend.findOne({ where: { id: response.backendId }, include: ['mappedClients'] })
+ backend.addMappedClients(newClient, { through: { externalId: response.id, externalType: response.type } })
}
- })
+ }
+ if (!feedback) res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`)
})
noAuthRouter.post('/:uuid/update', (req, res) => {
@@ -345,8 +327,8 @@ function getNextHookScript (groupids, sortvalue) {
// Gets the list of all groupids inclusive the recursive parents.
return getRecursiveParents(groupids).then(gids => {
// Get the list of all hooks where the parent is null or those who fullfill the group dependency.
- var options = { where: { '$groups.id$': { $or: [null, gids] } }, include: ['groups'], order: [['sortvalue', 'ASC']] }
- if (sortvalue !== undefined) options.where.sortvalue = { $gt: sortvalue }
+ var options = { where: { '$groups.id$': { [db.Op.or]: [null, gids] } }, include: ['groups'], order: [['sortvalue', 'ASC']] }
+ if (sortvalue !== undefined) options.where.sortvalue = { [db.Op.gt]: sortvalue }
return db.registrationhook.findAll(options).then(result => {
var resID = null
if (result.length >= 1) resID = result[0].id
@@ -386,7 +368,7 @@ function getRecursiveParents (groupIds) {
* Used by the manual registration.
*/
function buildIpxeMenu (id, name, groups, parents) {
- var basUrl = 'https://bas.intra.uni-freiburg.de'
+ var basUrl = 'https://' + url
var script = '#!ipxe\r\n'
// script = script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`)
diff --git a/server/api/users.js b/server/api/users.js
index c4d9a2f..744ffc6 100644
--- a/server/api/users.js
+++ b/server/api/users.js
@@ -89,7 +89,7 @@ router.postAsync(['/', '/:id'], async (req, res) => {
if (!authentication.validateUsername(username)) 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: { $not: id } } })
+ 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.' })
userinfo.username = username
}
diff --git a/server/config/config.template.json b/server/config/config.template.json
index 75e0c4f..a79376e 100644
--- a/server/config/config.template.json
+++ b/server/config/config.template.json
@@ -1,5 +1,6 @@
{
"https": {
+ "host": "<HOSTNAME>",
"port": "<HTTPS_PORT>"
}
}
diff --git a/server/lib/external-backends/backendhelper.js b/server/lib/external-backends/backendhelper.js
index dc4324c..752ccf7 100644
--- a/server/lib/external-backends/backendhelper.js
+++ b/server/lib/external-backends/backendhelper.js
@@ -28,9 +28,24 @@ module.exports = {
}
// Convert the parent group id to the external backend parentId.
- if (client.parentId) {
- var element = backend.mappedGroups.find(x => x.id === parseInt(client.parentId))
- if (element) tmpClient['parentId'] = element.backend_x_group.externalId
+ // if (client.parentId) {
+ if (client.parents) {
+ var elements = backend.mappedGroups.filter(x => client.parents.includes(x.id))
+ if (elements.length > 1) {
+ // TODO ADD MERGE CONFLICT
+ const conflict = await db.conflict.create({ description: 'Multiple parents found' })
+
+ // Add backend to the conflict.
+ conflict.createObject({ objectType: 'BACKEND', objectId: backend.id })
+
+ // Add the groups to the conflict.
+ for (let element of elements) {
+ conflict.createObject({ objectType: 'GROUP', objectId: element.id })
+ }
+ } else if (elements.length === 1) tmpClient['parentId'] = elements[0].backend_x_group.externalId
+
+ // var element = backend.mappedGroups.find(x => x.id === parseInt(client.parentId))
+ // if (element) tmpClient['parentId'] = element.backend_x_group.externalId
}
var addClient = await instance.addClient(backend.credentials, tmpClient)
diff --git a/server/lib/external-backends/backends/idoit-backend.js b/server/lib/external-backends/backends/idoit-backend.js
index 81a955b..43ab434 100644
--- a/server/lib/external-backends/backends/idoit-backend.js
+++ b/server/lib/external-backends/backends/idoit-backend.js
@@ -659,9 +659,9 @@ class IdoitBackend extends ExternalBackends {
}
}
try {
- var requestUpdate = await axios.post(c.url, bodies, config)
+ var requestUpdate = await axios.post(c.url, bodies, config)
} catch (error) {
- console.log(error)
+ console.log(error)
}
// 10 is the idoit object id for clients.
var result = {
diff --git a/server/lib/ip.js b/server/lib/ip.js
deleted file mode 100644
index 87c2eb5..0000000
--- a/server/lib/ip.js
+++ /dev/null
@@ -1,21 +0,0 @@
-module.exports = { toInt, toString, isIpv4 }
-
-// Takes an ip address and converts it to an integer.
-function toInt(ipString) {
- const ipArray = ipString.split('.')
- if (ipArray.length !== 4) return false
-
- let result = parseInt(ipArray[0]) * 256**3 + parseInt(ipArray[1]) * 256**2 + parseInt(ipArray[2]) * 256 + parseInt(ipArray[3])
- return result
-}
-
-// Converts an integer value in a human readable typical ip address.
-function toString(ipInt) {
- return [(ipInt>>24)&0xff, (ipInt>>16)&0xff, (ipInt>>8)&0xff, ipInt&0xff].join('.');
-}
-
-// Sanity check for an ipv4.
-function isIpv4(ipString) {
- const re = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
- return re.test(ipString)
-} \ No newline at end of file
diff --git a/server/lib/iphelper.js b/server/lib/iphelper.js
new file mode 100644
index 0000000..5c40313
--- /dev/null
+++ b/server/lib/iphelper.js
@@ -0,0 +1,62 @@
+/* global __appdir */
+var path = require('path')
+var db = require(path.join(__appdir, 'lib', 'sequelize'))
+module.exports = { toDecimal, toString, toIPv4, getGroups }
+
+// Finds the groups where the ip fits best in the subnets.
+async function getGroups (ipString) {
+ const ipInt = toDecimal(ipString)
+
+ let fittingIpRanges = await db.iprange.findAll({ where: { startIp: { [db.Op.lte]: ipInt }, endIp: { [db.Op.gte]: ipInt } } })
+ fittingIpRanges = fittingIpRanges.map(x => x.groupId)
+
+ // List with all groups mapped so that groups[id] = [parents]
+ let groups = await db.group.findAll({ include: ['parents'] })
+ let parentMap = {}
+ groups.forEach(group => {
+ parentMap[group.id] = group.parents
+ })
+
+ // foreach fittingIpRanges go through groups and eliminate parents in the fittingIpRanges
+ let result = fittingIpRanges
+ fittingIpRanges.forEach(groupid => {
+ result = eliminateParents(groupid, parentMap, result)
+ })
+
+ return result
+}
+
+function eliminateParents (groupId, groupMap, eliminateArray, alreadyChecked = []) {
+ // Check for cycles and return if there is one.
+ if (alreadyChecked.includes(groupId)) return eliminateArray
+ alreadyChecked.push(groupId)
+
+ const parents = groupMap[groupId]
+ parents.forEach(parent => {
+ const index = eliminateArray.indexOf(parent.id)
+ if (index !== -1) eliminateArray.splice(index, 1)
+ if (groupMap[parent.id].length > 0) eliminateArray = eliminateParents(parent.id, groupMap, eliminateArray, alreadyChecked)
+ })
+ return eliminateArray
+}
+
+// Takes an ip address and converts it to an integer.
+function toDecimal (ipString) {
+ if (isIPv4(ipString)) return false
+ const ipArray = ipString.split('.')
+ if (ipArray.length !== 4) return false
+
+ let result = parseInt(ipArray[0]) * 256 ** 3 + parseInt(ipArray[1]) * 256 ** 2 + parseInt(ipArray[2]) * 256 + parseInt(ipArray[3])
+ return result
+}
+
+// Converts an integer value in a human readable typical ip address.
+function toIPv4 (ipInt) {
+ return [(ipInt >> 24) & 0xff, (ipInt >> 16) & 0xff, (ipInt >> 8) & 0xff, ipInt & 0xff].join('.')
+}
+
+// Sanity check for an ipv4.
+function isIPv4 (ipString) {
+ const re = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+ return re.test(ipString)
+}
diff --git a/server/lib/permissions/index.js b/server/lib/permissions/index.js
index 79ce6b1..a0af9d4 100644
--- a/server/lib/permissions/index.js
+++ b/server/lib/permissions/index.js
@@ -19,7 +19,7 @@ function updatePermissionDatabase () {
// Delete entries from Database which are not in the permission.json
db.permission.destroy(
- { where: { $not: { name: permissionNames } } }
+ { where: { [db.Op.not]: { name: permissionNames } } }
)
}
diff --git a/server/lib/permissions/permissionutil.js b/server/lib/permissions/permissionutil.js
index 532af6c..8e91af9 100644
--- a/server/lib/permissions/permissionutil.js
+++ b/server/lib/permissions/permissionutil.js
@@ -31,7 +31,7 @@ async function hasPermission (userid, permissionName) {
var user
if (permission[1] === '*') {
user = await db.user.findOne({
- where: { id: userid, '$roles.permissions.name$': { $like: permission[0] + '%' } },
+ where: { id: userid, '$roles.permissions.name$': { [db.Op.like]: permission[0] + '%' } },
include: [{ as: 'roles', model: db.role, include: ['permissions'] }]
})
} else {
diff --git a/server/lib/sequelize.js b/server/lib/sequelize.js
index 3624723..b6b99dd 100644
--- a/server/lib/sequelize.js
+++ b/server/lib/sequelize.js
@@ -7,7 +7,12 @@ var Sequelize = require('sequelize')
var config = require(path.join(__appdir, 'config', 'database'))
var db = {}
-var sequelize = new Sequelize(config.database, config.username, config.password, config)
+var sequelize = new Sequelize(config.database, config.username, config.password, {
+ host: config.host,
+ dialect: config.dialect,
+ operatorsAliases: false
+})
+const Op = Sequelize.Op
fs
.readdirSync(path.join(__dirname, '/../models'))
@@ -24,5 +29,6 @@ Object.keys(db).forEach(modelName => {
db.sequelize = sequelize
db.Sequelize = Sequelize
+db.Op = Op
module.exports = db
diff --git a/server/migrations/20190307051433-create-conflict.js b/server/migrations/20190307051433-create-conflict.js
new file mode 100644
index 0000000..c5630dc
--- /dev/null
+++ b/server/migrations/20190307051433-create-conflict.js
@@ -0,0 +1,19 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('conflicts', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER
+ },
+ description: {
+ type: Sequelize.STRING
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('conflicts')
+ }
+}
diff --git a/server/migrations/20190307051633-create-conflict_x_object.js b/server/migrations/20190307051633-create-conflict_x_object.js
new file mode 100644
index 0000000..bead43f
--- /dev/null
+++ b/server/migrations/20190307051633-create-conflict_x_object.js
@@ -0,0 +1,25 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('conflict_x_object', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER
+ },
+ conflictId: {
+ type: Sequelize.INTEGER
+ },
+ objectType: {
+ type: Sequelize.STRING
+ },
+ objectId: {
+ type: Sequelize.INTEGER
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('conflict_x_object')
+ }
+}
diff --git a/server/models/conflict.js b/server/models/conflict.js
new file mode 100644
index 0000000..5769710
--- /dev/null
+++ b/server/models/conflict.js
@@ -0,0 +1,23 @@
+'use strict'
+module.exports = (sequelize, DataTypes) => {
+ var conflict = sequelize.define('conflict', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: DataTypes.INTEGER
+ },
+ description: DataTypes.STRING(2048)
+ }, {
+ timestamps: false
+ })
+ conflict.associate = function (models) {
+ var ConflictXObject = sequelize.define('conflict_x_object', {
+ objectType: DataTypes.STRING,
+ objectId: DataTypes.INTEGER
+ }, { timestamps: false, freezeTableName: true })
+ conflict.hasMany(ConflictXObject, { as: 'objects' })
+ }
+
+ return conflict
+}