2014-03-28 04:31:51 +00:00
|
|
|
package worker
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"os"
|
2016-06-08 02:42:09 +00:00
|
|
|
"time"
|
2014-03-28 04:31:51 +00:00
|
|
|
|
2017-12-09 21:42:07 +00:00
|
|
|
"github.com/gophish/gophish/mailer"
|
2016-01-10 17:03:17 +00:00
|
|
|
"github.com/gophish/gophish/models"
|
2014-03-28 04:31:51 +00:00
|
|
|
)
|
|
|
|
|
2015-06-13 04:12:43 +00:00
|
|
|
// Logger is the logger for the worker
|
2014-03-28 04:31:51 +00:00
|
|
|
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
|
|
|
|
|
2015-02-21 06:11:22 +00:00
|
|
|
// Worker is the background worker that handles watching for new campaigns and sending emails appropriately.
|
2016-06-08 02:42:09 +00:00
|
|
|
type Worker struct{}
|
2014-03-28 04:31:51 +00:00
|
|
|
|
2015-06-13 04:12:43 +00:00
|
|
|
// New creates a new worker object to handle the creation of campaigns
|
2014-03-28 04:31:51 +00:00
|
|
|
func New() *Worker {
|
2016-06-08 02:42:09 +00:00
|
|
|
return &Worker{}
|
2014-03-28 04:31:51 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 21:42:07 +00:00
|
|
|
// Start launches the worker to poll the database every minute for any pending maillogs
|
|
|
|
// that need to be processed.
|
2014-03-28 04:31:51 +00:00
|
|
|
func (w *Worker) Start() {
|
|
|
|
Logger.Println("Background Worker Started Successfully - Waiting for Campaigns")
|
2016-06-08 02:42:09 +00:00
|
|
|
for t := range time.Tick(1 * time.Minute) {
|
2017-12-09 21:42:07 +00:00
|
|
|
ms, err := models.GetQueuedMailLogs(t.UTC())
|
2016-06-08 02:42:09 +00:00
|
|
|
if err != nil {
|
|
|
|
Logger.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
2017-12-09 21:42:07 +00:00
|
|
|
// Lock the MailLogs (they will be unlocked after processing)
|
|
|
|
err = models.LockMailLogs(ms, true)
|
2014-06-27 00:55:56 +00:00
|
|
|
if err != nil {
|
|
|
|
Logger.Println(err)
|
2017-12-09 21:42:07 +00:00
|
|
|
continue
|
2014-06-27 00:55:56 +00:00
|
|
|
}
|
2017-12-09 21:42:07 +00:00
|
|
|
// We'll group the maillogs by campaign ID to (sort of) group
|
|
|
|
// them by sending profile. This lets the mailer re-use the Sender
|
|
|
|
// instead of having to re-connect to the SMTP server for every
|
|
|
|
// email.
|
|
|
|
msg := make(map[int64][]mailer.Mail)
|
|
|
|
for _, m := range ms {
|
|
|
|
msg[m.CampaignId] = append(msg[m.CampaignId], m)
|
2016-02-13 04:19:59 +00:00
|
|
|
}
|
2017-12-09 21:42:07 +00:00
|
|
|
|
|
|
|
// Next, we process each group of maillogs in parallel
|
|
|
|
for cid, msc := range msg {
|
|
|
|
go func(cid int64, msc []mailer.Mail) {
|
|
|
|
uid := msc[0].(*models.MailLog).UserId
|
|
|
|
c, err := models.GetCampaign(cid, uid)
|
|
|
|
if err != nil {
|
|
|
|
Logger.Println(err)
|
|
|
|
errorMail(err, msc)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if c.Status == models.CAMPAIGN_QUEUED {
|
|
|
|
err := c.UpdateStatus(models.CAMPAIGN_IN_PROGRESS)
|
|
|
|
if err != nil {
|
|
|
|
Logger.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Logger.Printf("Sending %d maillogs to Mailer", len(msc))
|
|
|
|
mailer.Mailer.Queue <- msc
|
|
|
|
}(cid, msc)
|
2014-06-05 04:54:46 +00:00
|
|
|
}
|
2014-03-28 04:31:51 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-25 02:03:53 +00:00
|
|
|
|
2017-12-09 21:42:07 +00:00
|
|
|
// LaunchCampaign starts a campaign
|
|
|
|
func (w *Worker) LaunchCampaign(c models.Campaign) {
|
|
|
|
ms, err := models.GetMailLogsByCampaign(c.Id)
|
2016-05-30 19:55:45 +00:00
|
|
|
if err != nil {
|
|
|
|
Logger.Println(err)
|
2017-12-09 21:42:07 +00:00
|
|
|
return
|
2016-07-07 04:25:28 +00:00
|
|
|
}
|
2017-12-09 21:42:07 +00:00
|
|
|
models.LockMailLogs(ms, true)
|
|
|
|
// This is required since you cannot pass a slice of values
|
|
|
|
// that implements an interface as a slice of that interface.
|
|
|
|
mailEntries := []mailer.Mail{}
|
|
|
|
for _, m := range ms {
|
|
|
|
mailEntries = append(mailEntries, m)
|
2016-01-25 02:03:53 +00:00
|
|
|
}
|
2017-12-09 21:42:07 +00:00
|
|
|
mailer.Mailer.Queue <- mailEntries
|
|
|
|
}
|
2017-02-20 00:43:08 +00:00
|
|
|
|
2017-12-09 21:42:07 +00:00
|
|
|
// SendTestEmail sends a test email
|
|
|
|
func (w *Worker) SendTestEmail(s *models.SendTestEmailRequest) error {
|
|
|
|
go func() {
|
|
|
|
mailer.Mailer.Queue <- []mailer.Mail{s}
|
|
|
|
}()
|
|
|
|
return <-s.ErrorChan
|
|
|
|
}
|
2017-02-20 00:43:08 +00:00
|
|
|
|
2017-12-09 21:42:07 +00:00
|
|
|
// errorMail is a helper to handle erroring out a slice of Mail instances
|
|
|
|
// in the case that an unrecoverable error occurs.
|
|
|
|
func errorMail(err error, ms []mailer.Mail) {
|
|
|
|
for _, m := range ms {
|
|
|
|
m.Error(err)
|
2016-01-25 02:03:53 +00:00
|
|
|
}
|
|
|
|
}
|