@@ -31,6 +31,7 @@ import (
3131 repo_model "code.gitea.io/gitea/models/repo"
3232 user_model "code.gitea.io/gitea/models/user"
3333 "code.gitea.io/gitea/modules/base"
34+ "code.gitea.io/gitea/modules/charset"
3435 "code.gitea.io/gitea/modules/emoji"
3536 "code.gitea.io/gitea/modules/git"
3637 giturl "code.gitea.io/gitea/modules/git/url"
@@ -42,6 +43,7 @@ import (
4243 "code.gitea.io/gitea/modules/setting"
4344 "code.gitea.io/gitea/modules/svg"
4445 "code.gitea.io/gitea/modules/timeutil"
46+ "code.gitea.io/gitea/modules/translation"
4547 "code.gitea.io/gitea/modules/util"
4648 "code.gitea.io/gitea/services/gitdiff"
4749
@@ -343,12 +345,15 @@ func NewFuncMap() []template.FuncMap {
343345 }
344346 return false
345347 },
346- "svg" : SVG ,
347- "avatar" : Avatar ,
348- "avatarHTML" : AvatarHTML ,
349- "avatarByAction" : AvatarByAction ,
350- "avatarByEmail" : AvatarByEmail ,
351- "repoAvatar" : RepoAvatar ,
348+ "svg" : SVG ,
349+ "avatar" : Avatar ,
350+ "avatarHTML" : AvatarHTML ,
351+ "avatarByAction" : AvatarByAction ,
352+ "avatarByEmail" : AvatarByEmail ,
353+ "escapeAmbiguous" : EscapeAmbiguous ,
354+ "escapeAmbiguousHTML" : EscapeAmbiguousHTML ,
355+ "escapeAmbiguousLink" : EscapeAmbiguousLink ,
356+ "repoAvatar" : RepoAvatar ,
352357 "SortArrow" : func (normSort , revSort , urlSort string , isDefault bool ) template.HTML {
353358 // if needed
354359 if len (normSort ) == 0 || len (urlSort ) == 0 {
@@ -680,6 +685,67 @@ func AvatarByEmail(email, name string, others ...interface{}) template.HTML {
680685 return template .HTML ("" )
681686}
682687
688+ // EscapeAmbiguous
689+ func EscapeAmbiguous (locale translation.Locale , text string ) template.HTML {
690+ sb := & strings.Builder {}
691+ status , _ := charset .EscapeControlStringWriter (text , sb , locale )
692+ escapeStatusSwitch (locale , sb , status )
693+
694+ return template .HTML (sb .String ())
695+ }
696+
697+ // EscapeAmbiguousHTML
698+ func EscapeAmbiguousHTML (locale translation.Locale , html string ) template.HTML {
699+ sb := & strings.Builder {}
700+ status , _ := charset .EscapeControlHTMLReader (strings .NewReader (html ), sb , locale )
701+ escapeStatusSwitch (locale , sb , status )
702+ return template .HTML (sb .String ())
703+ }
704+
705+ // EscapeAmbiguousLink takes a locale, text body - which is assumed to be a string not html, href and other attributes
706+ func EscapeAmbiguousLink (locale translation.Locale , text , href string , attrs ... string ) template.HTML {
707+ sb := & strings.Builder {}
708+ _ , _ = sb .WriteString (`<a href="` )
709+ template .HTMLEscape (sb , []byte (href ))
710+ _ , _ = sb .WriteString (`"` )
711+ attrValue := false
712+ for _ , attr := range attrs {
713+ if attrValue {
714+ _ , _ = sb .WriteString (`="` )
715+ } else {
716+ _ , _ = sb .WriteString (` ` )
717+ }
718+ template .HTMLEscape (sb , []byte (attr ))
719+ if attrValue {
720+ _ , _ = sb .WriteString (`"` )
721+ }
722+ attrValue = ! attrValue
723+ }
724+ _ , _ = sb .WriteString (`>` )
725+ status , _ := charset .EscapeControlStringWriter (text , sb , locale )
726+ _ , _ = sb .WriteString (`</a>` )
727+
728+ escapeStatusSwitch (locale , sb , status )
729+ return template .HTML (sb .String ())
730+ }
731+
732+ func escapeStatusSwitch (locale translation.Locale , sb * strings.Builder , status * charset.EscapeStatus ) {
733+ if status .Escaped {
734+ _ , _ = sb .WriteString (`<a href="" class="toggle-escape-button" title="` )
735+ if status .HasInvisible {
736+ _ , _ = sb .WriteString (locale .Tr ("invisible_runes" ))
737+ }
738+ if status .HasInvisible && status .HasAmbiguous {
739+ _ , _ = sb .WriteString (` ` )
740+ }
741+ if status .HasAmbiguous {
742+ _ , _ = sb .WriteString (locale .Tr ("ambiguous_runes" ))
743+ }
744+
745+ _ , _ = sb .WriteString (`"></a>` )
746+ }
747+ }
748+
683749// Safe render raw as HTML
684750func Safe (raw string ) template.HTML {
685751 return template .HTML (raw )
@@ -711,13 +777,13 @@ func DotEscape(raw string) string {
711777}
712778
713779// RenderCommitMessage renders commit message with XSS-safe and special links.
714- func RenderCommitMessage (ctx context.Context , msg , urlPrefix string , metas map [string ]string ) template.HTML {
715- return RenderCommitMessageLink (ctx , msg , urlPrefix , "" , metas )
780+ func RenderCommitMessage (ctx context.Context , locale translation. Locale , msg , urlPrefix string , metas map [string ]string ) template.HTML {
781+ return RenderCommitMessageLink (ctx , locale , msg , urlPrefix , "" , metas )
716782}
717783
718784// RenderCommitMessageLink renders commit message as a XXS-safe link to the provided
719785// default url, handling for special links.
720- func RenderCommitMessageLink (ctx context.Context , msg , urlPrefix , urlDefault string , metas map [string ]string ) template.HTML {
786+ func RenderCommitMessageLink (ctx context.Context , locale translation. Locale , msg , urlPrefix , urlDefault string , metas map [string ]string ) template.HTML {
721787 cleanMsg := template .HTMLEscapeString (msg )
722788 // we can safely assume that it will not return any error, since there
723789 // shouldn't be any special HTML.
@@ -731,16 +797,17 @@ func RenderCommitMessageLink(ctx context.Context, msg, urlPrefix, urlDefault str
731797 log .Error ("RenderCommitMessage: %v" , err )
732798 return ""
733799 }
734- msgLines := strings .Split (strings .TrimSpace (fullMessage ), "\n " )
800+ msgLines := strings .SplitN (strings .TrimSpace (fullMessage ), "\n " , 2 )
735801 if len (msgLines ) == 0 {
736802 return template .HTML ("" )
737803 }
738- return template .HTML (msgLines [0 ])
804+ _ , renderedMessage := charset .EscapeControlHTML (msgLines [0 ], locale )
805+ return template .HTML (renderedMessage )
739806}
740807
741808// RenderCommitMessageLinkSubject renders commit message as a XXS-safe link to
742809// the provided default url, handling for special links without email to links.
743- func RenderCommitMessageLinkSubject (ctx context.Context , msg , urlPrefix , urlDefault string , metas map [string ]string ) template.HTML {
810+ func RenderCommitMessageLinkSubject (ctx context.Context , locale translation. Locale , msg , urlPrefix , urlDefault string , metas map [string ]string ) template.HTML {
744811 msgLine := strings .TrimLeftFunc (msg , unicode .IsSpace )
745812 lineEnd := strings .IndexByte (msgLine , '\n' )
746813 if lineEnd > 0 {
@@ -763,11 +830,12 @@ func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlPrefix, urlDefa
763830 log .Error ("RenderCommitMessageSubject: %v" , err )
764831 return template .HTML ("" )
765832 }
833+ _ , renderedMessage = charset .EscapeControlHTML (renderedMessage , locale )
766834 return template .HTML (renderedMessage )
767835}
768836
769837// RenderCommitBody extracts the body of a commit message without its title.
770- func RenderCommitBody (ctx context.Context , msg , urlPrefix string , metas map [string ]string ) template.HTML {
838+ func RenderCommitBody (ctx context.Context , locale translation. Locale , msg , urlPrefix string , metas map [string ]string ) template.HTML {
771839 msgLine := strings .TrimRightFunc (msg , unicode .IsSpace )
772840 lineEnd := strings .IndexByte (msgLine , '\n' )
773841 if lineEnd > 0 {
@@ -789,11 +857,12 @@ func RenderCommitBody(ctx context.Context, msg, urlPrefix string, metas map[stri
789857 log .Error ("RenderCommitMessage: %v" , err )
790858 return ""
791859 }
860+ _ , renderedMessage = charset .EscapeControlHTML (renderedMessage , locale )
792861 return template .HTML (renderedMessage )
793862}
794863
795864// RenderIssueTitle renders issue/pull title with defined post processors
796- func RenderIssueTitle (ctx context.Context , text , urlPrefix string , metas map [string ]string ) template.HTML {
865+ func RenderIssueTitle (ctx context.Context , locale translation. Locale , text , urlPrefix string , metas map [string ]string ) template.HTML {
797866 renderedText , err := markup .RenderIssueTitle (& markup.RenderContext {
798867 Ctx : ctx ,
799868 URLPrefix : urlPrefix ,
@@ -803,6 +872,7 @@ func RenderIssueTitle(ctx context.Context, text, urlPrefix string, metas map[str
803872 log .Error ("RenderIssueTitle: %v" , err )
804873 return template .HTML ("" )
805874 }
875+ _ , renderedText = charset .EscapeControlHTML (renderedText , locale )
806876 return template .HTML (renderedText )
807877}
808878
@@ -830,7 +900,7 @@ func ReactionToEmoji(reaction string) template.HTML {
830900}
831901
832902// RenderNote renders the contents of a git-notes file as a commit message.
833- func RenderNote (ctx context.Context , msg , urlPrefix string , metas map [string ]string ) template.HTML {
903+ func RenderNote (ctx context.Context , locale translation. Locale , msg , urlPrefix string , metas map [string ]string ) template.HTML {
834904 cleanMsg := template .HTMLEscapeString (msg )
835905 fullMessage , err := markup .RenderCommitMessage (& markup.RenderContext {
836906 Ctx : ctx ,
@@ -841,6 +911,8 @@ func RenderNote(ctx context.Context, msg, urlPrefix string, metas map[string]str
841911 log .Error ("RenderNote: %v" , err )
842912 return ""
843913 }
914+ _ , fullMessage = charset .EscapeControlHTML (fullMessage , locale )
915+
844916 return template .HTML (fullMessage )
845917}
846918
0 commit comments