Skip to content

Commit

Permalink
Feat add qr code (#6)
Browse files Browse the repository at this point in the history
* add go-qrcode package

* add qr code html representation as template variable

* renamed testdata to attachment-testdata

* fix attachment tests to match path

* fix test on qr code change
  • Loading branch information
a-maccormack authored Feb 27, 2024
1 parent 1f64e25 commit 9c6fec9
Show file tree
Hide file tree
Showing 24 changed files with 64 additions and 5 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/oschwald/maxminddb-golang v1.6.0
github.com/sirupsen/logrus v1.4.2
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/ziutek/mymysql v1.5.4 // indirect
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions models/attachment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func (s *ModelsSuite) TestAttachment(c *check.C) {
RId: "1234567",
}

files, err := ioutil.ReadDir("testdata")
files, err := os.ReadDir("attachment-testdata")
if err != nil {
log.Fatalf("Failed to open attachment folder 'testdata': %v\n", err)
log.Fatalf("Failed to open attachment-testdata folder 'attachment-testdata': %v\n", err)
}
for _, ff := range files {
if !ff.IsDir() && !strings.Contains(ff.Name(), "templated") {
fname := ff.Name()
fmt.Printf("Checking attachment file -> %s\n", fname)
data := readFile("testdata/" + fname)
data := readFile("attachment-testdata/" + fname)
if filepath.Ext(fname) == ".b64" {
fname = fname[:len(fname)-4]
}
Expand All @@ -56,7 +56,7 @@ func (s *ModelsSuite) TestAttachment(c *check.C) {
log.Fatalf("Failed to parse templated file '%s': %v\n", fname, err)
}
templatedFile := base64.StdEncoding.EncodeToString(tt)
expectedOutput := readFile("testdata/" + strings.TrimSuffix(ff.Name(), filepath.Ext(ff.Name())) + ".templated" + filepath.Ext(ff.Name())) // e.g text-file-with-vars.templated.txt
expectedOutput := readFile("attachment-testdata/" + strings.TrimSuffix(ff.Name(), filepath.Ext(ff.Name())) + ".templated" + filepath.Ext(ff.Name())) // e.g text-file-with-vars.templated.txt
c.Assert(templatedFile, check.Equals, expectedOutput)
}
}
Expand Down
1 change: 1 addition & 0 deletions models/qr-test-data/test-qr-code.html

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions models/template_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package models

import (
"bytes"
"fmt"
"net/mail"
"net/url"
"path"
"strings"
"text/template"

qrcode "github.com/skip2/go-qrcode" //library for generating qrcode
)

// TemplateContext is an interface that allows both campaigns and email
Expand All @@ -24,6 +28,7 @@ type PhishingTemplateContext struct {
TrackingURL string
RId string
BaseURL string
QrCode string
BaseRecipient
}

Expand Down Expand Up @@ -61,6 +66,8 @@ func NewPhishingTemplateContext(ctx TemplateContext, r BaseRecipient, rid string
trackingURL.Path = path.Join(trackingURL.Path, "/track")
trackingURL.RawQuery = q.Encode()

qrCodeHtml := generateQRCodeHTML(phishURL.String())

return PhishingTemplateContext{
BaseRecipient: r,
BaseURL: baseURL.String(),
Expand All @@ -69,6 +76,7 @@ func NewPhishingTemplateContext(ctx TemplateContext, r BaseRecipient, rid string
Tracker: "<img alt='' style='display: none' src='" + trackingURL.String() + "'/>",
From: fn,
RId: rid,
QrCode: qrCodeHtml,
}, nil
}

Expand Down Expand Up @@ -124,3 +132,39 @@ func ValidateTemplate(text string) error {
}
return nil
}

// Generate Qrcode HTML representation
func generateQRCodeHTML(websiteURL string) string {
// Generate QR code
q, err := qrcode.New(websiteURL, qrcode.Medium)
if err != nil {
fmt.Println("Error generating QR code:", err)
return ""
}

// Get QR code bitmap
qrCode := q.Bitmap()

// Determine QR code dimensions
qrWidth := len(qrCode)

// Construct HTML table
var html strings.Builder
html.WriteString("<table style=\"border-collapse: collapse;\">")

for y := 0; y < qrWidth; y++ {
html.WriteString("<tr>")
for x := 0; x < qrWidth; x++ {
if qrCode[y][x] {
html.WriteString("<td style=\"width: 1px; height: 1px; background-color: black; border: 1px solid black;\"></td>")
} else {
html.WriteString("<td style=\"width: 1px; height: 1px; background-color: transparent; border: none;\"></td>")
}
}
html.WriteString("</tr>")
}

html.WriteString("</table>\n")

return html.String()
}
13 changes: 12 additions & 1 deletion models/template_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package models

import (
"fmt"
"os"

check "gopkg.in/check.v1"
)
Expand Down Expand Up @@ -29,16 +30,26 @@ func (s *ModelsSuite) TestNewTemplateContext(c *check.C) {
RId: "1234567",
}
ctx := mockTemplateContext{
URL: "http://example.com",
URL: "https://example.com",
FromAddress: "From Address <[email protected]>",
}

expectedHTMLFilePath := "./qr-test-data/test-qr-code.html"
expectedHTMLBytes, err := os.ReadFile(expectedHTMLFilePath)
if err != nil {
c.Fatalf("Failed to read new-html.html: %v", err)
}
// Remove extra backslashes from the read string
expectedHTMLString := string(expectedHTMLBytes)

expected := PhishingTemplateContext{
URL: fmt.Sprintf("%s?rid=%s", ctx.URL, r.RId),
BaseURL: ctx.URL,
BaseRecipient: r.BaseRecipient,
TrackingURL: fmt.Sprintf("%s/track?rid=%s", ctx.URL, r.RId),
From: "From Address",
RId: r.RId,
QrCode: expectedHTMLString,
}
expected.Tracker = "<img alt='' style='display: none' src='" + expected.TrackingURL + "'/>"
got, err := NewPhishingTemplateContext(ctx, r.BaseRecipient, r.RId)
Expand Down

0 comments on commit 9c6fec9

Please sign in to comment.