github.com/adacta-ru/mattermost-server/v6@v6.0.0/services/imageproxy/atmos_camo.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package imageproxy 5 6 import ( 7 "crypto/hmac" 8 "crypto/sha1" 9 "encoding/hex" 10 "io" 11 "net/http" 12 "net/url" 13 ) 14 15 type AtmosCamoBackend struct { 16 proxy *ImageProxy 17 siteURL *url.URL 18 remoteURL *url.URL 19 } 20 21 func makeAtmosCamoBackend(proxy *ImageProxy) *AtmosCamoBackend { 22 // We deliberately ignore the error because it's from config.json. 23 // The function returns a nil pointer in case of error, and we handle it when it's used. 24 siteURL, _ := url.Parse(*proxy.ConfigService.Config().ServiceSettings.SiteURL) 25 remoteURL, _ := url.Parse(*proxy.ConfigService.Config().ImageProxySettings.RemoteImageProxyURL) 26 27 return &AtmosCamoBackend{ 28 proxy: proxy, 29 siteURL: siteURL, 30 remoteURL: remoteURL, 31 } 32 } 33 34 func (backend *AtmosCamoBackend) GetImage(w http.ResponseWriter, r *http.Request, imageURL string) { 35 http.Redirect(w, r, backend.getAtmosCamoImageURL(imageURL), http.StatusFound) 36 } 37 38 func (backend *AtmosCamoBackend) GetImageDirect(imageURL string) (io.ReadCloser, string, error) { 39 req, err := http.NewRequest("GET", backend.getAtmosCamoImageURL(imageURL), nil) 40 if err != nil { 41 return nil, "", Error{err} 42 } 43 44 client := backend.proxy.HTTPService.MakeClient(false) 45 46 resp, err := client.Do(req) 47 if err != nil { 48 return nil, "", Error{err} 49 } 50 51 // Note that we don't do any additional validation of the received data since we expect the image proxy to do that 52 return resp.Body, resp.Header.Get("Content-Type"), nil 53 } 54 55 func (backend *AtmosCamoBackend) getAtmosCamoImageURL(imageURL string) string { 56 cfg := *backend.proxy.ConfigService.Config() 57 options := *cfg.ImageProxySettings.RemoteImageProxyOptions 58 59 if imageURL == "" || backend.siteURL == nil { 60 return imageURL 61 } 62 63 // Parse url, return siteURL in case of failure. 64 // Also if the URL is opaque. 65 parsedURL, err := url.Parse(imageURL) 66 if err != nil || parsedURL.Opaque != "" { 67 return backend.siteURL.String() 68 } 69 70 // If host is same as siteURL host/ remoteURL host, return. 71 if parsedURL.Host == backend.siteURL.Host || parsedURL.Host == backend.remoteURL.Host { 72 return parsedURL.String() 73 } 74 75 // Handle protocol-relative URLs. 76 if parsedURL.Scheme == "" { 77 parsedURL.Scheme = backend.siteURL.Scheme 78 } 79 80 // If it's a relative URL, fill up the hostname and scheme and return. 81 if parsedURL.Host == "" { 82 parsedURL.Host = backend.siteURL.Host 83 return parsedURL.String() 84 } 85 86 urlBytes := []byte(parsedURL.String()) 87 mac := hmac.New(sha1.New, []byte(options)) 88 mac.Write(urlBytes) 89 digest := hex.EncodeToString(mac.Sum(nil)) 90 91 return backend.remoteURL.String() + "/" + digest + "/" + hex.EncodeToString(urlBytes) 92 }