package models import ( "bytes" "net/mail" "net/url" "path" "text/template" "time" ) // 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 BaseURL string Now time.Time 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 } templateURL, err := ExecuteTemplate(ctx.getBaseURL(), r) if err != nil { return PhishingTemplateContext{}, err } // 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) q := phishURL.Query() q.Set(RecipientParameter, rid) phishURL.RawQuery = q.Encode() trackingURL, _ := url.Parse(templateURL) trackingURL.Path = path.Join(trackingURL.Path, "/track") trackingURL.RawQuery = q.Encode() return PhishingTemplateContext{ BaseRecipient: r, BaseURL: baseURL.String(), URL: phishURL.String(), TrackingURL: trackingURL.String(), Tracker: "", From: fn, RId: rid, Now: time.Now(), }, 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{} funcMap := template.FuncMap{ "date": time.Parse, "duration": time.ParseDuration, "location": time.LoadLocation, } tmpl, err := template.New("template").Funcs(funcMap).Parse(text) if err != nil { return buff.String(), err } err = tmpl.Execute(&buff, data) return buff.String(), err } // 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 }