plugins/viewhtml: add image proxy
This commit is contained in:
parent
8c4fd20e27
commit
a8a3c82579
2 changed files with 72 additions and 8 deletions
|
@ -1,10 +1,59 @@
|
||||||
package koushinviewhtml
|
package koushinviewhtml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.sr.ht/~emersion/koushin"
|
"git.sr.ht/~emersion/koushin"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
proxyEnabled = true
|
||||||
|
proxyMaxSize = 5 * 1024 * 1024 // 5 MiB
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
p := koushin.GoPlugin{Name: "viewhtml"}
|
p := koushin.GoPlugin{Name: "viewhtml"}
|
||||||
|
|
||||||
|
p.GET("/proxy", func(ctx *koushin.Context) error {
|
||||||
|
if !proxyEnabled {
|
||||||
|
return echo.NewHTTPError(http.StatusForbidden, "proxy disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(ctx.QueryParam("src"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Scheme != "https" {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid scheme")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
mediaType, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||||
|
if err != nil || !strings.HasPrefix(mediaType, "image/") {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid resource type")
|
||||||
|
}
|
||||||
|
|
||||||
|
size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
|
||||||
|
if err != nil || size > proxyMaxSize {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid resource length")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Response().Header().Set("Content-Length", strconv.Itoa(size))
|
||||||
|
lr := io.LimitedReader{resp.Body, int64(proxyMaxSize)}
|
||||||
|
return ctx.Stream(http.StatusOK, mediaType, &lr)
|
||||||
|
})
|
||||||
|
|
||||||
koushin.RegisterPluginLoader(p.Loader())
|
koushin.RegisterPluginLoader(p.Loader())
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,17 +80,32 @@ func (san *sanitizer) sanitizeImageURL(src string) string {
|
||||||
return "about:blank"
|
return "about:blank"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(u.Scheme) {
|
||||||
// TODO: mid support?
|
// TODO: mid support?
|
||||||
if !strings.EqualFold(u.Scheme, "cid") || san.msg == nil {
|
case "cid":
|
||||||
|
if san.msg == nil {
|
||||||
|
return "about:blank"
|
||||||
|
}
|
||||||
|
|
||||||
|
part := san.msg.PartByID(u.Opaque)
|
||||||
|
if part == nil || !strings.HasPrefix(part.MIMEType, "image/") {
|
||||||
|
return "about:blank"
|
||||||
|
}
|
||||||
|
|
||||||
|
return part.URL(true).String()
|
||||||
|
case "https":
|
||||||
|
if !proxyEnabled {
|
||||||
|
return "about:blank"
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyURL := url.URL{Path: "/proxy"}
|
||||||
|
proxyQuery := make(url.Values)
|
||||||
|
proxyQuery.Set("src", u.String())
|
||||||
|
proxyURL.RawQuery = proxyQuery.Encode()
|
||||||
|
return proxyURL.String()
|
||||||
|
default:
|
||||||
return "about:blank"
|
return "about:blank"
|
||||||
}
|
}
|
||||||
|
|
||||||
part := san.msg.PartByID(u.Opaque)
|
|
||||||
if part == nil || !strings.HasPrefix(part.MIMEType, "image/") {
|
|
||||||
return "about:blank"
|
|
||||||
}
|
|
||||||
|
|
||||||
return part.URL(true).String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (san *sanitizer) sanitizeCSSDecls(decls []*css.Declaration) []*css.Declaration {
|
func (san *sanitizer) sanitizeCSSDecls(decls []*css.Declaration) []*css.Declaration {
|
||||||
|
|
Loading…
Reference in a new issue