package models import ( "bytes" "net/mail" "net/url" "path" "text/template" "encoding/base64" log "github.com/gophish/gophish/logger" qrcode "github.com/skip2/go-qrcode" //library for generating qrcode ) // 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 QrURL string 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, err := url.Parse(templateURL) if err != nil { return PhishingTemplateContext{}, err } 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() qrDataUrl := generateQRCodeDataUrl(phishURL.String()) return PhishingTemplateContext{ BaseRecipient: r, BaseURL: baseURL.String(), URL: phishURL.String(), TrackingURL: trackingURL.String(), Tracker: "", From: fn, RId: rid, QrURL: qrDataUrl, }, 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{} tmpl, err := template.New("template").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 } //Generate QR code dataurl func generateQRCodeDataUrl(websiteURL string) string { // imageSize = 256 x 256 pixels imageSize := 256 qrCodeImageData, taskError := qrcode.Encode(websiteURL, qrcode.High, imageSize) if taskError != nil { log.Errorf("Error generating QR code. %s",taskError) } // Encode raw QR code data to base 64 encodedData := base64.StdEncoding.EncodeToString(qrCodeImageData) log.Infof("QR encodedData = %s", encodedData) return "data:image/png;base64, "+encodedData }