Use a specific xss sanitizer for long form content

This commit is contained in:
Daniele Tonon
2023-06-02 23:59:17 +02:00
parent ddaba769f9
commit 44f9c07ee5
9 changed files with 78 additions and 54 deletions

9
go.mod
View File

@@ -7,12 +7,19 @@ require (
github.com/die-net/lrucache v0.0.0-20220628165024-20a71bc65bf1
github.com/lukevers/freetype-go v0.0.0-20150513150840-77e276735410
github.com/mailru/easyjson v0.7.7
github.com/microcosm-cc/bluemonday v1.0.24
github.com/nbd-wtf/go-nostr v0.18.7
github.com/pelletier/go-toml v1.9.5
github.com/rs/zerolog v1.29.1
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
)
require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
golang.org/x/net v0.10.0 // indirect
)
replace github.com/nbd-wtf/go-nostr v0.18.7 => github.com/nbd-wtf/go-nostr v0.18.8-0.20230531153548-b7ec430166bb
require (
@@ -33,5 +40,5 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/sys v0.8.0 // indirect
)

12
go.sum
View File

@@ -1,6 +1,8 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/apatters/go-wordwrap v1.0.0 h1:G6ni4Pt7/I4ED+A5ZvsK8e9XwETD04veDKxEL2QN830=
github.com/apatters/go-wordwrap v1.0.0/go.mod h1:3sM7HcArQ+utXnjDQ4d1xjrd8b/wbKuDr/RmbiHgjwI=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
@@ -58,6 +60,8 @@ github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a/go.mod h1:JDGc
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -75,6 +79,8 @@ github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZb
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
github.com/nbd-wtf/go-nostr v0.18.8-0.20230531153548-b7ec430166bb h1:28eaYF27FKWf5aO4plC0z0b4ht9FntbKC9IkAaQwxAs=
github.com/nbd-wtf/go-nostr v0.18.8-0.20230531153548-b7ec430166bb/go.mod h1:F9y6+M8askJCjilLgMC3rD0moA6UtG1MCnyClNYXeys=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -121,8 +127,9 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -135,8 +142,9 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -252,7 +252,8 @@ func render(w http.ResponseWriter, r *http.Request) {
funcMap := template.FuncMap{
"basicFormatting": basicFormatting,
"mdToHTML": mdToHTML,
"sanitizeString": html.EscapeString,
"escapeString": html.EscapeString,
"sanitizeXSS": sanitizeXSS,
}
tmpl := template.Must(

View File

@@ -1,19 +1,19 @@
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}}">
<div class="label">Published at</div>
{{.createdAt | sanitizeString}}
{{.createdAt | escapeString}}
</div>
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}}">
<div class="label">Kind type</div>
{{.kindID}}
{{ if not (eq .kindNIP "")}}
- <a href="https://github.com/nostr-protocol/nips/blob/master/{{.kindNIP | sanitizeString}}.md">{{.kindDescription | sanitizeString}}</a>
- <a href="https://github.com/nostr-protocol/nips/blob/master/{{.kindNIP | escapeString}}.md">{{.kindDescription | escapeString}}</a>
{{ end }}
</div>
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}}">
<div class="label">Nevent</div>
<div>{{.nevent | sanitizeString}}</div>
<div>{{.nevent | escapeString}}</div>
</div>
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}} boxed">

View File

@@ -1,19 +1,19 @@
<head>
{{if eq .type "profile"}}
<title>Nostr Public Key {{.npub}}</title>
<meta property="og:site_name" content="{{.npub | sanitizeString}}" />
<meta property="og:title" content="{{.title | sanitizeString}}" />
<link rel="canonical" href="https://nostr.com/{{.npub | sanitizeString }}" />
<meta property="og:site_name" content="{{.npub | escapeString}}" />
<meta property="og:title" content="{{.title | escapeString}}" />
<link rel="canonical" href="https://nostr.com/{{.npub | escapeString }}" />
{{ if .metadata.Picture }}
<meta property="og:image" content="{{.metadata.Picture | sanitizeString}}" />
<meta property="og:image" content="{{.metadata.Picture | escapeString}}" />
<meta
property="twitter:image"
content="{{.proxy}}{{.metadata.Picture | sanitizeString}}"
content="{{.proxy}}{{.metadata.Picture | escapeString}}"
/>
{{end}} {{ if .metadata.About }}
<meta
property="og:description"
content="{{.metadata.About | sanitizeString}}"
content="{{.metadata.About | escapeString}}"
/>
{{end}}
<meta property="twitter:card" content="summary" />
@@ -21,45 +21,45 @@
<!----------->
{{ if eq .type "note" }}
<title>Nostr Event {{.nevent}}</title>
<meta property="og:site_name" content="{{.authorLong | sanitizeString}}" />
<meta property="og:title" content="{{.title | sanitizeString}}" />
<meta name="twitter:title" content="{{.twitterTitle | sanitizeString}}" />
<link rel="canonical" href="https://nostr.com/{{.note | sanitizeString }}" />
<meta property="og:site_name" content="{{.authorLong | escapeString}}" />
<meta property="og:title" content="{{.title | escapeString}}" />
<meta name="twitter:title" content="{{.twitterTitle | escapeString}}" />
<link rel="canonical" href="https://nostr.com/{{.note | escapeString }}" />
<!---->
{{ if .textImageURL }}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@nostrprotocol" />
<meta property="og:image" content="{{.textImageURL | sanitizeString}}" />
<meta name="twitter:image" content="{{.textImageURL | sanitizeString}}" />
<meta property="og:image" content="{{.textImageURL | escapeString}}" />
<meta name="twitter:image" content="{{.textImageURL | escapeString}}" />
{{ else }}
<!---->
<meta property="twitter:card" content="summary" />
{{ if .image }}
<meta property="og:image" content="{{.image | sanitizeString}}" />
<meta name="twitter:image" content="{{.proxy}}{{.image | sanitizeString}}" />
<meta property="og:image" content="{{.image | escapeString}}" />
<meta name="twitter:image" content="{{.proxy}}{{.image | escapeString}}" />
{{end}} {{ if .video }}
<meta property="og:video" content="{{.video | sanitizeString}}" />
<meta property="og:video:secure_url" content="{{.video | sanitizeString}}" />
<meta property="og:video" content="{{.video | escapeString}}" />
<meta property="og:video:secure_url" content="{{.video | escapeString}}" />
<meta
property="og:video:type"
content="video/{{.videoType | sanitizeString}}"
content="video/{{.videoType | escapeString}}"
/>
{{end}}
<!---->
{{end}}
<meta property="og:description" content="{{.description | sanitizeString}}" />
<meta property="og:description" content="{{.description | escapeString}}" />
<meta
name="twitter:description"
content="{{.description | sanitizeString}}"
content="{{.description | escapeString}}"
/>
{{end}}
<!----------->
{{ if eq .type "address" }}
<title>Nostr Address {{.naddr | sanitizeString }}</title>
<title>Nostr Address {{.naddr | escapeString }}</title>
{{end}}
<!----------->
{{ if eq .type "other" }}
<title>Nostr Event {{.kindID }} - {{.kindDescription | sanitizeString }}</title>
<title>Nostr Event {{.kindID }} - {{.kindDescription | escapeString }}</title>
{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@@ -10,26 +10,26 @@
<div class="container">
<div class="column column_content">
<div class="profile_intro">
<a href="/{{.npub | sanitizeString}}">
<a href="/{{.npub | escapeString}}">
<div class="pic-wrapper">
<img class="pic" src="{{.metadata.Picture | sanitizeString}}" />
<img class="pic" src="{{.metadata.Picture | escapeString}}" />
</div>
<div class="info-wrapper">
<div class="name">
{{.metadata.Name | sanitizeString}}
{{.metadata.Name | escapeString}}
<span class="display"
>{{.metadata.DisplayName | sanitizeString}}</span
>{{.metadata.DisplayName | escapeString}}</span
>
</div>
<div class="npub">{{.npubShort | sanitizeString}}</div>
<div class="npub">{{.npubShort | escapeString}}</div>
</div>
</a>
</div>
<div class="published_at">{{.createdAt | sanitizeString}}</div>
<div class="published_at">{{.createdAt | escapeString}}</div>
{{ if .parentNevent }}
<div class="reply_of">
In reply to {{ printf "%s%s" "nostr:" .parentNevent | sanitizeString | basicFormatting }}
In reply to {{ printf "%s%s" "nostr:" .parentNevent | escapeString | basicFormatting }}
</div>
{{ end }}
@@ -37,12 +37,12 @@
<div class="field content">
{{ if (not (eq .subject ""))}}
<h1>{{.subject | sanitizeString}}</h1>
<h1>{{.subject | escapeString}}</h1>
{{ end }}
{{ if (or (eq .kindID 30023) (eq .kindID 30024))}}
{{.content | sanitizeString | mdToHTML }}
{{.content | mdToHTML | sanitizeXSS }}
{{ else }}
{{.content | sanitizeString | basicFormatting }}
{{.content | escapeString | basicFormatting }}
{{ end }}
</div>
@@ -50,7 +50,7 @@
<div class="field">
<div class="label">Author Public key</div>
{{.npub | sanitizeString}}
{{.npub | escapeString}}
</div>
<div class="field advanced-switch-wrapper">

View File

@@ -12,7 +12,7 @@
<div class="profile_intro">
<div class="info-wrapper">
<div class="kind_desc">
{{.kindDescription | sanitizeString}}
{{.kindDescription | escapeString}}
</div>
</div>
</div>
@@ -21,7 +21,7 @@
<div class="field">
<div class="label">Author Public key</div>
<a href="/{{.npub | sanitizeString}}">{{.npub | sanitizeString}}</a>
<a href="/{{.npub | escapeString}}">{{.npub | escapeString}}</a>
</div>
{{template "details.html" .}}

View File

@@ -10,53 +10,53 @@
<div class="container">
<div class="column columnA">
<div class="info-wrapper">
{{.metadata.Name | sanitizeString}}
{{.metadata.Name | escapeString}}
<span class="display"
>{{.metadata.DisplayName | sanitizeString}}</span
>{{.metadata.DisplayName | escapeString}}</span
>
</div>
<div class="pic-wrapper">
<img class="pic" src="{{.metadata.Picture | sanitizeString}}" />
<img class="pic" src="{{.metadata.Picture | escapeString}}" />
</div>
<div class="last_update">
Last update:<br />
{{.createdAt | sanitizeString}}
{{.createdAt | escapeString}}
</div>
</div>
<div class="column column_content">
<div class="field info-wrapper">
<div class="name">
{{.metadata.Name | sanitizeString}}
{{.metadata.Name | escapeString}}
<span class="display"
>{{.metadata.DisplayName | sanitizeString}}</span
>{{.metadata.DisplayName | escapeString}}</span
>
</div>
</div>
<div class="field separator long"></div>
<div class="field">
<a href="{{.metadata.Website | sanitizeString}}"
>{{.metadata.Website | sanitizeString}}</a
<a href="{{.metadata.Website | escapeString}}"
>{{.metadata.Website | escapeString}}</a
>
</div>
<div class="field about">{{.metadata.About | sanitizeString | basicFormatting}}</div>
<div class="field about">{{.metadata.About | escapeString | basicFormatting}}</div>
<div class="field separator"></div>
<div class="field">
<div class="label">Public key</div>
{{.npub | sanitizeString}}
{{.npub | escapeString}}
</div>
<div class="field">
<div class="label">NIP-05</div>
{{.metadata.NIP05 | sanitizeString}}
{{.metadata.NIP05 | escapeString}}
</div>
<div class="field">
<div class="label">LN Address</div>
{{.metadata.LUD16 | sanitizeString}}
{{.metadata.LUD16 | escapeString}}
</div>
<div class="field last_update">
Last update:<br />
{{.createdAt | sanitizeString}}
{{.createdAt | escapeString}}
</div>
<div class="field separator"></div>

View File

@@ -10,6 +10,8 @@ import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/microcosm-cc/bluemonday"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip10"
"github.com/nbd-wtf/go-nostr/nip19"
@@ -271,3 +273,9 @@ func mdToHTML(md string) string {
return string(markdown.Render(doc, renderer))
}
func sanitizeXSS(html string) string {
p := bluemonday.UGCPolicy()
p.AllowStyling()
return p.Sanitize(html)
}