🎣 Open-Source Phishing Toolkit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

365 lines
9.3 KiB

  1. package models
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/mail"
  6. "time"
  7. log "github.com/gophish/gophish/logger"
  8. "github.com/jinzhu/gorm"
  9. "github.com/sirupsen/logrus"
  10. )
  11. // Group contains the fields needed for a user -> group mapping
  12. // Groups contain 1..* Targets
  13. type Group struct {
  14. Id int64 `json:"id"`
  15. UserId int64 `json:"-"`
  16. Name string `json:"name"`
  17. ModifiedDate time.Time `json:"modified_date"`
  18. Targets []Target `json:"targets" sql:"-"`
  19. }
  20. // GroupSummaries is a struct representing the overview of Groups.
  21. type GroupSummaries struct {
  22. Total int64 `json:"total"`
  23. Groups []GroupSummary `json:"groups"`
  24. }
  25. // GroupSummary represents a summary of the Group model. The only
  26. // difference is that, instead of listing the Targets (which could be expensive
  27. // for large groups), it lists the target count.
  28. type GroupSummary struct {
  29. Id int64 `json:"id"`
  30. Name string `json:"name"`
  31. ModifiedDate time.Time `json:"modified_date"`
  32. NumTargets int64 `json:"num_targets"`
  33. }
  34. // GroupTarget is used for a many-to-many relationship between 1..* Groups and 1..* Targets
  35. type GroupTarget struct {
  36. GroupId int64 `json:"-"`
  37. TargetId int64 `json:"-"`
  38. }
  39. // Target contains the fields needed for individual targets specified by the user
  40. // Groups contain 1..* Targets, but 1 Target may belong to 1..* Groups
  41. type Target struct {
  42. Id int64 `json:"-"`
  43. BaseRecipient
  44. }
  45. // BaseRecipient contains the fields for a single recipient. This is the base
  46. // struct used in members of groups and campaign results.
  47. type BaseRecipient struct {
  48. Email string `json:"email"`
  49. FirstName string `json:"first_name"`
  50. LastName string `json:"last_name"`
  51. Position string `json:"position"`
  52. }
  53. // FormatAddress returns the email address to use in the "To" header of the email
  54. func (r *BaseRecipient) FormatAddress() string {
  55. addr := r.Email
  56. if r.FirstName != "" && r.LastName != "" {
  57. a := &mail.Address{
  58. Name: fmt.Sprintf("%s %s", r.FirstName, r.LastName),
  59. Address: r.Email,
  60. }
  61. addr = a.String()
  62. }
  63. return addr
  64. }
  65. // FormatAddress returns the email address to use in the "To" header of the email
  66. func (t *Target) FormatAddress() string {
  67. addr := t.Email
  68. if t.FirstName != "" && t.LastName != "" {
  69. a := &mail.Address{
  70. Name: fmt.Sprintf("%s %s", t.FirstName, t.LastName),
  71. Address: t.Email,
  72. }
  73. addr = a.String()
  74. }
  75. return addr
  76. }
  77. // ErrEmailNotSpecified is thrown when no email is specified for the Target
  78. var ErrEmailNotSpecified = errors.New("No email address specified")
  79. // ErrGroupNameNotSpecified is thrown when a group name is not specified
  80. var ErrGroupNameNotSpecified = errors.New("Group name not specified")
  81. // ErrNoTargetsSpecified is thrown when no targets are specified by the user
  82. var ErrNoTargetsSpecified = errors.New("No targets specified")
  83. // Validate performs validation on a group given by the user
  84. func (g *Group) Validate() error {
  85. switch {
  86. case g.Name == "":
  87. return ErrGroupNameNotSpecified
  88. case len(g.Targets) == 0:
  89. return ErrNoTargetsSpecified
  90. }
  91. return nil
  92. }
  93. // GetGroups returns the groups owned by the given user.
  94. func GetGroups(uid int64) ([]Group, error) {
  95. gs := []Group{}
  96. err := db.Where("user_id=?", uid).Find(&gs).Error
  97. if err != nil {
  98. log.Error(err)
  99. return gs, err
  100. }
  101. for i := range gs {
  102. gs[i].Targets, err = GetTargets(gs[i].Id)
  103. if err != nil {
  104. log.Error(err)
  105. }
  106. }
  107. return gs, nil
  108. }
  109. // GetGroupSummaries returns the summaries for the groups
  110. // created by the given uid.
  111. func GetGroupSummaries(uid int64) (GroupSummaries, error) {
  112. gs := GroupSummaries{}
  113. query := db.Table("groups").Where("user_id=?", uid)
  114. err := query.Select("id, name, modified_date").Scan(&gs.Groups).Error
  115. if err != nil {
  116. log.Error(err)
  117. return gs, err
  118. }
  119. for i := range gs.Groups {
  120. query = db.Table("group_targets").Where("group_id=?", gs.Groups[i].Id)
  121. err = query.Count(&gs.Groups[i].NumTargets).Error
  122. if err != nil {
  123. return gs, err
  124. }
  125. }
  126. gs.Total = int64(len(gs.Groups))
  127. return gs, nil
  128. }
  129. // GetGroup returns the group, if it exists, specified by the given id and user_id.
  130. func GetGroup(id int64, uid int64) (Group, error) {
  131. g := Group{}
  132. err := db.Where("user_id=? and id=?", uid, id).Find(&g).Error
  133. if err != nil {
  134. log.Error(err)
  135. return g, err
  136. }
  137. g.Targets, err = GetTargets(g.Id)
  138. if err != nil {
  139. log.Error(err)
  140. }
  141. return g, nil
  142. }
  143. // GetGroupSummary returns the summary for the requested group
  144. func GetGroupSummary(id int64, uid int64) (GroupSummary, error) {
  145. g := GroupSummary{}
  146. query := db.Table("groups").Where("user_id=? and id=?", uid, id)
  147. err := query.Select("id, name, modified_date").Scan(&g).Error
  148. if err != nil {
  149. log.Error(err)
  150. return g, err
  151. }
  152. query = db.Table("group_targets").Where("group_id=?", id)
  153. err = query.Count(&g.NumTargets).Error
  154. if err != nil {
  155. return g, err
  156. }
  157. return g, nil
  158. }
  159. // GetGroupByName returns the group, if it exists, specified by the given name and user_id.
  160. func GetGroupByName(n string, uid int64) (Group, error) {
  161. g := Group{}
  162. err := db.Where("user_id=? and name=?", uid, n).Find(&g).Error
  163. if err != nil {
  164. log.Error(err)
  165. return g, err
  166. }
  167. g.Targets, err = GetTargets(g.Id)
  168. if err != nil {
  169. log.Error(err)
  170. }
  171. return g, err
  172. }
  173. // PostGroup creates a new group in the database.
  174. func PostGroup(g *Group) error {
  175. if err := g.Validate(); err != nil {
  176. return err
  177. }
  178. // Insert the group into the DB
  179. tx := db.Begin()
  180. err := tx.Save(g).Error
  181. if err != nil {
  182. tx.Rollback()
  183. log.Error(err)
  184. return err
  185. }
  186. for _, t := range g.Targets {
  187. err = insertTargetIntoGroup(tx, t, g.Id)
  188. if err != nil {
  189. tx.Rollback()
  190. log.Error(err)
  191. return err
  192. }
  193. }
  194. err = tx.Commit().Error
  195. if err != nil {
  196. log.Error(err)
  197. tx.Rollback()
  198. return err
  199. }
  200. return nil
  201. }
  202. // PutGroup updates the given group if found in the database.
  203. func PutGroup(g *Group) error {
  204. if err := g.Validate(); err != nil {
  205. return err
  206. }
  207. // Fetch group's existing targets from database.
  208. ts := []Target{}
  209. ts, err := GetTargets(g.Id)
  210. if err != nil {
  211. log.WithFields(logrus.Fields{
  212. "group_id": g.Id,
  213. }).Error("Error getting targets from group")
  214. return err
  215. }
  216. // Preload the caches
  217. cacheNew := make(map[string]int64, len(g.Targets))
  218. for _, t := range g.Targets {
  219. cacheNew[t.Email] = t.Id
  220. }
  221. cacheExisting := make(map[string]int64, len(ts))
  222. for _, t := range ts {
  223. cacheExisting[t.Email] = t.Id
  224. }
  225. tx := db.Begin()
  226. // Check existing targets, removing any that are no longer in the group.
  227. for _, t := range ts {
  228. if _, ok := cacheNew[t.Email]; ok {
  229. continue
  230. }
  231. // If the target does not exist in the group any longer, we delete it
  232. err := tx.Where("group_id=? and target_id=?", g.Id, t.Id).Delete(&GroupTarget{}).Error
  233. if err != nil {
  234. tx.Rollback()
  235. log.WithFields(logrus.Fields{
  236. "email": t.Email,
  237. }).Error("Error deleting email")
  238. }
  239. }
  240. // Add any targets that are not in the database yet.
  241. for _, nt := range g.Targets {
  242. // If the target already exists in the database, we should just update
  243. // the record with the latest information.
  244. if id, ok := cacheExisting[nt.Email]; ok {
  245. nt.Id = id
  246. err = UpdateTarget(tx, nt)
  247. if err != nil {
  248. log.Error(err)
  249. tx.Rollback()
  250. return err
  251. }
  252. continue
  253. }
  254. // Otherwise, add target if not in database
  255. err = insertTargetIntoGroup(tx, nt, g.Id)
  256. if err != nil {
  257. log.Error(err)
  258. tx.Rollback()
  259. return err
  260. }
  261. }
  262. err = tx.Save(g).Error
  263. if err != nil {
  264. log.Error(err)
  265. return err
  266. }
  267. err = tx.Commit().Error
  268. if err != nil {
  269. tx.Rollback()
  270. return err
  271. }
  272. return nil
  273. }
  274. // DeleteGroup deletes a given group by group ID and user ID
  275. func DeleteGroup(g *Group) error {
  276. // Delete all the group_targets entries for this group
  277. err := db.Where("group_id=?", g.Id).Delete(&GroupTarget{}).Error
  278. if err != nil {
  279. log.Error(err)
  280. return err
  281. }
  282. // Delete the group itself
  283. err = db.Delete(g).Error
  284. if err != nil {
  285. log.Error(err)
  286. return err
  287. }
  288. return err
  289. }
  290. func insertTargetIntoGroup(tx *gorm.DB, t Target, gid int64) error {
  291. if _, err := mail.ParseAddress(t.Email); err != nil {
  292. log.WithFields(logrus.Fields{
  293. "email": t.Email,
  294. }).Error("Invalid email")
  295. return err
  296. }
  297. err := tx.Where(t).FirstOrCreate(&t).Error
  298. if err != nil {
  299. log.WithFields(logrus.Fields{
  300. "email": t.Email,
  301. }).Error(err)
  302. return err
  303. }
  304. err = tx.Save(&GroupTarget{GroupId: gid, TargetId: t.Id}).Error
  305. if err != nil {
  306. log.Error(err)
  307. return err
  308. }
  309. if err != nil {
  310. log.WithFields(logrus.Fields{
  311. "email": t.Email,
  312. }).Error("Error adding many-many mapping")
  313. return err
  314. }
  315. return nil
  316. }
  317. // UpdateTarget updates the given target information in the database.
  318. func UpdateTarget(tx *gorm.DB, target Target) error {
  319. targetInfo := map[string]interface{}{
  320. "first_name": target.FirstName,
  321. "last_name": target.LastName,
  322. "position": target.Position,
  323. }
  324. err := tx.Model(&target).Where("id = ?", target.Id).Updates(targetInfo).Error
  325. if err != nil {
  326. log.WithFields(logrus.Fields{
  327. "email": target.Email,
  328. }).Error("Error updating target information")
  329. }
  330. return err
  331. }
  332. // GetTargets performs a many-to-many select to get all the Targets for a Group
  333. func GetTargets(gid int64) ([]Target, error) {
  334. ts := []Target{}
  335. err := db.Table("targets").Select("targets.id, targets.email, targets.first_name, targets.last_name, targets.position").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
  336. return ts, err
  337. }