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 }