gophish/models/campaign.go

238 lines
6.8 KiB
Go
Raw Normal View History

package models
import (
"errors"
"fmt"
"time"
"github.com/jinzhu/gorm"
)
//Campaign is a struct representing a created campaign
type Campaign struct {
2016-02-22 03:09:14 +00:00
Id int64 `json:"id"`
UserId int64 `json:"-"`
Name string `json:"name" sql:"not null"`
CreatedDate time.Time `json:"created_date"`
CompletedDate time.Time `json:"completed_date"`
TaskId int64 `json:"-"`
Tasks []Task `json:"tasks"`
2016-02-22 03:09:14 +00:00
Status string `json:"status"`
Results []Result `json:"results,omitempty"`
Groups []Group `json:"groups,omitempty"`
Events []Event `json:"timeline,omitemtpy"`
}
// ErrCampaignNameNotSpecified indicates there was no template given by the user
var ErrCampaignNameNotSpecified = errors.New("Campaign name not specified")
// ErrGroupNotSpecified indicates there was no template given by the user
var ErrGroupNotSpecified = errors.New("No groups specified")
// ErrTemplateNotSpecified indicates there was no template given by the user
var ErrTemplateNotSpecified = errors.New("No email template specified")
// ErrPageNotSpecified indicates a landing page was not provided for the campaign
var ErrPageNotSpecified = errors.New("No landing page specified")
// ErrSMTPNotSpecified indicates a sending profile was not provided for the campaign
var ErrSMTPNotSpecified = errors.New("No sending profile specified")
// ErrTasksNotSpecified indicates there were no tasks given by the user
var ErrTasksNotSpecified = errors.New("No tasks specified")
// ErrInvalidStartTask indicates the starting task was not sending an email
var ErrInvalidStartTask = errors.New("All campaigns must start by sending an email")
// Validate checks to make sure there are no invalid fields in a submitted campaign
func (c *Campaign) Validate() error {
switch {
case c.Name == "":
return ErrCampaignNameNotSpecified
case len(c.Groups) == 0:
return ErrGroupNotSpecified
case len(c.Tasks) == 0:
return ErrTasksNotSpecified
case c.Tasks[0].Type != "SEND_EMAIL":
return ErrInvalidStartTask
}
return nil
}
// SendTestEmailRequest is the structure of a request
// to send a test email to test an SMTP connection
type SendTestEmailRequest struct {
Template Template `json:"template"`
Page Page `json:"page"`
SMTP SMTP `json:"smtp"`
URL string `json:"url"`
Tracker string `json:"tracker"`
TrackingURL string `json:"tracking_url"`
From string `json:"from"`
Target
}
// Validate ensures the SendTestEmailRequest structure
// is valid.
func (s *SendTestEmailRequest) Validate() error {
switch {
case s.Email == "":
return ErrEmailNotSpecified
2016-02-22 03:09:14 +00:00
}
return nil
}
// UpdateStatus changes the campaign status appropriately
func (c *Campaign) UpdateStatus(s string) error {
// This could be made simpler, but I think there's a bug in gorm
return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error
}
// AddEvent creates a new campaign event in the database
func (c *Campaign) AddEvent(e Event) error {
e.CampaignId = c.Id
e.Time = time.Now()
return db.Save(&e).Error
}
// getDetails retrieves the related attributes of the campaign
// from the database. If the Events and the Results are not available,
// an error is returned. Otherwise, the attribute name is set to [Deleted],
// indicating the user deleted the attribute (template, smtp, etc.)
func (c *Campaign) getDetails() error {
err = db.Model(c).Related(&c.Results).Error
if err != nil {
Logger.Printf("%s: results not found for campaign\n", err)
return err
}
err = db.Model(c).Related(&c.Events).Error
if err != nil {
Logger.Printf("%s: events not found for campaign\n", err)
return err
}
c.Tasks, err = GetTasks(c.UserId, c.Id)
if err != nil {
Logger.Println(err)
return err
}
return nil
}
// Event contains the fields for an event
// that occurs during the campaign
type Event struct {
Id int64 `json:"-"`
CampaignId int64 `json:"-"`
Email string `json:"email"`
Time time.Time `json:"time"`
Message string `json:"message"`
Details string `json:"details"`
}
// GetCampaigns returns the campaigns owned by the given user.
func GetCampaigns(uid int64) ([]Campaign, error) {
cs := []Campaign{}
err := db.Model(&User{Id: uid}).Related(&cs).Error
if err != nil {
fmt.Println(err)
}
for i, _ := range cs {
err = cs[i].getDetails()
if err != nil {
Logger.Println(err)
}
}
return cs, err
}
// GetCampaign returns the campaign, if it exists, specified by the given id and user_id.
func GetCampaign(id int64, uid int64) (Campaign, error) {
c := Campaign{}
err := db.Where("id = ?", id).Where("user_id = ?", uid).Find(&c).Error
if err != nil {
Logger.Printf("%s: campaign not found\n", err)
return c, err
}
err = c.getDetails()
return c, err
}
// PostCampaign inserts a campaign and all associated records into the database.
func PostCampaign(c *Campaign, uid int64) error {
if err := c.Validate(); err != nil {
return err
}
// Fill in the details
c.UserId = uid
c.CreatedDate = time.Now()
c.CompletedDate = time.Time{}
c.Status = CAMPAIGN_QUEUED
// Check to make sure all the groups already exist
for i, g := range c.Groups {
c.Groups[i], err = GetGroupByName(g.Name, uid)
if err == gorm.ErrRecordNotFound {
Logger.Printf("Error - Group %s does not exist", g.Name)
return ErrGroupNotFound
} else if err != nil {
Logger.Println(err)
return err
}
}
for _, t := range c.Tasks {
err = PostTask(&t)
if err != nil {
Logger.Println(err)
return err
}
2016-02-22 03:09:14 +00:00
}
// Insert into the DB
err = db.Save(c).Error
if err != nil {
Logger.Println(err)
return err
}
err = c.AddEvent(Event{Message: "Campaign Created"})
if err != nil {
Logger.Println(err)
}
// Insert all the results
for _, g := range c.Groups {
// Insert a result for each target in the group
for _, t := range g.Targets {
r := &Result{Email: t.Email, Position: t.Position, Status: STATUS_SENDING, CampaignId: c.Id, UserId: c.UserId, FirstName: t.FirstName, LastName: t.LastName}
r.GenerateId()
err = db.Save(r).Error
if err != nil {
Logger.Printf("Error adding result record for target %s\n", t.Email)
Logger.Println(err)
}
c.Results = append(c.Results, *r)
}
}
return nil
}
//DeleteCampaign deletes the specified campaign
func DeleteCampaign(id int64) error {
Logger.Printf("Deleting campaign %d\n", id)
// Delete all the campaign results
2014-05-27 21:13:30 +00:00
err := db.Where("campaign_id=?", id).Delete(&Result{}).Error
if err != nil {
Logger.Println(err)
return err
}
err = db.Where("campaign_id=?", id).Delete(&Event{}).Error
if err != nil {
Logger.Println(err)
return err
}
// TODO Delete all the flows associated with the campaign
// Delete the campaign
err = db.Delete(&Campaign{Id: id}).Error
if err != nil {
Logger.Panicln(err)
return err
}
return err
}