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