Skip to content

Commit 97625b4

Browse files
zeripath6543wxiaoguang
authored
Provide configuration to allow camo-media proxying (#12802)
* Provide configuration to allow camo-media proxying Fix #916 Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: 6543 <[email protected]> Co-authored-by: wxiaoguang <[email protected]>
1 parent 76aa33d commit 97625b4

File tree

6 files changed

+133
-1
lines changed

6 files changed

+133
-1
lines changed

custom/conf/app.example.ini

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,23 @@ INTERNAL_TOKEN=
424424
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
425425
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
426426

427+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
428+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
429+
[camo]
430+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
431+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
432+
;;
433+
;; At the moment we only support images
434+
;;
435+
;; if the camo is enabled
436+
;ENABLED = false
437+
;; url to a camo image proxy, it **is required** if camo is enabled.
438+
;SERVER_URL =
439+
;; HMAC to encode urls with, it **is required** if camo is enabled.
440+
;HMAC_KEY =
441+
;; Set to true to use camo for https too lese only non https urls are proxyed
442+
;ALLWAYS = false
443+
427444
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
428445
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
429446
[oauth2]

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,14 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
513513
- spec - use one or more special characters as ``!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~``
514514
- off - do not check password complexity
515515
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
516-
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
516+
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
517+
518+
## Camo (`camo`)
519+
520+
- `ENABLED`: **false**: Enable media proxy, we support images only at the moment.
521+
- `SERVER_URL`: **<empty>**: url of camo server, it **is required** if camo is enabled.
522+
- `HMAC_KEY`: **<empty>**: Provide the HMAC key for encoding urls, it **is required** if camo is enabled.
523+
- `ALLWAYS`: **false**: Set to true to use camo for https too lese only non https urls are proxyed
517524

518525
## OpenID (`openid`)
519526

modules/markup/camo.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package markup
6+
7+
import (
8+
"crypto/hmac"
9+
"crypto/sha1"
10+
"encoding/base64"
11+
"net/url"
12+
"strings"
13+
14+
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/modules/util"
16+
)
17+
18+
// CamoEncode encodes a lnk to fit with the go-camo and camo proxy links. The purposes of camo-proxy are:
19+
// 1. Allow accessing "http://" images on a HTTPS site by using the "https://" URLs provided by camo-proxy.
20+
// 2. Hide the visitor's real IP (protect privacy) when accessing external images.
21+
func CamoEncode(link string) string {
22+
if strings.HasPrefix(link, setting.Camo.ServerURL) {
23+
return link
24+
}
25+
26+
mac := hmac.New(sha1.New, []byte(setting.Camo.HMACKey))
27+
_, _ = mac.Write([]byte(link)) // hmac does not return errors
28+
macSum := b64encode(mac.Sum(nil))
29+
encodedURL := b64encode([]byte(link))
30+
31+
return util.URLJoin(setting.Camo.ServerURL, macSum, encodedURL)
32+
}
33+
34+
func b64encode(data []byte) string {
35+
return strings.TrimRight(base64.URLEncoding.EncodeToString(data), "=")
36+
}
37+
38+
func camoHandleLink(link string) string {
39+
if setting.Camo.Enabled {
40+
lnkURL, err := url.Parse(link)
41+
if err == nil && lnkURL.IsAbs() && !strings.HasPrefix(link, setting.AppURL) &&
42+
(setting.Camo.Allways || lnkURL.Scheme != "https") {
43+
return CamoEncode(link)
44+
}
45+
}
46+
return link
47+
}

modules/markup/camo_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package markup
6+
7+
import (
8+
"testing"
9+
10+
"code.gitea.io/gitea/modules/setting"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestCamoHandleLink(t *testing.T) {
16+
setting.AppURL = "https://gitea.com"
17+
// Test media proxy
18+
setting.Camo.Enabled = true
19+
setting.Camo.ServerURL = "https://image.proxy"
20+
setting.Camo.HMACKey = "geheim"
21+
22+
assert.Equal(t,
23+
"https://gitea.com/img.jpg",
24+
camoHandleLink("https://gitea.com/img.jpg"))
25+
assert.Equal(t,
26+
"https://testimages.org/img.jpg",
27+
camoHandleLink("https://testimages.org/img.jpg"))
28+
assert.Equal(t,
29+
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
30+
camoHandleLink("http://testimages.org/img.jpg"))
31+
32+
setting.Camo.Allways = true
33+
assert.Equal(t,
34+
"https://gitea.com/img.jpg",
35+
camoHandleLink("https://gitea.com/img.jpg"))
36+
assert.Equal(t,
37+
"https://image.proxy/tkdlvmqpbIr7SjONfHNgEU622y0/aHR0cHM6Ly90ZXN0aW1hZ2VzLm9yZy9pbWcuanBn",
38+
camoHandleLink("https://testimages.org/img.jpg"))
39+
assert.Equal(t,
40+
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
41+
camoHandleLink("http://testimages.org/img.jpg"))
42+
43+
// Restore previous settings
44+
setting.Camo.Enabled = false
45+
}

modules/markup/html.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ func visitNode(ctx *RenderContext, procs, textProcs []processor, node *html.Node
386386

387387
attr.Val = util.URLJoin(prefix, attr.Val)
388388
}
389+
attr.Val = camoHandleLink(attr.Val)
389390
node.Attr[i] = attr
390391
}
391392
} else if node.Data == "a" {

modules/setting/setting.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ var (
197197
PasswordCheckPwn bool
198198
SuccessfulTokensCacheSize int
199199

200+
Camo = struct {
201+
Enabled bool
202+
ServerURL string `ini:"SERVER_URL"`
203+
HMACKey string `ini:"HMAC_KEY"`
204+
Allways bool
205+
}{}
206+
200207
// UI settings
201208
UI = struct {
202209
ExplorePagingNum int
@@ -1019,6 +1026,14 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
10191026
log.Fatal("Failed to map API settings: %v", err)
10201027
} else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil {
10211028
log.Fatal("Failed to map Metrics settings: %v", err)
1029+
} else if err = Cfg.Section("camo").MapTo(&Camo); err != nil {
1030+
log.Fatal("Failed to map Camo settings: %v", err)
1031+
}
1032+
1033+
if Camo.Enabled {
1034+
if Camo.ServerURL == "" || Camo.HMACKey == "" {
1035+
log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`)
1036+
}
10221037
}
10231038

10241039
u := *appURL

0 commit comments

Comments
 (0)