Shinobi/libs/webServerPaths.js

1918 lines
85 KiB
JavaScript
Raw Normal View History

2018-09-28 05:37:08 +00:00
var express = require('express');
var fs = require('fs');
var bodyParser = require('body-parser');
var os = require('os');
var moment = require('moment');
var request = require('request');
var execSync = require('child_process').execSync;
var exec = require('child_process').exec;
var spawn = require('child_process').spawn;
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({})
var ejs = require('ejs');
var fileupload = require("express-fileupload");
module.exports = function(s,config,lang,app,io){
2020-08-09 22:56:27 +00:00
if(config.productType === 'Pro'){
2018-09-28 20:26:24 +00:00
var LdapAuth = require('ldapauth-fork');
}
s.renderPage = function(req,res,paths,passables,callback){
passables.window = {}
passables.data = req.params
passables.originalURL = s.getOriginalUrl(req)
passables.baseUrl = req.protocol+'://'+req.hostname
passables.config = s.getConfigWithBranding(req.hostname)
res.render(paths,passables,callback)
2018-09-28 05:37:08 +00:00
}
//child node proxy check
//params = parameters
//cb = callback
//res = response, only needed for express (http server)
//request = request, only needed for express (http server)
2020-08-28 19:35:45 +00:00
s.checkChildProxy = function(params,cb,res,req) {
if(s.group[params.ke] && s.group[params.ke].activeMonitors && s.group[params.ke].activeMonitors[params.id] && s.group[params.ke].activeMonitors[params.id].childNode){
var url = 'http://' + s.group[params.ke].activeMonitors[params.id].childNode// + req.originalUrl
proxy.web(req, res, { target: url })
}else{
cb()
}
}
s.closeJsonResponse = function(res,endData){
res.setHeader('Content-Type', 'application/json')
res.end(s.prettyPrint(endData))
}
2018-10-05 21:19:48 +00:00
//get post data
s.getPostData = function(req,target,parseJSON){
if(!target)target = 'data'
if(!parseJSON)parseJSON = true
2018-10-05 21:19:48 +00:00
var postData = false
if(req.query && req.query[target]){
postData = req.query[target]
}else{
postData = req.body[target]
}
if(parseJSON === true){
postData = s.parseJSON(postData)
2018-10-05 21:19:48 +00:00
}
return postData
}
//get client ip address
s.getClientIp = function(req){
return req.headers['cf-connecting-ip']||req.headers["CF-Connecting-IP"]||req.headers["'x-forwarded-for"]||req.connection.remoteAddress;
}
2018-09-28 05:37:08 +00:00
////Pages
app.enable('trust proxy');
if(config.webPaths.home !== '/'){
app.use('/libs',express.static(s.mainDirectory + '/web/libs'))
}
app.use(s.checkCorrectPathEnding(config.webPaths.home)+'libs',express.static(s.mainDirectory + '/web/libs'))
app.use(s.checkCorrectPathEnding(config.webPaths.admin)+'libs',express.static(s.mainDirectory + '/web/libs'))
app.use(s.checkCorrectPathEnding(config.webPaths.super)+'libs',express.static(s.mainDirectory + '/web/libs'))
2018-09-28 05:37:08 +00:00
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(function (req,res,next){
res.header("Access-Control-Allow-Origin",'*');
next()
})
app.set('views', s.mainDirectory + '/web');
2018-09-28 05:37:08 +00:00
app.set('view engine','ejs');
//add template handler
if(config.renderPaths.handler!==undefined){require(s.mainDirectory+'/web/'+config.renderPaths.handler+'.js').addHandlers(s,app,io,config)}
2018-09-28 05:37:08 +00:00
/**
* API : Logout
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/logout/:ke/:id', function (req,res){
if(s.group[req.params.ke]&&s.group[req.params.ke].users[req.params.auth]){
delete(s.api[req.params.auth]);
delete(s.group[req.params.ke].users[req.params.auth]);
s.knexQuery({
action: "update",
table: "Users",
update: {
auth: '',
},
where: [
['auth','=',req.params.auth],
['ke','=',req.params.ke],
['uid','=',req.params.id],
]
})
res.end(s.prettyPrint({ok:true,msg:'You have been logged out, session key is now inactive.'}))
2018-09-28 05:37:08 +00:00
}else{
res.end(s.prettyPrint({ok:false,msg:'This group key does not exist or this user is not logged in.'}))
2018-09-28 05:37:08 +00:00
}
});
/**
* Page : Login Screen
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.home, function (req,res){
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config: s.getConfigWithBranding(req.hostname),screen:'dashboard'})
2018-09-28 05:37:08 +00:00
});
/**
* Page : Administrator Login Screen
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.admin, function (req,res){
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config: s.getConfigWithBranding(req.hostname),screen:'admin'})
2018-09-28 05:37:08 +00:00
});
/**
* Page : Superuser Login Screen
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.super, function (req,res){
s.renderPage(req,res,config.renderPaths.index,{
lang: lang,
config: s.getConfigWithBranding(req.hostname),
screen: 'super'
})
2018-09-28 05:37:08 +00:00
});
/**
* API : Get User Info
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/userInfo/:ke',function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
2020-08-06 17:44:38 +00:00
response.ok = true
response.user = user
res.end(s.prettyPrint(response));
2018-09-28 05:37:08 +00:00
},res,req);
})
//login function
s.deleteFactorAuth=function(r){
delete(s.factorAuth[r.ke][r.uid])
if(Object.keys(s.factorAuth[r.ke]).length===0){
delete(s.factorAuth[r.ke])
}
}
/**
* API : Login handler. Dashboard, Streamer, Dashcam Administrator, Superuser
*/
app.post([
config.webPaths.home,
config.webPaths.admin,
config.webPaths.super,
s.checkCorrectPathEnding(config.webPaths.home)+':screen',
s.checkCorrectPathEnding(config.webPaths.admin)+':screen',
s.checkCorrectPathEnding(config.webPaths.super)+':screen',
],function (req,res){
var response = {ok: false};
req.ip = s.getClientIp(req)
2018-11-06 18:09:38 +00:00
var screenChooser = function(screen){
var search = function(screen){
if(req.url.indexOf(screen) > -1){
return true
}
return false
}
switch(true){
case search(config.webPaths.admin):
return 'admin'
break;
case search(config.webPaths.super):
return 'super'
break;
default:
return 'dashboard'
break;
}
}
2018-09-28 05:37:08 +00:00
// brute check
if(s.failedLoginAttempts[req.body.mail] && s.failedLoginAttempts[req.body.mail].failCount >= 5){
if(req.query.json=='true'){
res.end(s.prettyPrint({ok:false}))
2018-09-28 05:37:08 +00:00
}else{
s.renderPage(req,res,config.renderPaths.index,{
2018-11-06 18:09:38 +00:00
failedLogin: true,
message: lang.failedLoginText1,
lang: s.copySystemDefaultLanguage(),
config: s.getConfigWithBranding(req.hostname),
2018-11-06 18:09:38 +00:00
screen: screenChooser(req.params.screen)
})
2018-09-28 05:37:08 +00:00
}
return false
}
//
renderPage = function(focus,data){
2018-09-28 05:37:08 +00:00
if(s.failedLoginAttempts[req.body.mail]){
clearTimeout(s.failedLoginAttempts[req.body.mail].timeout)
delete(s.failedLoginAttempts[req.body.mail])
}
if(req.query.json=='true'){
delete(data.config)
2020-08-06 17:44:38 +00:00
data.ok = true;
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
res.end(s.prettyPrint(data))
2018-09-28 05:37:08 +00:00
}else{
data.screen=req.params.screen
s.renderPage(req,res,focus,data)
2018-09-28 05:37:08 +00:00
}
}
failedAuthentication = function(board){
2018-09-28 05:37:08 +00:00
// brute protector
if(!s.failedLoginAttempts[req.body.mail]){
s.failedLoginAttempts[req.body.mail] = {
failCount : 0,
ips : {}
}
}
++s.failedLoginAttempts[req.body.mail].failCount
if(!s.failedLoginAttempts[req.body.mail].ips[req.ip]){
s.failedLoginAttempts[req.body.mail].ips[req.ip] = 0
}
++s.failedLoginAttempts[req.body.mail].ips[req.ip]
clearTimeout(s.failedLoginAttempts[req.body.mail].timeout)
s.failedLoginAttempts[req.body.mail].timeout = setTimeout(function(){
delete(s.failedLoginAttempts[req.body.mail])
},1000 * 60 * 15)
// check if JSON
2018-10-02 00:21:48 +00:00
if(req.query.json === 'true'){
res.setHeader('Content-Type', 'application/json')
res.end(s.prettyPrint({ok:false}))
2018-09-28 05:37:08 +00:00
}else{
s.renderPage(req,res,config.renderPaths.index,{
2018-11-06 18:09:38 +00:00
failedLogin: true,
message: lang.failedLoginText2,
lang: s.copySystemDefaultLanguage(),
config: s.getConfigWithBranding(req.hostname),
2018-11-06 18:09:38 +00:00
screen: screenChooser(req.params.screen)
})
}
var logTo = {
ke: '$',
mid: '$USER'
}
var logData = {
type: lang['Authentication Failed'],
msg: {
for: board,
mail: req.body.mail,
ip: req.ip
}
2018-09-28 05:37:08 +00:00
}
if(board === 'super'){
s.userLog(logTo,logData)
2018-09-28 05:37:08 +00:00
}else{
s.knexQuery({
action: "select",
columns: "ke,uid,details",
table: "Users",
where: [
['mail','=',req.body.mail],
]
},(err,r) => {
if(r && r[0]){
r = r[0]
r.details = JSON.parse(r.details)
r.lang = s.getLanguageFile(r.details.lang)
logData.id = r.uid
logData.type = r.lang['Authentication Failed']
logTo.ke = r.ke
2018-09-28 05:37:08 +00:00
}
s.userLog(logTo,logData)
2018-09-28 05:37:08 +00:00
})
}
}
checkRoute = function(r){
2018-09-28 05:37:08 +00:00
switch(req.body.function){
case'cam':
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',r.ke],
['type','=','dashcam'],
]
},(err,rr) => {
2020-08-06 17:44:38 +00:00
response.mons = rr
renderPage(config.renderPaths.dashcam,{
// config: s.getConfigWithBranding(req.hostname),
2020-08-06 17:44:38 +00:00
$user: response,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
2018-09-28 05:37:08 +00:00
})
break;
case'streamer':
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',r.ke],
['type','=','socket'],
]
},(err,rr) => {
2020-08-06 17:44:38 +00:00
response.mons=rr;
renderPage(config.renderPaths.streamer,{
// config: s.getConfigWithBranding(req.hostname),
2020-08-06 17:44:38 +00:00
$user: response,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
2018-09-28 05:37:08 +00:00
})
break;
case'admin':
if(!r.details.sub){
s.knexQuery({
action: "select",
columns: "uid,mail,details",
table: "Users",
where: [
['ke','=',r.ke],
['details','LIKE','%"sub"%'],
]
},(err,rr) => {
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',r.ke],
]
},(err,rrr) => {
renderPage(config.renderPaths.admin,{
config: s.getConfigWithBranding(req.hostname),
2020-08-06 17:44:38 +00:00
$user: response,
$subs: rr,
$mons: rrr,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
2018-09-28 05:37:08 +00:00
})
})
}else{
//not admin user
var chosenRender = 'home'
if(r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
chosenRender = r.details.landing_page
}
renderPage(config.renderPaths[chosenRender],{
2020-08-06 17:44:38 +00:00
$user:response,
config: s.getConfigWithBranding(req.hostname),
lang:r.lang,
define:s.getDefinitonFile(r.details.lang),
addStorage:s.dir.addStorage,
fs:fs,
__dirname:s.mainDirectory,
customAutoLoad: s.customAutoLoadTree
});
2018-09-28 05:37:08 +00:00
}
break;
default:
var chosenRender = 'home'
if(r.details.sub && r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
chosenRender = r.details.landing_page
}
renderPage(config.renderPaths[chosenRender],{
$user: response,
config: s.getConfigWithBranding(req.hostname),
lang:r.lang,
define:s.getDefinitonFile(r.details.lang),
addStorage:s.dir.addStorage,
fs:fs,
__dirname:s.mainDirectory,
customAutoLoad: s.customAutoLoadTree
})
2018-09-28 05:37:08 +00:00
break;
}
s.userLog({ke:r.ke,mid:'$USER'},{type:r.lang['New Authentication Token'],msg:{for:req.body.function,mail:r.mail,id:r.uid,ip:req.ip}})
2018-09-28 05:37:08 +00:00
// res.end();
}
if(req.body.mail&&req.body.pass){
req.default=function(){
s.knexQuery({
action: "select",
columns: "*",
table: "Users",
where: [
['mail','=',req.body.mail],
['pass','=',s.createHash(req.body.pass)],
],
limit: 1
},(err,r) => {
2020-08-06 17:44:38 +00:00
if(!err && r && r[0]){
2018-09-28 05:37:08 +00:00
r=r[0];r.auth=s.md5(s.gid());
s.knexQuery({
action: "update",
table: "Users",
update: {
auth: r.auth
},
where: [
['ke','=',r.ke],
['uid','=',r.uid],
]
})
response = {
2020-08-06 17:44:38 +00:00
ok: true,
auth_token: r.auth,
ke: r.ke,
uid: r.uid,
mail: r.mail,
details: r.details
};
r.details = JSON.parse(r.details);
r.lang = s.getLanguageFile(r.details.lang)
const factorAuth = function(cb){
req.params.auth = r.auth
req.params.ke = r.ke
if(r.details.factorAuth === "1"){
2018-09-28 05:37:08 +00:00
if(!r.details.acceptedMachines||!(r.details.acceptedMachines instanceof Object)){
r.details.acceptedMachines={}
}
if(!r.details.acceptedMachines[req.body.machineID]){
req.complete=function(){
s.factorAuth[r.ke][r.uid].function = req.body.function
2020-08-06 17:44:38 +00:00
s.factorAuth[r.ke][r.uid].info = response
2018-09-28 05:37:08 +00:00
clearTimeout(s.factorAuth[r.ke][r.uid].expireAuth)
s.factorAuth[r.ke][r.uid].expireAuth = setTimeout(function(){
2018-09-28 05:37:08 +00:00
s.deleteFactorAuth(r)
},1000*60*15)
renderPage(config.renderPaths.factorAuth,{$user:{
ke:r.ke,
uid:r.uid,
mail:r.mail
},lang:r.lang})
2018-09-28 05:37:08 +00:00
}
if(!s.factorAuth[r.ke]){s.factorAuth[r.ke]={}}
if(!s.factorAuth[r.ke][r.uid]){
s.factorAuth[r.ke][r.uid]={key:s.nid(),user:r}
s.onTwoFactorAuthCodeNotificationExtensions.forEach(function(extender){
extender(r)
})
2018-09-28 05:37:08 +00:00
req.complete()
}else{
req.complete()
}
}else{
checkRoute(r)
2018-09-28 05:37:08 +00:00
}
}else{
checkRoute(r)
2018-09-28 05:37:08 +00:00
}
}
if(r.details.sub){
s.knexQuery({
action: "select",
columns: "details",
table: "Users",
where: [
['ke','=',r.ke],
['details','NOT LIKE','%"sub"%'],
],
},function(err,rr) {
2018-10-27 17:36:20 +00:00
if(rr && rr[0]){
rr=rr[0];
rr.details = JSON.parse(rr.details);
r.details.mon_groups = rr.details.mon_groups;
response.details = JSON.stringify(r.details);
2020-08-06 17:44:38 +00:00
factorAuth()
2018-10-27 17:36:20 +00:00
}else{
failedAuthentication(req.body.function)
}
2018-09-28 05:37:08 +00:00
})
}else{
2020-08-06 17:44:38 +00:00
factorAuth()
2018-09-28 05:37:08 +00:00
}
}else{
failedAuthentication(req.body.function)
2018-09-28 05:37:08 +00:00
}
})
}
if(LdapAuth&&req.body.function==='ldap'&&req.body.key!==''){
s.knexQuery({
action: "select",
columns: "*",
table: "Users",
where: [
['ke','=',req.body.key],
['details','NOT LIKE','%"sub"%'],
],
},(err,r) => {
2018-09-28 05:37:08 +00:00
if(r&&r[0]){
r=r[0]
r.details=JSON.parse(r.details)
r.lang=s.getLanguageFile(r.details.lang)
if(r.details.use_ldap!=='0'&&r.details.ldap_enable==='1'&&r.details.ldap_url&&r.details.ldap_url!==''){
req.mailArray={}
req.body.mail.split(',').forEach(function(v){
v=v.split('=')
req.mailArray[v[0]]=v[1]
})
if(!r.details.ldap_bindDN||r.details.ldap_bindDN===''){
r.details.ldap_bindDN=req.body.mail
}
if(!r.details.ldap_bindCredentials||r.details.ldap_bindCredentials===''){
r.details.ldap_bindCredentials=req.body.pass
}
if(!r.details.ldap_searchFilter||r.details.ldap_searchFilter===''){
r.details.ldap_searchFilter=req.body.mail
if(req.mailArray.cn){
r.details.ldap_searchFilter='cn='+req.mailArray.cn
}
if(req.mailArray.uid){
r.details.ldap_searchFilter='uid='+req.mailArray.uid
}
}else{
r.details.ldap_searchFilter=r.details.ldap_searchFilter.replace('{{username}}',req.body.mail)
}
if(!r.details.ldap_searchBase||r.details.ldap_searchBase===''){
r.details.ldap_searchBase='dc=test,dc=com'
}
req.auth = new LdapAuth({
url:r.details.ldap_url,
bindDN:r.details.ldap_bindDN,
bindCredentials:r.details.ldap_bindCredentials,
searchBase:r.details.ldap_searchBase,
searchFilter:'('+r.details.ldap_searchFilter+')',
reconnect:true
});
req.auth.on('error', function (err) {
console.error('LdapAuth: ', err);
});
req.auth.authenticate(req.body.mail, req.body.pass, function(err, user) {
if(user){
//found user
if(!user.uid){
user.uid=s.gid()
}
response = {
2018-09-28 05:37:08 +00:00
ke:req.body.key,
uid:user.uid,
auth:s.createHash(s.gid()),
mail:user.mail,
pass:s.createHash(req.body.pass),
details:JSON.stringify({
sub:'1',
ldap:'1',
allmonitors:'1',
filter: {}
2018-09-28 05:37:08 +00:00
})
}
s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP Success'],msg:{user:user}})
s.knexQuery({
action: "select",
columns: "*",
table: "Users",
where: [
['ke','=',req.body.key],
['mail','=',user.cn],
],
},function(err,rr) {
2018-09-28 05:37:08 +00:00
if(rr&&rr[0]){
//already registered
rr = rr[0]
response = rr;
rr.details = JSON.parse(rr.details)
response.lang = s.getLanguageFile(rr.details.lang)
s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP User Authenticated'],msg:{user:user,shinobiUID:rr.uid}})
s.knexQuery({
action: "update",
table: "Users",
update: {
2020-08-06 17:44:38 +00:00
auth: response.auth
},
where: [
2020-08-06 17:44:38 +00:00
['ke','=',response.ke],
['uid','=',rr.uid],
]
})
2018-09-28 05:37:08 +00:00
}else{
//new ldap login
s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP User is New'],msg:{info:r.lang['Creating New Account'],user:user}})
2020-08-09 18:13:31 +00:00
response.lang = r.lang
s.knexQuery({
action: "insert",
table: "Users",
2020-08-06 17:44:38 +00:00
insert: response,
})
2018-09-28 05:37:08 +00:00
}
2020-08-06 17:44:38 +00:00
response.details = JSON.stringify(response.details)
response.auth_token = response.auth
response.ok = true
checkRoute(response)
2018-09-28 05:37:08 +00:00
})
return
}
s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP Failed'],msg:{err:err}})
2018-09-28 05:37:08 +00:00
//no user
req.default()
});
req.auth.close(function(err) {
})
}else{
req.default()
}
}else{
req.default()
}
})
}else{
if(req.body.function === 'super'){
2018-09-28 20:26:24 +00:00
if(!fs.existsSync(s.location.super)){
2018-09-28 05:37:08 +00:00
res.end(lang.superAdminText)
return
}
var ok = s.superAuth({
mail: req.body.mail,
pass: req.body.pass,
users: true,
md5: true
},function(data){
s.knexQuery({
action: "select",
columns: "*",
table: "Logs",
where: [
['ke','=','$'],
],
orderBy: ['time','desc'],
limit: 30
},(err,r) => {
2018-09-28 05:37:08 +00:00
if(!r){
r=[]
}
data.Logs = r
data.customAutoLoad = s.customAutoLoadTree
data.currentVersion = s.currentVersion
2018-09-28 20:26:24 +00:00
fs.readFile(s.location.config,'utf8',function(err,file){
data.plainConfig = JSON.parse(file)
renderPage(config.renderPaths.super,data)
2018-09-28 05:37:08 +00:00
})
})
})
if(ok === false){
failedAuthentication(req.body.function)
2018-09-28 05:37:08 +00:00
}
}else{
req.default()
}
}
}else{
if(req.body.machineID&&req.body.factorAuthKey){
if(s.factorAuth[req.body.ke]&&s.factorAuth[req.body.ke][req.body.id]&&s.factorAuth[req.body.ke][req.body.id].key===req.body.factorAuthKey){
if(s.factorAuth[req.body.ke][req.body.id].key===req.body.factorAuthKey){
if(req.body.remember==="1"){
req.details=JSON.parse(s.factorAuth[req.body.ke][req.body.id].info.details)
req.lang=s.getLanguageFile(req.details.lang)
if(!req.details.acceptedMachines||!(req.details.acceptedMachines instanceof Object)){
req.details.acceptedMachines={}
}
if(!req.details.acceptedMachines[req.body.machineID]){
req.details.acceptedMachines[req.body.machineID]={}
s.knexQuery({
action: "update",
table: "Users",
update: {
details: s.prettyPrint(req.details)
},
where: [
['ke','=',req.body.ke],
['uid','=',req.body.id],
]
})
2018-09-28 05:37:08 +00:00
}
}
req.body.function = s.factorAuth[req.body.ke][req.body.id].function
2020-08-17 18:25:42 +00:00
response = s.factorAuth[req.body.ke][req.body.id].info
response.lang = req.lang || s.getLanguageFile(JSON.parse(s.factorAuth[req.body.ke][req.body.id].info.details).lang)
checkRoute(s.factorAuth[req.body.ke][req.body.id].info)
2020-04-06 03:31:01 +00:00
clearTimeout(s.factorAuth[req.body.ke][req.body.id].expireAuth)
s.deleteFactorAuth({
ke: req.body.ke,
uid: req.body.id,
})
2018-09-28 05:37:08 +00:00
}else{
var info = s.factorAuth[req.body.ke][req.body.id].info
renderPage(config.renderPaths.factorAuth,{$user:{
ke: info.ke,
id: info.uid,
mail: info.mail,
},lang:req.lang});
2018-09-28 05:37:08 +00:00
res.end();
}
}else{
failedAuthentication(lang['2-Factor Authentication'])
2018-09-28 05:37:08 +00:00
}
}else{
failedAuthentication(lang['2-Factor Authentication'])
2018-09-28 05:37:08 +00:00
}
}
2018-10-05 21:19:48 +00:00
})
/**
* API : Brute Protection Lock Reset by API
*/
2018-09-28 05:37:08 +00:00
app.get([config.webPaths.apiPrefix+':auth/resetBruteProtection/:ke'], function (req,res){
s.auth(req.params,function(user){
if(s.failedLoginAttempts[user.mail]){
clearTimeout(s.failedLoginAttempts[user.mail].timeout)
delete(s.failedLoginAttempts[user.mail])
}
res.end(s.prettyPrint({ok:true}))
2018-09-28 05:37:08 +00:00
})
})
// /**
// * Page : Montage - stand alone squished view with gridstackjs
// */
// app.get([
// config.webPaths.apiPrefix+':auth/grid/:ke',
// config.webPaths.apiPrefix+':auth/grid/:ke/:group',
// config.webPaths.apiPrefix+':auth/cycle/:ke',
// config.webPaths.apiPrefix+':auth/cycle/:ke/:group'
// ], function(req,res) {
// s.auth(req.params,function(user){
// if(user.permissions.get_monitors==="0"){
// res.end(user.lang['Not Permitted'])
// return
// }
//
// req.params.protocol=req.protocol;
// req.sql='SELECT * FROM Monitors WHERE mode!=? AND mode!=? AND ke=?';req.ar=['stop','idle',req.params.ke];
// if(!req.params.id){
// if(user.details.sub&&user.details.monitors&&user.details.allmonitors!=='1'){
// try{user.details.monitors=JSON.parse(user.details.monitors);}catch(er){}
// req.or=[];
// user.details.monitors.forEach(function(v,n){
// req.or.push('mid=?');req.ar.push(v)
// })
// req.sql+=' AND ('+req.or.join(' OR ')+')'
// }
// }else{
// if(!user.details.sub||user.details.allmonitors!=='0'||user.details.monitors.indexOf(req.params.id)>-1){
// req.sql+=' and mid=?';req.ar.push(req.params.id)
// }else{
// res.end(user.lang['There are no monitors that you can view with this account.']);
// return;
// }
// }
// s.sqlQuery(req.sql,req.ar,function(err,r){
// if(req.params.group){
// var filteredByGroupCheck = {};
// var filteredByGroup = [];
// r.forEach(function(v,n){
// var details = JSON.parse(r[n].details);
// try{
// req.params.group.split('|').forEach(function(group){
// var groups = JSON.parse(details.groups);
// if(groups.indexOf(group) > -1 && !filteredByGroupCheck[v.mid]){
// filteredByGroupCheck[v.mid] = true;
// filteredByGroup.push(v)
// }
// })
// }catch(err){
//
// }
// })
// r = filteredByGroup;
// }
// r.forEach(function(v,n){
// if(s.group[v.ke]&&s.group[v.ke].activeMonitors[v.mid]&&s.group[v.ke].activeMonitors[v.mid].watch){
// r[n].currentlyWatching=Object.keys(s.group[v.ke].activeMonitors[v.mid].watch).length
// }
// r[n].subStream={}
// var details = JSON.parse(r[n].details)
// if(details.snap==='1'){
// r[n].subStream.jpeg = '/'+req.params.auth+'/jpeg/'+v.ke+'/'+v.mid+'/s.jpg'
// }
// if(details.stream_channels&&details.stream_channels!==''){
// try{
// details.stream_channels=JSON.parse(details.stream_channels)
// r[n].channels=[]
// details.stream_channels.forEach(function(b,m){
// var streamURL
// switch(b.stream_type){
// case'mjpeg':
// streamURL='/'+req.params.auth+'/mjpeg/'+v.ke+'/'+v.mid+'/'+m
// break;
// case'hls':
// streamURL='/'+req.params.auth+'/hls/'+v.ke+'/'+v.mid+'/'+m+'/s.m3u8'
// break;
// case'h264':
// streamURL='/'+req.params.auth+'/h264/'+v.ke+'/'+v.mid+'/'+m
// break;
// case'flv':
// streamURL='/'+req.params.auth+'/flv/'+v.ke+'/'+v.mid+'/'+m+'/s.flv'
// break;
// case'mp4':
// streamURL='/'+req.params.auth+'/mp4/'+v.ke+'/'+v.mid+'/'+m+'/s.mp4'
// break;
// }
// r[n].channels.push(streamURL)
// })
// }catch(err){
// s.userLog(req.params,{type:'Broken Monitor Object',msg:'Stream Channels Field is damaged. Skipping.'})
// }
// }
// })
// var page = config.renderPaths.grid
// if(req.path.indexOf('/cycle/') > -1){
// page = config.renderPaths.cycle
// }
// s.renderPage(req,res,page,{
// data:Object.assign(req.params,req.query),
// baseUrl:req.protocol+'://'+req.hostname,
// config: s.getConfigWithBranding(req.hostname),
// lang:user.lang,
// $user:user,
// monitors:r,
// query:req.query
// });
// })
// },res,req)
// });
/**
* API : Get TV Channels (Monitor Streams) json
*/
2018-09-28 05:37:08 +00:00
app.get([config.webPaths.apiPrefix+':auth/tvChannels/:ke',config.webPaths.apiPrefix+':auth/tvChannels/:ke/:id','/get.php'], function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
if(req.query.username&&req.query.password){
req.params.username = req.query.username
req.params.password = req.query.password
}
var output = ['h264','hls','mp4']
if(
req.query.output &&
req.query.output !== ''
){
2018-09-28 05:37:08 +00:00
output = req.query.output.split(',')
output.forEach(function(type,n){
if(type === 'ts'){
output[n] = 'h264'
if(output.indexOf('hls') === -1){
2018-09-28 05:37:08 +00:00
output.push('hls')
}
}
})
}
const isM3u8 = req.query.type === 'm3u8' || req.query.type === 'm3u_plus'
s.auth(req.params,function(user){
2020-07-12 01:06:07 +00:00
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && (user.permissions.get_monitors === "0" || monitorRestrictions.length === 0)){
s.closeJsonResponse(res,[]);
return
}
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',groupKey],
['mode','!=','stop'],
monitorRestrictions
]
},(err,r) => {
2018-09-28 05:37:08 +00:00
var tvChannelMonitors = [];
r.forEach(function(v,n){
var buildStreamURL = function(channelRow,type,channelNumber){
var streamURL
if(req.query.streamtype && req.query.streamtype != type){
return
}
if(channelNumber){channelNumber = '/' + channelNumber}else{channelNumber = ''}
2018-09-28 05:37:08 +00:00
switch(type){
case'mjpeg':
streamURL='/'+req.params.auth+'/mjpeg/'+v.ke+'/'+v.mid+channelNumber
break;
case'hls':
streamURL='/'+req.params.auth+'/hls/'+v.ke+'/'+v.mid+channelNumber+'/s.m3u8'
break;
case'h264':
streamURL='/'+req.params.auth+'/h264/'+v.ke+'/'+v.mid+channelNumber
break;
case'flv':
streamURL='/'+req.params.auth+'/flv/'+v.ke+'/'+v.mid+channelNumber+'/s.flv'
break;
case'mp4':
streamURL='/'+req.params.auth+'/mp4/'+v.ke+'/'+v.mid+channelNumber+'/s.ts'
break;
}
if(streamURL){
if(!channelRow.streamsSortedByType[type]){
channelRow.streamsSortedByType[type]=[]
}
channelRow.streamsSortedByType[type].push(streamURL)
channelRow.streams.push(streamURL)
}
return streamURL
}
var details = JSON.parse(r[n].details);
if(!details.tv_channel_id||details.tv_channel_id==='')details.tv_channel_id = 'temp_'+s.gid(5)
var channelRow = {
ke:v.ke,
mid:v.mid,
type:v.type,
groupTitle:details.tv_channel_group_title,
channel:details.tv_channel_id,
};
if(details.snap==='1'){
channelRow.snapshot = '/'+req.params.auth+'/jpeg/'+v.ke+'/'+v.mid+'/s.jpg'
}
channelRow.streams=[]
channelRow.streamsSortedByType={}
buildStreamURL(channelRow,details.stream_type)
if(details.stream_channels&&details.stream_channels!==''){
details.stream_channels=JSON.parse(details.stream_channels)
details.stream_channels.forEach(function(b,m){
buildStreamURL(channelRow,b.stream_type,m.toString())
})
}
if(details.tv_channel==='1'){
tvChannelMonitors.push(channelRow)
}
})
if(isM3u8){
var m3u8 = '#EXTM3U'+'\n'
tvChannelMonitors.forEach(function(channelRow,n){
output.forEach(function(type){
if(channelRow.streamsSortedByType[type]){
if(req.query.type === 'm3u_plus'){
2018-09-28 05:37:08 +00:00
m3u8 +='#EXTINF-1 tvg-id="'+channelRow.mid+'" tvg-name="'+channelRow.channel+'" tvg-logo="'+req.protocol+'://'+req.headers.host+channelRow.snapshot+'" group-title="'+channelRow.groupTitle+'",'+channelRow.channel+'\n'
}else{
m3u8 +='#EXTINF:-1,'+channelRow.channel+' ('+type.toUpperCase()+') \n'
}
m3u8 += req.protocol+'://'+req.headers.host+channelRow.streamsSortedByType[type][0]+'\n'
}
})
})
res.end(m3u8)
}else{
if(tvChannelMonitors.length === 1)tvChannelMonitors=tvChannelMonitors[0];
s.closeJsonResponse(res,tvChannelMonitors)
2018-09-28 05:37:08 +00:00
}
})
},res,req);
2018-09-28 05:37:08 +00:00
});
/**
* API : Get Monitors
*/
2018-09-28 05:37:08 +00:00
app.get([config.webPaths.apiPrefix+':auth/monitor/:ke',config.webPaths.apiPrefix+':auth/monitor/:ke/:id'], function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
2020-07-11 23:19:43 +00:00
s.auth(req.params,(user) => {
2020-07-12 01:06:07 +00:00
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && (user.permissions.get_monitors === "0" || monitorRestrictions.length === 0)){
s.closeJsonResponse(res,[]);
return
}
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',groupKey],
2020-07-12 01:06:07 +00:00
monitorRestrictions
]
},(err,r) => {
2018-09-28 05:37:08 +00:00
r.forEach(function(v,n){
if(s.group[v.ke] && s.group[v.ke].activeMonitors[v.mid]){
r[n].currentlyWatching = Object.keys(s.group[v.ke].activeMonitors[v.mid].watch).length
r[n].currentCpuUsage = s.group[v.ke].activeMonitors[v.mid].currentCpuUsage
r[n].status = s.group[v.ke].activeMonitors[v.mid].monitorStatus
2018-09-28 05:37:08 +00:00
}
var buildStreamURL = function(type,channelNumber){
var streamURL
if(channelNumber){channelNumber = '/'+channelNumber}else{channelNumber=''}
switch(type){
case'mjpeg':
streamURL='/'+req.params.auth+'/mjpeg/'+v.ke+'/'+v.mid+channelNumber
break;
case'hls':
streamURL='/'+req.params.auth+'/hls/'+v.ke+'/'+v.mid+channelNumber+'/s.m3u8'
break;
case'h264':
streamURL='/'+req.params.auth+'/h264/'+v.ke+'/'+v.mid+channelNumber
break;
case'flv':
streamURL='/'+req.params.auth+'/flv/'+v.ke+'/'+v.mid+channelNumber+'/s.flv'
break;
case'mp4':
streamURL='/'+req.params.auth+'/mp4/'+v.ke+'/'+v.mid+channelNumber+'/s.mp4'
break;
}
if(streamURL){
if(!r[n].streamsSortedByType[type]){
r[n].streamsSortedByType[type]=[]
}
r[n].streamsSortedByType[type].push(streamURL)
r[n].streams.push(streamURL)
}
return streamURL
}
var details = JSON.parse(r[n].details);
if(!details.tv_channel_id||details.tv_channel_id==='')details.tv_channel_id = 'temp_'+s.gid(5)
if(details.snap==='1'){
r[n].snapshot = '/'+req.params.auth+'/jpeg/'+v.ke+'/'+v.mid+'/s.jpg'
}
r[n].streams=[]
r[n].streamsSortedByType={}
buildStreamURL(details.stream_type)
if(details.stream_channels&&details.stream_channels!==''){
details.stream_channels=s.parseJSON(details.stream_channels)
2018-09-28 05:37:08 +00:00
details.stream_channels.forEach(function(b,m){
buildStreamURL(b.stream_type,m.toString())
})
}
})
s.closeJsonResponse(res,r);
2018-09-28 05:37:08 +00:00
})
},res,req);
2018-09-28 05:37:08 +00:00
});
/**
* API : Merge Recorded Videos into one file
*/
app.get(config.webPaths.apiPrefix+':auth/videosMerge/:ke', function (req,res){
var failed = function(resp){
res.setHeader('Content-Type', 'application/json');
res.end(s.prettyPrint(resp))
}
if(req.query.videos && req.query.videos !== ''){
s.auth(req.params,function(user){
var videosSelected = JSON.parse(req.query.videos)
const whereQuery = []
var didOne = false
videosSelected.forEach(function(video){
var time = s.nameToTime(video.filename)
if(req.query.isUTC === 'true'){
time = s.utcToLocal(time)
}
if(didOne){
whereQuery.push(['or','ke','=',req.params.ke])
}else{
didOne = true
whereQuery.push(['ke','=',req.params.ke])
}
whereQuery.push(
['mid','=',video.mid],
['time','=',time],
)
})
s.knexQuery({
action: "select",
columns: "*",
table: "Videos",
where: whereQuery
},(err,r) => {
var resp = {ok: false}
if(r && r[0]){
s.mergeRecordedVideos(r,req.params.ke,function(fullPath,filename){
res.setHeader('Content-Disposition', 'attachment; filename="'+filename+'"')
var file = fs.createReadStream(fullPath)
file.on('close',function(){
2019-01-31 18:51:35 +00:00
setTimeout(function(){
s.file('delete',fullPath)
},1000 * 60 * 3)
res.end()
})
file.pipe(res)
})
}else{
failed({ok:false,msg:'No Videos Found'})
}
})
},res,req);
}else{
failed({ok:false,msg:'"videos" query variable is missing from request.'})
}
})
/**
* API : Get Videos
*/
2018-09-28 05:37:08 +00:00
app.get([
config.webPaths.apiPrefix+':auth/videos/:ke',
config.webPaths.apiPrefix+':auth/videos/:ke/:id',
config.webPaths.apiPrefix+':auth/cloudVideos/:ke',
config.webPaths.apiPrefix+':auth/cloudVideos/:ke/:id'
], function (req,res){
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
2020-05-24 14:41:10 +00:00
const userDetails = user.details
const monitorId = req.params.id
const groupKey = req.params.ke
2020-05-24 15:44:44 +00:00
const hasRestrictions = userDetails.sub && userDetails.allmonitors !== '1';
2018-09-28 05:37:08 +00:00
var origURL = req.originalUrl.split('/')
var videoParam = origURL[origURL.indexOf(req.params.auth) + 1]
var videoSet = 'Videos'
switch(videoParam){
case'cloudVideos':
videoSet = 'Cloud Videos'
break;
}
2020-05-24 14:41:10 +00:00
s.sqlQueryBetweenTimesWithPermissions({
table: videoSet,
user: user,
noCount: true,
2020-05-24 14:41:10 +00:00
groupKey: req.params.ke,
monitorId: req.params.id,
startTime: req.query.start,
endTime: req.query.end,
startTimeOperator: req.query.startOperator,
endTimeOperator: req.query.endOperator,
limit: req.query.limit,
archived: req.query.archived,
endIsStartTo: !!req.query.endIsStartTo,
2020-05-24 15:44:44 +00:00
parseRowDetails: false,
2020-05-24 14:41:10 +00:00
rowName: 'videos',
preliminaryValidationFailed: (
user.permissions.watch_videos === "0" ||
hasRestrictions &&
(!userDetails.video_view || userDetails.video_view.indexOf(monitorId)===-1)
)
},(response) => {
if(response && response.videos){
s.buildVideoLinks(response.videos,{
auth : req.params.auth,
videoParam : videoParam,
hideRemote : config.hideCloudSaveUrls,
})
}
2020-05-24 14:41:10 +00:00
res.end(s.prettyPrint(response))
2018-09-28 05:37:08 +00:00
})
},res,req);
});
/**
* API : Get Events
*/
2019-07-19 20:43:05 +00:00
app.get([
config.webPaths.apiPrefix+':auth/events/:ke',
config.webPaths.apiPrefix+':auth/events/:ke/:id'
], function (req,res){
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
2020-05-24 15:44:44 +00:00
const userDetails = user.details
const monitorId = req.params.id
const groupKey = req.params.ke
const hasRestrictions = userDetails.sub && userDetails.allmonitors !== '1';
s.sqlQueryBetweenTimesWithPermissions({
table: 'Events',
user: user,
groupKey: req.params.ke,
monitorId: req.params.id,
startTime: req.query.start,
endTime: req.query.end,
startTimeOperator: req.query.startOperator,
endTimeOperator: req.query.endOperator,
limit: req.query.limit,
endIsStartTo: true,
parseRowDetails: true,
noFormat: true,
noCount: true,
rowName: 'events',
preliminaryValidationFailed: (
user.permissions.watch_videos === "0" ||
hasRestrictions &&
(!userDetails.video_view || userDetails.video_view.indexOf(monitorId)===-1)
)
},(response) => {
res.end(s.prettyPrint(response))
2018-09-28 05:37:08 +00:00
})
2020-05-24 15:44:44 +00:00
})
})
/**
* API : Get Logs
*/
2020-05-24 16:36:52 +00:00
app.get([
config.webPaths.apiPrefix+':auth/logs/:ke',
config.webPaths.apiPrefix+':auth/logs/:ke/:id'
], function (req,res){
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
2020-05-24 16:36:52 +00:00
const userDetails = user.details
const monitorId = req.params.id
const groupKey = req.params.ke
const hasRestrictions = userDetails.sub && userDetails.allmonitors !== '1';
s.sqlQueryBetweenTimesWithPermissions({
table: 'Logs',
user: user,
groupKey: req.params.ke,
monitorId: req.params.id,
startTime: req.query.start,
endTime: req.query.end,
startTimeOperator: req.query.startOperator,
endTimeOperator: req.query.endOperator,
limit: req.query.limit || 50,
endIsStartTo: true,
noFormat: true,
noCount: true,
rowName: 'logs',
preliminaryValidationFailed: (
user.permissions.get_logs === "0" || userDetails.sub && userDetails.view_logs !== '1'
)
},(response) => {
response.forEach(function(v,n){
v.info = JSON.parse(v.info)
2018-09-28 05:37:08 +00:00
})
2020-05-24 16:36:52 +00:00
res.end(s.prettyPrint(response))
2018-09-28 05:37:08 +00:00
})
2020-05-24 16:36:52 +00:00
},res,req)
2018-10-05 21:19:48 +00:00
})
/**
* API : Get Monitors Online
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/smonitor/:ke', function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,(user) => {
2020-07-12 01:06:07 +00:00
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && (user.permissions.get_monitors === "0" || monitorRestrictions.length === 0)){
s.closeJsonResponse(res,[]);
return
}
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',groupKey],
monitorRestrictions
]
},(err,r) => {
const startedMonitors = []
r.forEach(function(v){
if(
s.group[groupKey] &&
s.group[groupKey].activeMonitors[v.mid] &&
s.group[groupKey].activeMonitors[v.mid].isStarted === true
){
startedMonitors.push(v)
}
2018-09-28 05:37:08 +00:00
})
s.closeJsonResponse(res,startedMonitors)
2018-09-28 05:37:08 +00:00
})
},res,req);
2018-09-28 05:37:08 +00:00
});
/**
* API : Monitor Mode Controller
*/
2018-09-28 05:37:08 +00:00
app.get([config.webPaths.apiPrefix+':auth/monitor/:ke/:id/:f',config.webPaths.apiPrefix+':auth/monitor/:ke/:id/:f/:ff',config.webPaths.apiPrefix+':auth/monitor/:ke/:id/:f/:ff/:fff'], function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
if(user.permissions.control_monitors==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitor_edit.indexOf(req.params.id)===-1){
res.end(user.lang['Not Permitted'])
return
}
2020-08-06 17:44:38 +00:00
if(req.params.f===''){response.msg = user.lang.monitorGetText1;res.end(s.prettyPrint(response));return}
2018-09-28 05:37:08 +00:00
if(req.params.f!=='stop'&&req.params.f!=='start'&&req.params.f!=='record'){
2020-08-06 17:44:38 +00:00
response.msg = 'Mode not recognized.';
res.end(s.prettyPrint(response));
2018-09-28 05:37:08 +00:00
return;
}
s.knexQuery({
action: "select",
columns: "*",
table: "Monitors",
where: [
['ke','=',req.params.ke],
['mid','=',req.params.id],
],
limit: 1
},(err,r) => {
if(r && r[0]){
r = r[0];
if(req.query.reset==='1'||(s.group[r.ke]&&s.group[r.ke].rawMonitorConfigurations[r.mid].mode!==req.params.f)||req.query.fps&&(!s.group[r.ke].activeMonitors[r.mid].currentState||!s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on)){
if(req.query.reset!=='1'||!s.group[r.ke].activeMonitors[r.mid].trigger_timer){
if(!s.group[r.ke].activeMonitors[r.mid].currentState)s.group[r.ke].activeMonitors[r.mid].currentState={}
s.group[r.ke].activeMonitors[r.mid].currentState.mode=r.mode.toString()
s.group[r.ke].activeMonitors[r.mid].currentState.fps=r.fps.toString()
if(!s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on){
s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on=true
2018-09-28 05:37:08 +00:00
}else{
s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on=false
2018-09-28 05:37:08 +00:00
}
r.mode=req.params.f;
try{r.details=JSON.parse(r.details);}catch(er){}
if(req.query.fps){
r.fps=parseFloat(r.details.detector_trigger_record_fps)
s.group[r.ke].activeMonitors[r.mid].currentState.detector_trigger_record_fps=r.fps
2018-09-28 05:37:08 +00:00
}
r.id=r.mid;
s.knexQuery({
action: "update",
table: "Monitors",
update: {
mode: r.mode
},
where: [
['ke','=',r.ke],
['mid','=',r.mid],
]
})
s.group[r.ke].rawMonitorConfigurations[r.mid]=r;
2018-09-28 05:37:08 +00:00
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'GRP_'+r.ke);
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'STR_'+r.ke);
2018-09-29 01:38:14 +00:00
s.camera('stop',s.cleanMonitorObject(r));
2018-09-28 05:37:08 +00:00
if(req.params.f!=='stop'){
2018-09-29 01:38:14 +00:00
s.camera(req.params.f,s.cleanMonitorObject(r));
2018-09-28 05:37:08 +00:00
}
2020-08-06 17:44:38 +00:00
response.msg = user.lang['Monitor mode changed']+' : '+req.params.f;
2018-09-28 05:37:08 +00:00
}else{
2020-08-06 17:44:38 +00:00
response.msg = user.lang['Reset Timer'];
2018-09-28 05:37:08 +00:00
}
2020-08-06 17:44:38 +00:00
response.cmd_at=s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss');
response.ok = true;
2018-09-28 05:37:08 +00:00
if(req.params.ff&&req.params.f!=='stop'){
req.params.ff=parseFloat(req.params.ff);
clearTimeout(s.group[r.ke].activeMonitors[r.mid].trigger_timer)
2018-09-28 05:37:08 +00:00
switch(req.params.fff){
case'day':case'days':
req.timeout=req.params.ff*1000*60*60*24
break;
case'hr':case'hour':case'hours':
req.timeout=req.params.ff*1000*60*60
break;
case'min':case'minute':case'minutes':
req.timeout=req.params.ff*1000*60
break;
default://seconds
req.timeout=req.params.ff*1000
break;
}
s.group[r.ke].activeMonitors[r.mid].trigger_timer=setTimeout(function(){
delete(s.group[r.ke].activeMonitors[r.mid].trigger_timer)
s.knexQuery({
action: "update",
table: "Monitors",
update: {
mode: s.group[r.ke].activeMonitors[r.mid].currentState.mode
},
where: [
['ke','=',r.ke],
['mid','=',r.mid],
]
})
2018-09-28 05:37:08 +00:00
r.neglectTriggerTimer=1;
r.mode=s.group[r.ke].activeMonitors[r.mid].currentState.mode;
r.fps=s.group[r.ke].activeMonitors[r.mid].currentState.fps;
2018-09-29 01:38:14 +00:00
s.camera('stop',s.cleanMonitorObject(r),function(){
if(s.group[r.ke].activeMonitors[r.mid].currentState.mode!=='stop'){
s.camera(s.group[r.ke].activeMonitors[r.mid].currentState.mode,s.cleanMonitorObject(r));
2018-09-28 05:37:08 +00:00
}
s.group[r.ke].rawMonitorConfigurations[r.mid]=r;
2018-09-28 05:37:08 +00:00
});
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'GRP_'+r.ke);
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'STR_'+r.ke);
},req.timeout);
2020-08-06 17:44:38 +00:00
// response.end_at=s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss').add(req.timeout,'milliseconds');
2018-09-28 05:37:08 +00:00
}
}else{
2020-08-06 17:44:38 +00:00
response.msg = user.lang['Monitor mode is already']+' : '+req.params.f;
2018-09-28 05:37:08 +00:00
}
}else{
2020-08-06 17:44:38 +00:00
response.msg = user.lang['Monitor or Key does not exist.'];
2018-09-28 05:37:08 +00:00
}
2020-08-06 17:44:38 +00:00
res.end(s.prettyPrint(response));
2018-09-28 05:37:08 +00:00
})
},res,req);
})
/**
* API : Get Cloud Video File (proxy)
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/cloudVideos/:ke/:id/:file', function (req,res){
s.auth(req.params,function(user){
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && (user.permissions.watch_videos === "0" || monitorRestrictions.length === 0)){
s.closeJsonResponse(res,{
ok: false,
msg: lang['Not Permitted']
})
2018-09-28 05:37:08 +00:00
return
}
var time = s.nameToTime(req.params.file)
if(req.query.isUTC === 'true'){
time = s.utcToLocal(time)
}
time = new Date(time)
s.knexQuery({
action: "select",
columns: "*",
table: "Cloud Videos",
where: [
['ke','=',groupKey],
['mid','=',req.params.id],
['time','=',time]
],
limit: 1
},(err,r) => {
2018-09-28 05:37:08 +00:00
if(r&&r[0]){
r = r[0]
if(JSON.parse(r.details).type === 'googd' && s.cloudDiskUseOnGetVideoDataExtensions['googd']){
s.cloudDiskUseOnGetVideoDataExtensions['googd'](r).then((dataPipe) => {
dataPipe.pipe(res)
}).catch((err) => {
console.log(err)
res.end(user.lang['File Not Found in Database'])
})
}else{
req.pipe(request(r.href)).pipe(res)
}
2018-09-28 05:37:08 +00:00
}else{
res.end(user.lang['File Not Found in Database'])
}
})
},res,req);
});
/**
* API : Get Video File
*/
const videoRowCaches = {}
const videoRowCacheTimeouts = {}
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/videos/:ke/:id/:file', function (req,res){
s.auth(req.params,function(user){
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && (user.permissions.watch_videos === "0" || monitorRestrictions.length === 0)){
s.closeJsonResponse(res,{
ok: false,
msg: lang['Not Permitted']
})
2018-09-28 05:37:08 +00:00
return
}
var time = s.nameToTime(req.params.file)
if(req.query.isUTC === 'true'){
time = s.utcToLocal(time)
}
time = new Date(time)
const cacheName = Object.values(req.params).join('_')
const cacheVideoRow = (videoRow) => {
videoRowCaches[cacheName] = videoRow
clearTimeout(videoRowCacheTimeouts[cacheName])
videoRowCacheTimeouts[cacheName] = setTimeout(() => {
delete(videoRowCaches[cacheName])
},60000)
}
const sendVideo = (videoRow) => {
cacheVideoRow(videoRow)
const filePath = s.getVideoDirectory(videoRow) + req.params.file
fs.stat(filePath,function(err,stats){
if (!err){
if(req.query.json === 'true'){
s.closeJsonResponse(res,videoRow)
}else{
s.streamMp4FileOverHttp(filePath,req,res)
}
}else{
res.end(user.lang['File Not Found in Filesystem'])
}
})
}
if(videoRowCaches[cacheName]){
sendVideo(videoRowCaches[cacheName])
}else{
s.knexQuery({
action: "select",
columns: "*",
table: "Videos",
where: [
['ke','=',groupKey],
['mid','=',req.params.id],
['time','=',time]
],
limit: 1
},(err,r) => {
const videoRow = r[0]
if(videoRow){
sendVideo(videoRow)
}else{
res.end(user.lang['File Not Found in Database'])
}
})
}
2018-09-28 05:37:08 +00:00
},res,req);
});
/**
* API : Motion Trigger via GET request
*/
app.get(config.webPaths.apiPrefix+':auth/motion/:ke/:id', function (req,res){
s.auth(req.params,function(user){
const groupKey = req.params.ke
const monitorId = req.params.id
const monitorRestrictions = s.getMonitorRestrictions(user.details,monitorId)
if(user.details.sub && user.details.allmonitors === '0' && monitorRestrictions.length === 0){
s.closeJsonResponse(res,{
ok: false,
msg: lang['Not Permitted']
})
return
}
if(req.query.data){
try{
var d = {
id: req.params.id,
ke: req.params.ke,
2019-07-15 02:38:28 +00:00
details: s.parseJSON(req.query.data)
}
}catch(err){
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['Data Broken']
})
return
}
}else{
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['No Data']
})
return
}
if(!d.ke||!d.id||!s.group[d.ke]){
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['No Group with this key exists']
})
return
}
if(!s.group[d.ke].rawMonitorConfigurations[d.id]){
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['Monitor or Key does not exist.']
})
return
}
var details = s.group[d.ke].rawMonitorConfigurations[d.id].details
var detectorHttpApi = details.detector_http_api
2019-07-15 02:38:28 +00:00
var detectorOn = (details.detector === '1')
switch(detectorHttpApi){
case'0':
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['Trigger Blocked']
})
return
break;
case'2':
if(!detectorOn){
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['Trigger Blocked']
})
return
}
break;
case'2':
if(detectorOn){
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: false,
msg: user.lang['Trigger Blocked']
})
return
}
break;
}
d.doObjectDetection = (!d.details.matrices || d.details.matrices.length === 0) && (s.isAtleatOneDetectorPluginConnected && details.detector_use_detect_object === '1')
s.triggerEvent(d)
2019-07-15 02:38:28 +00:00
s.closeJsonResponse(res,{
ok: true,
msg: user.lang['Trigger Successful']
})
},res,req)
})
/**
* API : WebHook Tester
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/hookTester/:ke/:id', function (req,res){
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
s.userLog(req.params,{type:'Test',msg:'Hook Test'})
res.end(s.prettyPrint({ok:true}))
2018-09-28 05:37:08 +00:00
},res,req);
2020-05-05 15:02:23 +00:00
})
/**
2020-05-24 05:12:42 +00:00
* API : Object Detection Counter Status
2020-05-05 15:02:23 +00:00
*/
2020-05-24 05:12:42 +00:00
app.get(config.webPaths.apiPrefix+':auth/eventCountStatus/:ke/:id', function (req,res){
2020-05-05 15:02:23 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
if(user.permissions.watch_videos==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
res.end(user.lang['Not Permitted'])
return
}
2020-05-24 05:12:42 +00:00
var selectedObject = s.group[req.params.ke].activeMonitors[req.params.id].eventsCounted
2020-05-05 15:02:23 +00:00
res.end(s.prettyPrint({
2020-05-24 05:12:42 +00:00
ok: true,
counted: Object.keys(selectedObject).length,
tags: selectedObject,
2020-05-05 15:02:23 +00:00
}))
2020-05-24 20:55:48 +00:00
},res,req)
2020-05-05 15:02:23 +00:00
})
/**
* API : Object Detection Counter Status
*/
2020-05-24 05:12:42 +00:00
app.get([
config.webPaths.apiPrefix+':auth/eventCounts/:ke',
config.webPaths.apiPrefix+':auth/eventCounts/:ke/:id'
], function (req,res){
res.setHeader('Content-Type', 'application/json')
2020-05-05 15:02:23 +00:00
s.auth(req.params,function(user){
2020-05-24 14:41:10 +00:00
const userDetails = user.details
const monitorId = req.params.id
const groupKey = req.params.ke
2020-05-24 15:44:44 +00:00
var hasRestrictions = userDetails.sub && userDetails.allmonitors !== '1';
s.sqlQueryBetweenTimesWithPermissions({
table: 'Events Counts',
user: user,
noCount: true,
groupKey: req.params.ke,
monitorId: req.params.id,
startTime: req.query.start,
endTime: req.query.end,
startTimeOperator: req.query.startOperator,
endTimeOperator: req.query.endOperator,
limit: req.query.limit,
archived: req.query.archived,
endIsStartTo: !!req.query.endIsStartTo,
parseRowDetails: true,
2020-05-24 14:41:10 +00:00
rowName: 'counts',
preliminaryValidationFailed: (
user.permissions.watch_videos === "0" ||
hasRestrictions &&
(!userDetails.video_view || userDetails.video_view.indexOf(monitorId)===-1)
)
},(response) => {
res.end(s.prettyPrint(response))
2020-05-24 05:12:42 +00:00
})
2020-05-24 20:55:48 +00:00
},res,req)
2018-09-28 05:37:08 +00:00
})
/**
* API : Camera PTZ Controller
*/
2018-09-28 05:37:08 +00:00
app.get(config.webPaths.apiPrefix+':auth/control/:ke/:id/:direction', function (req,res){
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
s.cameraControl(req.params,function(msg){
2020-08-11 20:29:15 +00:00
s.userLog({
id: req.params.id,
ke: req.params.ke,
},{
msg: msg,
direction: req.params.direction,
})
res.end(s.prettyPrint(msg))
2018-09-28 05:37:08 +00:00
});
},res,req);
})
/**
* API : Upload Video File
* API : Add "streamIn" query string to Push to "Dashcam (Streamer v2)" FFMPEG Process
*/
app.post(config.webPaths.apiPrefix+':auth/videos/:ke/:id',fileupload(), async (req,res) => {
var response = {ok:false}
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
if(user.permissions.watch_videos==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.video_delete.indexOf(req.params.id)===-1){
res.end(user.lang['Not Permitted'])
return
}
var groupKey = req.params.ke
var monitorId = req.params.id
// req.query.overwrite === '1'
if(s.group[groupKey] && s.group[groupKey].activeMonitors && s.group[groupKey].activeMonitors[monitorId]){
var monitor = s.group[groupKey].rawMonitorConfigurations[monitorId]
try {
if(!req.files) {
res.send({
status: false,
message: 'No file uploaded'
});
} else {
let video = req.files.video;
var time = new Date(parseInt(video.name.split('.')[0]))
var filename = s.formattedTime(time) + '.' + monitor.ext
video.mv(s.getVideoDirectory(monitor) + filename,function(){
s.insertCompletedVideo(monitor,{
file: filename,
events: s.group[groupKey].activeMonitors[monitorId].detector_motion_count,
endTime: req.body.endTime.indexOf('-') > -1 ? s.nameToTime(req.body.endTime) : parseInt(req.body.endTime) || null,
},function(){
response.ok = true
response.filename = filename
res.end(s.prettyPrint({
ok: true,
message: 'File is uploaded',
data: {
name: video.name,
mimetype: video.mimetype,
size: video.size
}
}))
})
});
}
} catch (err) {
response.err = err
res.status(500).end(response)
}
}else{
response.error = 'Non Existant Monitor'
res.end(s.prettyPrint(response))
}
},res,req);
})
/**
* API : Modify Video File
*/
2018-09-28 05:37:08 +00:00
app.get([
config.webPaths.apiPrefix+':auth/videos/:ke/:id/:file/:mode',
config.webPaths.apiPrefix+':auth/videos/:ke/:id/:file/:mode/:f',
config.webPaths.apiPrefix+':auth/cloudVideos/:ke/:id/:file/:mode',
config.webPaths.apiPrefix+':auth/cloudVideos/:ke/:id/:file/:mode/:f'
], function (req,res){
2020-08-06 17:44:38 +00:00
var response = {ok:false};
2018-09-28 05:37:08 +00:00
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
if(user.permissions.watch_videos==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.video_delete.indexOf(req.params.id)===-1){
res.end(user.lang['Not Permitted'])
return
}
var time = s.nameToTime(req.params.file)
if(req.query.isUTC === 'true'){
time = s.utcToLocal(time)
}
time = new Date(time)
var origURL = req.originalUrl.split('/')
var videoParam = origURL[origURL.indexOf(req.params.auth) + 1]
var videoSet = 'Videos'
switch(videoParam){
case'cloudVideos':
videoSet = 'Cloud Videos'
break;
}
2020-07-12 01:06:07 +00:00
const groupKey = req.params.ke
const monitorId = req.params.id
s.knexQuery({
action: "select",
columns: "*",
table: videoSet,
where: [
['ke','=',groupKey],
['mid','=',req.params.id],
['time','=',time]
],
limit: 1
},(err,r) => {
if(r && r[0]){
2018-09-28 05:37:08 +00:00
r=r[0];r.filename=s.formattedTime(r.time)+'.'+r.ext;
switch(req.params.mode){
case'fix':
2020-08-06 17:44:38 +00:00
response.ok = true;
2018-09-28 05:37:08 +00:00
s.video('fix',r)
break;
case'status':
r.f = 'video_edit'
switch(videoParam){
case'cloudVideos':
r.f += '_cloud'
break;
}
r.status = parseInt(req.params.f)
if(isNaN(req.params.f)||req.params.f===0){
2020-08-06 17:44:38 +00:00
response.msg = 'Not a valid value.';
2018-09-28 05:37:08 +00:00
}else{
2020-08-06 17:44:38 +00:00
response.ok = true;
s.knexQuery({
action: "update",
table: videoSet,
update: {
status: req.params.f
},
where: [
['ke','=',groupKey],
['mid','=',req.params.id],
['time','=',time]
]
})
2018-09-28 05:37:08 +00:00
s.tx(r,'GRP_'+r.ke);
}
break;
case'delete':
2020-08-06 17:44:38 +00:00
response.ok = true;
2018-09-28 05:37:08 +00:00
switch(videoParam){
case'cloudVideos':
s.deleteVideoFromCloud(r)
2018-09-28 05:37:08 +00:00
break;
default:
s.deleteVideo(r)
2018-09-28 05:37:08 +00:00
break;
}
break;
default:
2020-08-06 17:44:38 +00:00
response.msg = user.lang.modifyVideoText1;
2018-09-28 05:37:08 +00:00
break;
}
}else{
2020-08-06 17:44:38 +00:00
response.msg = user.lang['No such file'];
2018-09-28 05:37:08 +00:00
}
2020-08-06 17:44:38 +00:00
res.end(s.prettyPrint(response));
2018-09-28 05:37:08 +00:00
})
},res,req);
})
/**
* API : Stream In to push data to ffmpeg by HTTP
*/
app.all('/:auth/streamIn/:ke/:id', function (req, res) {
s.auth(req.params,function(user){
const ipAddress = s.getClientIp(req)
const groupKey = req.params.ke
const monitorId = req.params.id
const timeStartedConnection = new Date();
s.userLog({
ke: groupKey,
mid: monitorId,
},{
type: "HTTP streamIn Started",
msg: {
ipAddress: ipAddress,
}
})
2018-09-28 05:37:08 +00:00
res.connection.setTimeout(0);
req.on('data', function(buffer){
s.group[groupKey].activeMonitors[monitorId].spawn.stdin.write(buffer)
2018-09-28 05:37:08 +00:00
});
req.on('end',function(){
s.userLog({
ke: groupKey,
mid: monitorId,
},{
type: "HTTP streamIn Closed",
msg: {
timeStartedConnection: timeStartedConnection,
ipAddress: ipAddress,
}
})
2018-09-28 05:37:08 +00:00
});
},res,req)
2018-09-28 05:37:08 +00:00
})
/**
* API : Account Edit from Dashboard
*/
app.all(config.webPaths.apiPrefix+':auth/accounts/:ke/edit',function (req,res){
s.auth(req.params,function(user){
var endData = {
ok : false
}
var form = s.getPostData(req)
if(form){
endData.ok = true
s.accountSettingsEdit({
ke: req.params.ke,
uid: user.uid,
form: form,
cnid: user.cnid
})
}else{
endData.msg = lang.postDataBroken
}
s.closeJsonResponse(res,endData)
},res,req)
})
2018-12-04 16:34:59 +00:00
/**
* API : Get Definitions JSON
*/
app.get(config.webPaths.apiPrefix+':auth/definitions/:ke',function (req,res){
s.auth(req.params,function(user){
var endData = {
ok: true,
definitions: s.getDefinitonFile(user.details.lang)
}
s.closeJsonResponse(res,endData)
},res,req)
})
/**
* API : Get Language JSON
*/
app.get(config.webPaths.apiPrefix+':auth/language/:ke',function (req,res){
s.auth(req.params,function(user){
var endData = {
ok: true,
definitions: s.getLanguageFile(user.details.lang)
}
s.closeJsonResponse(res,endData)
},res,req)
})
/**
2018-12-04 16:34:59 +00:00
* Robots.txt
*/
app.get('/robots.txt', function (req,res){
res.on('finish',function(){
res.end()
})
fs.createReadStream(s.mainDirectory + '/web/pages/robots.txt').pipe(res)
})
2018-09-28 05:37:08 +00:00
}