MM-26425: Make URL parsing for image proxy more robust (#16197)

* MM-26425: Make URL parsing for image proxy more robust

- We don't bypass protocol relative URLs.
- We don't bypass hostnames with a similar prefix.

https: //mattermost.atlassian.net/browse/MM-26425

```release-note
NONE
```

* fix tests and incorporate review comments

* Handle opaque URLs

* Fix path tests

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Agniva De Sarker
2020-11-10 13:06:59 +05:30
коммит произвёл GitHub
родитель 39b5b601f8
Коммит 0ca8cb36b4
6 изменённых файлов: 206 добавлений и 65 удалений

Просмотреть файл

@@ -29,6 +29,7 @@ type ImageProxy struct {
Logger *mlog.Logger
siteURL *url.URL
lock sync.RWMutex
backend ImageProxyBackend
}
@@ -50,6 +51,11 @@ func MakeImageProxy(configService configservice.ConfigService, httpService https
Logger: logger,
}
// We deliberately ignore the error because it's from config.json.
// The function returns a nil pointer in case of error, and we handle it when it's used.
siteURL, _ := url.Parse(*configService.Config().ServiceSettings.SiteURL)
proxy.siteURL = siteURL
proxy.configListenerId = proxy.ConfigService.AddConfigListener(proxy.OnConfigChange)
config := proxy.ConfigService.Config()
@@ -118,15 +124,32 @@ func (proxy *ImageProxy) GetImageDirect(imageURL string) (io.ReadCloser, string,
// GetProxiedImageURL takes the URL of an image and returns a URL that can be used to view that image through the
// image proxy.
func (proxy *ImageProxy) GetProxiedImageURL(imageURL string) string {
return getProxiedImageURL(imageURL, *proxy.ConfigService.Config().ServiceSettings.SiteURL)
}
func getProxiedImageURL(imageURL, siteURL string) string {
if imageURL == "" || imageURL[0] == '/' || strings.HasPrefix(imageURL, siteURL) {
if imageURL == "" || proxy.siteURL == nil {
return imageURL
}
// Parse url, return siteURL in case of failure.
// Also if the URL is opaque.
parsedURL, err := url.Parse(imageURL)
if err != nil || parsedURL.Opaque != "" {
return proxy.siteURL.String()
}
// If host is same as siteURL host, return.
if parsedURL.Host == proxy.siteURL.Host {
return parsedURL.String()
}
return siteURL + "/api/v4/image?url=" + url.QueryEscape(imageURL)
// Handle protocol-relative URLs.
if parsedURL.Scheme == "" {
parsedURL.Scheme = proxy.siteURL.Scheme
}
// If it's a relative URL, fill up the hostname and return.
if parsedURL.Host == "" {
parsedURL.Host = proxy.siteURL.Host
return parsedURL.String()
}
return proxy.siteURL.String() + "/api/v4/image?url=" + url.QueryEscape(parsedURL.String())
}
// GetUnproxiedImageURL takes the URL of an image on the image proxy and returns the original URL of the image.