github.com/edermi/gophish_mods@v0.7.0/models/maillog_test.go (about)

     1  package models
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math"
     8  	"net/textproto"
     9  	"time"
    10  
    11  	"github.com/gophish/gophish/config"
    12  
    13  	"github.com/gophish/gomail"
    14  	"github.com/jordan-wright/email"
    15  	"gopkg.in/check.v1"
    16  )
    17  
    18  func (s *ModelsSuite) emailFromFirstMailLog(campaign Campaign, ch *check.C) *email.Email {
    19  	result := campaign.Results[0]
    20  	m := &MailLog{}
    21  	err := db.Where("r_id=? AND campaign_id=?", result.RId, campaign.Id).
    22  		Find(m).Error
    23  	ch.Assert(err, check.Equals, nil)
    24  
    25  	msg := gomail.NewMessage()
    26  	err = m.Generate(msg)
    27  	ch.Assert(err, check.Equals, nil)
    28  
    29  	msgBuff := &bytes.Buffer{}
    30  	_, err = msg.WriteTo(msgBuff)
    31  	ch.Assert(err, check.Equals, nil)
    32  
    33  	got, err := email.NewEmailFromReader(msgBuff)
    34  	ch.Assert(err, check.Equals, nil)
    35  	return got
    36  }
    37  
    38  func (s *ModelsSuite) TestGetQueuedMailLogs(ch *check.C) {
    39  	campaign := s.createCampaign(ch)
    40  	ms, err := GetQueuedMailLogs(campaign.LaunchDate)
    41  	ch.Assert(err, check.Equals, nil)
    42  	got := make(map[string]*MailLog)
    43  	for _, m := range ms {
    44  		got[m.RId] = m
    45  	}
    46  	for _, r := range campaign.Results {
    47  		if m, ok := got[r.RId]; ok {
    48  			ch.Assert(m.RId, check.Equals, r.RId)
    49  			ch.Assert(m.CampaignId, check.Equals, campaign.Id)
    50  			ch.Assert(m.SendDate, check.Equals, campaign.LaunchDate)
    51  			ch.Assert(m.UserId, check.Equals, campaign.UserId)
    52  			ch.Assert(m.SendAttempt, check.Equals, 0)
    53  		} else {
    54  			ch.Fatalf("Result not found in maillogs: %s", r.RId)
    55  		}
    56  	}
    57  }
    58  
    59  func (s *ModelsSuite) TestMailLogBackoff(ch *check.C) {
    60  	campaign := s.createCampaign(ch)
    61  	result := campaign.Results[0]
    62  	m := &MailLog{}
    63  	err := db.Where("r_id=? AND campaign_id=?", result.RId, campaign.Id).
    64  		Find(m).Error
    65  	ch.Assert(err, check.Equals, nil)
    66  	ch.Assert(m.SendAttempt, check.Equals, 0)
    67  	ch.Assert(m.SendDate, check.Equals, campaign.LaunchDate)
    68  
    69  	expectedError := &textproto.Error{
    70  		Code: 500,
    71  		Msg:  "Recipient not found",
    72  	}
    73  	for i := m.SendAttempt; i < MaxSendAttempts; i++ {
    74  		err = m.Lock()
    75  		ch.Assert(err, check.Equals, nil)
    76  		ch.Assert(m.Processing, check.Equals, true)
    77  
    78  		expectedDuration := math.Pow(2, float64(m.SendAttempt+1))
    79  		expectedSendDate := m.SendDate.Add(time.Minute * time.Duration(expectedDuration))
    80  		err = m.Backoff(expectedError)
    81  		ch.Assert(err, check.Equals, nil)
    82  		ch.Assert(m.SendDate, check.Equals, expectedSendDate)
    83  		ch.Assert(m.Processing, check.Equals, false)
    84  		result, err := GetResult(m.RId)
    85  		ch.Assert(err, check.Equals, nil)
    86  		ch.Assert(result.SendDate, check.Equals, expectedSendDate)
    87  		ch.Assert(result.Status, check.Equals, STATUS_RETRY)
    88  	}
    89  	// Get our updated campaign and check for the added event
    90  	campaign, err = GetCampaign(campaign.Id, int64(1))
    91  	ch.Assert(err, check.Equals, nil)
    92  
    93  	// We expect MaxSendAttempts + the initial campaign created event
    94  	ch.Assert(len(campaign.Events), check.Equals, MaxSendAttempts+1)
    95  
    96  	// Check that we receive our error after meeting the maximum send attempts
    97  	err = m.Backoff(expectedError)
    98  	ch.Assert(err, check.Equals, ErrMaxSendAttempts)
    99  }
   100  
   101  func (s *ModelsSuite) TestMailLogError(ch *check.C) {
   102  	campaign := s.createCampaign(ch)
   103  	result := campaign.Results[0]
   104  	m := &MailLog{}
   105  	err := db.Where("r_id=? AND campaign_id=?", result.RId, campaign.Id).
   106  		Find(m).Error
   107  	ch.Assert(err, check.Equals, nil)
   108  	ch.Assert(m.RId, check.Equals, result.RId)
   109  
   110  	expectedError := &textproto.Error{
   111  		Code: 500,
   112  		Msg:  "Recipient not found",
   113  	}
   114  	err = m.Error(expectedError)
   115  	ch.Assert(err, check.Equals, nil)
   116  
   117  	// Get our result and make sure the status is set correctly
   118  	result, err = GetResult(result.RId)
   119  	ch.Assert(err, check.Equals, nil)
   120  	ch.Assert(result.Status, check.Equals, ERROR)
   121  
   122  	// Get our updated campaign and check for the added event
   123  	campaign, err = GetCampaign(campaign.Id, int64(1))
   124  	ch.Assert(err, check.Equals, nil)
   125  
   126  	expectedEventLength := 2
   127  	ch.Assert(len(campaign.Events), check.Equals, expectedEventLength)
   128  
   129  	gotEvent := campaign.Events[1]
   130  	es := EventError{Error: expectedError.Error()}
   131  	ej, _ := json.Marshal(es)
   132  	expectedEvent := Event{
   133  		Id:         gotEvent.Id,
   134  		Email:      result.Email,
   135  		Message:    EVENT_SENDING_ERROR,
   136  		CampaignId: campaign.Id,
   137  		Details:    string(ej),
   138  		Time:       gotEvent.Time,
   139  	}
   140  	ch.Assert(gotEvent, check.DeepEquals, expectedEvent)
   141  
   142  	ms, err := GetMailLogsByCampaign(campaign.Id)
   143  	ch.Assert(err, check.Equals, nil)
   144  	ch.Assert(len(ms), check.Equals, len(campaign.Results)-1)
   145  }
   146  
   147  func (s *ModelsSuite) TestMailLogSuccess(ch *check.C) {
   148  	campaign := s.createCampaign(ch)
   149  	result := campaign.Results[0]
   150  	m := &MailLog{}
   151  	err := db.Where("r_id=? AND campaign_id=?", result.RId, campaign.Id).
   152  		Find(m).Error
   153  	ch.Assert(err, check.Equals, nil)
   154  	ch.Assert(m.RId, check.Equals, result.RId)
   155  
   156  	err = m.Success()
   157  	ch.Assert(err, check.Equals, nil)
   158  
   159  	// Get our result and make sure the status is set correctly
   160  	result, err = GetResult(result.RId)
   161  	ch.Assert(err, check.Equals, nil)
   162  	ch.Assert(result.Status, check.Equals, EVENT_SENT)
   163  
   164  	// Get our updated campaign and check for the added event
   165  	campaign, err = GetCampaign(campaign.Id, int64(1))
   166  	ch.Assert(err, check.Equals, nil)
   167  
   168  	expectedEventLength := 2
   169  	ch.Assert(len(campaign.Events), check.Equals, expectedEventLength)
   170  
   171  	gotEvent := campaign.Events[1]
   172  	expectedEvent := Event{
   173  		Id:         gotEvent.Id,
   174  		Email:      result.Email,
   175  		Message:    EVENT_SENT,
   176  		CampaignId: campaign.Id,
   177  		Time:       gotEvent.Time,
   178  	}
   179  	ch.Assert(gotEvent, check.DeepEquals, expectedEvent)
   180  	ch.Assert(result.SendDate, check.Equals, gotEvent.Time)
   181  
   182  	ms, err := GetMailLogsByCampaign(campaign.Id)
   183  	ch.Assert(err, check.Equals, nil)
   184  	ch.Assert(len(ms), check.Equals, len(campaign.Results)-1)
   185  }
   186  
   187  func (s *ModelsSuite) TestGenerateMailLog(ch *check.C) {
   188  	campaign := Campaign{
   189  		Id:         1,
   190  		UserId:     1,
   191  		LaunchDate: time.Now().UTC(),
   192  	}
   193  	result := Result{
   194  		RId: "abc1234",
   195  	}
   196  	err := GenerateMailLog(&campaign, &result, campaign.LaunchDate)
   197  	ch.Assert(err, check.Equals, nil)
   198  
   199  	m := MailLog{}
   200  	err = db.Where("r_id=?", result.RId).Find(&m).Error
   201  	ch.Assert(err, check.Equals, nil)
   202  	ch.Assert(m.RId, check.Equals, result.RId)
   203  	ch.Assert(m.CampaignId, check.Equals, campaign.Id)
   204  	ch.Assert(m.SendDate, check.Equals, campaign.LaunchDate)
   205  	ch.Assert(m.UserId, check.Equals, campaign.UserId)
   206  	ch.Assert(m.SendAttempt, check.Equals, 0)
   207  	ch.Assert(m.Processing, check.Equals, false)
   208  }
   209  
   210  func (s *ModelsSuite) TestMailLogGenerate(ch *check.C) {
   211  	campaign := s.createCampaign(ch)
   212  	result := campaign.Results[0]
   213  	expected := &email.Email{
   214  		Subject: fmt.Sprintf("%s - Subject", result.RId),
   215  		Text:    []byte(fmt.Sprintf("%s - Text", result.RId)),
   216  		HTML:    []byte(fmt.Sprintf("%s - HTML", result.RId)),
   217  	}
   218  	got := s.emailFromFirstMailLog(campaign, ch)
   219  	ch.Assert(got.Subject, check.Equals, expected.Subject)
   220  	ch.Assert(string(got.Text), check.Equals, string(expected.Text))
   221  	ch.Assert(string(got.HTML), check.Equals, string(expected.HTML))
   222  }
   223  
   224  func (s *ModelsSuite) TestMailLogGenerateTransparencyHeaders(ch *check.C) {
   225  	config.Conf.ContactAddress = "test@test.com"
   226  	expectedHeaders := map[string]string{
   227  		"X-Mailer":          config.ServerName,
   228  		"X-Gophish-Contact": config.Conf.ContactAddress,
   229  	}
   230  	campaign := s.createCampaign(ch)
   231  	got := s.emailFromFirstMailLog(campaign, ch)
   232  	for k, v := range expectedHeaders {
   233  		ch.Assert(got.Headers.Get(k), check.Equals, v)
   234  	}
   235  }
   236  
   237  func (s *ModelsSuite) TestMailLogGenerateOverrideTransparencyHeaders(ch *check.C) {
   238  	expectedHeaders := map[string]string{
   239  		"X-Mailer":          "",
   240  		"X-Gophish-Contact": "",
   241  	}
   242  	smtp := SMTP{
   243  		Name:        "Test SMTP",
   244  		Host:        "1.1.1.1:25",
   245  		FromAddress: "Foo Bar <foo@example.com>",
   246  		UserId:      1,
   247  		Headers: []Header{
   248  			Header{Key: "X-Gophish-Contact", Value: ""},
   249  			Header{Key: "X-Mailer", Value: ""},
   250  		},
   251  	}
   252  	ch.Assert(PostSMTP(&smtp), check.Equals, nil)
   253  	campaign := s.createCampaignDependencies(ch)
   254  	campaign.SMTP = smtp
   255  
   256  	ch.Assert(PostCampaign(&campaign, campaign.UserId), check.Equals, nil)
   257  	got := s.emailFromFirstMailLog(campaign, ch)
   258  	for k, v := range expectedHeaders {
   259  		ch.Assert(got.Headers.Get(k), check.Equals, v)
   260  	}
   261  }
   262  
   263  func (s *ModelsSuite) TestUnlockAllMailLogs(ch *check.C) {
   264  	campaign := s.createCampaign(ch)
   265  	ms, err := GetMailLogsByCampaign(campaign.Id)
   266  	ch.Assert(err, check.Equals, nil)
   267  	for _, m := range ms {
   268  		ch.Assert(m.Processing, check.Equals, false)
   269  	}
   270  	err = LockMailLogs(ms, true)
   271  	ms, err = GetMailLogsByCampaign(campaign.Id)
   272  	ch.Assert(err, check.Equals, nil)
   273  	for _, m := range ms {
   274  		ch.Assert(m.Processing, check.Equals, true)
   275  	}
   276  	err = UnlockAllMailLogs()
   277  	ch.Assert(err, check.Equals, nil)
   278  	ms, err = GetMailLogsByCampaign(campaign.Id)
   279  	ch.Assert(err, check.Equals, nil)
   280  	for _, m := range ms {
   281  		ch.Assert(m.Processing, check.Equals, false)
   282  	}
   283  }
   284  
   285  func (s *ModelsSuite) TestURLTemplateRendering(ch *check.C) {
   286  	template := Template{
   287  		Name:    "URLTemplate",
   288  		UserId:  1,
   289  		Text:    "{{.URL}}",
   290  		HTML:    "{{.URL}}",
   291  		Subject: "{{.URL}}",
   292  	}
   293  	ch.Assert(PostTemplate(&template), check.Equals, nil)
   294  	campaign := s.createCampaignDependencies(ch)
   295  	campaign.URL = "http://127.0.0.1/{{.Email}}/"
   296  	campaign.Template = template
   297  
   298  	ch.Assert(PostCampaign(&campaign, campaign.UserId), check.Equals, nil)
   299  	result := campaign.Results[0]
   300  	expectedURL := fmt.Sprintf("http://127.0.0.1/%s/?%s=%s", result.Email, RecipientParameter, result.RId)
   301  
   302  	got := s.emailFromFirstMailLog(campaign, ch)
   303  	ch.Assert(got.Subject, check.Equals, expectedURL)
   304  	ch.Assert(string(got.Text), check.Equals, expectedURL)
   305  	ch.Assert(string(got.HTML), check.Equals, expectedURL)
   306  }
   307  
   308  func (s *ModelsSuite) TestMailLogGenerateEmptySubject(ch *check.C) {
   309  
   310  	// in place of using createCampaign, we replicate its small code body
   311  	// here internally as we want to specify an empty subject to createCampaignDependencies
   312  	// campaign := s.createCampaign(ch)
   313  	campaign := s.createCampaignDependencies(ch, "") // specify empty subject
   314  	// Setup and "launch" our campaign
   315  	ch.Assert(PostCampaign(&campaign, campaign.UserId), check.Equals, nil)
   316  	result := campaign.Results[0]
   317  
   318  	expected := &email.Email{
   319  		Subject: "",
   320  		Text:    []byte(fmt.Sprintf("%s - Text", result.RId)),
   321  		HTML:    []byte(fmt.Sprintf("%s - HTML", result.RId)),
   322  	}
   323  	got := s.emailFromFirstMailLog(campaign, ch)
   324  	ch.Assert(got.Subject, check.Equals, expected.Subject)
   325  }