vargoPhishRegex=regexp.MustCompile("(\\?rid=(3D)?([A-Za-z0-9]{7}))")// We include the optional quoted-printable 3D at the front, just in case decoding fails
// Monitor is a worker that monitors IMAP servers for reported campaign emails
typeMonitorstruct{
cancelfunc()
}
// Monitor.start() checks for campaign emails
// As each account can have its own polling frequency set we need to run one Go routine for
// each, as well as keeping an eye on newly created user accounts.
func(im*Monitor)start(ctxcontext.Context){
usermap:=make(map[int64]int)// Keep track of running go routines, one per user. We assume incrementing non-repeating UIDs (for the case where users are deleted and re-added).
for{
select{
case<-ctx.Done():
return
default:
dbusers,err:=models.GetUsers()//Slice of all user ids. Each user gets their own IMAP monitor routine.
iferr!=nil{
log.Error(err)
break
}
for_,dbuser:=rangedbusers{
if_,ok:=usermap[dbuser.Id];!ok{// If we don't currently have a running Go routine for this user, start one.
log.Info("Starting new IMAP monitor for user ",dbuser.Username)
usermap[dbuser.Id]=1
gomonitor(dbuser.Id,ctx)
}
}
time.Sleep(10*time.Second)// Every ten seconds we check if a new user has been created
}
}
}
// monitor will continuously login to the IMAP settings associated to the supplied user id (if the user account has IMAP settings, and they're enabled.)
// It also verifies the user account exists, and returns if not (for the case of a user being deleted).
funcmonitor(uidint64,ctxcontext.Context){
for{
select{
case<-ctx.Done():
return
default:
// 1. Check if user exists, if not, return.
_,err:=models.GetUser(uid)
iferr!=nil{// Not sure if there's a better way to determine user existence via id.
log.Info("User ",uid," seems to have been deleted. Stopping IMAP monitor for this user.")
return
}
// 2. Check if user has IMAP settings.
imapSettings,err:=models.GetIMAP(uid)
iferr!=nil{
log.Error(err)
break
}
iflen(imapSettings)>0{
im:=imapSettings[0]
// 3. Check if IMAP is enabled
ifim.Enabled{
log.Debug("Checking IMAP for user ",uid,": ",im.Username,"@",im.Host)
checkForNewEmails(im)
time.Sleep((time.Duration(im.IMAPFreq)-10)*time.Second)// Subtract 10 to compensate for the default sleep of 10 at the bottom
}
}
}
time.Sleep(10*time.Second)
}
}
// NewMonitor returns a new instance of imap.Monitor
funcNewMonitor()*Monitor{
im:=&Monitor{}
returnim
}
// Start launches the IMAP campaign monitor
func(im*Monitor)Start()error{
log.Info("Starting IMAP monitor manager")
ctx,cancel:=context.WithCancel(context.Background())// ctx is the derivedContext
im.cancel=cancel
goim.start(ctx)
returnnil
}
// Shutdown attempts to gracefully shutdown the IMAP monitor.
func(im*Monitor)Shutdown()error{
log.Info("Shutting down IMAP monitor manager")
im.cancel()
returnnil
}
// checkForNewEmails logs into an IMAP account and checks unread emails
// for the rid campaign identifier.
funccheckForNewEmails(immodels.IMAP){
im.Host=im.Host+":"+strconv.Itoa(int(im.Port))// Append port