mirror of https://github.com/gophish/gophish
adding extended_templates feature
parent
07b46d226a
commit
7debe78745
|
@ -265,11 +265,13 @@ func (ps *PhishingServer) PhishHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// connection. This usually involves writing out the page HTML or redirecting
|
||||
// the user to the correct URL.
|
||||
func renderPhishResponse(w http.ResponseWriter, r *http.Request, ptx models.PhishingTemplateContext, p models.Page) {
|
||||
// Getting all template params.. current + extended.
|
||||
allTemplateParams := models.GetAllTemplateParams(ptx)
|
||||
// If the request was a form submit and a redirect URL was specified, we
|
||||
// should send the user to that URL
|
||||
if r.Method == "POST" {
|
||||
if p.RedirectURL != "" {
|
||||
redirectURL, err := models.ExecuteTemplate(p.RedirectURL, ptx)
|
||||
redirectURL, err := models.ExecuteTemplate(p.RedirectURL, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.NotFound(w, r)
|
||||
|
@ -280,7 +282,7 @@ func renderPhishResponse(w http.ResponseWriter, r *http.Request, ptx models.Phis
|
|||
}
|
||||
}
|
||||
// Otherwise, we just need to write out the templated HTML
|
||||
html, err := models.ExecuteTemplate(p.HTML, ptx)
|
||||
html, err := models.ExecuteTemplate(p.HTML, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.NotFound(w, r)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
-- +goose Up
|
||||
-- SQL in this section is executed when the migration is applied.
|
||||
ALTER TABLE `targets` ADD COLUMN extended_template BLOB;
|
||||
ALTER TABLE `email_requests` ADD COLUMN extended_template BLOB;
|
||||
ALTER TABLE `results` ADD COLUMN extended_template BLOB;
|
||||
-- +goose Down
|
||||
-- SQL in this section is executed when the migration is rolled back.
|
|
@ -0,0 +1,7 @@
|
|||
-- +goose Up
|
||||
-- SQL in this section is executed when the migration is applied.
|
||||
ALTER TABLE targets ADD COLUMN extended_template BLOB;
|
||||
ALTER TABLE email_requests ADD COLUMN extended_template BLOB;
|
||||
ALTER TABLE results ADD COLUMN extended_template BLOB;
|
||||
-- +goose Down
|
||||
-- SQL in this section is executed when the migration is rolled back.
|
|
@ -556,6 +556,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
Position: t.Position,
|
||||
FirstName: t.FirstName,
|
||||
LastName: t.LastName,
|
||||
ExtendedTemplate: t.ExtendedTemplate,
|
||||
},
|
||||
Status: StatusScheduled,
|
||||
CampaignId: c.Id,
|
||||
|
|
|
@ -113,8 +113,10 @@ func (s *EmailRequest) Generate(msg *gomail.Message) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Getting all template params.. current + extended.
|
||||
allTemplateParams := GetAllTemplateParams(ptx)
|
||||
|
||||
url, err := ExecuteTemplate(s.URL, ptx)
|
||||
url, err := ExecuteTemplate(s.URL, allTemplateParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,12 +130,12 @@ func (s *EmailRequest) Generate(msg *gomail.Message) error {
|
|||
|
||||
// Parse the customHeader templates
|
||||
for _, header := range s.SMTP.Headers {
|
||||
key, err := ExecuteTemplate(header.Key, ptx)
|
||||
key, err := ExecuteTemplate(header.Key, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
value, err := ExecuteTemplate(header.Value, ptx)
|
||||
value, err := ExecuteTemplate(header.Value, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
@ -143,7 +145,7 @@ func (s *EmailRequest) Generate(msg *gomail.Message) error {
|
|||
}
|
||||
|
||||
// Parse remaining templates
|
||||
subject, err := ExecuteTemplate(s.Template.Subject, ptx)
|
||||
subject, err := ExecuteTemplate(s.Template.Subject, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
@ -154,14 +156,14 @@ func (s *EmailRequest) Generate(msg *gomail.Message) error {
|
|||
|
||||
msg.SetHeader("To", s.FormatAddress())
|
||||
if s.Template.Text != "" {
|
||||
text, err := ExecuteTemplate(s.Template.Text, ptx)
|
||||
text, err := ExecuteTemplate(s.Template.Text, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
msg.SetBody("text/plain", text)
|
||||
}
|
||||
if s.Template.HTML != "" {
|
||||
html, err := ExecuteTemplate(s.Template.HTML, ptx)
|
||||
html, err := ExecuteTemplate(s.Template.HTML, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ type BaseRecipient struct {
|
|||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Position string `json:"position"`
|
||||
ExtendedTemplate string `json:"extended_template,omitempty"`
|
||||
}
|
||||
|
||||
// FormatAddress returns the email address to use in the "To" header of the email
|
||||
|
@ -348,6 +349,10 @@ func UpdateTarget(tx *gorm.DB, target Target) error {
|
|||
"last_name": target.LastName,
|
||||
"position": target.Position,
|
||||
}
|
||||
// handling front end overrides..extended_template is not sent from front end.
|
||||
if target.ExtendedTemplate != "" {
|
||||
targetInfo["extended_template"] = target.ExtendedTemplate
|
||||
}
|
||||
err := tx.Model(&target).Where("id = ?", target.Id).Updates(targetInfo).Error
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
|
@ -360,6 +365,6 @@ func UpdateTarget(tx *gorm.DB, target Target) error {
|
|||
// GetTargets performs a many-to-many select to get all the Targets for a Group
|
||||
func GetTargets(gid int64) ([]Target, error) {
|
||||
ts := []Target{}
|
||||
err := db.Table("targets").Select("targets.id, targets.email, targets.first_name, targets.last_name, targets.position").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
|
||||
err := db.Table("targets").Select("targets.id, targets.email, targets.first_name, targets.last_name, targets.position,targets.extended_template").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
|
||||
return ts, err
|
||||
}
|
||||
|
|
|
@ -179,6 +179,8 @@ func (m *MailLog) Generate(msg *gomail.Message) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Getting all template params.. current + extended.
|
||||
allTemplateParams := GetAllTemplateParams(ptx)
|
||||
|
||||
// Add the transparency headers
|
||||
msg.SetHeader("X-Mailer", config.ServerName)
|
||||
|
@ -195,12 +197,12 @@ func (m *MailLog) Generate(msg *gomail.Message) error {
|
|||
|
||||
// Parse the customHeader templates
|
||||
for _, header := range c.SMTP.Headers {
|
||||
key, err := ExecuteTemplate(header.Key, ptx)
|
||||
key, err := ExecuteTemplate(header.Key, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
||||
value, err := ExecuteTemplate(header.Value, ptx)
|
||||
value, err := ExecuteTemplate(header.Value, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
@ -210,7 +212,7 @@ func (m *MailLog) Generate(msg *gomail.Message) error {
|
|||
}
|
||||
|
||||
// Parse remaining templates
|
||||
subject, err := ExecuteTemplate(c.Template.Subject, ptx)
|
||||
subject, err := ExecuteTemplate(c.Template.Subject, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
@ -221,14 +223,14 @@ func (m *MailLog) Generate(msg *gomail.Message) error {
|
|||
|
||||
msg.SetHeader("To", r.FormatAddress())
|
||||
if c.Template.Text != "" {
|
||||
text, err := ExecuteTemplate(c.Template.Text, ptx)
|
||||
text, err := ExecuteTemplate(c.Template.Text, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
msg.SetBody("text/plain", text)
|
||||
}
|
||||
if c.Template.HTML != "" {
|
||||
html, err := ExecuteTemplate(c.Template.HTML, ptx)
|
||||
html, err := ExecuteTemplate(c.Template.HTML, allTemplateParams)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
|
|
@ -79,12 +79,13 @@ func (p *Page) Validate() error {
|
|||
if p.CapturePasswords && !p.CaptureCredentials {
|
||||
p.CaptureCredentials = true
|
||||
}
|
||||
if err := ValidateTemplate(p.HTML); err != nil {
|
||||
// bypass this.. since we can't predict with all extended params in advance.
|
||||
/*if err := ValidateTemplate(p.HTML); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ValidateTemplate(p.RedirectURL); err != nil {
|
||||
return err
|
||||
}
|
||||
}*/
|
||||
return p.parseHTML()
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,8 @@ func (s *ModelsSuite) TestPageValidation(c *check.C) {
|
|||
err = p.Validate()
|
||||
c.Assert(err, check.Equals, nil)
|
||||
c.Assert(p.CaptureCredentials, check.Equals, true)
|
||||
|
||||
// bypassing..no longer needed
|
||||
/*
|
||||
// Validate that if the HTML contains an invalid template tag, that we
|
||||
// catch it
|
||||
p.HTML = `<html>
|
||||
|
@ -138,5 +139,5 @@ func (s *ModelsSuite) TestPageValidation(c *check.C) {
|
|||
p.HTML = "valid data"
|
||||
p.RedirectURL = "http://example.com/{{.INVALIDTAG}}"
|
||||
err = p.Validate()
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err, check.NotNil)*/
|
||||
}
|
||||
|
|
|
@ -34,12 +34,14 @@ func (t *Template) Validate() error {
|
|||
case t.Text == "" && t.HTML == "":
|
||||
return ErrTemplateMissingParameter
|
||||
}
|
||||
if err := ValidateTemplate(t.HTML); err != nil {
|
||||
|
||||
// bypass this.. since we can't predict all extended params in advance.
|
||||
/*if err := ValidateTemplate(t.HTML); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ValidateTemplate(t.Text); err != nil {
|
||||
return err
|
||||
}
|
||||
}*/
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -109,7 +111,6 @@ func GetTemplateByName(n string, uid int64) (Template, error) {
|
|||
|
||||
// PostTemplate creates a new template in the database.
|
||||
func PostTemplate(t *Template) error {
|
||||
// Insert into the DB
|
||||
if err := t.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package models
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"path"
|
||||
|
@ -76,7 +77,8 @@ func NewPhishingTemplateContext(ctx TemplateContext, r BaseRecipient, rid string
|
|||
// template body and data.
|
||||
func ExecuteTemplate(text string, data interface{}) (string, error) {
|
||||
buff := bytes.Buffer{}
|
||||
tmpl, err := template.New("template").Parse(text)
|
||||
// replacing template params with no corresponding map keys with empty string.
|
||||
tmpl, err := template.New("template").Option("missingkey=zero").Parse(text)
|
||||
if err != nil {
|
||||
return buff.String(), err
|
||||
}
|
||||
|
@ -124,3 +126,31 @@ func ValidateTemplate(text string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllTemplateParams merges the PhishingTemplateContext with the extended_parameters
|
||||
// if extended_parameters are valid JSON
|
||||
func GetAllTemplateParams(ptx PhishingTemplateContext) map[string]string {
|
||||
currentTemplateParams := map[string]string{
|
||||
"From": ptx.From,
|
||||
"URL": ptx.URL,
|
||||
"Tracker": ptx.Tracker,
|
||||
"TrackingURL": ptx.TrackingURL,
|
||||
"RId": ptx.RId,
|
||||
"BaseURL": ptx.BaseURL,
|
||||
"Email": ptx.BaseRecipient.Email,
|
||||
"FirstName": ptx.BaseRecipient.FirstName,
|
||||
"LastName": ptx.BaseRecipient.LastName,
|
||||
"Position": ptx.BaseRecipient.Position,
|
||||
}
|
||||
extendedTemplateParams := map[string]string{}
|
||||
err := json.Unmarshal([]byte(ptx.BaseRecipient.ExtendedTemplate), &extendedTemplateParams)
|
||||
|
||||
if err == nil {
|
||||
// only merge if we have a valid JSON in extended_parameters
|
||||
for k, v := range extendedTemplateParams {
|
||||
currentTemplateParams[k] = v
|
||||
}
|
||||
}
|
||||
return currentTemplateParams
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue