mirror of https://github.com/gophish/gophish
Moved phishing handlers into separate file and added a ton of tests.
parent
b6653d5c94
commit
e42302ebf9
|
@ -24,6 +24,9 @@ type ControllersSuite struct {
|
|||
// as is the Admin Server for our API calls
|
||||
var as *httptest.Server = httptest.NewUnstartedServer(handlers.CombinedLoggingHandler(os.Stdout, CreateAdminRouter()))
|
||||
|
||||
// ps is the Phishing Server
|
||||
var ps *httptest.Server = httptest.NewUnstartedServer(handlers.CombinedLoggingHandler(os.Stdout, CreatePhishingRouter()))
|
||||
|
||||
func (s *ControllersSuite) SetupSuite() {
|
||||
config.Conf.DBName = "sqlite3"
|
||||
config.Conf.DBPath = ":memory:"
|
||||
|
@ -40,6 +43,63 @@ func (s *ControllersSuite) SetupSuite() {
|
|||
u, err := models.GetUser(1)
|
||||
s.Nil(err)
|
||||
s.ApiKey = u.ApiKey
|
||||
// Start the phishing server
|
||||
ps.Config.Addr = config.Conf.PhishConf.ListenURL
|
||||
ps.Start()
|
||||
// Move our cwd up to the project root for help with resolving
|
||||
// static assets
|
||||
err = os.Chdir("../")
|
||||
s.Nil(err)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TearDownTest() {
|
||||
campaigns, _ := models.GetCampaigns(1)
|
||||
for _, campaign := range campaigns {
|
||||
models.DeleteCampaign(campaign.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) SetupTest() {
|
||||
// Add a group
|
||||
group := models.Group{Name: "Test Group"}
|
||||
group.Targets = []models.Target{
|
||||
models.Target{Email: "test1@example.com", FirstName: "First", LastName: "Example"},
|
||||
models.Target{Email: "test2@example.com", FirstName: "Second", LastName: "Example"},
|
||||
}
|
||||
group.UserId = 1
|
||||
models.PostGroup(&group)
|
||||
|
||||
// Add a template
|
||||
t := models.Template{Name: "Test Template"}
|
||||
t.Subject = "Test subject"
|
||||
t.Text = "Text text"
|
||||
t.HTML = "<html>Test</html>"
|
||||
t.UserId = 1
|
||||
models.PostTemplate(&t)
|
||||
|
||||
// Add a landing page
|
||||
p := models.Page{Name: "Test Page"}
|
||||
p.HTML = "<html>Test</html>"
|
||||
p.UserId = 1
|
||||
models.PostPage(&p)
|
||||
|
||||
// Add a sending profile
|
||||
smtp := models.SMTP{Name: "Test Page"}
|
||||
smtp.UserId = 1
|
||||
smtp.Host = "example.com"
|
||||
smtp.FromAddress = "test@test.com"
|
||||
models.PostSMTP(&smtp)
|
||||
|
||||
// Setup and "launch" our campaign
|
||||
// Set the status such that no emails are attempted
|
||||
c := models.Campaign{Name: "Test campaign"}
|
||||
c.UserId = 1
|
||||
c.Template = t
|
||||
c.Page = p
|
||||
c.SMTP = smtp
|
||||
c.Groups = []models.Group{group}
|
||||
models.PostCampaign(&c, c.UserId)
|
||||
c.UpdateStatus(models.CAMPAIGN_EMAILS_SENT)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestSiteImportBaseHref() {
|
||||
|
@ -65,8 +125,9 @@ func (s *ControllersSuite) TestSiteImportBaseHref() {
|
|||
}
|
||||
|
||||
func (s *ControllersSuite) TearDownSuite() {
|
||||
// Tear down the admin server
|
||||
// Tear down the admin and phishing servers
|
||||
as.Close()
|
||||
ps.Close()
|
||||
}
|
||||
|
||||
func TestControllerSuite(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
ctx "github.com/gophish/gophish/context"
|
||||
"github.com/gophish/gophish/models"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// ErrInvalidRequest is thrown when a request with an invalid structure is
|
||||
// received
|
||||
var ErrInvalidRequest = errors.New("Invalid request")
|
||||
|
||||
// ErrCampaignComplete is thrown when an event is received for a campaign that
|
||||
// has already been marked as complete.
|
||||
var ErrCampaignComplete = errors.New("Event received on completed campaign")
|
||||
|
||||
// eventDetails is a struct that wraps common attributes we want to store
|
||||
// in an event
|
||||
type eventDetails struct {
|
||||
Payload url.Values `json:"payload"`
|
||||
Browser map[string]string `json:"browser"`
|
||||
}
|
||||
|
||||
// CreatePhishingRouter creates the router that handles phishing connections.
|
||||
func CreatePhishingRouter() http.Handler {
|
||||
router := mux.NewRouter()
|
||||
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/endpoint/"))))
|
||||
router.HandleFunc("/track", PhishTracker)
|
||||
router.HandleFunc("/robots.txt", RobotsHandler)
|
||||
router.HandleFunc("/{path:.*}/track", PhishTracker)
|
||||
router.HandleFunc("/{path:.*}", PhishHandler)
|
||||
return router
|
||||
}
|
||||
|
||||
// PhishTracker tracks emails as they are opened, updating the status for the given Result
|
||||
func PhishTracker(w http.ResponseWriter, r *http.Request) {
|
||||
err, r := setupContext(r)
|
||||
if err != nil {
|
||||
// Log the error if it wasn't something we can safely ignore
|
||||
if err != ErrInvalidRequest && err != ErrCampaignComplete {
|
||||
Logger.Println(err)
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
rs := ctx.Get(r, "result").(models.Result)
|
||||
c := ctx.Get(r, "campaign").(models.Campaign)
|
||||
rj := ctx.Get(r, "details").([]byte)
|
||||
c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_OPENED, Details: string(rj)})
|
||||
// Don't update the status if the user already clicked the link
|
||||
// or submitted data to the campaign
|
||||
if rs.Status == models.EVENT_CLICKED || rs.Status == models.EVENT_DATA_SUBMIT {
|
||||
http.ServeFile(w, r, "static/images/pixel.png")
|
||||
return
|
||||
}
|
||||
err = rs.UpdateStatus(models.EVENT_OPENED)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
http.ServeFile(w, r, "static/images/pixel.png")
|
||||
}
|
||||
|
||||
// PhishHandler handles incoming client connections and registers the associated actions performed
|
||||
// (such as clicked link, etc.)
|
||||
func PhishHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err, r := setupContext(r)
|
||||
if err != nil {
|
||||
// Log the error if it wasn't something we can safely ignore
|
||||
if err != ErrInvalidRequest && err != ErrCampaignComplete {
|
||||
Logger.Println(err)
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
rs := ctx.Get(r, "result").(models.Result)
|
||||
c := ctx.Get(r, "campaign").(models.Campaign)
|
||||
rj := ctx.Get(r, "details").([]byte)
|
||||
p, err := models.GetPage(c.PageId, c.UserId)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
switch {
|
||||
case r.Method == "GET":
|
||||
if rs.Status != models.EVENT_CLICKED && rs.Status != models.EVENT_DATA_SUBMIT {
|
||||
rs.UpdateStatus(models.EVENT_CLICKED)
|
||||
}
|
||||
err = c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_CLICKED, Details: string(rj)})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
case r.Method == "POST":
|
||||
// If data was POST'ed, let's record it
|
||||
rs.UpdateStatus(models.EVENT_DATA_SUBMIT)
|
||||
// Store the data in an event
|
||||
c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_DATA_SUBMIT, Details: string(rj)})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Redirect to the desired page
|
||||
if p.RedirectURL != "" {
|
||||
http.Redirect(w, r, p.RedirectURL, 302)
|
||||
return
|
||||
}
|
||||
}
|
||||
var htmlBuff bytes.Buffer
|
||||
tmpl, err := template.New("html_template").Parse(p.HTML)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
f, err := mail.ParseAddress(c.SMTP.FromAddress)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
fn := f.Name
|
||||
if fn == "" {
|
||||
fn = f.Address
|
||||
}
|
||||
rsf := struct {
|
||||
models.Result
|
||||
URL string
|
||||
From string
|
||||
}{
|
||||
rs,
|
||||
c.URL + "?rid=" + rs.RId,
|
||||
fn,
|
||||
}
|
||||
err = tmpl.Execute(&htmlBuff, rsf)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
w.Write(htmlBuff.Bytes())
|
||||
}
|
||||
|
||||
// RobotsHandler prevents search engines, etc. from indexing phishing materials
|
||||
func RobotsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "User-agent: *\nDisallow: /")
|
||||
}
|
||||
|
||||
// setupContext handles some of the administrative work around receiving a new request, such as checking the result ID, the campaign, etc.
|
||||
func setupContext(r *http.Request) (error, *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err, r
|
||||
}
|
||||
id := r.Form.Get("rid")
|
||||
if id == "" {
|
||||
return ErrInvalidRequest, r
|
||||
}
|
||||
rs, err := models.GetResult(id)
|
||||
if err != nil {
|
||||
return err, r
|
||||
}
|
||||
c, err := models.GetCampaign(rs.CampaignId, rs.UserId)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err, r
|
||||
}
|
||||
// Don't process events for completed campaigns
|
||||
if c.Status == models.CAMPAIGN_COMPLETE {
|
||||
return ErrCampaignComplete, r
|
||||
}
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err, r
|
||||
}
|
||||
// Respect X-Forwarded headers
|
||||
if fips := r.Header.Get("X-Forwarded-For"); fips != "" {
|
||||
ip = strings.Split(fips, ", ")[0]
|
||||
}
|
||||
// Handle post processing such as GeoIP
|
||||
err = rs.UpdateGeo(ip)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
d := eventDetails{
|
||||
Payload: r.Form,
|
||||
Browser: make(map[string]string),
|
||||
}
|
||||
d.Browser["address"] = ip
|
||||
d.Browser["user-agent"] = r.Header.Get("User-Agent")
|
||||
rj, err := json.Marshal(d)
|
||||
|
||||
r = ctx.Set(r, "result", rs)
|
||||
r = ctx.Set(r, "campaign", c)
|
||||
r = ctx.Set(r, "details", rj)
|
||||
return nil, r
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gophish/gophish/models"
|
||||
)
|
||||
|
||||
func (s *ControllersSuite) getFirstCampaign() models.Campaign {
|
||||
campaigns, err := models.GetCampaigns(1)
|
||||
s.Nil(err)
|
||||
return campaigns[0]
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) openEmail(rid string) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/track?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
s.Nil(err)
|
||||
expected, err := ioutil.ReadFile("static/images/pixel.png")
|
||||
s.Nil(err)
|
||||
s.Equal(bytes.Compare(body, expected), 0)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) openEmail404(rid string) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/track?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
defer resp.Body.Close()
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) clickLink(rid string, campaign models.Campaign) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
s.Nil(err)
|
||||
s.Equal(bytes.Compare(body, []byte(campaign.Page.HTML)), 0)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) clickLink404(rid string) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
defer resp.Body.Close()
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestOpenedPhishingEmail() {
|
||||
campaign := s.getFirstCampaign()
|
||||
result := campaign.Results[0]
|
||||
s.Equal(result.Status, models.STATUS_SENDING)
|
||||
|
||||
s.openEmail(result.RId)
|
||||
|
||||
campaign = s.getFirstCampaign()
|
||||
result = campaign.Results[0]
|
||||
s.Equal(result.Status, models.EVENT_OPENED)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestClickedPhishingLinkAfterOpen() {
|
||||
campaign := s.getFirstCampaign()
|
||||
result := campaign.Results[0]
|
||||
s.Equal(result.Status, models.STATUS_SENDING)
|
||||
|
||||
s.openEmail(result.RId)
|
||||
s.clickLink(result.RId, campaign)
|
||||
|
||||
campaign = s.getFirstCampaign()
|
||||
result = campaign.Results[0]
|
||||
s.Equal(result.Status, models.EVENT_CLICKED)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestNoRecipientID() {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/track", ps.URL))
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
|
||||
resp, err = http.Get(ps.URL)
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestInvalidRecipientID() {
|
||||
rid := "XXXXXXXXXX"
|
||||
resp, err := http.Get(fmt.Sprintf("%s/track?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
|
||||
resp, err = http.Get(fmt.Sprintf("%s/?rid=%s", ps.URL, rid))
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestCompletedCampaignClick() {
|
||||
campaign := s.getFirstCampaign()
|
||||
result := campaign.Results[0]
|
||||
s.Equal(result.Status, models.STATUS_SENDING)
|
||||
s.openEmail(result.RId)
|
||||
|
||||
campaign = s.getFirstCampaign()
|
||||
result = campaign.Results[0]
|
||||
s.Equal(result.Status, models.EVENT_OPENED)
|
||||
|
||||
models.CompleteCampaign(campaign.Id, 1)
|
||||
s.openEmail404(result.RId)
|
||||
s.clickLink404(result.RId)
|
||||
|
||||
campaign = s.getFirstCampaign()
|
||||
result = campaign.Results[0]
|
||||
s.Equal(result.Status, models.EVENT_OPENED)
|
||||
}
|
||||
|
||||
func (s *ControllersSuite) TestRobotsHandler() {
|
||||
expected := []byte("User-agent: *\nDisallow: /\n")
|
||||
resp, err := http.Get(fmt.Sprintf("%s/robots.txt", ps.URL))
|
||||
s.Nil(err)
|
||||
s.Equal(resp.StatusCode, http.StatusOK)
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
s.Nil(err)
|
||||
s.Equal(bytes.Compare(body, expected), 0)
|
||||
}
|
|
@ -1,17 +1,11 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gophish/gophish/auth"
|
||||
"github.com/gophish/gophish/config"
|
||||
|
@ -79,204 +73,6 @@ func CreateAdminRouter() http.Handler {
|
|||
return Use(csrfRouter.ServeHTTP, mid.CSRFExceptions, mid.GetContext)
|
||||
}
|
||||
|
||||
// CreatePhishingRouter creates the router that handles phishing connections.
|
||||
func CreatePhishingRouter() http.Handler {
|
||||
router := mux.NewRouter()
|
||||
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/endpoint/"))))
|
||||
router.HandleFunc("/track", PhishTracker)
|
||||
router.HandleFunc("/robots.txt", RobotsHandler)
|
||||
router.HandleFunc("/{path:.*}/track", PhishTracker)
|
||||
router.HandleFunc("/{path:.*}", PhishHandler)
|
||||
return router
|
||||
}
|
||||
|
||||
// PhishTracker tracks emails as they are opened, updating the status for the given Result
|
||||
func PhishTracker(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
id := r.Form.Get("rid")
|
||||
if id == "" {
|
||||
Logger.Println("Missing Result ID")
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
rs, err := models.GetResult(id)
|
||||
if err != nil {
|
||||
Logger.Println("No Results found")
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
c, err := models.GetCampaign(rs.CampaignId, rs.UserId)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Don't process events for completed campaigns
|
||||
if c.Status == models.CAMPAIGN_COMPLETE {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return
|
||||
}
|
||||
// Respect X-Forwarded headers
|
||||
if fips := r.Header.Get("X-Forwarded-For"); fips != "" {
|
||||
ip = strings.Split(fips, ", ")[0]
|
||||
}
|
||||
// Handle post processing such as GeoIP
|
||||
err = rs.UpdateGeo(ip)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
d := struct {
|
||||
Payload url.Values `json:"payload"`
|
||||
Browser map[string]string `json:"browser"`
|
||||
}{
|
||||
Payload: r.Form,
|
||||
Browser: make(map[string]string),
|
||||
}
|
||||
d.Browser["address"] = ip
|
||||
d.Browser["user-agent"] = r.Header.Get("User-Agent")
|
||||
rj, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_OPENED, Details: string(rj)})
|
||||
// Don't update the status if the user already clicked the link
|
||||
// or submitted data to the campaign
|
||||
if rs.Status == models.EVENT_CLICKED || rs.Status == models.EVENT_DATA_SUBMIT {
|
||||
http.ServeFile(w, r, "static/images/pixel.png")
|
||||
return
|
||||
}
|
||||
err = rs.UpdateStatus(models.EVENT_OPENED)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
http.ServeFile(w, r, "static/images/pixel.png")
|
||||
}
|
||||
|
||||
// PhishHandler handles incoming client connections and registers the associated actions performed
|
||||
// (such as clicked link, etc.)
|
||||
func PhishHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
id := r.Form.Get("rid")
|
||||
if id == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
rs, err := models.GetResult(id)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
c, err := models.GetCampaign(rs.CampaignId, rs.UserId)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Don't process events for completed campaigns
|
||||
if c.Status == models.CAMPAIGN_COMPLETE {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
p, err := models.GetPage(c.PageId, c.UserId)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
d := struct {
|
||||
Payload url.Values `json:"payload"`
|
||||
Browser map[string]string `json:"browser"`
|
||||
}{
|
||||
Payload: r.Form,
|
||||
Browser: make(map[string]string),
|
||||
}
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return
|
||||
}
|
||||
// Respect X-Forwarded headers
|
||||
if fips := r.Header.Get("X-Forwarded-For"); fips != "" {
|
||||
ip = strings.Split(fips, ", ")[0]
|
||||
}
|
||||
// Handle post processing such as GeoIP
|
||||
err = rs.UpdateGeo(ip)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
d.Browser["address"] = ip
|
||||
d.Browser["user-agent"] = r.Header.Get("User-Agent")
|
||||
rj, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case r.Method == "GET":
|
||||
if rs.Status != models.EVENT_CLICKED && rs.Status != models.EVENT_DATA_SUBMIT {
|
||||
rs.UpdateStatus(models.EVENT_CLICKED)
|
||||
}
|
||||
err = c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_CLICKED, Details: string(rj)})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
case r.Method == "POST":
|
||||
// If data was POST'ed, let's record it
|
||||
rs.UpdateStatus(models.EVENT_DATA_SUBMIT)
|
||||
// Store the data in an event
|
||||
c.AddEvent(models.Event{Email: rs.Email, Message: models.EVENT_DATA_SUBMIT, Details: string(rj)})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Redirect to the desired page
|
||||
if p.RedirectURL != "" {
|
||||
http.Redirect(w, r, p.RedirectURL, 302)
|
||||
return
|
||||
}
|
||||
}
|
||||
var htmlBuff bytes.Buffer
|
||||
tmpl, err := template.New("html_template").Parse(p.HTML)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
f, err := mail.ParseAddress(c.SMTP.FromAddress)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
fn := f.Name
|
||||
if fn == "" {
|
||||
fn = f.Address
|
||||
}
|
||||
rsf := struct {
|
||||
models.Result
|
||||
URL string
|
||||
From string
|
||||
}{
|
||||
rs,
|
||||
c.URL + "?rid=" + rs.RId,
|
||||
fn,
|
||||
}
|
||||
err = tmpl.Execute(&htmlBuff, rsf)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
w.Write(htmlBuff.Bytes())
|
||||
}
|
||||
|
||||
// RobotsHandler prevents search engines, etc. from indexing phishing materials
|
||||
func RobotsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "User-agent: *\nDisallow: /")
|
||||
}
|
||||
|
||||
// Use allows us to stack middleware to process the request
|
||||
// Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172
|
||||
func Use(handler http.HandlerFunc, mid ...func(http.Handler) http.HandlerFunc) http.HandlerFunc {
|
||||
|
|
Loading…
Reference in New Issue