From 44fa8127fca87427b62140d808643d486bf3f900 Mon Sep 17 00:00:00 2001 From: Jordan Wright Date: Thu, 25 Feb 2016 19:58:49 -0600 Subject: [PATCH] Adding the ability to capture submitted data via the UI. Fixes #124 --- controllers/api.go | 7 +-- ...160225173824_0.1.2_capture_credentials.sql | 9 +++ models/page.go | 59 ++++++++++++++++--- static/js/app/landing_pages.js | 23 ++++---- 4 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 db/migrations/20160225173824_0.1.2_capture_credentials.sql diff --git a/controllers/api.go b/controllers/api.go index 8c009f11..88fe51bc 100644 --- a/controllers/api.go +++ b/controllers/api.go @@ -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) diff --git a/db/migrations/20160225173824_0.1.2_capture_credentials.sql b/db/migrations/20160225173824_0.1.2_capture_credentials.sql new file mode 100644 index 00000000..eff45de5 --- /dev/null +++ b/db/migrations/20160225173824_0.1.2_capture_credentials.sql @@ -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 + diff --git a/models/page.go b/models/page.go index 23af64c3..0132aacc 100644 --- a/models/page.go +++ b/models/page.go @@ -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) } diff --git a/static/js/app/landing_pages.js b/static/js/app/landing_pages.js index 4450eeff..ccbc94db 100644 --- a/static/js/app/landing_pages.js +++ b/static/js/app/landing_pages.js @@ -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() + } } }