2018-06-09 02:20:52 +00:00
|
|
|
package models
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"net/mail"
|
|
|
|
"net/url"
|
|
|
|
"path"
|
|
|
|
"text/template"
|
2019-06-04 02:58:59 +00:00
|
|
|
"time"
|
2018-06-09 02:20:52 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// TemplateContext is an interface that allows both campaigns and email
|
|
|
|
// requests to have a PhishingTemplateContext generated for them.
|
|
|
|
type TemplateContext interface {
|
|
|
|
getFromAddress() string
|
|
|
|
getBaseURL() string
|
|
|
|
}
|
|
|
|
|
|
|
|
// PhishingTemplateContext is the context that is sent to any template, such
|
|
|
|
// as the email or landing page content.
|
|
|
|
type PhishingTemplateContext struct {
|
|
|
|
From string
|
|
|
|
URL string
|
|
|
|
Tracker string
|
|
|
|
TrackingURL string
|
|
|
|
RId string
|
2018-09-04 01:28:32 +00:00
|
|
|
BaseURL string
|
2019-06-04 02:58:59 +00:00
|
|
|
Now time.Time
|
2018-06-09 02:20:52 +00:00
|
|
|
BaseRecipient
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPhishingTemplateContext returns a populated PhishingTemplateContext,
|
|
|
|
// parsing the correct fields from the provided TemplateContext and recipient.
|
|
|
|
func NewPhishingTemplateContext(ctx TemplateContext, r BaseRecipient, rid string) (PhishingTemplateContext, error) {
|
|
|
|
f, err := mail.ParseAddress(ctx.getFromAddress())
|
|
|
|
if err != nil {
|
|
|
|
return PhishingTemplateContext{}, err
|
|
|
|
}
|
|
|
|
fn := f.Name
|
|
|
|
if fn == "" {
|
|
|
|
fn = f.Address
|
|
|
|
}
|
2018-09-04 01:28:32 +00:00
|
|
|
templateURL, err := ExecuteTemplate(ctx.getBaseURL(), r)
|
2018-06-09 02:20:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return PhishingTemplateContext{}, err
|
|
|
|
}
|
|
|
|
|
2018-09-04 01:28:32 +00:00
|
|
|
// For the base URL, we'll reset the the path and the query
|
|
|
|
// This will create a URL in the form of http://example.com
|
|
|
|
baseURL, _ := url.Parse(templateURL)
|
|
|
|
baseURL.Path = ""
|
|
|
|
baseURL.RawQuery = ""
|
|
|
|
|
|
|
|
phishURL, _ := url.Parse(templateURL)
|
2018-06-09 02:20:52 +00:00
|
|
|
q := phishURL.Query()
|
|
|
|
q.Set(RecipientParameter, rid)
|
|
|
|
phishURL.RawQuery = q.Encode()
|
|
|
|
|
2018-09-04 01:28:32 +00:00
|
|
|
trackingURL, _ := url.Parse(templateURL)
|
2018-06-09 02:20:52 +00:00
|
|
|
trackingURL.Path = path.Join(trackingURL.Path, "/track")
|
|
|
|
trackingURL.RawQuery = q.Encode()
|
|
|
|
|
|
|
|
return PhishingTemplateContext{
|
|
|
|
BaseRecipient: r,
|
2018-09-04 01:28:32 +00:00
|
|
|
BaseURL: baseURL.String(),
|
2018-06-09 02:20:52 +00:00
|
|
|
URL: phishURL.String(),
|
|
|
|
TrackingURL: trackingURL.String(),
|
|
|
|
Tracker: "<img alt='' style='display: none' src='" + trackingURL.String() + "'/>",
|
|
|
|
From: fn,
|
|
|
|
RId: rid,
|
2019-06-04 02:58:59 +00:00
|
|
|
Now: time.Now(),
|
2018-06-09 02:20:52 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExecuteTemplate creates a templated string based on the provided
|
|
|
|
// template body and data.
|
|
|
|
func ExecuteTemplate(text string, data interface{}) (string, error) {
|
|
|
|
buff := bytes.Buffer{}
|
2019-06-04 02:58:59 +00:00
|
|
|
funcMap := template.FuncMap{
|
|
|
|
"date": time.Parse,
|
|
|
|
"duration": time.ParseDuration,
|
|
|
|
"location": time.LoadLocation,
|
|
|
|
}
|
|
|
|
tmpl, err := template.New("template").Funcs(funcMap).Parse(text)
|
2018-06-09 02:20:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return buff.String(), err
|
|
|
|
}
|
|
|
|
err = tmpl.Execute(&buff, data)
|
|
|
|
return buff.String(), err
|
|
|
|
}
|
2018-09-09 16:33:51 +00:00
|
|
|
|
|
|
|
// ValidationContext is used for validating templates and pages
|
|
|
|
type ValidationContext struct {
|
|
|
|
FromAddress string
|
|
|
|
BaseURL string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (vc ValidationContext) getFromAddress() string {
|
|
|
|
return vc.FromAddress
|
|
|
|
}
|
|
|
|
|
|
|
|
func (vc ValidationContext) getBaseURL() string {
|
|
|
|
return vc.BaseURL
|
|
|
|
}
|
|
|
|
|
|
|
|
// ValidateTemplate ensures that the provided text in the page or template
|
|
|
|
// uses the supported template variables correctly.
|
|
|
|
func ValidateTemplate(text string) error {
|
|
|
|
vc := ValidationContext{
|
|
|
|
FromAddress: "foo@bar.com",
|
|
|
|
BaseURL: "http://example.com",
|
|
|
|
}
|
|
|
|
td := Result{
|
|
|
|
BaseRecipient: BaseRecipient{
|
|
|
|
Email: "foo@bar.com",
|
|
|
|
FirstName: "Foo",
|
|
|
|
LastName: "Bar",
|
|
|
|
Position: "Test",
|
|
|
|
},
|
|
|
|
RId: "123456",
|
|
|
|
}
|
|
|
|
ptx, err := NewPhishingTemplateContext(vc, td.BaseRecipient, td.RId)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = ExecuteTemplate(text, ptx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|