@@ -10,7 +10,7 @@ import (
1010)
1111
1212func (s * Sender ) formatNotificationBody (sub * notifier.Subscription , thread * notifier.Thread , posts []* notifier.Post ) string {
13- var b strings.Builder
13+ var b strings.Builder //nolint:varnamelen // Standard short variable name for strings.Builder
1414
1515 b .WriteString ("<!DOCTYPE html>\n <html lang=\" en\" >\n <head>\n " )
1616 b .WriteString ("<meta charset=\" utf-8\" >\n " )
@@ -52,6 +52,7 @@ func (s *Sender) formatNotificationBody(sub *notifier.Subscription, thread *noti
5252 for _ , post := range posts {
5353 b .WriteString ("<div class=\" post\" >\n " )
5454 b .WriteString ("<div class=\" meta\" >\n " )
55+ //nolint:gocritic // %q would add extra quotes in HTML context
5556 b .WriteString (fmt .Sprintf ("<a href=\" %s\" class=\" post-number\" >#%s</a>\n " , escapeHTML (post .URL ), escapeHTML (post .ID )))
5657 b .WriteString (fmt .Sprintf ("<span class=\" author\" > • %s</span>\n " , escapeHTML (post .Author )))
5758 if post .Timestamp != "" {
@@ -82,6 +83,7 @@ func (s *Sender) formatNotificationBody(sub *notifier.Subscription, thread *noti
8283 if len (posts ) > 1 {
8384 footerClass = "footer with-border"
8485 }
86+ //nolint:gocritic // %q would add extra quotes in HTML context
8587 b .WriteString (fmt .Sprintf ("<div class=\" %s\" >\n " , footerClass ))
8688
8789 // Link to the last page with anchor to latest post (e.g., .../page-12#post-12345)
@@ -90,9 +92,11 @@ func (s *Sender) formatNotificationBody(sub *notifier.Subscription, thread *noti
9092 if len (posts ) > 0 && posts [len (posts )- 1 ].URL != "" {
9193 threadLink = posts [len (posts )- 1 ].URL
9294 }
95+ //nolint:gocritic // %q would add extra quotes in HTML context
9396 b .WriteString (fmt .Sprintf ("<a href=\" %s\" >View thread on ADVrider</a>\n " , escapeHTML (threadLink )))
9497
9598 manageURL := fmt .Sprintf ("%s/manage?token=%s" , s .baseURL , url .QueryEscape (sub .Token ))
99+ //nolint:gocritic // %q would add extra quotes in HTML context
96100 b .WriteString (fmt .Sprintf ("<a href=\" %s\" >Manage subscriptions</a>\n " , escapeHTML (manageURL )))
97101 b .WriteString ("</div>\n " )
98102
@@ -144,8 +148,10 @@ func (s *Sender) formatWelcomeBody(sub *notifier.Subscription, thread *notifier.
144148 b .WriteString ("</div>\n " )
145149
146150 b .WriteString ("<div class=\" footer\" >\n " )
151+ //nolint:gocritic // %q would add extra quotes in HTML context
147152 b .WriteString (fmt .Sprintf ("<a href=\" %s\" >View thread on ADVrider</a>\n " , escapeHTML (thread .ThreadURL )))
148153 b .WriteString (" • \n " )
154+ //nolint:gocritic // %q would add extra quotes in HTML context
149155 b .WriteString (fmt .Sprintf ("<a href=\" %s\" >Manage subscriptions</a>\n " , escapeHTML (manageURL )))
150156 b .WriteString ("</div>\n " )
151157
@@ -166,6 +172,8 @@ func escapeHTML(s string) string {
166172// sanitizeHTML sanitizes untrusted HTML content using a strict whitelist approach.
167173// Only allows safe tags and attributes to prevent XSS, phishing, and tracking.
168174// This is designed for email contexts where security is critical.
175+ //
176+ //nolint:gocognit,funlen // Security-critical HTML sanitizer - complexity justified for comprehensive safety
169177func sanitizeHTML (html string ) string {
170178 // Whitelist of allowed tags (no scripts, forms, iframes, etc.)
171179 allowedTags := map [string ]bool {
@@ -190,6 +198,7 @@ func sanitizeHTML(html string) string {
190198 inTag := false
191199 tagStart := 0
192200
201+ //nolint:intrange,varnamelen // Index used for look-ahead parsing - range loop not suitable
193202 for i := 0 ; i < len (html ); i ++ {
194203 if html [i ] == '<' {
195204 if inTag {
0 commit comments