summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/notification.go2
-rw-r--r--app/post.go132
-rw-r--r--app/post_test.go81
-rw-r--r--app/reaction.go2
4 files changed, 212 insertions, 5 deletions
diff --git a/app/notification.go b/app/notification.go
index 4929d56f4..62aad4c28 100644
--- a/app/notification.go
+++ b/app/notification.go
@@ -270,7 +270,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POSTED, "", post.ChannelId, "", nil)
- message.Add("post", post.ToJson())
+ message.Add("post", a.PostWithProxyAddedToImageURLs(post).ToJson())
message.Add("channel_type", channel.Type)
message.Add("channel_display_name", channelName)
message.Add("channel_name", channel.Name)
diff --git a/app/post.go b/app/post.go
index 192c2effb..bf4725e77 100644
--- a/app/post.go
+++ b/app/post.go
@@ -4,6 +4,11 @@
package app
import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/hex"
"encoding/json"
"fmt"
"net/http"
@@ -309,7 +314,7 @@ func (a *App) SendEphemeralPost(userId string, post *model.Post) *model.Post {
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_EPHEMERAL_MESSAGE, "", post.ChannelId, userId, nil)
- message.Add("post", post.ToJson())
+ message.Add("post", a.PostWithProxyAddedToImageURLs(post).ToJson())
a.Go(func() {
a.Publish(message)
@@ -419,7 +424,7 @@ func (a *App) PatchPost(postId string, patch *model.PostPatch) (*model.Post, *mo
func (a *App) sendUpdatedPostEvent(post *model.Post) {
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_EDITED, "", post.ChannelId, "", nil)
- message.Add("post", post.ToJson())
+ message.Add("post", a.PostWithProxyAddedToImageURLs(post).ToJson())
a.Go(func() {
a.Publish(message)
@@ -562,7 +567,7 @@ func (a *App) DeletePost(postId string) (*model.Post, *model.AppError) {
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_DELETED, "", post.ChannelId, "", nil)
- message.Add("post", post.ToJson())
+ message.Add("post", a.PostWithProxyAddedToImageURLs(post).ToJson())
a.Go(func() {
a.Publish(message)
@@ -823,3 +828,124 @@ func (a *App) DoPostAction(postId string, actionId string, userId string) *model
return nil
}
+
+func (a *App) PostListWithProxyAddedToImageURLs(list *model.PostList) *model.PostList {
+ if f := a.ImageProxyAdder(); f != nil {
+ return list.WithRewrittenImageURLs(f)
+ }
+ return list
+}
+
+func (a *App) PostWithProxyAddedToImageURLs(post *model.Post) *model.Post {
+ if f := a.ImageProxyAdder(); f != nil {
+ return post.WithRewrittenImageURLs(f)
+ }
+ return post
+}
+
+func (a *App) PostWithProxyRemovedFromImageURLs(post *model.Post) *model.Post {
+ if f := a.ImageProxyRemover(); f != nil {
+ return post.WithRewrittenImageURLs(f)
+ }
+ return post
+}
+
+func (a *App) PostPatchWithProxyRemovedFromImageURLs(patch *model.PostPatch) *model.PostPatch {
+ if f := a.ImageProxyRemover(); f != nil {
+ return patch.WithRewrittenImageURLs(f)
+ }
+ return patch
+}
+
+func (a *App) imageProxyConfig() (proxyType, proxyURL, options, siteURL string) {
+ cfg := a.Config()
+
+ if cfg.ServiceSettings.ImageProxyURL == nil || cfg.ServiceSettings.ImageProxyType == nil || cfg.ServiceSettings.SiteURL == nil {
+ return
+ }
+
+ proxyURL = *cfg.ServiceSettings.ImageProxyURL
+ proxyType = *cfg.ServiceSettings.ImageProxyType
+ siteURL = *cfg.ServiceSettings.SiteURL
+
+ if proxyURL == "" || proxyType == "" {
+ return "", "", "", ""
+ }
+
+ if proxyURL[len(proxyURL)-1] != '/' {
+ proxyURL += "/"
+ }
+
+ if cfg.ServiceSettings.ImageProxyOptions != nil {
+ options = *cfg.ServiceSettings.ImageProxyOptions
+ }
+
+ return
+}
+
+func (a *App) ImageProxyAdder() func(string) string {
+ proxyType, proxyURL, options, siteURL := a.imageProxyConfig()
+ if proxyType == "" {
+ return nil
+ }
+
+ return func(url string) string {
+ if strings.HasPrefix(url, proxyURL) {
+ return url
+ }
+
+ if url[0] == '/' {
+ url = siteURL + url
+ }
+
+ switch proxyType {
+ case "atmos/camo":
+ mac := hmac.New(sha1.New, []byte(options))
+ mac.Write([]byte(url))
+ digest := hex.EncodeToString(mac.Sum(nil))
+ return proxyURL + digest + "/" + hex.EncodeToString([]byte(url))
+ case "willnorris/imageproxy":
+ options := strings.Split(options, "|")
+ if len(options) > 1 {
+ mac := hmac.New(sha256.New, []byte(options[1]))
+ mac.Write([]byte(url))
+ digest := base64.URLEncoding.EncodeToString(mac.Sum(nil))
+ if options[0] == "" {
+ return proxyURL + "s" + digest + "/" + url
+ }
+ return proxyURL + options[0] + ",s" + digest + "/" + url
+ }
+ return proxyURL + options[0] + "/" + url
+ }
+
+ return url
+ }
+}
+
+func (a *App) ImageProxyRemover() (f func(string) string) {
+ proxyType, proxyURL, _, _ := a.imageProxyConfig()
+ if proxyType == "" {
+ return nil
+ }
+
+ return func(url string) string {
+ switch proxyType {
+ case "atmos/camo":
+ if strings.HasPrefix(url, proxyURL) {
+ if slash := strings.IndexByte(url[len(proxyURL):], '/'); slash >= 0 {
+ if decoded, err := hex.DecodeString(url[len(proxyURL)+slash+1:]); err == nil {
+ return string(decoded)
+ }
+ }
+ }
+ case "willnorris/imageproxy":
+ if strings.HasPrefix(url, proxyURL) {
+ if slash := strings.IndexByte(url[len(proxyURL):], '/'); slash >= 0 {
+ return url[len(proxyURL)+slash+1:]
+ }
+ }
+ }
+
+ return url
+ }
+}
diff --git a/app/post_test.go b/app/post_test.go
index 82eac3cd1..9854bb707 100644
--- a/app/post_test.go
+++ b/app/post_test.go
@@ -185,3 +185,84 @@ func TestPostChannelMentions(t *testing.T) {
},
}, result.Props["channel_mentions"])
}
+
+func TestImageProxy(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ for name, tc := range map[string]struct {
+ ProxyType string
+ ProxyURL string
+ ProxyOptions string
+ ImageURL string
+ ProxiedImageURL string
+ }{
+ "atmos/camo": {
+ ProxyType: "atmos/camo",
+ ProxyURL: "https://127.0.0.1",
+ ProxyOptions: "foo",
+ ImageURL: "http://mydomain.com/myimage",
+ ProxiedImageURL: "https://127.0.0.1/f8dace906d23689e8d5b12c3cefbedbf7b9b72f5/687474703a2f2f6d79646f6d61696e2e636f6d2f6d79696d616765",
+ },
+ "willnorris/imageproxy": {
+ ProxyType: "willnorris/imageproxy",
+ ProxyURL: "https://127.0.0.1",
+ ProxyOptions: "x1000",
+ ImageURL: "http://mydomain.com/myimage",
+ ProxiedImageURL: "https://127.0.0.1/x1000/http://mydomain.com/myimage",
+ },
+ "willnorris/imageproxy_WithSigning": {
+ ProxyType: "willnorris/imageproxy",
+ ProxyURL: "https://127.0.0.1",
+ ProxyOptions: "x1000|foo",
+ ImageURL: "http://mydomain.com/myimage",
+ ProxiedImageURL: "https://127.0.0.1/x1000,sbhHVoG5d60UvnNtGh6Iy6x4PaMmnsh8JfZ7JfErKjGU=/http://mydomain.com/myimage",
+ },
+ } {
+ t.Run(name, func(t *testing.T) {
+ th.App.UpdateConfig(func(cfg *model.Config) {
+ cfg.ServiceSettings.ImageProxyType = model.NewString(tc.ProxyType)
+ cfg.ServiceSettings.ImageProxyOptions = model.NewString(tc.ProxyOptions)
+ cfg.ServiceSettings.ImageProxyURL = model.NewString(tc.ProxyURL)
+ })
+
+ post := &model.Post{
+ Id: model.NewId(),
+ Message: "![foo](" + tc.ImageURL + ")",
+ }
+
+ list := model.NewPostList()
+ list.Posts[post.Id] = post
+
+ assert.Equal(t, "![foo]("+tc.ProxiedImageURL+")", th.App.PostListWithProxyAddedToImageURLs(list).Posts[post.Id].Message)
+ assert.Equal(t, "![foo]("+tc.ProxiedImageURL+")", th.App.PostWithProxyAddedToImageURLs(post).Message)
+
+ assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
+ post.Message = "![foo](" + tc.ProxiedImageURL + ")"
+ assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
+ })
+ }
+}
+
+var imageProxyBenchmarkSink *model.Post
+
+func BenchmarkPostWithProxyRemovedFromImageURLs(b *testing.B) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ th.App.UpdateConfig(func(cfg *model.Config) {
+ cfg.ServiceSettings.ImageProxyType = model.NewString("willnorris/imageproxy")
+ cfg.ServiceSettings.ImageProxyOptions = model.NewString("x1000|foo")
+ cfg.ServiceSettings.ImageProxyURL = model.NewString("https://127.0.0.1")
+ })
+
+ post := &model.Post{
+ Message: "![foo](http://mydomain.com/myimage)",
+ }
+
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ imageProxyBenchmarkSink = th.App.PostWithProxyAddedToImageURLs(post)
+ }
+}
diff --git a/app/reaction.go b/app/reaction.go
index bf0d20e2b..062622f34 100644
--- a/app/reaction.go
+++ b/app/reaction.go
@@ -62,6 +62,6 @@ func (a *App) sendReactionEvent(event string, reaction *model.Reaction, post *mo
post.HasReactions = true
post.UpdateAt = model.GetMillis()
umessage := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_EDITED, "", post.ChannelId, "", nil)
- umessage.Add("post", post.ToJson())
+ umessage.Add("post", a.PostWithProxyAddedToImageURLs(post).ToJson())
a.Publish(umessage)
}