plugins/viewhtml: add opt-in query param to load remote resources
Loading remote resources by default has privacy implications.
This commit is contained in:
parent
a8a3c82579
commit
b3f98de1da
4 changed files with 33 additions and 3 deletions
|
@ -9,6 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.sr.ht/~emersion/koushin"
|
"git.sr.ht/~emersion/koushin"
|
||||||
|
koushinbase "git.sr.ht/~emersion/koushin/plugins/base"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +21,17 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
p := koushin.GoPlugin{Name: "viewhtml"}
|
p := koushin.GoPlugin{Name: "viewhtml"}
|
||||||
|
|
||||||
|
p.Inject("message.html", func(ctx *koushin.Context, _data koushin.RenderData) error {
|
||||||
|
data := _data.(*koushinbase.MessageRenderData)
|
||||||
|
data.Extra["RemoteResourcesAllowed"] = ctx.QueryParam("allow-remote-resources") == "1"
|
||||||
|
hasRemoteResources := false
|
||||||
|
if v := ctx.Get("viewhtml.hasRemoteResources"); v != nil {
|
||||||
|
hasRemoteResources = v.(bool)
|
||||||
|
}
|
||||||
|
data.Extra["HasRemoteResources"] = hasRemoteResources
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
p.GET("/proxy", func(ctx *koushin.Context) error {
|
p.GET("/proxy", func(ctx *koushin.Context) error {
|
||||||
if !proxyEnabled {
|
if !proxyEnabled {
|
||||||
return echo.NewHTTPError(http.StatusForbidden, "proxy disabled")
|
return echo.NewHTTPError(http.StatusForbidden, "proxy disabled")
|
||||||
|
|
|
@ -71,7 +71,9 @@ var allowedStyles = map[string]bool{
|
||||||
}
|
}
|
||||||
|
|
||||||
type sanitizer struct {
|
type sanitizer struct {
|
||||||
msg *koushinbase.IMAPMessage
|
msg *koushinbase.IMAPMessage
|
||||||
|
allowRemoteResources bool
|
||||||
|
hasRemoteResources bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (san *sanitizer) sanitizeImageURL(src string) string {
|
func (san *sanitizer) sanitizeImageURL(src string) string {
|
||||||
|
@ -94,7 +96,9 @@ func (san *sanitizer) sanitizeImageURL(src string) string {
|
||||||
|
|
||||||
return part.URL(true).String()
|
return part.URL(true).String()
|
||||||
case "https":
|
case "https":
|
||||||
if !proxyEnabled {
|
san.hasRemoteResources = true
|
||||||
|
|
||||||
|
if !proxyEnabled || !san.allowRemoteResources {
|
||||||
return "about:blank"
|
return "about:blank"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ var tpl = template.Must(template.New("view-html.html").Parse(tplSrc))
|
||||||
type viewer struct{}
|
type viewer struct{}
|
||||||
|
|
||||||
func (viewer) ViewMessagePart(ctx *koushin.Context, msg *koushinbase.IMAPMessage, part *message.Entity) (interface{}, error) {
|
func (viewer) ViewMessagePart(ctx *koushin.Context, msg *koushinbase.IMAPMessage, part *message.Entity) (interface{}, error) {
|
||||||
|
allowRemoteResources := ctx.QueryParam("allow-remote-resources") == "1"
|
||||||
|
|
||||||
mimeType, _, err := part.Header.ContentType()
|
mimeType, _, err := part.Header.ContentType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -38,12 +40,17 @@ func (viewer) ViewMessagePart(ctx *koushin.Context, msg *koushinbase.IMAPMessage
|
||||||
return nil, fmt.Errorf("failed to read part body: %v", err)
|
return nil, fmt.Errorf("failed to read part body: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
san := sanitizer{msg}
|
san := sanitizer{
|
||||||
|
msg: msg,
|
||||||
|
allowRemoteResources: allowRemoteResources,
|
||||||
|
}
|
||||||
body, err = san.sanitizeHTML(body)
|
body, err = san.sanitizeHTML(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to sanitize HTML part: %v", err)
|
return nil, fmt.Errorf("failed to sanitize HTML part: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Set("viewhtml.hasRemoteResources", san.hasRemoteResources)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err = tpl.Execute(&buf, string(body))
|
err = tpl.Execute(&buf, string(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -99,6 +99,13 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
{{if and .Extra.HasRemoteResources (not .Extra.RemoteResourcesAllowed)}}
|
||||||
|
<p class="alert alert-info">
|
||||||
|
This message contains remote content.
|
||||||
|
<a href="?part={{.PartPath}}&allow-remote-resources=1" class="alert-link">Load</a>
|
||||||
|
</p>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if .View}}
|
{{if .View}}
|
||||||
{{.View}}
|
{{.View}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
Loading…
Reference in a new issue