github.com/Ne0nd0g/gophish@v0.7.1-0.20190220040016-11493024a07d/models/page.go (about)

     1  package models
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/PuerkitoBio/goquery"
     9  	log "github.com/gophish/gophish/logger"
    10  )
    11  
    12  // Page contains the fields used for a Page model
    13  type Page struct {
    14  	Id                 int64     `json:"id" gorm:"column:id; primary_key:yes"`
    15  	UserId             int64     `json:"-" gorm:"column:user_id"`
    16  	Name               string    `json:"name"`
    17  	HTML               string    `json:"html" gorm:"column:html"`
    18  	CaptureCredentials bool      `json:"capture_credentials" gorm:"column:capture_credentials"`
    19  	CapturePasswords   bool      `json:"capture_passwords" gorm:"column:capture_passwords"`
    20  	RedirectURL        string    `json:"redirect_url" gorm:"column:redirect_url"`
    21  	ModifiedDate       time.Time `json:"modified_date"`
    22  }
    23  
    24  // ErrPageNameNotSpecified is thrown if the name of the landing page is blank.
    25  var ErrPageNameNotSpecified = errors.New("Page Name not specified")
    26  
    27  // parseHTML parses the page HTML on save to handle the
    28  // capturing (or lack thereof!) of credentials and passwords
    29  func (p *Page) parseHTML() error {
    30  	d, err := goquery.NewDocumentFromReader(strings.NewReader(p.HTML))
    31  	if err != nil {
    32  		return err
    33  	}
    34  	forms := d.Find("form")
    35  	forms.Each(func(i int, f *goquery.Selection) {
    36  		// We always want the submitted events to be
    37  		// sent to our server
    38  		f.SetAttr("action", "")
    39  		if p.CaptureCredentials {
    40  			// If we don't want to capture passwords,
    41  			// find all the password fields and remove the "name" attribute.
    42  			if !p.CapturePasswords {
    43  				inputs := f.Find("input")
    44  				inputs.Each(func(j int, input *goquery.Selection) {
    45  					if t, _ := input.Attr("type"); strings.EqualFold(t, "password") {
    46  						input.RemoveAttr("name")
    47  					}
    48  				})
    49  			} else {
    50  				// If the user chooses to re-enable the capture passwords setting,
    51  				// we need to re-add the name attribute
    52  				inputs := f.Find("input")
    53  				inputs.Each(func(j int, input *goquery.Selection) {
    54  					if t, _ := input.Attr("type"); strings.EqualFold(t, "password") {
    55  						input.SetAttr("name", "password")
    56  					}
    57  				})
    58  			}
    59  		} else {
    60  			// Otherwise, remove the name from all
    61  			// inputs.
    62  			inputFields := f.Find("input")
    63  			inputFields.Each(func(j int, input *goquery.Selection) {
    64  				input.RemoveAttr("name")
    65  			})
    66  		}
    67  	})
    68  	p.HTML, err = d.Html()
    69  	return err
    70  }
    71  
    72  // Validate ensures that a page contains the appropriate details
    73  func (p *Page) Validate() error {
    74  	if p.Name == "" {
    75  		return ErrPageNameNotSpecified
    76  	}
    77  	// If the user specifies to capture passwords,
    78  	// we automatically capture credentials
    79  	if p.CapturePasswords && !p.CaptureCredentials {
    80  		p.CaptureCredentials = true
    81  	}
    82  	if err := ValidateTemplate(p.HTML); err != nil {
    83  		return err
    84  	}
    85  	if err := ValidateTemplate(p.RedirectURL); err != nil {
    86  		return err
    87  	}
    88  	return p.parseHTML()
    89  }
    90  
    91  // GetPages returns the pages owned by the given user.
    92  func GetPages(uid int64) ([]Page, error) {
    93  	ps := []Page{}
    94  	err := db.Where("user_id=?", uid).Find(&ps).Error
    95  	if err != nil {
    96  		log.Error(err)
    97  		return ps, err
    98  	}
    99  	return ps, err
   100  }
   101  
   102  // GetPage returns the page, if it exists, specified by the given id and user_id.
   103  func GetPage(id int64, uid int64) (Page, error) {
   104  	p := Page{}
   105  	err := db.Where("user_id=? and id=?", uid, id).Find(&p).Error
   106  	if err != nil {
   107  		log.Error(err)
   108  	}
   109  	return p, err
   110  }
   111  
   112  // GetPageByName returns the page, if it exists, specified by the given name and user_id.
   113  func GetPageByName(n string, uid int64) (Page, error) {
   114  	p := Page{}
   115  	err := db.Where("user_id=? and name=?", uid, n).Find(&p).Error
   116  	if err != nil {
   117  		log.Error(err)
   118  	}
   119  	return p, err
   120  }
   121  
   122  // PostPage creates a new page in the database.
   123  func PostPage(p *Page) error {
   124  	err := p.Validate()
   125  	if err != nil {
   126  		log.Error(err)
   127  		return err
   128  	}
   129  	// Insert into the DB
   130  	err = db.Save(p).Error
   131  	if err != nil {
   132  		log.Error(err)
   133  	}
   134  	return err
   135  }
   136  
   137  // PutPage edits an existing Page in the database.
   138  // Per the PUT Method RFC, it presumes all data for a page is provided.
   139  func PutPage(p *Page) error {
   140  	err := p.Validate()
   141  	err = db.Where("id=?", p.Id).Save(p).Error
   142  	if err != nil {
   143  		log.Error(err)
   144  	}
   145  	return err
   146  }
   147  
   148  // DeletePage deletes an existing page in the database.
   149  // An error is returned if a page with the given user id and page id is not found.
   150  func DeletePage(id int64, uid int64) error {
   151  	err := db.Where("user_id=?", uid).Delete(Page{Id: id}).Error
   152  	if err != nil {
   153  		log.Error(err)
   154  	}
   155  	return err
   156  }