github.com/amar224/phishing-tool@v0.9.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 return s, err 150 } 151 err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error 152 if err != nil && err != gorm.ErrRecordNotFound { 153 log.Error(err) 154 return s, err 155 } 156 return s, err 157 } 158 159 // GetSMTPByName returns the SMTP, if it exists, specified by the given name and user_id. 160 func GetSMTPByName(n string, uid int64) (SMTP, error) { 161 s := SMTP{} 162 err := db.Where("user_id=? and name=?", uid, n).Find(&s).Error 163 if err != nil { 164 log.Error(err) 165 return s, err 166 } 167 err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error 168 if err != nil && err != gorm.ErrRecordNotFound { 169 log.Error(err) 170 } 171 return s, err 172 } 173 174 // PostSMTP creates a new SMTP in the database. 175 func PostSMTP(s *SMTP) error { 176 err := s.Validate() 177 if err != nil { 178 log.Error(err) 179 return err 180 } 181 // Insert into the DB 182 err = db.Save(s).Error 183 if err != nil { 184 log.Error(err) 185 } 186 // Save custom headers 187 for i := range s.Headers { 188 s.Headers[i].SMTPId = s.Id 189 err := db.Save(&s.Headers[i]).Error 190 if err != nil { 191 log.Error(err) 192 return err 193 } 194 } 195 return err 196 } 197 198 // PutSMTP edits an existing SMTP in the database. 199 // Per the PUT Method RFC, it presumes all data for a SMTP is provided. 200 func PutSMTP(s *SMTP) error { 201 err := s.Validate() 202 if err != nil { 203 log.Error(err) 204 return err 205 } 206 err = db.Where("id=?", s.Id).Save(s).Error 207 if err != nil { 208 log.Error(err) 209 } 210 // Delete all custom headers, and replace with new ones 211 err = db.Where("smtp_id=?", s.Id).Delete(&Header{}).Error 212 if err != nil && err != gorm.ErrRecordNotFound { 213 log.Error(err) 214 return err 215 } 216 // Save custom headers 217 for i := range s.Headers { 218 s.Headers[i].SMTPId = s.Id 219 err := db.Save(&s.Headers[i]).Error 220 if err != nil { 221 log.Error(err) 222 return err 223 } 224 } 225 return err 226 } 227 228 // DeleteSMTP deletes an existing SMTP in the database. 229 // An error is returned if a SMTP with the given user id and SMTP id is not found. 230 func DeleteSMTP(id int64, uid int64) error { 231 // Delete all custom headers 232 err := db.Where("smtp_id=?", id).Delete(&Header{}).Error 233 if err != nil { 234 log.Error(err) 235 return err 236 } 237 err = db.Where("user_id=?", uid).Delete(SMTP{Id: id}).Error 238 if err != nil { 239 log.Error(err) 240 } 241 return err 242 }