diff options
author | 2022-09-02 05:54:32 -0400 | |
---|---|---|
committer | 2022-09-02 11:54:32 +0200 | |
commit | 1e1cdee06a3bd5aaa0f97ad3c0d25aa505e723ef (patch) | |
tree | 85be3b04d0737980082c5f78c52b51759aa0bb5b /internal/router | |
parent | [bugfix] Fix occasional federatingdb test fail (#792) (diff) | |
download | gotosocial-1e1cdee06a3bd5aaa0f97ad3c0d25aa505e723ef.tar.xz |
[feature] Emojify spoiler and content in web templates (#785)
* Emojify spoiler and content in web templates
* Use more performance emojify code (thanks NyaaaWhatsUpDoc!)
Diffstat (limited to 'internal/router')
-rw-r--r-- | internal/router/template.go | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/internal/router/template.go b/internal/router/template.go index ebd8629e8..a9d5726ea 100644 --- a/internal/router/template.go +++ b/internal/router/template.go @@ -19,7 +19,9 @@ package router import ( + "bytes" "fmt" + "html" "html/template" "os" "path/filepath" @@ -28,6 +30,7 @@ import ( "github.com/gin-gonic/gin" "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/regexes" ) // LoadTemplates loads html templates for use by the given engine @@ -57,6 +60,11 @@ func oddOrEven(n int) string { return "odd" } +func escape(str string) template.HTML { + /* #nosec G203 */ + return template.HTML(template.HTMLEscapeString(str)) +} + func noescape(str string) template.HTML { /* #nosec G203 */ return template.HTML(str) @@ -97,12 +105,56 @@ func visibilityIcon(visibility model.Visibility) template.HTML { return template.HTML(fmt.Sprintf(`<i aria-label="Visibility: %v" class="fa fa-%v"></i>`, icon.label, icon.faIcon)) } +// replaces shortcodes in `text` with the emoji in `emojis` +// text is a template.HTML to affirm that the input of this function is already escaped +func emojify(emojis []model.Emoji, text template.HTML) template.HTML { + emojisMap := make(map[string]model.Emoji, len(emojis)) + + for _, emoji := range emojis { + shortcode := ":" + emoji.Shortcode + ":" + emojisMap[shortcode] = emoji + } + + out := regexes.ReplaceAllStringFunc( + regexes.EmojiFinder, + string(text), + func(shortcode string, buf *bytes.Buffer) string { + // Look for emoji according to this shortcode + emoji, ok := emojisMap[shortcode] + if !ok { + return shortcode + } + + // Escape raw emoji content + safeURL := html.EscapeString(emoji.URL) + safeCode := html.EscapeString(emoji.Shortcode) + + // Write HTML emoji repr to buffer + buf.WriteString(`<img src="`) + buf.WriteString(safeURL) + buf.WriteString(`" title=":`) + buf.WriteString(safeCode) + buf.WriteString(`:" alt=":`) + buf.WriteString(safeCode) + buf.WriteString(`:" class="emoji"/>`) + + return buf.String() + }, + ) + + /* #nosec G203 */ + // (this is escaped above) + return template.HTML(out) +} + func LoadTemplateFunctions(engine *gin.Engine) { engine.SetFuncMap(template.FuncMap{ + "escape": escape, "noescape": noescape, "oddOrEven": oddOrEven, "visibilityIcon": visibilityIcon, "timestamp": timestamp, "timestampShort": timestampShort, + "emojify": emojify, }) } |