mirror of https://github.com/gophish/gophish
Adding the ability to capture submitted data via the UI. Fixes #124
parent
af76603949
commit
44fa8127fc
|
@ -334,16 +334,11 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "/:id and /:page_id mismatch"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = p.Validate()
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Invalid attributes given"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
p.ModifiedDate = time.Now()
|
||||
p.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutPage(&p)
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error updating page"}, http.StatusInternalServerError)
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error updating page: " + err.Error()}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, p, http.StatusOK)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
ALTER TABLE pages ADD COLUMN capture_credentials BOOLEAN;
|
||||
ALTER TABLE pages ADD COLUMN capture_passwords BOOLEAN;
|
||||
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
||||
|
|
@ -2,27 +2,71 @@ package models
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
)
|
||||
|
||||
// Page contains the fields used for a Page model
|
||||
type Page struct {
|
||||
Id int64 `json:"id" gorm:"column:id; primary_key:yes"`
|
||||
UserId int64 `json:"-" gorm:"column:user_id"`
|
||||
Name string `json:"name"`
|
||||
HTML string `json:"html" gorm:"column:html"`
|
||||
ModifiedDate time.Time `json:"modified_date"`
|
||||
Id int64 `json:"id" gorm:"column:id; primary_key:yes"`
|
||||
UserId int64 `json:"-" gorm:"column:user_id"`
|
||||
Name string `json:"name"`
|
||||
HTML string `json:"html" gorm:"column:html"`
|
||||
CaptureCredentials bool `json:"capture_credentials" gorm:"column:capture_credentials"`
|
||||
CapturePasswords bool `json:"capture_passwords" gorm:"column:capture_passwords"`
|
||||
ModifiedDate time.Time `json:"modified_date"`
|
||||
}
|
||||
|
||||
// ErrPageNameNotSpecified is thrown if the name of the landing page is blank.
|
||||
var ErrPageNameNotSpecified = errors.New("Page Name not specified")
|
||||
|
||||
// parseHTML parses the page HTML on save to handle the
|
||||
// capturing (or lack thereof!) of credentials and passwords
|
||||
func (p *Page) parseHTML() error {
|
||||
d, err := goquery.NewDocumentFromReader(strings.NewReader(p.HTML))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
forms := d.Find("form")
|
||||
forms.Each(func(i int, f *goquery.Selection) {
|
||||
// We always want the submitted events to be
|
||||
// sent to our server
|
||||
f.SetAttr("action", "")
|
||||
if p.CaptureCredentials {
|
||||
// If we don't want to capture passwords,
|
||||
// find all the password fields and remove the "name" attribute.
|
||||
if !p.CapturePasswords {
|
||||
passwordFields := f.Find("input[type=\"password\"]")
|
||||
passwordFields.Each(func(j int, pass *goquery.Selection) {
|
||||
pass.RemoveAttr("name")
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Otherwise, remove the name from all
|
||||
// inputs.
|
||||
inputFields := f.Find("input")
|
||||
inputFields.Each(func(j int, input *goquery.Selection) {
|
||||
input.RemoveAttr("name")
|
||||
})
|
||||
}
|
||||
})
|
||||
p.HTML, err = d.Html()
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate ensures that a page contains the appropriate details
|
||||
func (p *Page) Validate() error {
|
||||
if p.Name == "" {
|
||||
return ErrPageNameNotSpecified
|
||||
}
|
||||
return nil
|
||||
// If the user specifies to capture passwords,
|
||||
// we automatically capture credentials
|
||||
if p.CapturePasswords && !p.CaptureCredentials {
|
||||
p.CaptureCredentials = true
|
||||
}
|
||||
return p.parseHTML()
|
||||
}
|
||||
|
||||
// GetPages returns the pages owned by the given user.
|
||||
|
@ -74,7 +118,8 @@ func PostPage(p *Page) error {
|
|||
// PutPage edits an existing Page in the database.
|
||||
// Per the PUT Method RFC, it presumes all data for a page is provided.
|
||||
func PutPage(p *Page) error {
|
||||
err := db.Where("id=?", p.Id).Save(p).Error
|
||||
err := p.Validate()
|
||||
err = db.Where("id=?", p.Id).Save(p).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
|
|
@ -10,19 +10,9 @@ function save(idx) {
|
|||
var page = {}
|
||||
page.name = $("#name").val()
|
||||
editor = CKEDITOR.instances["html_editor"]
|
||||
html = editor.getData();
|
||||
ck_dom = $(html)
|
||||
// Handle capturing credentials
|
||||
if ($("#capture_credentials_checkbox").prop("checked")) {
|
||||
ck_dom.find("form").attr("action", "")
|
||||
if (!$("#capture_passwords_checkbox").prop("checked")) {
|
||||
// Remove the name so the credential isn't submitted
|
||||
ck_dom.find("input[type='password']").removeAttr("name")
|
||||
}
|
||||
} else {
|
||||
ck_dom.find("form").attr("action", "#")
|
||||
}
|
||||
page.html = editor.getData();
|
||||
page.html = editor.getData()
|
||||
page.capture_credentials = $("#capture_credentials_checkbox").prop("checked")
|
||||
page.capture_passwords = $("#capture_passwords_checkbox").prop("checked")
|
||||
if (idx != -1) {
|
||||
page.id = pages[idx].id
|
||||
api.pageId.put(page)
|
||||
|
@ -49,6 +39,8 @@ function dismiss() {
|
|||
$("#modal\\.flashes").empty()
|
||||
$("#name").val("")
|
||||
$("#html_editor").val("")
|
||||
$("#newLandingPageModal").find("input[type='checkbox']").prop("checked", false)
|
||||
$("#capture_passwords").hide()
|
||||
$("#newLandingPageModal").modal('hide')
|
||||
}
|
||||
|
||||
|
@ -92,6 +84,11 @@ function edit(idx) {
|
|||
page = pages[idx]
|
||||
$("#name").val(page.name)
|
||||
$("#html_editor").val(page.html)
|
||||
$("#capture_credentials_checkbox").prop("checked", page.capture_credentials)
|
||||
$("#capture_passwords_checkbox").prop("checked", page.capture_passwords)
|
||||
if (page.capture_credentials){
|
||||
$("#capture_passwords").show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue