|
|
|
|
@@ -1,44 +1,67 @@
|
|
|
|
|
package render
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"regexp"
|
|
|
|
|
"encoding/xml"
|
|
|
|
|
"net/url"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"codeberg.org/rimgo/rimgo/utils"
|
|
|
|
|
"github.com/microcosm-cc/bluemonday"
|
|
|
|
|
"gitlab.com/golang-commonmark/linkify"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var imgurRe = regexp.MustCompile(`https?://imgur\.com/(gallery|a)?/(.*)`)
|
|
|
|
|
var imgurRe2 = regexp.MustCompile(`https?://imgur\.com/(.*)`)
|
|
|
|
|
var imgRe = regexp.MustCompile(`https?://i\.imgur\.com/(.*)\.(png|gif|jpe?g|webp)`)
|
|
|
|
|
var vidRe = regexp.MustCompile(`https?://i\.imgur\.com/(.*)\.(mp4|webm)`)
|
|
|
|
|
var vidFormatRe = regexp.MustCompile(`\.(mp4|webm)`)
|
|
|
|
|
var iImgurRe = regexp.MustCompile(`https?://i\.imgur\.com`)
|
|
|
|
|
|
|
|
|
|
func sanitizeDescription(src string) string {
|
|
|
|
|
src = strings.ReplaceAll(src, "\n", "<br>")
|
|
|
|
|
return bluemonday.UGCPolicy().Sanitize(src)
|
|
|
|
|
}
|
|
|
|
|
func sanitizeComment(src string) string {
|
|
|
|
|
src = strings.ReplaceAll(src, "\n", "<br>")
|
|
|
|
|
|
|
|
|
|
for _, match := range imgRe.FindAllString(src, -1) {
|
|
|
|
|
img := iImgurRe.ReplaceAllString(match, "")
|
|
|
|
|
img = `<img src="` + img + `" class="comment__media" loading="lazy"/>`
|
|
|
|
|
src = strings.Replace(src, match, img, 1)
|
|
|
|
|
}
|
|
|
|
|
for _, match := range vidRe.FindAllString(src, -1) {
|
|
|
|
|
vid := iImgurRe.ReplaceAllString(match, "")
|
|
|
|
|
vid = `<video class="comment__media" controls loop preload="none" poster="` + vidFormatRe.ReplaceAllString(vid, ".webp") + `"><source type="` + strings.Split(vid, ".")[1] + `" src="` + vid + `" /></video>`
|
|
|
|
|
src = strings.Replace(src, match, vid, 1)
|
|
|
|
|
}
|
|
|
|
|
buf := new(strings.Builder)
|
|
|
|
|
enc := xml.NewEncoder(buf)
|
|
|
|
|
from := 0
|
|
|
|
|
for _, l := range linkify.Links(src) {
|
|
|
|
|
origLink := (src)[l.Start:l.End]
|
|
|
|
|
link := `<a href="` + origLink + `">` + origLink + `</a>`
|
|
|
|
|
src = strings.Replace(src, origLink, link, 1)
|
|
|
|
|
buf.WriteString(src[from:l.Start])
|
|
|
|
|
origLink := src[l.Start:l.End]
|
|
|
|
|
url, err := url.Parse(origLink)
|
|
|
|
|
if err != nil {
|
|
|
|
|
buf.WriteString(origLink)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
newLink := utils.RewriteUrl(url)
|
|
|
|
|
if url.Host == "i.imgur.com" {
|
|
|
|
|
name, ext := utils.SplitNameExt(newLink)
|
|
|
|
|
switch ext {
|
|
|
|
|
case "png", "gif", "jpg", "jpeg", "webp":
|
|
|
|
|
start(enc, "img",
|
|
|
|
|
"src", newLink,
|
|
|
|
|
"class", "comment__media",
|
|
|
|
|
"loading", "lazy")
|
|
|
|
|
//self-closing tag
|
|
|
|
|
case "mp4", "webm":
|
|
|
|
|
start(enc, "video",
|
|
|
|
|
"class", "comment__media",
|
|
|
|
|
"controls", "controls",
|
|
|
|
|
"loop", "loop",
|
|
|
|
|
"preload", "none",
|
|
|
|
|
"poster", name+"webp")
|
|
|
|
|
start(enc, "source",
|
|
|
|
|
"type", ext,
|
|
|
|
|
"src", newLink)
|
|
|
|
|
end(enc, "source")
|
|
|
|
|
end(enc, "video")
|
|
|
|
|
default:
|
|
|
|
|
goto link
|
|
|
|
|
}
|
|
|
|
|
from = l.End
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
link:
|
|
|
|
|
start(enc, "a", "href", newLink)
|
|
|
|
|
xml.EscapeText(buf, []byte(origLink))
|
|
|
|
|
end(enc, "a")
|
|
|
|
|
from = l.End
|
|
|
|
|
}
|
|
|
|
|
src = imgurRe.ReplaceAllString(src, "/$1/$2")
|
|
|
|
|
src = imgurRe2.ReplaceAllString(src, "/$1")
|
|
|
|
|
buf.WriteString(src[from:])
|
|
|
|
|
|
|
|
|
|
p := bluemonday.UGCPolicy()
|
|
|
|
|
p.AllowImages()
|
|
|
|
|
@@ -49,5 +72,29 @@ func sanitizeComment(src string) string {
|
|
|
|
|
p.RequireNoReferrerOnLinks(true)
|
|
|
|
|
p.RequireNoFollowOnLinks(true)
|
|
|
|
|
p.RequireCrossOriginAnonymous(true)
|
|
|
|
|
return p.Sanitize(src)
|
|
|
|
|
return p.Sanitize(buf.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func start(enc *xml.Encoder, name string, attrs ...string) {
|
|
|
|
|
if len(attrs)%2 == 1 {
|
|
|
|
|
panic("odd number of arguments to attrs")
|
|
|
|
|
}
|
|
|
|
|
xmlAttrs := make([]xml.Attr, len(attrs)/2)
|
|
|
|
|
for i := 0; i < len(attrs); i += 2 {
|
|
|
|
|
xmlAttrs[i/2] = xml.Attr{
|
|
|
|
|
Name: xml.Name{Space: "", Local: attrs[i]},
|
|
|
|
|
Value: attrs[i+1],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
enc.EncodeToken(xml.StartElement{
|
|
|
|
|
Name: xml.Name{Space: "", Local: name},
|
|
|
|
|
Attr: xmlAttrs,
|
|
|
|
|
})
|
|
|
|
|
enc.Flush()
|
|
|
|
|
}
|
|
|
|
|
func end(enc *xml.Encoder, name string) {
|
|
|
|
|
enc.EncodeToken(xml.EndElement{
|
|
|
|
|
Name: xml.Name{Space: "", Local: name},
|
|
|
|
|
})
|
|
|
|
|
enc.Flush()
|
|
|
|
|
}
|
|
|
|
|
|