2017-12-12 16:04:54 -08:00
/ * *
2018-01-04 12:15:21 -08:00
* @ description MeshCentral e - mail server communication modules
2017-12-12 16:04:54 -08:00
* @ author Ylian Saint - Hilaire
2018-01-04 12:15:21 -08:00
* @ copyright Intel Corporation 2018
* @ license Apache - 2.0
2017-12-12 16:04:54 -08:00
* @ version v0 . 0.1
* /
// Construct a MeshAgent object, called upon connection
module . exports . CreateMeshMain = function ( parent ) {
var obj = { } ;
obj . pendingMails = [ ] ;
obj . parent = parent ;
obj . retry = 0 ;
obj . sendingMail = false ;
2017-12-13 14:52:57 -08:00
obj . mailCookieEncryptionKey = null ;
2017-12-12 16:04:54 -08:00
const nodemailer = require ( 'nodemailer' ) ;
// Default account email validation mail
var accountCheckSubject = '[[[SERVERNAME]]] - Email Verification' ;
var accountCheckMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b></td></tr></table><p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to verify your e-mail address.</a></p>If you did not initiate this request, please ignore this mail.</div>' ;
var accountCheckMailText = '[[[SERVERNAME]]] - Verification\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n' ;
// Default account reset mail
var accountResetSubject = '[[[SERVERNAME]]] - Account Reset' ;
var accountResetMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b></td></tr></table><p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting an account password reset, click on the following link to complete the process.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to reset your account password.</a></p>If you did not initiate this request, please ignore this mail.</div>' ;
var accountResetMailText = '[[[SERVERNAME]]] - Account Reset\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting an account password reset. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n' ;
// Setup mail server
2017-12-12 18:23:26 -08:00
var options = { host : parent . config . smtp . host , secure : ( parent . config . smtp . tls == true ) , tls : { rejectUnauthorized : false } } ;
2017-12-12 16:04:54 -08:00
if ( parent . config . smtp . port != null ) { options . port = parent . config . smtp . port ; }
2017-12-12 18:23:26 -08:00
if ( ( parent . config . smtp . user != null ) && ( parent . config . smtp . pass != null ) ) { options . auth = { user : parent . config . smtp . user , pass : parent . config . smtp . pass } ; }
2017-12-12 16:04:54 -08:00
obj . smtpServer = nodemailer . createTransport ( options ) ;
// Perform all e-mail substitution
function mailReplacements ( text , domain , username , email , cookie ) {
2018-01-04 12:15:21 -08:00
var url ;
if ( domain . dns == null ) {
// Default domain or subdomain of the default.
url = 'http' + ( ( obj . parent . args . notls == null ) ? 's' : '' ) + '://' + parent . certificates . CommonName + ':' + obj . parent . args . port + domain . url ;
} else {
// Domain with a DNS name.
url = 'http' + ( ( obj . parent . args . notls == null ) ? 's' : '' ) + '://' + domain . dns + ':' + obj . parent . args . port + domain . url ;
}
2017-12-12 16:04:54 -08:00
if ( cookie != null ) { text = text . split ( '[[[CALLBACKURL]]]' ) . join ( url + 'checkmail?c=' + cookie ) }
return text . split ( '[[[USERNAME]]]' ) . join ( username ) . split ( '[[[SERVERURL]]]' ) . join ( url ) . split ( '[[[SERVERNAME]]]' ) . join ( domain . title ) ;
}
// Send a mail
obj . sendMail = function ( to , subject , text , html ) {
obj . pendingMails . push ( { to : to , from : parent . config . smtp . from , subject : subject , text : text , html : html } ) ;
sendNextMail ( ) ;
}
// Send account check mail
obj . sendAccountCheckMail = function ( domain , username , email ) {
if ( ( parent . certificates == null ) || ( parent . certificates . CommonName == null ) ) return ; // If the server name is not set, no reset possible.
2017-12-13 14:52:57 -08:00
var cookie = obj . parent . encodeCookie ( { u : domain . id + '/' + username , e : email , a : 1 } , obj . mailCookieEncryptionKey ) ;
2017-12-12 16:04:54 -08:00
obj . pendingMails . push ( { to : email , from : parent . config . smtp . from , subject : mailReplacements ( accountCheckSubject , domain , username , email ) , text : mailReplacements ( accountCheckMailText , domain , username , email , cookie ) , html : mailReplacements ( accountCheckMailHtml , domain , username , email , cookie ) } ) ;
sendNextMail ( ) ;
}
// Send account reset mail
obj . sendAccountResetMail = function ( domain , username , email ) {
if ( ( parent . certificates == null ) || ( parent . certificates . CommonName == null ) ) return ; // If the server name is not set, don't validate the email address.
2017-12-13 14:52:57 -08:00
var cookie = obj . parent . encodeCookie ( { u : domain . id + '/' + username , e : email , a : 2 } , obj . mailCookieEncryptionKey ) ;
2017-12-12 16:04:54 -08:00
obj . pendingMails . push ( { to : email , from : parent . config . smtp . from , subject : mailReplacements ( accountResetSubject , domain , username , email ) , text : mailReplacements ( accountResetMailText , domain , username , email , cookie ) , html : mailReplacements ( accountResetMailHtml , domain , username , email , cookie ) } ) ;
sendNextMail ( ) ;
}
// Send out the next mail in the pending list
function sendNextMail ( ) {
if ( ( obj . sendingMail == true ) || ( obj . pendingMails . length == 0 ) ) { return ; }
var mailToSend = obj . pendingMails [ 0 ] ;
obj . sendingMail = true ;
//console.log('SMTP sending mail to ' + mailToSend.to + '.');
obj . smtpServer . sendMail ( mailToSend , function ( err , info ) {
//console.log(JSON.stringify(err), JSON.stringify(info));
obj . sendingMail = false ;
if ( err == null ) {
obj . pendingMails . shift ( ) ;
obj . retry = 0 ;
sendNextMail ( ) ; // Send the next mail
} else {
obj . retry ++ ;
2017-12-13 14:52:57 -08:00
console . log ( 'SMTP server failed: ' + JSON . stringify ( err ) ) ;
2017-12-12 18:23:26 -08:00
if ( obj . retry < 6 ) { setTimeout ( sendNextMail , 60000 ) ; } // Wait and try again
}
} ) ;
}
// Send out the next mail in the pending list
obj . verify = function ( ) {
obj . smtpServer . verify ( function ( err , info ) {
if ( err == null ) {
console . log ( 'SMTP mail server ' + parent . config . smtp . host + ' working as expected.' ) ;
} else {
2017-12-13 14:52:57 -08:00
console . log ( 'SMTP mail server ' + parent . config . smtp . host + ' failed: ' + JSON . stringify ( err ) ) ;
2017-12-12 16:04:54 -08:00
}
} ) ;
}
2017-12-13 14:52:57 -08:00
// Load the cookie encryption key from the database
obj . parent . db . Get ( 'MailCookieEncryptionKey' , function ( err , docs ) {
2017-12-14 14:57:52 -08:00
if ( ( docs . length > 0 ) && ( docs [ 0 ] . key != null ) && ( obj . parent . mailtokengen == null ) ) {
2017-12-13 14:52:57 -08:00
// Key is present, use it.
obj . mailCookieEncryptionKey = Buffer . from ( docs [ 0 ] . key , 'hex' ) ;
} else {
// Key is not present, generate one.
obj . mailCookieEncryptionKey = obj . parent . generateCookieKey ( ) ;
obj . parent . db . Set ( { _id : 'MailCookieEncryptionKey' , key : obj . mailCookieEncryptionKey . toString ( 'hex' ) , time : Date . now ( ) } ) ;
}
} ) ;
2017-12-12 16:04:54 -08:00
return obj ;
}