mirror of https://github.com/gophish/gophish
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 #38pull/64/head
parent
b574fb2741
commit
01c3da611b
|
@ -97,7 +97,11 @@ func PhishTracker(w http.ResponseWriter, r *http.Request) {
|
||||||
Logger.Println(err)
|
Logger.Println(err)
|
||||||
}
|
}
|
||||||
c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_OPENED})
|
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
|
// 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 {
|
if err != nil {
|
||||||
Logger.Println(err)
|
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})
|
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
|
// Use allows us to stack middleware to process the request
|
||||||
|
|
|
@ -20,12 +20,12 @@ type Campaign struct {
|
||||||
PageId int64 `json:"-"`
|
PageId int64 `json:"-"`
|
||||||
Page Page `json:"page"`
|
Page Page `json:"page"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
EmailsSent string `json:"emails_sent"`
|
|
||||||
Results []Result `json:"results,omitempty"`
|
Results []Result `json:"results,omitempty"`
|
||||||
Groups []Group `json:"groups,omitempty"`
|
Groups []Group `json:"groups,omitempty"`
|
||||||
Events []Event `json:"timeline,omitemtpy"`
|
Events []Event `json:"timeline,omitemtpy"`
|
||||||
SMTP SMTP `json:"smtp"`
|
SMTP SMTP `json:"smtp"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
Errors []string `json:"errors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrCampaignNameNotSpecified indicates there was no template given by the user
|
// 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
|
// ErrTemplateNotSpecified indicates there was no template given by the user
|
||||||
var ErrTemplateNotSpecified = errors.New("No email template specified")
|
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
|
// ErrTemplateNotFound indicates the template specified does not exist in the database
|
||||||
var ErrTemplateNotFound = errors.New("Template not found")
|
var ErrTemplateNotFound = errors.New("Template not found")
|
||||||
|
|
||||||
// ErrGroupnNotFound indicates a group specified by the user does not exist in the database
|
// ErrGroupnNotFound indicates a group specified by the user does not exist in the database
|
||||||
var ErrGroupNotFound = errors.New("Group not found")
|
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
|
// Validate checks to make sure there are no invalid fields in a submitted campaign
|
||||||
func (c *Campaign) Validate() error {
|
func (c *Campaign) Validate() error {
|
||||||
switch {
|
switch {
|
||||||
|
@ -52,6 +58,8 @@ func (c *Campaign) Validate() error {
|
||||||
return ErrGroupNotSpecified
|
return ErrGroupNotSpecified
|
||||||
case c.Template.Name == "":
|
case c.Template.Name == "":
|
||||||
return ErrTemplateNotSpecified
|
return ErrTemplateNotSpecified
|
||||||
|
case c.Page.Name == "":
|
||||||
|
return ErrPageNotSpecified
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -97,6 +105,10 @@ func GetCampaigns(uid int64) ([]Campaign, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Println(err)
|
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
|
return cs, err
|
||||||
}
|
}
|
||||||
|
@ -117,6 +129,10 @@ func GetCampaign(id int64, uid int64) (Campaign, error) {
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
err = db.Table("templates").Where("id=?", c.TemplateId).Find(&c.Template).Error
|
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
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +168,17 @@ func PostCampaign(c *Campaign, uid int64) error {
|
||||||
}
|
}
|
||||||
c.Template = t
|
c.Template = t
|
||||||
c.TemplateId = t.Id
|
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
|
// Insert into the DB
|
||||||
err = db.Save(c).Error
|
err = db.Save(c).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,6 +21,9 @@ function save(){
|
||||||
name: $("#template").val()
|
name: $("#template").val()
|
||||||
},
|
},
|
||||||
url: $("#url").val(),
|
url: $("#url").val(),
|
||||||
|
page: {
|
||||||
|
name: $("#page").val()
|
||||||
|
},
|
||||||
smtp: {
|
smtp: {
|
||||||
from_address: $("input[name=from]").val(),
|
from_address: $("input[name=from]").val(),
|
||||||
host: $("input[name=host]").val(),
|
host: $("input[name=host]").val(),
|
||||||
|
@ -51,6 +54,7 @@ function edit(campaign){
|
||||||
// Clear the bloodhound instance
|
// Clear the bloodhound instance
|
||||||
group_bh.clear();
|
group_bh.clear();
|
||||||
template_bh.clear();
|
template_bh.clear();
|
||||||
|
page_bh.clear();
|
||||||
if (campaign == "new") {
|
if (campaign == "new") {
|
||||||
api.groups.get()
|
api.groups.get()
|
||||||
.success(function(groups){
|
.success(function(groups){
|
||||||
|
@ -72,6 +76,16 @@ function edit(campaign){
|
||||||
template_bh.add(templates)
|
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
|
// Create the group typeahead objects
|
||||||
groupTable = $("#groupTable").DataTable()
|
groupTable = $("#groupTable").DataTable()
|
||||||
suggestion_template = Hogan.compile('<div>{{name}}</div>')
|
|
||||||
group_bh = new Bloodhound({
|
group_bh = new Bloodhound({
|
||||||
datumTokenizer: function(g) { return Bloodhound.tokenizers.whitespace(g.name) },
|
datumTokenizer: function(g) { return Bloodhound.tokenizers.whitespace(g.name) },
|
||||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||||
|
@ -140,6 +153,9 @@ $(document).ready(function(){
|
||||||
})
|
})
|
||||||
.bind('typeahead:select', function(ev, group){
|
.bind('typeahead:select', function(ev, group){
|
||||||
$("#groupSelect").typeahead('val', group.name)
|
$("#groupSelect").typeahead('val', group.name)
|
||||||
|
})
|
||||||
|
.bind('typeahead:autocomplete', function(ev, group){
|
||||||
|
$("#groupSelect").typeahead('val', group.name)
|
||||||
});
|
});
|
||||||
// Create the template typeahead objects
|
// Create the template typeahead objects
|
||||||
template_bh = new Bloodhound({
|
template_bh = new Bloodhound({
|
||||||
|
@ -164,4 +180,33 @@ $(document).ready(function(){
|
||||||
.bind('typeahead:select', function(ev, template){
|
.bind('typeahead:select', function(ev, template){
|
||||||
$("#template").typeahead('val', template.name)
|
$("#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 '<div class="tt-suggestion">No pages matched that query</div>' },
|
||||||
|
suggestion: function(data){ return '<div>' + data.name + '</div>' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.bind('typeahead:select', function(ev, page){
|
||||||
|
$("#page").typeahead('val', page.name)
|
||||||
|
})
|
||||||
|
.bind('typeahead:autocomplete', function(ev, page){
|
||||||
|
$("#page").typeahead('val', page.name)
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
|
@ -68,9 +68,12 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name:</label>
|
<label for="name">Name:</label>
|
||||||
<input type="text" class="form-control" id="name" placeholder="Campaign name" autofocus>
|
<input type="text" class="form-control" id="name" placeholder="Campaign name" autofocus>
|
||||||
<label class="control-label" for="template">Template:</label>
|
<label class="control-label" for="template">Email Template:</label>
|
||||||
<input type="text" class="typeahead form-control" placeholder="Template Name" id="template"/>
|
<input type="text" class="typeahead form-control" placeholder="Template Name" id="template"/>
|
||||||
<br>
|
<br>
|
||||||
|
<label class="control-label" for="page">Landing Page:</label>
|
||||||
|
<input type="text" class="typeahead form-control" placeholder="Landing Page" id="page"/>
|
||||||
|
<br>
|
||||||
<label class="control-label" for="url">URL: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="Location of gophish listener (must be reachable by targets!)"></i></label>
|
<label class="control-label" for="url">URL: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="Location of gophish listener (must be reachable by targets!)"></i></label>
|
||||||
<input type="text" class="form-control" placeholder="http://192.168.1.1" id="url"/>
|
<input type="text" class="form-control" placeholder="http://192.168.1.1" id="url"/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
|
@ -110,7 +110,7 @@ func processCampaign(c *models.Campaign) {
|
||||||
err = e.Send(c.SMTP.Host, auth)
|
err = e.Send(c.SMTP.Host, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Println(err)
|
Logger.Println(err)
|
||||||
err = t.UpdateStatus("Error")
|
err = t.UpdateStatus(models.ERROR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Println(err)
|
Logger.Println(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue