var fs = require("fs") var Discord = require("discord.js") var template = require("./notifications/emailTemplate.js") module.exports = function(s,config,lang){ //discord bot if(config.discordBot === true){ try{ s.discordMsg = function(data,files,groupKey){ if(!data)data = {}; var bot = s.group[groupKey].discordBot if(!bot){ s.userLog({ke:groupKey,mid:'$USER'},{type:lang.DiscordFailedText,msg:lang.DiscordNotEnabledText}) return } const sendBody = Object.assign({ color: 3447003, title: 'Alert from Shinobi', description: "", fields: [], timestamp: new Date(), footer: { icon_url: config.iconURL, text: "Shinobi Systems" } },data) const discordChannel = bot.channels.cache.get(s.group[groupKey].init.discordbot_channel) if(discordChannel && discordChannel.send){ discordChannel.send({ embed: sendBody, files: files }).catch(err => { if(err){ s.userLog({ke:groupKey,mid:'$USER'},{type:lang.DiscordErrorText,msg:err}) s.group[groupKey].discordBot = null s.loadGroupApps({ke:groupKey}) } }) }else{ s.userLog({ ke: groupKey, mid: '$USER' },{ type: lang.DiscordErrorText, msg: 'Check the Channel ID' }) } } const onEventTriggerBeforeFilterForDiscord = function(d,filter){ filter.discord = true } const onEventTriggerForDiscord = async (d,filter) => { // d = event object //discord bot if(filter.discord && s.group[d.ke].discordBot && d.mon.details.detector_discordbot === '1' && !s.group[d.ke].activeMonitors[d.id].detector_discordbot){ var detector_discordbot_timeout if(!d.mon.details.detector_discordbot_timeout||d.mon.details.detector_discordbot_timeout===''){ detector_discordbot_timeout = 1000*60*10; }else{ detector_discordbot_timeout = parseFloat(d.mon.details.detector_discordbot_timeout)*1000*60; } //lock mailer so you don't get emailed on EVERY trigger event. s.group[d.ke].activeMonitors[d.id].detector_discordbot = setTimeout(function(){ clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_discordbot); delete(s.group[d.ke].activeMonitors[d.id].detector_discordbot); },detector_discordbot_timeout) if(d.mon.details.detector_discordbot_send_video === '1'){ // change to function that captures on going video capture, waits, grabs new video file, slices portion (max for transmission) and prepares for delivery s.mergeDetectorBufferChunks(d,function(mergedFilepath,filename){ s.discordMsg({ author: { name: s.group[d.ke].rawMonitorConfigurations[d.id].name, icon_url: config.iconURL }, title: filename, fields: [], timestamp: d.currentTime, footer: { icon_url: config.iconURL, text: "Shinobi Systems" } },[ { attachment: mergedFilepath, name: filename } ],d.ke) }) } const {screenShot, isStaticFile} = await s.getRawSnapshotFromMonitor(d.mon,{ secondsInward: d.mon.details.snap_seconds_inward }) if(screenShot[screenShot.length - 2] === 0xFF && screenShot[screenShot.length - 1] === 0xD9){ d.screenshotBuffer = screenShot s.discordMsg({ author: { name: s.group[d.ke].rawMonitorConfigurations[d.id].name, icon_url: config.iconURL }, title: lang.Event+' - '+d.screenshotName, description: lang.EventText1+' '+d.currentTimestamp, fields: [], timestamp: d.currentTime, footer: { icon_url: config.iconURL, text: "Shinobi Systems" } },[ { attachment: screenShot, name: d.screenshotName+'.jpg' } ],d.ke) } } } const onTwoFactorAuthCodeNotificationForDiscord = function(r){ // r = user if(r.details.factor_discord === '1'){ s.discordMsg({ author: { name: r.lang['2-Factor Authentication'], icon_url: config.iconURL }, title: r.lang['Enter this code to proceed'], description: '**'+s.factorAuth[r.ke][r.uid].key+'** '+r.lang.FactorAuthText1, fields: [], timestamp: new Date(), footer: { icon_url: config.iconURL, text: "Shinobi Systems" } },[],r.ke) } } const loadDiscordBotForUser = function(user){ const userDetails = s.parseJSON(user.details); //discordbot if(!s.group[user.ke].discordBot && config.discordBot === true && userDetails.discordbot === '1' && userDetails.discordbot_token !== '' ){ s.group[user.ke].discordBot = new Discord.Client() s.group[user.ke].discordBot.on('ready', () => { s.userLog({ ke: user.ke, mid: '$USER' },{ type: lang.DiscordLoggedIn, msg: s.group[user.ke].discordBot.user.tag }) }) s.group[user.ke].discordBot.login(userDetails.discordbot_token) } } const unloadDiscordBotForUser = function(user){ if(s.group[user.ke].discordBot && s.group[user.ke].discordBot.destroy){ s.group[user.ke].discordBot.destroy() delete(s.group[user.ke].discordBot) } } const onDetectorNoTriggerTimeoutForDiscord = function(e){ //e = monitor object var currentTime = new Date() if(e.details.detector_notrigger_discord === '1'){ var html = '*'+lang.NoMotionEmailText2+' ' + (e.details.detector_notrigger_timeout || 10) + ' '+lang.minutes+'.*\n' html += '**' + lang['Monitor Name'] + '** : '+e.name + '\n' html += '**' + lang['Monitor ID'] + '** : '+e.id + '\n' html += currentTime s.discordMsg({ author: { name: s.group[e.ke].rawMonitorConfigurations[e.id].name, icon_url: config.iconURL }, title: lang['\"No Motion"\ Detector'], description: html, fields: [], timestamp: currentTime, footer: { icon_url: config.iconURL, text: "Shinobi Systems" } },[],e.ke) } } s.loadGroupAppExtender(loadDiscordBotForUser) s.unloadGroupAppExtender(unloadDiscordBotForUser) s.onTwoFactorAuthCodeNotification(onTwoFactorAuthCodeNotificationForDiscord) s.onEventTrigger(onEventTriggerForDiscord) s.onEventTriggerBeforeFilter(onEventTriggerBeforeFilterForDiscord) s.onDetectorNoTriggerTimeout(onDetectorNoTriggerTimeoutForDiscord) }catch(err){ console.log(err) console.log('Could not start Discord bot, please run "npm install discord.js" inside the Shinobi folder.') s.discordMsg = function(){} } } // mailing with nodemailer try{ if(config.mail){ if(config.mail.from === undefined){config.mail.from = '"ShinobiCCTV" '} s.nodemailer = require('nodemailer').createTransport(config.mail); } const onDetectorNoTriggerTimeoutForEmail = function(e){ //e = monitor object if(config.mail && e.details.detector_notrigger_mail === '1'){ s.knexQuery({ action: "select", columns: "mail", table: "Users", where: [ ['ke','=',e.ke], ['details','NOT LIKE','%"sub"%'], ] },(err,r) => { r = r[0] var mailOptions = { from: config.mail.from, // sender address to: r.mail, // list of receivers subject: lang.NoMotionEmailText1+' '+e.name+' ('+e.id+')', // Subject line html: ''+lang.NoMotionEmailText2+' ' + (e.details.detector_notrigger_timeout || 10) + ' '+lang.minutes+'.', } mailOptions.html+='
'+lang['Monitor Name']+' : '+e.name+'
' mailOptions.html+='
'+lang['Monitor ID']+' : '+e.id+'
' s.nodemailer.sendMail(mailOptions, (error, info) => { if (error) { s.systemLog('detector:notrigger:sendMail',error) s.tx({f:'error',ff:'detector_notrigger_mail',id:e.id,ke:e.ke,error:error},'GRP_'+e.ke); return ; } s.tx({f:'detector_notrigger_mail',id:e.id,ke:e.ke,info:info},'GRP_'+e.ke); }) }) } } const onTwoFactorAuthCodeNotificationForEmail = function(r){ // r = user object if(r.details.factor_mail !== '0'){ s.nodemailer.sendMail({ from: config.mail.from, to: r.mail, subject: r.lang['2-Factor Authentication'], html: r.lang['Enter this code to proceed']+' '+s.factorAuth[r.ke][r.uid].key+'. '+r.lang.FactorAuthText1, }, (error, info) => { if (error) { s.systemLog(r.lang.MailError,error) return } }) } } const onFilterEventForEmail = function(x,d){ // x = filter function // d = filter event object if(x === 'email'){ if(d.videos && d.videos.length > 0){ d.mailOptions = { from: config.mail.from, // sender address to: d.mail, // list of receivers subject: lang['Filter Matches']+' : '+d.name, // Subject line html: lang.FilterMatchesText1+' '+d.videos.length+' '+lang.FilterMatchesText2, }; if(d.execute&&d.execute!==''){ d.mailOptions.html+='
'+lang.Executed+' : '+d.execute+'
' } if(d.delete==='1'){ d.mailOptions.html+='
'+lang.Deleted+' : '+lang.Yes+'
' } d.mailOptions.html+='
'+lang.Query+' : '+d.query+'
' d.mailOptions.html+='
'+lang['Filter ID']+' : '+d.id+'
' s.nodemailer.sendMail(d.mailOptions, (error, info) => { if (error) { s.tx({f:'error',ff:'filter_mail',ke:d.ke,error:error},'GRP_'+d.ke); return ; } s.tx({f:'filter_mail',ke:d.ke,info:info},'GRP_'+d.ke); }) } } } const onEventTriggerBeforeFilterForEmail = function(d,filter){ if(d.mon.details.detector_mail === '1'){ filter.mail = true }else{ filter.mail = false } } const onEventTriggerForEmail = async (d,filter) => { if(filter.mail && config.mail && !s.group[d.ke].activeMonitors[d.id].detector_mail){ s.knexQuery({ action: "select", columns: "mail", table: "Users", where: [ ['ke','=',d.ke], ['details','NOT LIKE','%"sub"%'], ] },async (err,r) => { r = r[0]; var detector_mail_timeout if(!d.mon.details.detector_mail_timeout||d.mon.details.detector_mail_timeout===''){ detector_mail_timeout = 1000*60*10; }else{ detector_mail_timeout = parseFloat(d.mon.details.detector_mail_timeout)*1000*60; } //lock mailer so you don't get emailed on EVERY trigger event. s.group[d.ke].activeMonitors[d.id].detector_mail = setTimeout(function(){ //unlock so you can mail again. clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_mail); delete(s.group[d.ke].activeMonitors[d.id].detector_mail); },detector_mail_timeout); const sendMail = function(files){ const infoRows = [] Object.keys(d.details).forEach(function(key){ var value = d.details[key] var text = value if(value instanceof Object){ text = JSON.stringify(value,null,3) } infoRows.push(template.createRow({ title: key, text: text })) }) s.nodemailer.sendMail({ from: config.mail.from, to: r.mail, subject: lang.Event+' - '+d.screenshotName, html: template.createFramework({ title: lang.EventText1 + ' ' + d.currentTimestamp, subtitle: 'Shinobi Event', body: infoRows.join(''), }), attachments: files || [] }, (error, info) => { if (error) { s.systemLog(lang.MailError,error) return false; } }) } if(d.mon.details.detector_mail_send_video === '1'){ // change to function that captures on going video capture, waits, grabs new video file, slices portion (max for transmission) and prepares for delivery s.mergeDetectorBufferChunks(d,function(mergedFilepath,filename){ fs.readFile(mergedFilepath,function(err,buffer){ if(buffer){ s.nodemailer.sendMail({ from: config.mail.from, to: r.mail, subject: filename, html: '', attachments: [ { filename: filename, content: buffer } ] }, (error, info) => { if (error) { s.systemLog(lang.MailError,error) return false; } }) } }) }) } if(!d.screenshotBuffer){ const {screenShot, isStaticFile} = await s.getRawSnapshotFromMonitor(d.mon,{ secondsInward: d.mon.details.snap_seconds_inward }) d.screenshotBuffer = screenShot } sendMail([ { filename: d.screenshotName + '.jpg', content: d.screenshotBuffer } ]) }) } } s.onTwoFactorAuthCodeNotification(onTwoFactorAuthCodeNotificationForEmail) s.onEventTriggerBeforeFilter(onEventTriggerBeforeFilterForEmail) s.onEventTrigger(onEventTriggerForEmail) s.onFilterEvent(onFilterEventForEmail) s.onDetectorNoTriggerTimeout(onDetectorNoTriggerTimeoutForEmail) }catch(err){ console.log(err) } }