github.com/topsteplocal/gophish@v0.6.0/models/smtp.go (about) 1 package models 2 3 import ( 4 "crypto/tls" 5 "errors" 6 "net/mail" 7 "os" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/gophish/gomail" 13 log "github.com/gophish/gophish/logger" 14 "github.com/gophish/gophish/mailer" 15 "github.com/jinzhu/gorm" 16 ) 17 18 // Dialer is a wrapper around a standard gomail.Dialer in order 19 // to implement the mailer.Dialer interface. This allows us to better 20 // separate the mailer package as opposed to forcing a connection 21 // between mailer and gomail. 22 type Dialer struct { 23 *gomail.Dialer 24 } 25 26 // Dial wraps the gomail dialer's Dial command 27 func (d *Dialer) Dial() (mailer.Sender, error) { 28 return d.Dialer.Dial() 29 } 30 31 // SMTP contains the attributes needed to handle the sending of campaign emails 32 type SMTP struct { 33 Id int64 `json:"id" gorm:"column:id; primary_key:yes"` 34 UserId int64 `json:"-" gorm:"column:user_id"` 35 Interface string `json:"interface_type" gorm:"column:interface_type"` 36 Name string `json:"name"` 37 Host string `json:"host"` 38 Username string `json:"username,omitempty"` 39 Password string `json:"password,omitempty"` 40 FromAddress string `json:"from_address"` 41 IgnoreCertErrors bool `json:"ignore_cert_errors"` 42 Headers []Header `json:"headers"` 43 ModifiedDate time.Time `json:"modified_date"` 44 } 45 46 // Header contains the fields and methods for a sending profile to have 47 // custom headers 48 type Header struct { 49 Id int64 `json:"-"` 50 SMTPId int64 `json:"-"` 51 Key string `json:"key"` 52 Value string `json:"value"` 53 } 54 55 // ErrFromAddressNotSpecified is thrown when there is no "From" address 56 // specified in the SMTP configuration 57 var ErrFromAddressNotSpecified = errors.New("No From Address specified") 58 59 // ErrHostNotSpecified is thrown when there is no Host specified 60 // in the SMTP configuration 61 var ErrHostNotSpecified = errors.New("No SMTP Host specified") 62 63 // ErrInvalidHost indicates that the SMTP server string is invalid 64 var ErrInvalidHost = errors.New("Invalid SMTP server address") 65 66 // TableName specifies the database tablename for Gorm to use 67 func (s SMTP) TableName() string { 68 return "smtp" 69 } 70 71 // Validate ensures that SMTP configs/connections are valid 72 func (s *SMTP) Validate() error { 73 switch { 74 case s.FromAddress == "": 75 return ErrFromAddressNotSpecified 76 case s.Host == "": 77 return ErrHostNotSpecified 78 } 79 _, err := mail.ParseAddress(s.FromAddress) 80 if err != nil { 81 return err 82 } 83 // Make sure addr is in host:port format 84 hp := strings.Split(s.Host, ":") 85 if len(hp) > 2 { 86 return ErrInvalidHost 87 } else if len(hp) < 2 { 88 hp = append(hp, "25") 89 } 90 _, err = strconv.Atoi(hp[1]) 91 if err != nil { 92 return ErrInvalidHost 93 } 94 return err 95 } 96 97 // GetDialer returns a dialer for the given SMTP profile 98 func (s *SMTP) GetDialer() (mailer.Dialer, error) { 99 // Setup the message and dial 100 hp := strings.Split(s.Host, ":") 101 if len(hp) < 2 { 102 hp = append(hp, "25") 103 } 104 // Any issues should have been caught in validation, but we'll 105 // double check here. 106 port, err := strconv.Atoi(hp[1]) 107 if err != nil { 108 log.Error(err) 109 return nil, err 110 } 111 d := gomail.NewDialer(hp[0], port, s.Username, s.Password) 112 d.TLSConfig = &tls.Config{ 113 ServerName: s.Host, 114 InsecureSkipVerify: s.IgnoreCertErrors, 115 } 116 hostname, err := os.Hostname() 117 if err != nil { 118 log.Error(err) 119 hostname = "localhost" 120 } 121 d.LocalName = hostname 122 return &Dialer{d}, err 123 } 124 125 // GetSMTPs returns the SMTPs owned by the given user. 126 func GetSMTPs(uid int64) ([]SMTP, error) { 127 ss := []SMTP{} 128 err := db.Where("user_id=?", uid).Find(&ss).Error 129 if err != nil { 130 log.Error(err) 131 return ss, err 132 } 133 for i := range ss { 134 err = db.Where("smtp_id=?", ss[i].Id).Find(&ss[i].Headers).Error 135 if err != nil && err != gorm.ErrRecordNotFound { 136 log.Error(err) 137 return ss, err 138 } 139 } 140 return ss, nil 141 } 142 143 // GetSMTP returns the SMTP, if it exists, specified by the given id and user_id. 144 func GetSMTP(id int64, uid int64) (SMTP, error) { 145 s := SMTP{} 146 err := db.Where("user_id=? and id=?", uid, id).Find(&s).Error 147 if err != nil { 148 log.Error(err) 149 } 150 err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error 151 if err != nil && err != gorm.ErrRecordNotFound { 152 log.Error(err) 153 return s, err 154 } 155 return s, err 156 } 157 158 // GetSMTPByName returns the SMTP, if it exists, specified by the given name and user_id. 159 func GetSMTPByName(n string, uid int64) (SMTP, error) { 160 s := SMTP{} 161 err := db.Where("user_id=? and name=?", uid, n).Find(&s).Error 162 if err != nil { 163 log.Error(err) 164 return s, err 165 } 166 err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error 167 if err != nil && err != gorm.ErrRecordNotFound { 168 log.Error(err) 169 } 170 return s, err 171 } 172 173 // PostSMTP creates a new SMTP in the database. 174 func PostSMTP(s *SMTP) error { 175 err := s.Validate() 176 if err != nil { 177 log.Error(err) 178 return err 179 } 180 // Insert into the DB 181 err = db.Save(s).Error 182 if err != nil { 183 log.Error(err) 184 } 185 // Save custom headers 186 for i := range s.Headers { 187 s.Headers[i].SMTPId = s.Id 188 err := db.Save(&s.Headers[i]).Error 189 if err != nil { 190 log.Error(err) 191 return err 192 } 193 } 194 return err 195 } 196 197 // PutSMTP edits an existing SMTP in the database. 198 // Per the PUT Method RFC, it presumes all data for a SMTP is provided. 199 func PutSMTP(s *SMTP) error { 200 err := s.Validate() 201 if err != nil { 202 log.Error(err) 203 return err 204 } 205 err = db.Where("id=?", s.Id).Save(s).Error 206 if err != nil { 207 log.Error(err) 208 } 209 // Delete all custom headers, and replace with new ones 210 err = db.Where("smtp_id=?", s.Id).Delete(&Header{}).Error 211 if err != nil && err != gorm.ErrRecordNotFound { 212 log.Error(err) 213 return err 214 } 215 for i := range s.Headers { 216 s.Headers[i].SMTPId = s.Id 217 err := db.Save(&s.Headers[i]).Error 218 if err != nil { 219 log.Error(err) 220 return err 221 } 222 } 223 return err 224 } 225 226 // DeleteSMTP deletes an existing SMTP in the database. 227 // An error is returned if a SMTP with the given user id and SMTP id is not found. 228 func DeleteSMTP(id int64, uid int64) error { 229 // Delete all custom headers 230 err = db.Where("smtp_id=?", id).Delete(&Header{}).Error 231 if err != nil { 232 log.Error(err) 233 return err 234 } 235 err = db.Where("user_id=?", uid).Delete(SMTP{Id: id}).Error 236 if err != nil { 237 log.Error(err) 238 } 239 return err 240 }