mgmt-iot-web
Version:
web platform to configure and interact with iot devices using mqtt
641 lines (559 loc) • 19.4 kB
JavaScript
var path = require('path');
var express = require('express');
const session = require('express-session');
var expressValidation = require('express-validation');
var useragent = require('express-useragent');
var bodyParser = require('body-parser');
//var cookieParser = require('cookie-parser');
var httpStatus = require('http-status-codes');
const fs = require('fs');
const async = require('async');
const packageJson = require(__dirname+'/package.json');
const packageVersion = packageJson.version;
var auth = require('./server/controllers/auth');
var routes = require('./server/routes');
var validate = require('./server/controllers/params_validator');
var user = require('./server/controllers/users');
var client = require('./server/controllers/clients');
var firmware = require('./server/controllers/firmwares');
var project = require('./server/controllers/projects');
var model = require('./server/controllers/models');
var Device = require('./server/models/devices');
var User = require('./server/models/users');
var Client = require('./server/models/clients');
var Project = require('./server/models/projects');
var Model = require('./server/models/models');
var Firmware = require('./server/models/firmwares');
var Sensor = require('./server/models/sensors');
var Templates = require('./server/models/templates');
var Lwm2mTemplate = require('./server/models/lwm2mTemplate');
var serveIndex = require('serve-index'); // well known
const app = express();
var config = require('./config/env');
app.use(useragent.express());
app.use(bodyParser.json());
app.use(session({
secret: config.jwtSecret,
resave: false,
saveUninitialized: false
}));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('trust proxy', true);
//app.get('/api/firmware/:fwId/download',auth.fw_check_token,firmware.get)
app.get('/api/firmware/:fwId/download',firmware.get)
app.use('/api', auth.api_check_authentication,routes);
app.use('/api', (req,res) => {
res.status(httpStatus.BAD_GATEWAY)
.json({
status: "error",
message: 'path not available'
});
});
app.set('view engine', 'ejs'); // set the view engine to ejs
app.use('*/assets', express.static(path.join(__dirname, config.public_path+'/assets')))
app.use((req,res,next) => {
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
//log.debug("platform:",req.device.platform);
log.debug(fullUrl);
next();
});
app.post('/login',validate.body([{
param_key: 'user',
required: true,
type: 'string',
validator_functions: [(param) => {return param.length > 1}]
},{
param_key: 'password',
required: true,
type: 'string',
validator_functions: [(param) => {return param.length > 1}]
}]),auth.authenticate,auth.generateToken,auth.respondJWT);
app.post('/login/google/user',validate.body([{
param_key: 'token',
required: true,
type: 'string',
validator_functions: [(param) => {return param.length > 1}]
}]),auth.authenticate_google,auth.generateToken,auth.respondJWT);
app.use(auth.check_authentication,(req,res,next)=>{
if(!req.user){
log.warn("not authenticated")
//res.render(path.join(__dirname, config.public_path+'/views/pages/login'));
res.render(path.join(__dirname, config.public_path+'/views/pages/login'),{googleclientID:config.googleClientId});
}else{
req.user.mgmt_iot_web_version = packageVersion;
req.user.mgmt_iot_version = mgmt_iot_version;
next()
}
});
app.use('*/js',express.static(path.join(__dirname, config.public_path+'/js')))
app.use('*/lib',express.static(path.join(__dirname, config.public_path+'/lib')))
app.use('*/files',express.static(path.join(__dirname, config.public_path+'/files')))
app.get('*/moment.js',(req,res)=>{
fs.readFile("node_modules/moment/dist/moment.js", function(err, data) {
if (err) {
res.writeHead(500, {'Content-Type': 'text/plain'});
res.end('Error loading module');
} else {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end(data);
}
});
});
app.get('*/moment-locales.js',(req,res)=>{
fs.readFile("node_modules/moment/min/moment-with-locales.js", function(err, data) {
if (err) {
res.writeHead(500, {'Content-Type': 'text/plain'});
res.end('Error loading module');
} else {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end(data);
}
});
});
app.get('*/locale/*',(req,res)=>{
fs.readFile("node_modules/moment/locale/pt.js", function(err, data) {
if (err) {
res.writeHead(500, {'Content-Type': 'text/plain'});
res.end('Error loading module');
} else {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end(data);
}
});
});
app.get('/logout',(req,res)=>{
let host = req.protocol + '://' + req.get('host');
auth.deauth(req,res,(req,res)=>{
res.redirect(host +'/home');
});
});
// --- HOME ---
app.get('/home',(req,res)=>{
let clients = [];
let users = [];
let projects = [];
let models = [];
let firmwares = [];
if(req.user.level >= 4){
User.list((err,rows)=>{
users = rows
});
Client.list((err,rows)=>{
clients = rows
});
Project.list((err,rows)=>{
projects = rows;
});
Model.list((err,rows)=>{
models = rows;
});
Firmware.list((err,rows)=>{
firmwares = rows
});
}else{
Model.listWithClientPermission(req.user.client_id,(err,rows)=>{
models = rows;
});
Firmware.listWithClientPermission(req.user.client_id,(err,rows)=>{
firmwares = rows
});
}
setTimeout(()=>{
Client.getMqttCredentials(req.user.client_id,(err,mqtt)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/dashboard'),{
user:req.user,
mqtt:mqtt,
users:users?.length,
clients:clients?.length,
projects:projects?.length,
models:models?.length,
firmwares:firmwares?.length,
container:config.container,
page:'Dashboard'
});
});
},100);
});
// --- users ---
/*
app.get('/users',(req,res)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/users_list',{user:req.user,page:'Users'}));
});
app.get('/user/:user_id',(req,res)=>{
res.json({'msg':'In development'});
});
*/
// --- mqtt users ---
app.get('/users',(req,res)=>{
if(req.user.level >= 4)
res.render(path.join(__dirname, config.public_path+'/views/pages/users_list'),{user:req.user,page:'Users'});
});
// --- ----- ---
// --- mqtt clients ---
app.get('/clients',(req,res)=>{
if(req.user.level >= 4)
res.render(path.join(__dirname, config.public_path+'/views/pages/clients_list'),{user:req.user,page:'Clients'});
});
app.get('/client/:client_id',(req,res)=>{
if(req.user.level >= 4){
if(req.originalUrl.endsWith("/"))
res.redirect(req.protocol + '://' + req.get('host') + req.originalUrl + "access");
else
res.redirect(req.protocol + '://' + req.get('host') + req.originalUrl + "/access");
}
});
app.get('/client/:client_id/access',(req,res,next)=>{
//app.get('/client/:client_id/access',(req,res,next)=>{
if(req.user.level >= 4)
res.render(path.join(__dirname, config.public_path+'/views/pages/client/access'),{user:req.user,page:'Access'});
});
// --- projects ---
app.get('/projects',(req,res)=>{
if(req.user.level >= 2){
if(req.user.level >= 4){
Project.list((err,projects)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/projects_list'),{user:req.user,projects:projects,page:'Projects'});
});
}else{
Project.listWithClientPermission(req.user.client_id,(err,projects)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/projects_list'),{user:req.user,projects:projects,page:'Projects'});
});
}
}
});
app.use('/project/:project_id',(req,res,next)=>{
Project.getById(req.params.project_id,(err,project)=>{
req.project = project;
next();
})
})
app.get('/project/:project_id/models',(req,res)=>{
project.checkAccess(req,res,()=>{
Project.getModels(req.params?.project_id,(err,models)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/project/models'),{project:req.project,models:models,user:req.user,page:'ProjectModels'});
})
});
});
app.get('/project/:project_id/access',project.checkOwnership,(req,res)=>{
if(req.user.level >= 4){
res.render(path.join(__dirname, config.public_path+'/views/pages/project/access'),{project:req.project,user:req.user,page:'ProjectAccess'});
}
});
app.get('/project/:project_id/settings',project.checkOwnership,(req,res)=>{
if(req.user.level >= 4){
res.render(path.join(__dirname, config.public_path+'/views/pages/project/settings'),{project:req.project,user:req.user,page:'ProjectSettings'});
}
});
app.get('/project/:project_id/sensors',(req,res)=>{
if(req.user.level >= 4 ){
res.render(path.join(__dirname, config.public_path+'/views/pages/project/sensors'),{project:req.project,user:req.user,page:'ProjectSensors'});
}
});
app.get('/project/:project_id/templates',(req,res)=>{
project.checkAccess(req,res,()=>{
Project.getTemplates(req.params?.project_id,(err,templates)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/project/templates'),{project:req.project,templates:templates,user:req.user,page:'ProjectTemplates'});
})
});
});
app.get('/templates/:template_id/edit',(req,res)=>{
Templates.getById(req.params?.template_id,(err,template)=>{
Project.getById(template.project_id,(err,projectData) => {
if(projectData.name === "lwm2m"){
res.render(path.join(__dirname, config.public_path+'/views/pages/template/lwm2mEdit'),{
project:projectData,
template,
user:req.user,
page:'Edit'
});
}else{
res.redirect('/project/' + req.params.project_id + '/templates');
}
})
})
});
// --- models ---
app.get('/models',(req,res)=>{
if(req.user.level >= 2){
if(req.user.level >= 4){
Model.list((err,models)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/models_list'),{user:req.user,models:models,page:'Models'});
});
}else{
Model.listWithClientPermission(req.user.client_id,(err,models)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/models_list'),{user:req.user,models:models,page:'Models'});
});
}
}
});
app.use('/model/:model_id',(req,res,next)=>{
Model.getModelById(req.params.model_id,(err,model)=>{
req.model = model;
next();
})
})
app.get('/model/:model_id/devices',(req,res)=>{
if(req.user.level >= 2){
if(req.user.level >= 4){
Device.list(req.params.model_id,null,(err,devices)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/model/devices'),{model:req.model,devices:devices,user:req.user,page:'Devices'});
})
}else{
Device.list(req.params.model_id,req.user.client_id,(err,devices)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/model/devices'),{model:req.model,devices:devices,user:req.user,page:'Devices'});
})
}
}
});
app.get('/model/:model_id/access',model.checkOwnership,(req,res)=>{
if(req.user.level >= 4){
res.render(path.join(__dirname, config.public_path+'/views/pages/model/access'),{model:req.model,user:req.user,page:'Access'});
}
});
app.get('/model/:model_id/settings',model.checkOwnership,(req,res)=>{
if(req.user.level >= 4){
res.render(path.join(__dirname, config.public_path+'/views/pages/model/settings'),{model:req.model,user:req.user,page:'Settings'});
}
});
app.get('/model/:model_id/sensors',(req,res)=>{
if(req.user.level >= 4 ){
res.render(path.join(__dirname, config.public_path+'/views/pages/model/sensors'),{model:req.model,user:req.user,page:'Sensors'});
}
});
app.get('/model/:model_id/firmwares',(req,res)=>{
if(req.user.level >= 4 && req.model?.fw_enabled){
res.render(path.join(__dirname, config.public_path+'/views/pages/model/firmwares'),{model:req.model,user:req.user,page:'Firmwares'});
}
});
// --- templates ---
app.get('/template/:template_id/edit',(req,res)=>{
if(req.user.level >= 4){
const templateId = req.params.template_id;
res.render(path.join(__dirname, config.public_path+'/views/template/edit/templateLwm2mEdit'),{
user: req.user,
templateId: templateId,
page: 'Template Edit'
});
} else {
res.redirect('/home');
}
});
// --- devices ---
app.get('/devices',(req,res)=>{
res.render(path.join(__dirname, config.public_path+'/views/pages/devices_list'),{user:req.user,page:'Devices'});
});
app.use('/device/:device_id',client.checkDeviceReadAccess,(req,res,next)=>{
if(! (req.originalUrl.endsWith(".js") || req.originalUrl.endsWith(".mjs")) ){
collectData(req,(err,data)=>{
req.user.data = data;
next()
});
}else next()
});
app.get('/device/:device_id',(req,res)=>{
if(req.originalUrl.endsWith("/"))
res.redirect(req.protocol + '://' + req.get('host') + req.originalUrl + "dashboard");
else
res.redirect(req.protocol + '://' + req.get('host') + req.originalUrl + "/dashboard");
});
//app.get('/device/:device_id/dashboard',(req,res)=>{
app.get('/device/:device_id/sensors',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.model){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/sensors'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Sensors'});
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
app.get('/device/:device_id/settings',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.model){
if(data.project_name === "lwm2m"){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/lwm2mSettings'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Settings'
});
}else{
res.render(path.join(__dirname, config.public_path+'/views/pages/device/settings'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Settings'
});
}
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
app.get('/device/:device_id/access',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.model){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/access'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Access'});
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
app.get('/device/:device_id/autorequests',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.modelFeat?.ar_enabled){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/autorequests'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Autorequests'});
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
app.get('/device/:device_id/alarms',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.modelFeat?.alarms_enabled){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/alarms'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'Alarms'});
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
app.get('/device/:device_id/jscode',(req,res)=>{
let data = req.user.data;
if(data.device != null && data.mqtt != null && data.modelFeat?.js_code_enabled){
res.render(path.join(__dirname, config.public_path+'/views/pages/device/jscode'),{
project_name:data.project_name,
model_name:data.model_name,
device:data.device,
project:data.project,
model:data.model,
modelFeat:data.modelFeat,
fw:data.fw,
sensors:data.sensors,
mqtt:data.mqtt,
user:req.user,
page:'JSCODE'});
}else{
res.redirect(req.protocol + '://' + req.get('host') + "/devices");
}
});
if(typeof middleware !== 'undefined')
app.use(middleware);
else{
app.use((req,res,next)=>{
res.redirect(req.protocol + '://' + req.get('host') +'/home');
});
}
/*
app.use((err, req, res, next) => {
if (err instanceof expressValidation.ValidationError) {
res.status(err.status).json(err);
} else {
res.status(500)
.json({
status: err.status,
message: err.message
});
}
});
*/
module.exports = app;
function collectData(req,callback){
let data ={
project_name:null,
model_name:null,
device:null,
project:null,
model:null,
fw:null,
sensors:null,
associated:null,
ar:null,
alarms:null,
mqtt:null,
}
async.waterfall([
(next)=>{
Device.getInfo(req.params.device_id,(err,row)=>{
data.project_name = row?.project_name != null ? row.project_name : "";
data.model_name = row?.model_name != null ? row.model_name : "";
data.device = row?.device != null ? row.device : {};
data.project = row?.project != null ? row.project : {};
data.model = row?.model != null ? row.model : {};
data.modelFeat = row?.modelFeat != null ? row.modelFeat : {};
data.fw = row?.fw != null ? row.fw : {};
data.associated = row?.associated != null ? row.associated : {};
next(err);
});
},
(next)=>{
Device.getSensors(req.params.device_id,data.device?.model_id,(err,row)=>{
data.sensors = row;
if(err){
log.warn(`warning - no table for model ${data.device?.model}`);
}
next();
});
},
(next)=>{
Client.getMqttCredentials(req.user.client_id,(err,row)=>{
data.mqtt = row;
next(err);
});
},
],(err)=>{
if(err) log.error(err);
return callback(err,data);
})
}