From 01c3da611b85e734ad5aca277314caad67151637 Mon Sep 17 00:00:00 2001 From: Jordan Wright Date: Thu, 22 Oct 2015 22:29:10 -0500 Subject: [PATCH] PhishHandler now loads landing page content. Fixes #37 Now supports autocomplete for modal typeahead. Fixes #40 Users can now specify landing pages in campaigns. Fixes #39 Implemented "Email Opened" status. Fixes #38 --- controllers/route.go | 12 ++++++++-- models/campaign.go | 29 ++++++++++++++++++++++- static/js/app/campaigns.js | 47 +++++++++++++++++++++++++++++++++++++- templates/campaigns.html | 5 +++- worker/worker.go | 2 +- 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/controllers/route.go b/controllers/route.go index 1b30df7a..15f08351 100644 --- a/controllers/route.go +++ b/controllers/route.go @@ -97,7 +97,11 @@ func PhishTracker(w http.ResponseWriter, r *http.Request) { Logger.Println(err) } c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_OPENED}) - w.Write([]byte("It Works!")) + err = rs.UpdateStatus(models.EVENT_OPENED) + if err != nil { + Logger.Println(err) + } + w.Write([]byte("")) } // PhishHandler handles incoming client connections and registers the associated actions performed @@ -119,8 +123,12 @@ func PhishHandler(w http.ResponseWriter, r *http.Request) { if err != nil { Logger.Println(err) } + p, err := models.GetPage(c.PageId, c.UserId) + if err != nil { + Logger.Println(err) + } c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_CLICKED}) - w.Write([]byte("It Works!")) + w.Write([]byte(p.HTML)) } // Use allows us to stack middleware to process the request diff --git a/models/campaign.go b/models/campaign.go index 4bdfb292..9e76e20d 100644 --- a/models/campaign.go +++ b/models/campaign.go @@ -20,12 +20,12 @@ type Campaign struct { PageId int64 `json:"-"` Page Page `json:"page"` Status string `json:"status"` - EmailsSent string `json:"emails_sent"` Results []Result `json:"results,omitempty"` Groups []Group `json:"groups,omitempty"` Events []Event `json:"timeline,omitemtpy"` SMTP SMTP `json:"smtp"` URL string `json:"url"` + Errors []string `json:"errors,omitempty"` } // ErrCampaignNameNotSpecified indicates there was no template given by the user @@ -37,12 +37,18 @@ 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") + // ErrTemplateNotFound indicates the template specified does not exist in the database var ErrTemplateNotFound = errors.New("Template not found") // ErrGroupnNotFound indicates a group specified by the user does not exist in the database var ErrGroupNotFound = errors.New("Group not found") +// ErrPageNotFound indicates a page specified by the user does not exist in the database +var ErrPageNotFound = errors.New("Page not found") + // Validate checks to make sure there are no invalid fields in a submitted campaign func (c *Campaign) Validate() error { switch { @@ -52,6 +58,8 @@ func (c *Campaign) Validate() error { return ErrGroupNotSpecified case c.Template.Name == "": return ErrTemplateNotSpecified + case c.Page.Name == "": + return ErrPageNotSpecified } return nil } @@ -97,6 +105,10 @@ func GetCampaigns(uid int64) ([]Campaign, error) { if err != nil { Logger.Println(err) } + err = db.Table("pages").Where("id=?", cs[i].PageId).Find(&cs[i].Page).Error + if err != nil { + Logger.Println(err) + } } return cs, err } @@ -117,6 +129,10 @@ func GetCampaign(id int64, uid int64) (Campaign, error) { return c, err } err = db.Table("templates").Where("id=?", c.TemplateId).Find(&c.Template).Error + if err != nil { + return c, err + } + err = db.Table("pages").Where("id=?", c.PageId).Find(&c.Page).Error return c, err } @@ -152,6 +168,17 @@ func PostCampaign(c *Campaign, uid int64) error { } c.Template = t c.TemplateId = t.Id + // Check to make sure the page exists + p, err := GetPageByName(c.Page.Name, uid) + if err == gorm.RecordNotFound { + Logger.Printf("Error - Page %s does not exist", p.Name) + return ErrPageNotFound + } else if err != nil { + Logger.Println(err) + return err + } + c.Page = p + c.PageId = p.Id // Insert into the DB err = db.Save(c).Error if err != nil { diff --git a/static/js/app/campaigns.js b/static/js/app/campaigns.js index 9f6b2943..4c3a1045 100644 --- a/static/js/app/campaigns.js +++ b/static/js/app/campaigns.js @@ -21,6 +21,9 @@ function save(){ name: $("#template").val() }, url: $("#url").val(), + page: { + name: $("#page").val() + }, smtp: { from_address: $("input[name=from]").val(), host: $("input[name=host]").val(), @@ -51,6 +54,7 @@ function edit(campaign){ // Clear the bloodhound instance group_bh.clear(); template_bh.clear(); + page_bh.clear(); if (campaign == "new") { api.groups.get() .success(function(groups){ @@ -72,6 +76,16 @@ function edit(campaign){ template_bh.add(templates) } }) + api.pages.get() + .success(function(pages){ + if (pages.length == 0){ + modalError("No pages found!") + return false + } + else { + page_bh.add(pages) + } + }) } } @@ -118,7 +132,6 @@ $(document).ready(function(){ }) // Create the group typeahead objects groupTable = $("#groupTable").DataTable() - suggestion_template = Hogan.compile('
{{name}}
') group_bh = new Bloodhound({ datumTokenizer: function(g) { return Bloodhound.tokenizers.whitespace(g.name) }, queryTokenizer: Bloodhound.tokenizers.whitespace, @@ -140,6 +153,9 @@ $(document).ready(function(){ }) .bind('typeahead:select', function(ev, group){ $("#groupSelect").typeahead('val', group.name) + }) + .bind('typeahead:autocomplete', function(ev, group){ + $("#groupSelect").typeahead('val', group.name) }); // Create the template typeahead objects template_bh = new Bloodhound({ @@ -164,4 +180,33 @@ $(document).ready(function(){ .bind('typeahead:select', function(ev, template){ $("#template").typeahead('val', template.name) }) + .bind('typeahead:autocomplete', function(ev, template){ + $("#template").typeahead('val', template.name) + }); + // Create the landing page typeahead objects + page_bh = new Bloodhound({ + datumTokenizer: function(p) { return Bloodhound.tokenizers.whitespace(p.name) }, + queryTokenizer: Bloodhound.tokenizers.whitespace, + local: [] + }) + page_bh.initialize() + $("#page.typeahead.form-control").typeahead({ + hint: true, + highlight: true, + minLength: 1 + }, + { + name: "pages", + source: page_bh, + templates: { + empty: function(data) {return '
No pages matched that query
' }, + suggestion: function(data){ return '
' + data.name + '
' } + } + }) + .bind('typeahead:select', function(ev, page){ + $("#page").typeahead('val', page.name) + }) + .bind('typeahead:autocomplete', function(ev, page){ + $("#page").typeahead('val', page.name) + }); }) diff --git a/templates/campaigns.html b/templates/campaigns.html index f0090dbc..8c8354c6 100644 --- a/templates/campaigns.html +++ b/templates/campaigns.html @@ -68,9 +68,12 @@
- +
+ + +

diff --git a/worker/worker.go b/worker/worker.go index fffa2bd3..dc19cbb9 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -110,7 +110,7 @@ func processCampaign(c *models.Campaign) { err = e.Send(c.SMTP.Host, auth) if err != nil { Logger.Println(err) - err = t.UpdateStatus("Error") + err = t.UpdateStatus(models.ERROR) if err != nil { Logger.Println(err) }