diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index fae06b8f..ca08d249 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -21,6 +21,7 @@ services: environment: IMGPROXY_KEY: ${READFLOW_HASH_SECRET_KEY:-736563726574} IMGPROXY_SALT: ${READFLOW_HASH_SECRET_SALT:-706570706572} + IMGPROXY_ENABLE_WEBP_DETECTION: true ports: - "${IMAGOR_PORT:-8081}:8080" ####################################### diff --git a/docker-compose.yml b/docker-compose.yml index f9a0dbd3..d07ac1a7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,8 @@ services: image: darthsim/imgproxy environment: IMGPROXY_KEY: ${READFLOW_HASH_SECRET_KEY:-736563726574} - IMGPROXY_SALT: ${READFLOW_HASH_SECRET_SALT:-706570706572} + IMGPROXY_SALT: ${READFLOW_HASH_SECRET_SALT:-706570706572} + IMGPROXY_ENABLE_WEBP_DETECTION: true logging: driver: "json-file" options: diff --git a/pkg/api/image-proxy.go b/pkg/api/image-proxy.go index ebfbedef..134c5d0c 100644 --- a/pkg/api/image-proxy.go +++ b/pkg/api/image-proxy.go @@ -8,10 +8,9 @@ import ( "github.com/ncarlier/readflow/pkg/config" "github.com/ncarlier/readflow/pkg/constant" + "github.com/ncarlier/readflow/pkg/helper" ) -const defaultUserAgent = "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0" - var hopHeaders = []string{ "Connection", "Keep-Alive", @@ -26,7 +25,11 @@ var hopHeaders = []string{ func copyHeader(dst, src http.Header) { for k, vv := range src { for _, v := range vv { - dst.Add(k, v) + if dst.Get(k) != "" { + dst.Set(k, v) + } else { + dst.Add(k, v) + } } } } @@ -71,16 +74,12 @@ func imgProxyHandler(conf *config.Config) http.Handler { return } - // Manage request headers - userAgent := r.Header.Get("User-Agent") - if userAgent == "" { - userAgent = defaultUserAgent - } - req.Header.Set("User-Agent", userAgent) + // Manage request headers: copy, add x-forward, del hop + copyHeader(req.Header, r.Header) if clientIP, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { appendHostToXForwardHeader(req.Header, clientIP) } - delHopHeaders(r.Header) + delHopHeaders(req.Header) // Do proxy request resp, err := constant.DefaultClient.Do(req) @@ -90,6 +89,17 @@ func imgProxyHandler(conf *config.Config) http.Handler { } defer resp.Body.Close() + // Redirect if image proxy failed + if resp.StatusCode >= 400 { + // decode image URL from proxy path + if img, err := helper.DecodeImageProxyPath(path); err != nil { + http.Error(w, err.Error(), http.StatusBadGateway) + } else { + http.Redirect(w, r, string(img), http.StatusTemporaryRedirect) + } + return + } + // Create proxy response delHopHeaders(resp.Header) copyHeader(w.Header(), resp.Header) diff --git a/pkg/helper/image-proxy.go b/pkg/helper/image-proxy.go new file mode 100644 index 00000000..7f17a472 --- /dev/null +++ b/pkg/helper/image-proxy.go @@ -0,0 +1,23 @@ +package helper + +import ( + "encoding/base64" + "strings" +) + +// Encode image URL to Image Proxy path +func EncodeImageProxyPath(url, size string) string { + return "/resize:fit:" + size + "/" + base64.StdEncoding.EncodeToString([]byte(url)) +} + +// Decode image URL from Image Proxy Path +func DecodeImageProxyPath(path string) (url string, err error) { + url = path[strings.LastIndex(path, "/")+1:] + var decoded []byte + decoded, err = base64.StdEncoding.DecodeString(url) + if err == nil { + url = string(decoded) + } + + return +} diff --git a/pkg/helper/sign.go b/pkg/helper/sign.go deleted file mode 100644 index f0e8adb8..00000000 --- a/pkg/helper/sign.go +++ /dev/null @@ -1,18 +0,0 @@ -package helper - -import ( - "crypto/hmac" - "encoding/base64" - "hash" -) - -// Sign value with secret -func Sign(algo func() hash.Hash, value, secret string, truncate int) string { - h := hmac.New(algo, []byte(secret)) - h.Write([]byte(value)) - sig := base64.URLEncoding.EncodeToString(h.Sum(nil)) - if truncate > 0 && len(sig) > truncate { - return sig[:truncate] - } - return sig -} diff --git a/pkg/service/articles_thumbnail.go b/pkg/service/articles_thumbnail.go index 1ba0dd1b..71c519d4 100644 --- a/pkg/service/articles_thumbnail.go +++ b/pkg/service/articles_thumbnail.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/base64" + "github.com/ncarlier/readflow/pkg/helper" "github.com/ncarlier/readflow/pkg/model" ) @@ -13,7 +14,7 @@ func (reg *Registry) GetArticleThumbnailHash(article *model.Article, size string if article.Image == nil || *article.Image == "" { return "" } - path := "/resize:fit:" + size + "/" + base64.StdEncoding.EncodeToString([]byte(*article.Image)) + path := helper.EncodeImageProxyPath(*article.Image, size) mac := hmac.New(sha256.New, reg.conf.Hash.SecretKey.Value) mac.Write(reg.conf.Hash.SecretSalt.Value)