1
0
Fork 0
mirror of https://gitlab.com/Shinobi-Systems/ShinobiCE.git synced 2025-03-09 15:40:15 +00:00

Kicking Kangaroo

This commit is contained in:
Moe 2018-11-10 20:06:56 -08:00
parent bc01b19714
commit e0f7c135af
37 changed files with 1642 additions and 518 deletions

View file

@ -6,6 +6,7 @@ module.exports = function(s,config,lang){
// WebDAV
var beforeAccountSaveForWebDav = function(d){
//d = save event
d.form.details.webdav_use_global=d.d.webdav_use_global
d.form.details.use_webdav=d.d.use_webdav
}
var cloudDiskUseStartupForWebDav = function(group,userDetails){
@ -20,6 +21,15 @@ module.exports = function(s,config,lang){
var loadWebDavForUser = function(e){
// e = user
var ar = JSON.parse(e.details);
if(ar.webdav_use_global === '1' && config.cloudUploaders && config.cloudUploaders.WebDAV){
// {
// webdav_user: "",
// webdav_pass: "",
// webdav_url: "",
// webdav_dir: "",
// }
ar = Object.assign(ar,config.cloudUploaders.WebDAV)
}
//owncloud/webdav
if(!s.group[e.ke].webdav &&
ar.webdav_user&&
@ -150,6 +160,7 @@ module.exports = function(s,config,lang){
//Amazon S3
var beforeAccountSaveForAmazonS3 = function(d){
//d = save event
d.form.details.aws_use_global=d.d.aws_use_global
d.form.details.use_aws_s3=d.d.use_aws_s3
}
var cloudDiskUseStartupForAmazonS3 = function(group,userDetails){
@ -163,7 +174,17 @@ module.exports = function(s,config,lang){
}
var loadAmazonS3ForUser = function(e){
// e = user
var ar = JSON.parse(e.details);
var ar = JSON.parse(e.details)
if(ar.aws_use_global === '1' && config.cloudUploaders && config.cloudUploaders.AmazonS3){
// {
// aws_accessKeyId: "",
// aws_secretAccessKey: "",
// aws_region: "",
// aws_s3_bucket: "",
// aws_s3_dir: "",
// }
ar = Object.assign(ar,config.cloudUploaders.AmazonS3)
}
//Amazon S3
if(!s.group[e.ke].aws &&
!s.group[e.ke].aws_s3 &&
@ -262,7 +283,8 @@ module.exports = function(s,config,lang){
//Backblaze B2
var beforeAccountSaveForBackblazeB2 = function(d){
//d = save event
d.form.details.use_aws_s3=d.d.use_bb_b2
d.form.details.b2_use_global=d.d.b2_use_global
d.form.details.use_bb_b2=d.d.use_bb_b2
}
var cloudDiskUseStartupForBackblazeB2 = function(group,userDetails){
group.cloudDiskUse['b2'].name = 'Backblaze B2'
@ -276,6 +298,15 @@ module.exports = function(s,config,lang){
var loadBackblazeB2ForUser = function(e){
var ar = JSON.parse(e.details);
try{
if(ar.b2_use_global === '1' && config.cloudUploaders && config.cloudUploaders.BackblazeB2){
// {
// bb_b2_accountId: "",
// bb_b2_applicationKey: "",
// bb_b2_bucket: "",
// bb_b2_dir: "",
// }
ar = Object.assign(ar,config.cloudUploaders.BackblazeB2)
}
if(!s.group[e.ke].bb_b2 &&
ar.bb_b2_accountId &&
ar.bb_b2_accountId !=='' &&

View file

@ -1,5 +1,6 @@
var P2P = require('pipe2pam');
var PamDiff = require('pam-diff');
// pamDiff is based on https://www.npmjs.com/package/pam-diff
var PamDiff = require('./detectorPamDiff.js');
module.exports = function(s,config){
s.createPamDiffEngine = function(e){
var width,
@ -64,12 +65,13 @@ module.exports = function(s,config){
plug:'built-in',
name:trigger.name,
reason:'motion',
confidence:trigger.percent,
confidence:trigger.percent
},
plates:[],
imgHeight:height,
imgWidth:width
imgHeight:e.details.detector_scale_y,
imgWidth:e.details.detector_scale_x
}
if(trigger.matrix)detectorObject.details.matrices = [trigger.matrix]
var region = Object.values(regionJson).find(x => x.name == detectorObject.name)
s.checkMaximumSensitivity(e, region, detectorObject, function() {
s.checkTriggerThreshold(e, region, detectorObject, function() {

622
libs/detectorPamDiff.js Normal file
View file

@ -0,0 +1,622 @@
//
// Shinobi - fork of pam-diff
// Copyright (C) 2018 Kevin Godell
// Author : Kevin Godell, https://github.com/kevinGodell
// npmjs : https://www.npmjs.com/package/pam-diff
// Github : https://github.com/kevinGodell/pam-diff
//
'use strict';
const { Transform } = require('stream');
const PP = require('polygon-points');
/**
*
* @param chunk
* @private
*/
var _getMatrixFromPoints = function(thisRegion) {
var coordinates = [
thisRegion.topLeft,
{"x" : thisRegion.bottomRight.x, "y" : thisRegion.topLeft.y},
thisRegion.bottomRight
]
var width = Math.sqrt( Math.pow(coordinates[1].x - coordinates[0].x, 2) + Math.pow(coordinates[1].y - coordinates[0].y, 2));
var height = Math.sqrt( Math.pow(coordinates[2].x - coordinates[1].x, 2) + Math.pow(coordinates[2].y - coordinates[1].y, 2))
return {
x: coordinates[0].x,
y: coordinates[0].y,
width: width,
height: height,
tag: thisRegion.name
}
}
class PamDiff extends Transform {
/**
*
* @param [options] {Object}
* @param [callback] {Function}
*/
constructor(options, callback) {
super(options);
Transform.call(this, {objectMode: true});
this.difference = PamDiff._parseOptions('difference', options);//global option, can be overridden per region
this.percent = PamDiff._parseOptions('percent', options);//global option, can be overridden per region
this.regions = PamDiff._parseOptions('regions', options);//can be no regions or a single region or multiple regions. if no regions, all pixels will be compared.
this.callback = callback;//callback function to be called when pixel difference is detected
this._parseChunk = this._parseFirstChunk;//first parsing will be reading settings and configuring internal pixel reading
}
/**
*
* @param option {String}
* @param options {Object}
* @return {*}
* @private
*/
static _parseOptions(option, options) {
if (options && options.hasOwnProperty(option)) {
return options[option];
}
return null;
}
/**
*
* @param number {Number}
* @param def {Number}
* @param low {Number}
* @param high {Number}
* @return {Number}
* @private
*/
static _validateNumber(number, def, low, high) {
if (isNaN(number)) {
return def;
} else if (number < low) {
return low;
} else if (number > high) {
return high;
} else {
return number;
}
}
/**
*
* @deprecated
* @param string {String}
*/
setGrayscale(string) {
console.warn('grayscale option has been removed, "average" has proven to most accurate and is the default');
}
/**
*
* @param number {Number}
*/
set difference(number) {
this._difference = PamDiff._validateNumber(parseInt(number), 5, 1, 255);
}
/**
*
* @return {Number}
*/
get difference() {
return this._difference;
}
/**
*
* @param number {Number}
* @return {PamDiff}
*/
setDifference(number) {
this.difference = number;
return this;
}
/**
*
* @param number {Number}
*/
set percent(number) {
this._percent = PamDiff._validateNumber(parseInt(number), 5, 1, 100);
}
/**
*
* @return {Number}
*/
get percent() {
return this._percent;
}
/**
*
* @param number {Number}
* @return {PamDiff}
*/
setPercent(number) {
this.percent = number;
return this;
}
/**
*
* @param array {Array}
*/
set regions(array) {
if (!array) {
if (this._regions) {
delete this._regions;
delete this._regionsLength;
delete this._minDiff;
}
this._diffs = 0;
} else if (!Array.isArray(array) || array.length < 1) {
throw new Error(`Regions must be an array of at least 1 region object {name: 'region1', difference: 10, percent: 10, polygon: [[0, 0], [0, 50], [50, 50], [50, 0]]}`);
} else {
this._regions = [];
this._minDiff = 255;
for (const region of array) {
if (!region.hasOwnProperty('name') || !region.hasOwnProperty('polygon')) {
throw new Error('Region must include a name and a polygon property');
}
const polygonPoints = new PP(region.polygon);
const difference = PamDiff._validateNumber(parseInt(region.difference), this._difference, 1, 255);
const percent = PamDiff._validateNumber(parseInt(region.percent), this._percent, 1, 100);
this._minDiff = Math.min(this._minDiff, difference);
this._regions.push(
{
name: region.name,
polygon: polygonPoints,
difference: difference,
percent: percent,
diffs: 0
}
);
}
this._regionsLength = this._regions.length;
this._createPointsInPolygons(this._regions, this._width, this._height);
}
}
/**
*
* @return {Array}
*/
get regions() {
return this._regions;
}
/**
*
* @param array {Array}
* @return {PamDiff}
*/
setRegions(array) {
this.regions = array;
return this;
}
/**
*
* @param func {Function}
*/
set callback(func) {
if (!func) {
delete this._callback;
} else if (typeof func === 'function' && func.length === 1) {
this._callback = func;
} else {
throw new Error('Callback must be a function that accepts 1 argument.');
}
}
/**
*
* @return {Function}
*/
get callback() {
return this._callback;
}
/**
*
* @param func {Function}
* @return {PamDiff}
*/
setCallback(func) {
this.callback = func;
return this;
}
/**
*
* @return {PamDiff}
*/
resetCache() {
//delete this._oldPix;
//delete this._newPix;
//delete this._width;
//delete this._length;
this._parseChunk = this._parseFirstChunk;
return this;
}
/**
*
* @param regions {Array}
* @param width {Number}
* @param height {Number}
* @private
*/
_createPointsInPolygons(regions, width, height) {
if (regions && width && height) {
this._pointsInPolygons = [];
for (const region of regions) {
const bitset = region.polygon.getBitset(this._width, this._height);
region.pointsLength = bitset.count;
this._pointsInPolygons.push(bitset.buffer);
}
}
}
/**
*
* @param chunk
* @private
*/
_blackAndWhitePixelDiff(chunk) {
this._newPix = chunk.pixels;
for (let y = 0, i = 0; y < this._height; y++) {
for (let x = 0; x < this._width; x++, i++) {
const diff = this._oldPix[i] !== this._newPix[i];
if (this._regions && diff === true) {
for (let j = 0; j < this._regionsLength; j++) {
if (this._pointsInPolygons[j][i]) {
this._regions[j].diffs++;
}
}
} else if (diff === true) {
this._diffs++;
}
}
}
if (this._regions) {
const regionDiffArray = [];
for (let i = 0; i < this._regionsLength; i++) {
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
if (percent >= this._regions[i].percent) {
regionDiffArray.push({name: this._regions[i].name, percent: percent});
}
this._regions[i].diffs = 0;
}
if (regionDiffArray.length > 0) {
const data = {trigger: regionDiffArray, pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
} else {
const percent = Math.floor(100 * this._diffs / this._length);
if (percent >= this._percent) {
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
this._diffs = 0;
}
this._oldPix = this._newPix;
}
/**
*
* @param chunk
* @private
*/
_grayScalePixelDiff(chunk) {
this._newPix = chunk.pixels;
for (let j = 0; j < this._regionsLength; j++) {
this._regions[j].topLeft = {
x: this._width,
y: this._height
}
this._regions[j].bottomRight = {
x: 0,
y: 0
}
}
this.topLeft = {
x: this._width,
y: this._height
}
this.bottomRight = {
x: 0,
y: 0
}
for (let y = 0, i = 0; y < this._height; y++) {
for (let x = 0; x < this._width; x++, i++) {
if (this._oldPix[i] !== this._newPix[i]) {
const diff = Math.abs(this._oldPix[i] - this._newPix[i]);
if (this._regions && diff >= this._minDiff) {
for (let j = 0; j < this._regionsLength; j++) {
if (this._pointsInPolygons[j][i] && diff >= this._regions[j].difference) {
var theRegion = this._regions[j]
theRegion.diffs++;
if(theRegion.topLeft.x > x && theRegion.topLeft.y > y){
theRegion.topLeft.x = x
theRegion.topLeft.y = y
}
if(theRegion.bottomRight.x < x && theRegion.bottomRight.y < y){
theRegion.bottomRight.x = x
theRegion.bottomRight.y = y
}
}
}
} else if (diff >= this._difference) {
this._diffs++;
if(this.topLeft.x > x && this.topLeft.y > y){
this.topLeft.x = x
this.topLeft.y = y
}
if(this.bottomRight.x < x && this.bottomRight.y < y){
this.bottomRight.x = x
this.bottomRight.y = y
}
}
}
}
}
if (this._regions) {
const regionDiffArray = [];
for (let i = 0; i < this._regionsLength; i++) {
var thisRegion = this._regions[i]
const percent = Math.floor(100 * thisRegion.diffs / thisRegion.pointsLength);
if (percent >= thisRegion.percent) {
// create matrix from points >>
thisRegion._matrix = _getMatrixFromPoints(thisRegion)
// create matrix from points />>
regionDiffArray.push({name: thisRegion.name, percent: percent, matrix: thisRegion._matrix});
}
thisRegion.diffs = 0;
}
if (regionDiffArray.length > 0) {
this._matrix = _getMatrixFromPoints(this)
const data = {trigger: regionDiffArray, pam: chunk.pam, matrix: this._matrix};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
} else {
const percent = Math.floor(100 * this._diffs / this._length);
if (percent >= this._percent) {
this._matrix = _getMatrixFromPoints(this)
const data = {trigger: [{name: 'percent', percent: percent, matrix: this._matrix}], pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
this._diffs = 0;
}
this._oldPix = this._newPix;
}
/**
*
* @param chunk
* @private
*/
_rgbPixelDiff(chunk) {
this._newPix = chunk.pixels;
for (let y = 0, i = 0, p = 0; y < this._height; y++) {
for (let x = 0; x < this._width; x++, i += 3, p++) {
if (this._oldPix[i] !== this._newPix[i] || this._oldPix[i + 1] !== this._newPix[i + 1] || this._oldPix[i + 2] !== this._newPix[i + 2]) {
const diff = Math.abs(this._oldPix[i] + this._oldPix[i + 1] + this._oldPix[i + 2] - this._newPix[i] - this._newPix[i + 1] - this._newPix[i + 2])/3;
if (this._regions && diff >= this._minDiff) {
for (let j = 0; j < this._regionsLength; j++) {
if (this._pointsInPolygons[j][p] && diff >= this._regions[j].difference) {
this._regions[j].diffs++;
}
}
} else {
if (diff >= this._difference) {
this._diffs++;
}
}
}
}
}
if (this._regions) {
const regionDiffArray = [];
for (let i = 0; i < this._regionsLength; i++) {
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
if (percent >= this._regions[i].percent) {
regionDiffArray.push({name: this._regions[i].name, percent: percent});
}
this._regions[i].diffs = 0;
}
if (regionDiffArray.length > 0) {
const data = {trigger: regionDiffArray, pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
} else {
const percent = Math.floor(100 * this._diffs / this._length);
if (percent >= this._percent) {
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
this._diffs = 0;
}
this._oldPix = this._newPix;
}
/**
*
* @param chunk
* @private
*/
_rgbAlphaPixelDiff(chunk) {
this._newPix = chunk.pixels;
for (let y = 0, i = 0, p = 0; y < this._height; y++) {
for (let x = 0; x < this._width; x++, i += 4, p++) {
if (this._oldPix[i] !== this._newPix[i] || this._oldPix[i + 1] !== this._newPix[i + 1] || this._oldPix[i + 2] !== this._newPix[i + 2]) {
const diff = Math.abs(this._oldPix[i] + this._oldPix[i + 1] + this._oldPix[i + 2] - this._newPix[i] - this._newPix[i + 1] - this._newPix[i + 2])/3;
if (this._regions && diff >= this._minDiff) {
for (let j = 0; j < this._regionsLength; j++) {
if (this._pointsInPolygons[j][p] && diff >= this._regions[j].difference) {
this._regions[j].diffs++;
}
}
} else {
if (diff >= this._difference) {
this._diffs++;
}
}
}
}
}
if (this._regions) {
const regionDiffArray = [];
for (let i = 0; i < this._regionsLength; i++) {
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
if (percent >= this._regions[i].percent) {
regionDiffArray.push({name: this._regions[i].name, percent: percent});
}
this._regions[i].diffs = 0;
}
if (regionDiffArray.length > 0) {
const data = {trigger: regionDiffArray, pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
} else {
const percent = Math.floor(100 * this._diffs / this._length);
if (percent >= this._percent) {
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
if (this._callback) {
this._callback(data);
}
if (this._readableState.pipesCount > 0) {
this.push(data);
}
if (this.listenerCount('diff') > 0) {
this.emit('diff', data);
}
}
this._diffs = 0;
}
this._oldPix = this._newPix;
}
/**
*
* @param chunk
* @private
*/
_parseFirstChunk(chunk) {
this._width = parseInt(chunk.width);
this._height = parseInt(chunk.height);
this._oldPix = chunk.pixels;
this._length = this._width * this._height;
this._createPointsInPolygons(this._regions, this._width, this._height);
switch (chunk.tupltype) {
case 'blackandwhite' :
this._parseChunk = this._blackAndWhitePixelDiff;
break;
case 'grayscale' :
this._parseChunk = this._grayScalePixelDiff;
break;
case 'rgb' :
this._parseChunk = this._rgbPixelDiff;
//this._increment = 3;//future use
break;
case 'rgb_alpha' :
this._parseChunk = this._rgbAlphaPixelDiff;
//this._increment = 4;//future use
break;
default :
throw Error(`Unsupported tupltype: ${chunk.tupltype}. Supported tupltypes include grayscale(gray), blackandwhite(monob), rgb(rgb24), and rgb_alpha(rgba).`);
}
}
/**
*
* @param chunk
* @param encoding
* @param callback
* @private
*/
_transform(chunk, encoding, callback) {
this._parseChunk(chunk);
callback();
}
/**
*
* @param callback
* @private
*/
_flush(callback) {
this.resetCache();
callback();
}
}
/**
*
* @type {PamDiff}
*/
module.exports = PamDiff;
//todo get bounding box of all regions combined to exclude some pixels before checking if they exist inside specific regions

View file

@ -12,9 +12,7 @@ module.exports = function(s,config,lang){
})
break;
case'delete':
d.videos.forEach(function(v,n){
s.deleteVideo(v)
})
s.deleteListOfVideos(d.videos)
break;
case'execute':
exec(d.execute,{detached: true})
@ -373,6 +371,7 @@ module.exports = function(s,config,lang){
delete(s.api[d.auth])
s.userLog(d,{type:"Traditional Recording",msg:'Clear Recorder Process'})
delete(s.group[d.ke].mon[d.id].eventBasedRecording.process)
clearTimeout(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
delete(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
clearTimeout(s.group[d.ke].mon[d.id].recordingChecker)
})

View file

@ -526,12 +526,9 @@ module.exports = function(s,config,onFinish){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.stream)
}
console.log('x.cust_stream',x.cust_stream)
if(x.stream_fps && (e.details.stream_vcodec !== 'copy' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64')){
x.cust_stream += x.stream_fps
}
console.log('x.cust_stream',x.cust_stream)
switch(e.details.stream_type){
case'mp4':
x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1'

View file

@ -1,31 +1,31 @@
var fs = require('fs');
module.exports = function(s,config){
//directories
s.group={};
s.group = {}
if(!config.windowsTempDir&&s.isWin===true){config.windowsTempDir='C:/Windows/Temp'}
if(!config.defaultMjpeg){config.defaultMjpeg=s.mainDirectory+'/web/libs/img/bg.jpg'}
//default stream folder check
if(!config.streamDir){
if(s.isWin===false){
config.streamDir='/dev/shm'
if(s.isWin === false){
config.streamDir = '/dev/shm'
}else{
config.streamDir=config.windowsTempDir
config.streamDir = config.windowsTempDir
}
if(!fs.existsSync(config.streamDir)){
config.streamDir=s.mainDirectory+'/streams/'
config.streamDir = s.mainDirectory+'/streams/'
}else{
config.streamDir+='/streams/'
config.streamDir += '/streams/'
}
}
if(!config.videosDir){config.videosDir=s.mainDirectory+'/videos/'}
if(!config.binDir){config.binDir=s.mainDirectory+'/fileBin/'}
if(!config.addStorage){config.addStorage=[]}
s.dir={
videos:s.checkCorrectPathEnding(config.videosDir),
streams:s.checkCorrectPathEnding(config.streamDir),
fileBin:s.checkCorrectPathEnding(config.binDir),
addStorage:config.addStorage,
languages:s.location.languages+'/'
videos: s.checkCorrectPathEnding(config.videosDir),
streams: s.checkCorrectPathEnding(config.streamDir),
fileBin: s.checkCorrectPathEnding(config.binDir),
addStorage: config.addStorage,
languages: s.location.languages+'/'
};
//streams dir
if(!fs.existsSync(s.dir.streams)){
@ -41,7 +41,7 @@ module.exports = function(s,config){
}
//additional storage areas
s.dir.addStorage.forEach(function(v,n){
v.path=s.checkCorrectPathEnding(v.path)
v.path = s.checkCorrectPathEnding(v.path)
if(!fs.existsSync(v.path)){
fs.mkdirSync(v.path);
}

View file

@ -73,6 +73,16 @@ module.exports = function(s,config,lang){
if(noPath !== true)url += e.path
return url
}
s.cleanMonitorObjectForDatabase = function(dirtyMonitor){
var cleanMonitor = {}
var acceptedFields = ['mid','ke','name','shto','shfr','details','type','ext','protocol','host','path','port','fps','mode','width','height']
Object.keys(dirtyMonitor).forEach(function(key){
if(acceptedFields.indexOf(key) > -1){
cleanMonitor[key] = dirtyMonitor[key]
}
})
return cleanMonitor
}
s.cleanMonitorObject = function(e){
x={keys:Object.keys(e),ar:{}};
x.keys.forEach(function(v){
@ -89,18 +99,28 @@ module.exports = function(s,config,lang){
}
var url
var runExtraction = function(){
var snapBuffer = []
var snapProcess = spawn(config.ffmpegDir,('-loglevel quiet -re -i '+url+options+' -frames:v 1 -f mjpeg pipe:1').split(' '),{detached: true})
snapProcess.stdout.on('data',function(data){
snapBuffer.push(data)
});
snapProcess.stderr.on('data',function(data){
console.log(data.toString())
});
snapProcess.on('close',function(data){
snapBuffer = Buffer.concat(snapBuffer)
callback(snapBuffer,false)
})
try{
var snapBuffer = []
var snapProcess = spawn(config.ffmpegDir,('-loglevel quiet -re -i '+url+options+' -frames:v 1 -f image2pipe pipe:1').split(' '),{detached: true})
snapProcess.stdout.on('data',function(data){
snapBuffer.push(data)
})
snapProcess.stderr.on('data',function(data){
console.log(data.toString())
})
snapProcess.on('exit',function(data){
clearTimeout(snapProcessTimeout)
snapBuffer = Buffer.concat(snapBuffer)
callback(snapBuffer,false)
})
var snapProcessTimeout = setTimeout(function(){
snapProcess.stdin.setEncoding('utf8')
snapProcess.stdin.write('q')
delete(snapProcessTimeout)
},5000)
}catch(err){
callback(fs.readFileSync(config.defaultMjpeg,'binary'),false)
}
}
var checkExists = function(localStream,callback){
fs.stat(localStream,function(err){
@ -230,6 +250,7 @@ module.exports = function(s,config,lang){
clearTimeout(s.group[e.ke].mon[e.id].watchdog_stop);
delete(s.group[e.ke].mon[e.id].watchdog_stop);
delete(s.group[e.ke].mon[e.id].lastJpegDetectorFrame);
delete(s.group[e.ke].mon[e.id].detectorFrameSaveBuffer);
clearTimeout(s.group[e.ke].mon[e.id].recordingSnapper);
clearInterval(s.group[e.ke].mon[e.id].getMonitorCpuUsage);
if(s.group[e.ke].mon[e.id].onChildNodeExit){
@ -377,7 +398,7 @@ module.exports = function(s,config,lang){
}
}
//create onvif connection
if(!s.group[e.ke].mon[e.id].onvifConnection){
if(!s.group[e.ke].mon[e.id].onvifConnection || !s.group[e.ke].mon[e.id].onvifConnection.current_profile || !s.group[e.ke].mon[e.id].onvifConnection.current_profile.token){
s.group[e.ke].mon[e.id].onvifConnection = new onvif.OnvifDevice({
xaddr : 'http://' + controlURLOptions.host + ':' + controlURLOptions.port + '/onvif/device_service',
user : controlURLOptions.username,
@ -494,8 +515,8 @@ module.exports = function(s,config,lang){
}
s.cameraSendSnapshot = function(e){
s.checkDetails(e)
if(config.doSnapshot===true){
if(e.mon.mode!=='stop'){
if(config.doSnapshot === true){
if(e.mon.mode !== 'stop'){
var pathDir = s.dir.streams+e.ke+'/'+e.mid+'/'
fs.stat(pathDir+'icon.jpg',function(err){
if(!err){
@ -505,36 +526,22 @@ module.exports = function(s,config,lang){
})
}else{
e.url = s.buildMonitorUrl(e.mon)
switch(e.mon.type){
case'mjpeg':case'h264':case'local':
if(e.mon.type==='local'){e.url=e.mon.path;}
s.getRawSnapshotFromMonitor(e.mon,'-s 200x200',function(data,isStaticFile){
if((data[data.length-2] === 0xFF && data[data.length-1] === 0xD9)){
if(!isStaticFile){
fs.writeFile(s.dir.streams+e.ke+'/'+e.mid+'/icon.jpg',data,function(){})
}
s.tx({
f:'monitor_snapshot',
snapshot:data.toString('base64'),
snapshot_format:'b64',
mid:e.mid,
ke:e.ke
},'GRP_'+e.ke)
}else{
s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
}
})
break;
case'jpeg':
request({url:e.url,method:'GET',encoding:null},function(err,data){
if(err){s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke);return};
s.tx({f:'monitor_snapshot',snapshot:data.body,snapshot_format:'ab',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
})
break;
default:
s.tx({f:'monitor_snapshot',snapshot:'...',snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
break;
}
s.getRawSnapshotFromMonitor(e.mon,'-s 200x200',function(data,isStaticFile){
if((data[data.length-2] === 0xFF && data[data.length-1] === 0xD9)){
if(!isStaticFile){
fs.writeFile(s.dir.streams+e.ke+'/'+e.mid+'/icon.jpg',data,function(){})
}
s.tx({
f: 'monitor_snapshot',
snapshot: data.toString('base64'),
snapshot_format: 'b64',
mid: e.mid,
ke: e.ke
},'GRP_'+e.ke)
}else{
s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
}
})
}
})
}else{
@ -777,10 +784,34 @@ module.exports = function(s,config,lang){
s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d
})
}
}else{
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
})
}else if(s.ocv){
if(s.ocv.connectionType !== 'ram'){
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
})
}else{
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
if(!s.group[e.ke].mon[e.id].detectorFrameSaveBuffer){
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer=[d]
}else{
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer.push(d)
}
if(d[d.length-2] === 0xFF && d[d.length-1] === 0xD9){
var buffer = Buffer.concat(s.group[e.ke].mon[e.id].detectorFrameSaveBuffer);
var frameLocation = s.dir.streams + e.ke + '/' + e.id + '/' + s.gid(5) + '.jpg'
if(s.ocv){
fs.writeFile(frameLocation,buffer,function(err){
if(err){
s.debugLog(err)
}else{
s.ocvTx({f:'frameFromRam',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frameLocation:frameLocation})
}
})
}
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer = null;
}
})
}
}
}
//frames to stream
@ -1192,6 +1223,92 @@ module.exports = function(s,config,lang){
}catch(err){}
return false
}
s.addOrEditMonitor = function(form,callback,user){
var endData = {
ok: false
}
if(!form.mid){
endData.msg = lang['No Monitor ID Present in Form']
callback(endData)
return
}
form.mid = form.mid.replace(/[^\w\s]/gi,'').replace(/ /g,'')
form = s.cleanMonitorObjectForDatabase(form)
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[form.ke,form.mid],function(er,r){
var affectMonitor = false
var monitorQuery = []
var monitorQueryValues = []
var txData = {
f: 'monitor_edit',
mid: form.mid,
ke: form.ke,
mon: form
}
if(r&&r[0]){
txData.new = false
Object.keys(form).forEach(function(v){
if(form[v]&&form[v]!==''){
monitorQuery.push(v+'=?')
if(form[v] instanceof Object){
form[v] = s.s(form[v])
}
monitorQueryValues.push(form[v])
}
})
monitorQuery = monitorQuery.join(',')
monitorQueryValues.push(form.ke)
monitorQueryValues.push(form.mid)
s.userLog(form,{type:'Monitor Updated',msg:'by user : '+user.uid})
endData.msg = user.lang['Monitor Updated by user']+' : '+user.uid
s.sqlQuery('UPDATE Monitors SET '+monitorQuery+' WHERE ke=? AND mid=?',monitorQueryValues)
affectMonitor = true
}else if(
!s.group[form.ke].init.max_camera ||
s.group[form.ke].init.max_camera === '' ||
Object.keys(s.group[form.ke].mon).length <= parseInt(s.group[form.ke].init.max_camera)
){
txData.new = true
monitorQueryInsertValues = []
Object.keys(form).forEach(function(v){
if(form[v] && form[v] !== ''){
monitorQuery.push(v)
monitorQueryInsertValues.push('?')
if(form[v] instanceof Object){
form[v] = s.s(form[v])
}
monitorQueryValues.push(form[v])
}
})
monitorQuery = monitorQuery.join(',')
monitorQueryInsertValues = monitorQueryInsertValues.join(',')
s.userLog(form,{type:'Monitor Added',msg:'by user : '+user.uid})
endData.msg = user.lang['Monitor Added by user']+' : '+user.uid
s.sqlQuery('INSERT INTO Monitors ('+monitorQuery+') VALUES ('+monitorQueryInsertValues+')',monitorQueryValues)
affectMonitor = true
}else{
txData.f = 'monitor_edit_failed'
txData.ff = 'max_reached'
endData.msg = user.lang.monitorEditFailedMaxReached
}
if(affectMonitor === true){
form.details = JSON.parse(form.details)
endData.ok = true
s.initiateMonitorObject({mid:form.mid,ke:form.ke})
s.group[form.ke].mon_conf[form.mid] = s.cleanMonitorObject(form)
if(form.mode === 'stop'){
s.camera('stop',form)
}else{
s.camera('stop',form)
setTimeout(function(){
s.camera(form.mode,form)
},5000)
}
s.tx(txData,'STR_'+form.ke)
}
s.tx(txData,'GRP_'+form.ke)
callback(!endData.ok,endData)
})
}
s.camera = function(x,e,cn){
// x = function or mode
// e = monitor object

View file

@ -30,8 +30,15 @@ module.exports = function(s,config,lang){
s.systemLog('Connected to plugin : Detector - '+d.plug+' - '+d.type)
switch(d.type){
default:case'detector':
s.ocv={started:s.timeObject(),id:cn.id,plug:d.plug,notice:d.notice,isClientPlugin:true};
cn.ocv=1;
s.ocv = {
started: s.timeObject(),
id: cn.id,
plug: d.plug,
notice: d.notice,
isClientPlugin: true,
connectionType: d.connectionType
};
cn.ocv = 1;
s.tx({f:'detector_plugged',plug:d.plug,notice:d.notice},'CPU')
break;
}
@ -39,7 +46,14 @@ module.exports = function(s,config,lang){
//is in host mode (camera.js is client)
switch(d.type){
default:case'detector':
s.ocv={started:s.timeObject(),id:"host",plug:d.plug,notice:d.notice,isHostPlugin:true};
s.ocv = {
started:s.timeObject(),
id:"host",
plug:d.plug,
notice:d.notice,
isHostPlugin:true,
connectionType: d.connectionType
};
break;
}
}

View file

@ -6,6 +6,7 @@ var spawn = require('child_process').spawn;
var jsonfile = require("jsonfile");
var onvif = require("node-onvif");
module.exports = function(s,config,lang,io){
s.clientSocketConnection = {}
//send data to detector plugin
s.ocvTx=function(data){
if(!s.ocv){return}
@ -426,7 +427,15 @@ module.exports = function(s,config,lang,io){
// if(!s.group[d.ke].vid)s.group[d.ke].vid={};
if(!s.group[d.ke].users)s.group[d.ke].users={};
// s.group[d.ke].vid[cn.id]={uid:d.uid};
s.group[d.ke].users[d.auth]={cnid:cn.id,uid:r.uid,mail:r.mail,details:JSON.parse(r.details),logged_in_at:s.timeObject(new Date).format(),login_type:'Dashboard'}
s.group[d.ke].users[d.auth] = {
cnid: cn.id,
uid: r.uid,
mail: r.mail,
details: JSON.parse(r.details),
logged_in_at: s.timeObject(new Date).format(),
login_type: 'Dashboard'
}
s.clientSocketConnection[cn.id] = cn
try{s.group[d.ke].users[d.auth].details=JSON.parse(r.details)}catch(er){}
if(s.group[d.ke].users[d.auth].details.get_server_log!=='0'){
cn.join('GRPLOG_'+d.ke)
@ -588,75 +597,8 @@ module.exports = function(s,config,lang,io){
}
break;
case'edit':
s.sqlQuery('SELECT details FROM Users WHERE ke=? AND uid=?',[d.ke,d.uid],function(err,r){
if(r&&r[0]){
r=r[0];
d.d=JSON.parse(r.details);
if(!d.d.sub || d.d.user_change === "1"){
if(d.d.get_server_log==='1'){
cn.join('GRPLOG_'+d.ke)
}else{
cn.leave('GRPLOG_'+d.ke)
}
///unchangeable from client side, so reset them in case they did.
d.form.details=JSON.parse(d.form.details)
s.beforeAccountSaveExtensions.forEach(function(extender){
extender(d)
})
//admin permissions
d.form.details.permissions=d.d.permissions
d.form.details.edit_size=d.d.edit_size
d.form.details.edit_days=d.d.edit_days
d.form.details.use_admin=d.d.use_admin
d.form.details.use_ldap=d.d.use_ldap
//check
if(d.d.edit_days=="0"){
d.form.details.days=d.d.days;
}
if(d.d.edit_size=="0"){
d.form.details.size=d.d.size;
}
if(d.d.sub){
d.form.details.sub=d.d.sub;
if(d.d.monitors){d.form.details.monitors=d.d.monitors;}
if(d.d.allmonitors){d.form.details.allmonitors=d.d.allmonitors;}
if(d.d.monitor_create){d.form.details.monitor_create=d.d.monitor_create;}
if(d.d.video_delete){d.form.details.video_delete=d.d.video_delete;}
if(d.d.video_view){d.form.details.video_view=d.d.video_view;}
if(d.d.monitor_edit){d.form.details.monitor_edit=d.d.monitor_edit;}
if(d.d.size){d.form.details.size=d.d.size;}
if(d.d.days){d.form.details.days=d.d.days;}
delete(d.form.details.mon_groups)
}
var newSize = d.form.details.size || 10000
d.form.details=JSON.stringify(d.form.details)
///
d.set=[],d.ar=[];
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.createHash(d.form.pass);}else{delete(d.form.pass)};
delete(d.form.password_again);
d.for=Object.keys(d.form);
d.for.forEach(function(v){
d.set.push(v+'=?'),d.ar.push(d.form[v]);
});
d.ar.push(d.ke),d.ar.push(d.uid);
s.sqlQuery('UPDATE Users SET '+d.set.join(',')+' WHERE ke=? AND uid=?',d.ar,function(err,r){
if(!d.d.sub){
var user = Object.assign(d.form,{ke : d.ke})
var userDetails = JSON.parse(d.form.details)
s.group[d.ke].sizeLimit = parseFloat(newSize)
s.onAccountSaveExtensions.forEach(function(extender){
extender(s.group[d.ke],userDetails)
})
s.unloadGroupAppExtensions.forEach(function(extender){
extender(user)
})
s.loadGroupApps(d)
}
tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form});
});
}
}
})
d.cnid = cn.id
s.accountSettingsEdit(d)
break;
}
break;
@ -1428,6 +1370,7 @@ module.exports = function(s,config,lang,io){
if(cn.superSessionKey){
delete(s.superUsersApi[cn.superSessionKey])
}
delete(s.clientSocketConnection[cn.id])
})
});
}

View file

@ -50,6 +50,9 @@ module.exports = function(s,config){
if(!onMoveOn){onMoveOn=function(){}}
var mergedQuery = s.mergeQueryValues(query,values)
s.debugLog('s.sqlQuery QUERY',mergedQuery)
if(!s.databaseEngine || !s.databaseEngine.raw){
s.connectDatabase()
}
return s.databaseEngine
.raw(query,values)
.asCallback(function(err,r){
@ -70,11 +73,18 @@ module.exports = function(s,config){
}
})
}
s.connectDatabase = function(){
s.databaseEngine = require('knex')(s.databaseOptions)
}
s.preQueries = function(){
//add Cloud Videos table, will remove in future
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\' COMMENT \'0:Complete,1:Read,2:Archive\',`details` text) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
// if(err)console.log(err)
},true)
//add monitorStates to Preset ENUM
s.sqlQuery('ALTER TABLE `Presets` CHANGE COLUMN `type` `type` VARCHAR(50) NULL DEFAULT NULL AFTER `details`;',[],function(err){
// if(err)console.log(err)
},true)
//create Files table
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Files` (`ke` varchar(50) NOT NULL,`mid` varchar(50) NOT NULL,`name` tinytext NOT NULL,`size` float NOT NULL DEFAULT \'0\',`details` text NOT NULL,`status` int(1) NOT NULL DEFAULT \'0\') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
// if(err)console.log(err)

View file

@ -29,6 +29,7 @@ module.exports = function(s,config,lang,io){
orphanedVideosForMonitors[monitor.ke][monitor.mid] += orphanedFilesCount
}
s.group[monitor.ke].mon_conf[monitor.mid] = monitor
s.sendMonitorStatus({id:monitor.mid,ke:monitor.ke,status:'Stopped'});
var monObj = Object.assign(monitor,{id : monitor.mid})
s.camera(monitor.mode,monObj)
++loadCompleted

View file

@ -230,6 +230,79 @@ module.exports = function(s,config){
s.group[e.ke].init[v]=ar[v]
})
}
});
})
}
s.accountSettingsEdit = function(d){
s.sqlQuery('SELECT details FROM Users WHERE ke=? AND uid=?',[d.ke,d.uid],function(err,r){
if(r&&r[0]){
r=r[0];
d.d=JSON.parse(r.details);
if(!d.d.sub || d.d.user_change !== "0"){
if(d.cnid){
if(d.d.get_server_log==='1'){
s.clientSocketConnection[d.cnid].join('GRPLOG_'+d.ke)
}else{
s.clientSocketConnection[d.cnid].leave('GRPLOG_'+d.ke)
}
}
///unchangeable from client side, so reset them in case they did.
d.form.details=JSON.parse(d.form.details)
s.beforeAccountSaveExtensions.forEach(function(extender){
extender(d)
})
//admin permissions
d.form.details.permissions=d.d.permissions
d.form.details.edit_size=d.d.edit_size
d.form.details.edit_days=d.d.edit_days
d.form.details.use_admin=d.d.use_admin
d.form.details.use_ldap=d.d.use_ldap
//check
if(d.d.edit_days=="0"){
d.form.details.days=d.d.days;
}
if(d.d.edit_size=="0"){
d.form.details.size=d.d.size;
}
if(d.d.sub){
d.form.details.sub=d.d.sub;
if(d.d.monitors){d.form.details.monitors=d.d.monitors;}
if(d.d.allmonitors){d.form.details.allmonitors=d.d.allmonitors;}
if(d.d.monitor_create){d.form.details.monitor_create=d.d.monitor_create;}
if(d.d.video_delete){d.form.details.video_delete=d.d.video_delete;}
if(d.d.video_view){d.form.details.video_view=d.d.video_view;}
if(d.d.monitor_edit){d.form.details.monitor_edit=d.d.monitor_edit;}
if(d.d.size){d.form.details.size=d.d.size;}
if(d.d.days){d.form.details.days=d.d.days;}
delete(d.form.details.mon_groups)
}
var newSize = d.form.details.size || 10000
d.form.details=JSON.stringify(d.form.details)
///
d.set=[],d.ar=[];
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.createHash(d.form.pass);}else{delete(d.form.pass)};
delete(d.form.password_again);
d.for=Object.keys(d.form);
d.for.forEach(function(v){
d.set.push(v+'=?'),d.ar.push(d.form[v]);
});
d.ar.push(d.ke),d.ar.push(d.uid);
s.sqlQuery('UPDATE Users SET '+d.set.join(',')+' WHERE ke=? AND uid=?',d.ar,function(err,r){
if(!d.d.sub){
var user = Object.assign(d.form,{ke : d.ke})
var userDetails = JSON.parse(d.form.details)
s.group[d.ke].sizeLimit = parseFloat(newSize)
s.onAccountSaveExtensions.forEach(function(extender){
extender(s.group[d.ke],userDetails)
})
s.unloadGroupAppExtensions.forEach(function(extender){
extender(user)
})
s.loadGroupApps(d)
}
if(d.cnid)s.tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form},d.cnid)
})
}
}
})
}
}

View file

@ -230,17 +230,69 @@ module.exports = function(s,config,lang){
})
})
})
var videoSnap = s.dir.videoSnaps + e.ke + '/' + e.mid + '/' + filename.split('.')[0] + '.jpg'
fs.chmod(videoSnap,0o777,function(err){
if(!err){
fs.unlink(videoSnap,function(err){})
}
})
}else{
console.log(new Error())
console.log(lang['Database row does not exist'],queryValues)
}
})
}
s.deleteListOfVideos = function(videos){
var query = 'DELETE FROM Videos WHERE '
var videoQuery = []
var queryValues = []
videos.forEach(function(video){
s.checkDetails(video)
//e = video object
video.dir = s.getVideoDirectory(video)
if(!video.filename && video.time){
video.filename = s.formattedTime(video.time)
}
var filename,
time
if(video.filename.indexOf('.')>-1){
filename = video.filename
}else{
filename = video.filename+'.'+video.ext
}
if(video.filename && !video.time){
time = s.nameToTime(filename)
}else{
time = video.time
}
time = new Date(time)
fs.chmod(video.dir+filename,0o777,function(err){
s.tx({
f: 'video_delete',
filename: filename,
mid: video.id,
ke: video.ke,
time: s.nameToTime(filename),
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
},'GRP_'+video.ke);
s.setDiskUsedForGroup(video,-(video.size / 1000000))
fs.unlink(video.dir+filename,function(err){
fs.stat(video.dir+filename,function(err){
if(!err){
s.file('delete',video.dir+filename)
}
})
})
})
videoQuery.push('(`mid`=? AND `ke`=? AND `time`=?)')
queryValues = queryValues.concat([video.id,video.ke,time])
})
query += videoQuery.join(' OR ')
s.sqlQuery(query,queryValues,function(err){
if(err){
s.systemLog(lang['List of Videos Delete Error'],err)
}
})
}
s.deleteVideoFromCloudExtensions = {}
s.deleteVideoFromCloudExtensionsRunner = function(e,storageType,video){
// e = user

View file

@ -4,7 +4,52 @@ var https = require('https');
var express = require('express');
var app = express()
module.exports = function(s,config,lang,io){
var server = http.createServer(app);
//get page URL
if(!config.baseURL){
config.baseURL = ""
}else if(config.baseURL !== ''){
config.baseURL = s.checkCorrectPathEnding(config.baseURL)
}
//Render Configurations - Web Paths
if(config.webPaths === undefined){config.webPaths={}}
//main access URI
if(config.webPaths.home === undefined){config.webPaths.home='/'}
//Super User URI
if(config.webPaths.super === undefined){config.webPaths.super='/super'}
//Admin URI
if(config.webPaths.admin === undefined){config.webPaths.admin='/admin'}
//Libraries URI
if(config.webPaths.libs === undefined){config.webPaths.libs='/libs'}
//API Prefix
if(config.webPaths.apiPrefix === undefined){config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.home)}else{config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.apiPrefix)}
//Admin API Prefix
if(config.webPaths.adminApiPrefix === undefined){config.webPaths.adminApiPrefix=s.checkCorrectPathEnding(config.webPaths.admin)}else{config.webPaths.adminApiPrefix = s.checkCorrectPathEnding(config.webPaths.adminApiPrefix)}
//Super API Prefix
if(config.webPaths.superApiPrefix === undefined){config.webPaths.superApiPrefix=s.checkCorrectPathEnding(config.webPaths.super)}else{config.webPaths.superApiPrefix = s.checkCorrectPathEnding(config.webPaths.superApiPrefix)}
//Render Configurations - Page Render Paths
if(config.renderPaths === undefined){config.renderPaths={}}
//login page
if(config.renderPaths.index === undefined){config.renderPaths.index='pages/index'}
//dashboard page
if(config.renderPaths.home === undefined){config.renderPaths.home='pages/home'}
//sub-account administration page
if(config.renderPaths.admin === undefined){config.renderPaths.admin='pages/admin'}
//superuser page
if(config.renderPaths.super === undefined){config.renderPaths.super='pages/super'}
//2-Factor Auth page
if(config.renderPaths.factorAuth === undefined){config.renderPaths.factorAuth='pages/factor'}
//Streamer v1 (Dashcam Prototype) page
if(config.renderPaths.streamer === undefined){config.renderPaths.streamer='pages/streamer'}
//Streamer v2 (Dashcam) page
if(config.renderPaths.dashcam === undefined){config.renderPaths.dashcam='pages/dashcam'}
//embeddable widget page
if(config.renderPaths.embed === undefined){config.renderPaths.embed='pages/embed'}
//mjpeg full screen page
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
//gridstack only page
if(config.renderPaths.grid === undefined){config.renderPaths.grid='pages/grid'}
//slick.js (cycle) page
if(config.renderPaths.cycle === undefined){config.renderPaths.cycle='pages/cycle'}
//SSL options
if(config.ssl&&config.ssl.key&&config.ssl.cert){
config.ssl.key=fs.readFileSync(s.checkRelativePath(config.ssl.key),'utf8')
@ -24,12 +69,47 @@ module.exports = function(s,config,lang,io){
serverHTTPS.listen(config.ssl.port,config.bindip,function(){
console.log('SSL '+lang.Shinobi+' : SSL Web Server Listening on '+config.ssl.port);
});
io.attach(serverHTTPS);
if(config.webPaths.home !== '/'){
io.attach(serverHTTPS,{
path:'/socket.io',
transports: ['websocket']
})
}
io.attach(serverHTTPS,{
path:s.checkCorrectPathEnding(config.webPaths.home)+'socket.io',
transports: ['websocket']
})
io.attach(serverHTTPS,{
path:s.checkCorrectPathEnding(config.webPaths.admin)+'socket.io',
transports: ['websocket']
})
io.attach(serverHTTPS,{
path:s.checkCorrectPathEnding(config.webPaths.super)+'socket.io',
transports: ['websocket']
})
}
//start HTTP
var server = http.createServer(app);
server.listen(config.port,config.bindip,function(){
console.log(lang.Shinobi+' : Web Server Listening on '+config.port);
});
io.attach(server);
if(config.webPaths.home !== '/'){
io.attach(server,{
path:'/socket.io',
transports: ['websocket']
})
}
io.attach(server,{
path:s.checkCorrectPathEnding(config.webPaths.home)+'socket.io',
transports: ['websocket']
})
io.attach(server,{
path:s.checkCorrectPathEnding(config.webPaths.admin)+'socket.io',
transports: ['websocket']
})
io.attach(server,{
path:s.checkCorrectPathEnding(config.webPaths.super)+'socket.io',
transports: ['websocket']
})
return app
}

View file

@ -7,10 +7,6 @@ var exec = require('child_process').exec;
var spawn = require('child_process').spawn;
var execSync = require('child_process').execSync;
module.exports = function(s,config,lang,app){
var closeResponse = function(res,endData){
res.setHeader('Content-Type', 'application/json')
res.end(s.prettyPrint(endData))
}
/**
* API : Administrator : Edit Sub-Account (Account to share cameras with)
*/
@ -21,7 +17,7 @@ module.exports = function(s,config,lang,app){
}
if(user.details.sub){
endData.msg = user.lang['Not Permitted']
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
return
}
var form = s.getPostData(req)
@ -56,7 +52,7 @@ module.exports = function(s,config,lang,app){
}else{
endData.msg = lang.postDataBroken
}
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
},res,req)
})
/**
@ -69,7 +65,7 @@ module.exports = function(s,config,lang,app){
}
if(user.details.sub){
endData.msg = user.lang['Not Permitted']
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
return
}
var uid = s.getPostData(req,'uid',false)
@ -90,7 +86,7 @@ module.exports = function(s,config,lang,app){
mail: mail
},'ADM_'+req.params.ke)
endData.ok = true
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
},res,req)
})
/**
@ -109,7 +105,7 @@ module.exports = function(s,config,lang,app){
s.auth(req.params,function(user){
if(user.details.sub){
endData.msg = user.lang['Not an Administrator Account']
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
return
}
var form = s.getPostData(req)
@ -159,7 +155,9 @@ module.exports = function(s,config,lang,app){
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id',
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id/:f'
], function (req,res){
req.ret={ok:false};
var endData = {
ok: false
}
res.setHeader('Content-Type', 'application/json');
res.header("Access-Control-Allow-Origin",req.headers.origin);
s.auth(req.params,function(user){
@ -167,88 +165,28 @@ module.exports = function(s,config,lang,app){
if(req.params.f !== 'delete'){
var form = s.getPostData(req)
if(!form){
req.ret.msg = user.lang.monitorEditText1;
res.end(s.prettyPrint(req.ret))
return
endData.msg = user.lang.monitorEditText1;
res.end(s.prettyPrint(endData))
return
}
form.mid = req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,'')
if(!user.details.sub ||
user.details.allmonitors === '1' ||
hasRestrictions && user.details.monitor_edit.indexOf(form.mid) >- 1 ||
hasRestrictions && user.details.monitor_create === '1'){
if(form&&form.mid&&form.name){
req.set=[],req.ar=[];
form.mid=req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,'');
try{
JSON.parse(form.details)
}catch(er){
if(!form.details||!form.details.stream_type){
req.ret.msg=user.lang.monitorEditText2;
res.end(s.prettyPrint(req.ret))
return
}else{
form.details=JSON.stringify(form.details)
}
}
form.ke=req.params.ke
req.logObject={details:JSON.parse(form.details),ke:req.params.ke,mid:req.params.id}
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[form.ke,form.mid],function(er,r){
req.tx={f:'monitor_edit',mid:form.mid,ke:form.ke,mon:form};
if(r&&r[0]){
req.tx.new=false;
Object.keys(form).forEach(function(v){
if(form[v]&&form[v]!==''){
req.set.push(v+'=?'),req.ar.push(form[v]);
}
})
req.set=req.set.join(',');
req.ar.push(form.ke),req.ar.push(form.mid);
s.userLog(form,{type:'Monitor Updated',msg:'by user : '+user.uid});
req.ret.msg=user.lang['Monitor Updated by user']+' : '+user.uid;
s.sqlQuery('UPDATE Monitors SET '+req.set+' WHERE ke=? AND mid=?',req.ar)
req.finish=1;
}else{
if(!s.group[form.ke].init.max_camera||s.group[form.ke].init.max_camera==''||Object.keys(s.group[form.ke].mon).length <= parseInt(s.group[form.ke].init.max_camera)){
req.tx.new=true;
req.st=[];
Object.keys(form).forEach(function(v){
if(form[v]&&form[v]!==''){
req.set.push(v),req.st.push('?'),req.ar.push(form[v]);
}
})
// req.set.push('ke'),req.st.push('?'),req.ar.push(form.ke);
req.set=req.set.join(','),req.st=req.st.join(',');
s.userLog(form,{type:'Monitor Added',msg:'by user : '+user.uid});
req.ret.msg=user.lang['Monitor Added by user']+' : '+user.uid;
s.sqlQuery('INSERT INTO Monitors ('+req.set+') VALUES ('+req.st+')',req.ar)
req.finish=1;
}else{
req.tx.f='monitor_edit_failed';
req.tx.ff='max_reached';
req.ret.msg=user.lang.monitorEditFailedMaxReached;
}
}
if(req.finish===1){
form.details=JSON.parse(form.details)
req.ret.ok=true;
s.initiateMonitorObject({mid:form.mid,ke:form.ke});
s.group[form.ke].mon_conf[form.mid]=s.cleanMonitorObject(form);
if(form.mode==='stop'){
s.camera('stop',form);
}else{
s.camera('stop',form);setTimeout(function(){s.camera(form.mode,form);},5000)
};
s.tx(req.tx,'STR_'+form.ke);
};
s.tx(req.tx,'GRP_'+form.ke);
res.end(s.prettyPrint(req.ret))
})
if(form && form.name){
s.checkDetails(form)
form.ke = req.params.ke
s.addOrEditMonitor(form,function(err,endData){
res.end(s.prettyPrint(endData))
},user)
}else{
req.ret.msg=user.lang.monitorEditText1;
res.end(s.prettyPrint(req.ret))
endData.msg = user.lang.monitorEditText1;
res.end(s.prettyPrint(endData))
}
}else{
req.ret.msg=user.lang['Not Permitted'];
res.end(s.prettyPrint(req.ret))
endData.msg = user.lang['Not Permitted']
res.end(s.prettyPrint(endData))
}
}else{
if(!user.details.sub || user.details.allmonitors === '1' || user.details.monitor_edit.indexOf(req.params.id) > -1 || hasRestrictions && user.details.monitor_create === '1'){
@ -281,12 +219,12 @@ module.exports = function(s,config,lang,app){
}
})
}
req.ret.ok=true;
req.ret.msg='Monitor Deleted by user : '+user.uid
res.end(s.prettyPrint(req.ret))
endData.ok=true;
endData.msg='Monitor Deleted by user : '+user.uid
res.end(s.prettyPrint(endData))
}else{
req.ret.msg=user.lang['Not Permitted'];
res.end(s.prettyPrint(req.ret))
endData.msg=user.lang['Not Permitted'];
res.end(s.prettyPrint(endData))
}
}
},res,req)
@ -328,11 +266,11 @@ module.exports = function(s,config,lang,app){
},'GRP_' + req.params.ke)
endData.ok = true
}
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
})
}else{
endData.msg = lang.postDataBroken
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
}
},res,req)
})
@ -359,7 +297,7 @@ module.exports = function(s,config,lang,app){
form:'APIs'
},'GRP_' + req.params.ke)
endData.msg = lang.postDataBroken
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
return
}
var row = {
@ -381,11 +319,11 @@ module.exports = function(s,config,lang,app){
endData.ok = true
delete(s.api[row.code])
}
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
})
}else{
endData.msg = lang.postDataBroken
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
}
},res,req)
})
@ -421,8 +359,143 @@ module.exports = function(s,config,lang,app){
endData.ke = user.ke
endData.keys = rows
}
closeResponse(res,endData)
s.closeJsonResponse(res,endData)
})
},res,req)
})
/**
* API : Administrator : Change Group Preset. Currently affects Monitors only.
*/
app.all([
config.webPaths.apiPrefix+':auth/monitorStates/:ke/:stateName',
config.webPaths.apiPrefix+':auth/monitorStates/:ke/:stateName/:action',
config.webPaths.adminApiPrefix+':auth/monitorStates/:ke/:stateName',
config.webPaths.adminApiPrefix+':auth/monitorStates/:ke/:stateName/:action',
],function (req,res){
s.auth(req.params,function(user){
var endData = {
ok : false
}
if(user.details.sub){
endData.msg = user.lang['Not Permitted']
s.closeJsonResponse(res,endData)
return
}
var findPreset = function(callback){
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",[req.params.ke,'monitorStates',req.params.stateName],function(err,presets){
var preset
var notFound = false
if(presets && presets[0]){
preset = presets[0]
s.checkDetails(preset)
}else{
notFound = true
}
callback(notFound,preset)
})
}
switch(req.params.action){
case'insert':case'edit':
var form = s.getPostData(req)
s.checkDetails(form)
if(!form || !form.monitors){
endData.msg = user.lang['Form Data Not Found']
s.closeJsonResponse(res,endData)
return
}
findPreset(function(notFound,preset){
if(notFound === true){
endData.msg = lang["Inserted State Configuration"]
var details = {
monitors : form.monitors
}
var insertData = {
ke: req.params.ke,
name: req.params.stateName,
details: s.s(details),
type: 'monitorStates'
}
s.sqlQuery('INSERT INTO Presets ('+Object.keys(insertData).join(',')+') VALUES (?,?,?,?)',Object.values(insertData))
s.tx({
f: 'add_group_state',
details: details,
ke: req.params.ke,
name: req.params.stateName
},'GRP_'+req.params.ke)
}else{
endData.msg = lang["Edited State Configuration"]
var details = Object.assign(preset.details,{
monitors : form.monitors
})
s.sqlQuery('UPDATE Presets SET details=? WHERE ke=? AND name=?',[s.s(details),req.params.ke,req.params.stateName])
s.tx({
f: 'edit_group_state',
details: details,
ke: req.params.ke,
name: req.params.stateName
},'GRP_'+req.params.ke)
}
endData.ok = true
s.closeJsonResponse(res,endData)
})
break;
case'delete':
findPreset(function(notFound,preset){
if(notFound === true){
endData.msg = user.lang['State Configuration Not Found']
s.closeJsonResponse(res,endData)
}else{
s.sqlQuery('DELETE FROM Presets WHERE ke=? AND name=?',[req.params.ke,req.params.stateName],function(err){
if(!err){
endData.msg = lang["Deleted State Configuration"]
endData.ok = true
}
s.closeJsonResponse(res,endData)
})
}
})
break;
default://change monitors according to state
findPreset(function(notFound,preset){
if(notFound === false){
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
var monitorQuery = []
var sqlQueryValues = [req.params.ke]
var monitorPresets = {}
preset.details.monitors.forEach(function(monitor){
monitorQuery.push('mid=?')
sqlQueryValues.push(monitor.mid)
monitorPresets[monitor.mid] = monitor
})
sqlQuery += '('+monitorQuery.join(' OR ')+')'
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
if(monitors && monitors[0]){
monitors.forEach(function(monitor){
s.checkDetails(monitor)
s.checkDetails(monitorPresets[monitor.mid])
var monitorPreset = monitorPresets[monitor.mid]
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
monitor.details = JSON.stringify(monitor.details)
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
},user)
})
endData.ok = true
s.tx({f:'change_group_state',ke:req.params.ke,name:req.params.stateName},'GRP_'+req.params.ke)
s.closeJsonResponse(res,endData)
}else{
endData.msg = user.lang['State Configuration has no monitors associated']
s.closeJsonResponse(res,endData)
}
})
}else{
endData.msg = user.lang['State Configuration Not Found']
s.closeJsonResponse(res,endData)
}
})
break;
}
},res,req)
})
}

View file

@ -11,54 +11,15 @@ var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({})
var ejs = require('ejs');
var CircularJSON = require('circular-json');
module.exports = function(s,config,lang,app){
module.exports = function(s,config,lang,app,io){
if(config.productType==='Pro'){
var LdapAuth = require('ldapauth-fork');
}
//get page URL
if(!config.baseURL){
config.baseURL = ""
}else if(config.baseURL !== ''){
config.baseURL = s.checkCorrectPathEnding(config.baseURL)
s.renderPage = function(req,res,paths,passables,callback){
passables.window = {}
passables.originalURL = s.getOriginalUrl(req)
res.render(paths,passables,callback)
}
//Render Configurations - Web Paths
if(config.webPaths === undefined){config.webPaths={}}
//main access URI
if(config.webPaths.home === undefined){config.webPaths.home='/'}
//Super User URI
if(config.webPaths.super === undefined){config.webPaths.super='/super'}
//Admin URI
if(config.webPaths.admin === undefined){config.webPaths.admin='/admin'}
//API Prefix
if(config.webPaths.apiPrefix === undefined){config.webPaths.apiPrefix='/'}else{config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.apiPrefix)}
//Admin API Prefix
if(config.webPaths.adminApiPrefix === undefined){config.webPaths.adminApiPrefix='/admin/'}else{config.webPaths.adminApiPrefix = s.checkCorrectPathEnding(config.webPaths.adminApiPrefix)}
//Super API Prefix
if(config.webPaths.superApiPrefix === undefined){config.webPaths.superApiPrefix='/super/'}else{config.webPaths.superApiPrefix = s.checkCorrectPathEnding(config.webPaths.superApiPrefix)}
//Render Configurations - Page Render Paths
if(config.renderPaths === undefined){config.renderPaths={}}
//login page
if(config.renderPaths.index === undefined){config.renderPaths.index='pages/index'}
//dashboard page
if(config.renderPaths.home === undefined){config.renderPaths.home='pages/home'}
//sub-account administration page
if(config.renderPaths.admin === undefined){config.renderPaths.admin='pages/admin'}
//superuser page
if(config.renderPaths.super === undefined){config.renderPaths.super='pages/super'}
//2-Factor Auth page
if(config.renderPaths.factorAuth === undefined){config.renderPaths.factorAuth='pages/factor'}
//Streamer v1 (Dashcam Prototype) page
if(config.renderPaths.streamer === undefined){config.renderPaths.streamer='pages/streamer'}
//Streamer v2 (Dashcam) page
if(config.renderPaths.dashcam === undefined){config.renderPaths.dashcam='pages/dashcam'}
//embeddable widget page
if(config.renderPaths.embed === undefined){config.renderPaths.embed='pages/embed'}
//mjpeg full screen page
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
//gridstack only page
if(config.renderPaths.grid === undefined){config.renderPaths.grid='pages/grid'}
//slick.js (cycle) page
if(config.renderPaths.cycle === undefined){config.renderPaths.cycle='pages/cycle'}
//child node proxy check
//params = parameters
//cb = callback
@ -72,6 +33,10 @@ module.exports = function(s,config,lang,app){
cb()
}
}
s.closeJsonResponse = function(res,endData){
res.setHeader('Content-Type', 'application/json')
res.end(s.prettyPrint(endData))
}
//get post data
s.getPostData = function(req,target,parseJSON){
if(!target)target = 'data'
@ -93,13 +58,18 @@ module.exports = function(s,config,lang,app){
}
////Pages
app.enable('trust proxy');
app.use('/libs',express.static(s.mainDirectory + '/web/libs'));
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'))
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.set('views', s.mainDirectory + '/web');
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)}
if(config.renderPaths.handler!==undefined){require(s.mainDirectory+'/web/'+config.renderPaths.handler+'.js').addHandlers(s,app,io,config)}
/**
* API : Logout
@ -118,7 +88,7 @@ module.exports = function(s,config,lang,app){
* Page : Login Screen
*/
app.get(config.webPaths.home, function (req,res){
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'dashboard',originalURL:s.getOriginalUrl(req)},function(err,html){
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'dashboard'},function(err,html){
if(err){
s.systemLog(err)
}
@ -129,7 +99,7 @@ module.exports = function(s,config,lang,app){
* Page : Administrator Login Screen
*/
app.get(config.webPaths.admin, function (req,res){
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'admin',originalURL:s.getOriginalUrl(req)},function(err,html){
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'admin'},function(err,html){
if(err){
s.systemLog(err)
}
@ -141,7 +111,7 @@ module.exports = function(s,config,lang,app){
*/
app.get(config.webPaths.super, function (req,res){
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'super',originalURL:s.getOriginalUrl(req)},function(err,html){
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'super'},function(err,html){
if(err){
s.systemLog(err)
}
@ -171,23 +141,48 @@ module.exports = function(s,config,lang,app){
/**
* API : Login handler. Dashboard, Streamer, Dashcam Administrator, Superuser
*/
app.post([config.webPaths.home,s.checkCorrectPathEnding(config.webPaths.home)+':screen'],function (req,res){
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){
req.ip = s.getClientIp(req)
if(req.query.json === 'true'){
res.header("Access-Control-Allow-Origin",req.headers.origin);
}
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;
}
}
// 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}))
}else{
res.render(config.renderPaths.index,{
failedLogin:true,
message:lang.failedLoginText1,
lang:lang,
config:config,
screen:req.params.screen,
originalURL:s.getOriginalUrl(req)
s.renderPage(req,res,config.renderPaths.index,{
failedLogin: true,
message: lang.failedLoginText1,
lang: lang,
config: config,
screen: screenChooser(req.params.screen)
},function(err,html){
if(err){
s.systemLog(err)
@ -209,9 +204,8 @@ module.exports = function(s,config,lang,app){
res.setHeader('Content-Type', 'application/json');
res.end(s.prettyPrint(data))
}else{
data.originalURL = s.getOriginalUrl(req)
data.screen=req.params.screen
res.render(focus,data,function(err,html){
s.renderPage(req,res,focus,data,function(err,html){
if(err){
s.systemLog(err)
}
@ -241,13 +235,12 @@ module.exports = function(s,config,lang,app){
res.setHeader('Content-Type', 'application/json')
res.end(s.prettyPrint({ok:false}))
}else{
res.render(config.renderPaths.index,{
failedLogin:true,
message:lang.failedLoginText2,
lang:lang,
config:config,
screen:req.params.screen,
originalURL:s.getOriginalUrl(req)
s.renderPage(req,res,config.renderPaths.index,{
failedLogin: true,
message: lang.failedLoginText2,
lang: lang,
config: config,
screen: screenChooser(req.params.screen)
},function(err,html){
if(err){
s.systemLog(err)
@ -344,7 +337,7 @@ module.exports = function(s,config,lang,app){
r.details=JSON.parse(r.details);
r.lang=s.getLanguageFile(r.details.lang)
req.factorAuth=function(cb){
if(r.details.factorAuth==="1"){
if(r.details.factorAuth === "1"){
if(!r.details.acceptedMachines||!(r.details.acceptedMachines instanceof Object)){
r.details.acceptedMachines={}
}
@ -671,14 +664,13 @@ module.exports = function(s,config,lang,app){
if(req.path.indexOf('/cycle/') > -1){
page = config.renderPaths.cycle
}
res.render(page,{
s.renderPage(req,res,page,{
data:Object.assign(req.params,req.query),
baseUrl:req.protocol+'://'+req.hostname,
config:config,
lang:user.lang,
$user:user,
monitors:r,
originalURL:s.getOriginalUrl(req),
query:req.query
});
})
@ -1490,17 +1482,22 @@ module.exports = function(s,config,lang,app){
req.ext=req.params.file.split('.')[1];
var total = fs.statSync(req.dir).size;
if (req.headers['range']) {
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
var file = fs.createReadStream(req.dir, {start: start, end: end});
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+req.ext }
req.writeCode=206
try{
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
var file = fs.createReadStream(req.dir, {start: start, end: end});
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+req.ext }
req.writeCode=206
}catch(err){
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
var file = fs.createReadStream(req.dir)
req.writeCode=200
}
} else {
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
var file=fs.createReadStream(req.dir)
@ -1844,4 +1841,27 @@ module.exports = function(s,config,lang,app){
}
},res,req);
})
/**
* 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)
})
}

View file

@ -26,7 +26,7 @@ module.exports = function(s,config,lang,app){
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[req.params.id]){
if(s.group[req.params.ke].mon[req.params.id].isStarted === true){
req.params.uid=user.uid;
res.render(config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config:config,lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].mon_conf[req.params.id])),originalURL:s.getOriginalUrl(req)});
s.renderPage(req,res,config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config:config,lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].mon_conf[req.params.id])),originalURL:s.getOriginalUrl(req)});
res.end()
}else{
res.end(user.lang['Cannot watch a monitor that isn\'t running.'])
@ -102,7 +102,7 @@ module.exports = function(s,config,lang,app){
app.get([config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id',config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id/:channel'], function(req,res) {
res.header("Access-Control-Allow-Origin",req.headers.origin);
if(req.query.full=='true'){
res.render(config.renderPaths.mjpeg,{url:'/'+req.params.auth+'/mjpeg/'+req.params.ke+'/'+req.params.id,originalURL:s.getOriginalUrl(req)});
s.renderPage(req,res,config.renderPaths.mjpeg,{url:config.webPaths.apiPrefix + req.params.auth+'/mjpeg/'+req.params.ke+'/'+req.params.id,originalURL:s.getOriginalUrl(req)});
res.end()
}else{
s.auth(req.params,function(user){