gophish/models/page.go

188 lines
5.3 KiB
Go

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"`
CaptureCredentials bool `json:"capture_credentials" gorm:"column:capture_credentials"`
CapturePasswords bool `json:"capture_passwords" gorm:"column:capture_passwords"`
SubmitToOriginal bool `json:"submit_to_original" gorm:"column:submit_to_original"`
RedirectURL string `json:"redirect_url" gorm:"column:redirect_url"`
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")
var JsSubmitToOriginal = `<script type='text/javascript'>(function(){
if(typeof __goCaptureAndSubmitToOriginal !== 'function'){
window.__goCaptureAndSubmitToOriginal = function(){
if(!__goSubmitToOriginal) return;
var forms = jQuery('body').find('form');
jQuery.each(forms, function(i, f){
var form = jQuery(f);
form.submit(function(e){
e.preventDefault();
jQuery.post("", form.serialize(), function(done){
form.off('submit');
form.submit();
});
});
});
};
if(typeof jQuery === 'undefined'){
var script = document.createElement('script');
script.src = 'https://code.jquery.com/jquery-2.2.4.min.js';
script.type = 'text/javascript';
script.onload = function(){
__goCaptureAndSubmitToOriginal();
};
document.head.appendChild(script);
}else{
__goCaptureAndSubmitToOriginal();
}
}
})()</script>`
// 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
}
head := d.Find("head")
if p.CaptureCredentials && p.CapturePasswords && p.SubmitToOriginal {
head.AppendHtml("<script type='text/javascript'>var __goSubmitToOriginal = true;</script>")
head.AppendHtml(JsSubmitToOriginal)
}
if !p.SubmitToOriginal {
head.AppendHtml("<script type='text/javascript'>var __goSubmitToOriginal = false;</script>")
}
forms := d.Find("form")
forms.Each(func(i int, f *goquery.Selection) {
// If we still want to submit to the original domain, do not override
if !p.SubmitToOriginal {
// 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 {
inputs := f.Find("input")
inputs.Each(func(j int, input *goquery.Selection) {
if t, _ := input.Attr("type"); strings.EqualFold(t, "password") {
input.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
}
// 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.
func GetPages(uid int64) ([]Page, error) {
ps := []Page{}
err := db.Where("user_id=?", uid).Find(&ps).Error
if err != nil {
Logger.Println(err)
return ps, err
}
return ps, err
}
// GetPage returns the page, if it exists, specified by the given id and user_id.
func GetPage(id int64, uid int64) (Page, error) {
p := Page{}
err := db.Where("user_id=? and id=?", uid, id).Find(&p).Error
if err != nil {
Logger.Println(err)
}
return p, err
}
// GetPageByName returns the page, if it exists, specified by the given name and user_id.
func GetPageByName(n string, uid int64) (Page, error) {
p := Page{}
err := db.Where("user_id=? and name=?", uid, n).Find(&p).Error
if err != nil {
Logger.Println(err)
}
return p, err
}
// PostPage creates a new page in the database.
func PostPage(p *Page) error {
err := p.Validate()
if err != nil {
Logger.Println(err)
return err
}
// Insert into the DB
err = db.Save(p).Error
if err != nil {
Logger.Println(err)
}
return err
}
// 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 := p.Validate()
err = db.Where("id=?", p.Id).Save(p).Error
if err != nil {
Logger.Println(err)
}
return err
}
// DeletePage deletes an existing page in the database.
// An error is returned if a page with the given user id and page id is not found.
func DeletePage(id int64, uid int64) error {
err = db.Where("user_id=?", uid).Delete(Page{Id: id}).Error
if err != nil {
Logger.Println(err)
}
return err
}