Skip to content

Commit

Permalink
Add proxy settings and support for migration and webhook (#16704)
Browse files Browse the repository at this point in the history
* Add proxy settings and support for migration and webhook

* Fix default value

* Add newline for example ini

* Add lfs proxy support

* Fix lint

* Follow @zeripath's review

* Fix git clone

* Fix test

* missgin http requests for proxy

* use empty

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
  • Loading branch information
3 people authored Aug 18, 2021
1 parent 422c30d commit f9acad8
Show file tree
Hide file tree
Showing 20 changed files with 302 additions and 41 deletions.
8 changes: 8 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2127,3 +2127,11 @@ PATH =
;;
;; Minio enabled ssl only available when STORAGE_TYPE is `minio`
;MINIO_USE_SSL = false

;[proxy]
;; Enable the proxy, all requests to external via HTTP will be affected
;PROXY_ENABLED = false
;; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy/no_proxy
;PROXY_URL =
;; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
;PROXY_HOSTS =
18 changes: 16 additions & 2 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,8 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
- `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks.
- `SKIP_TLS_VERIFY`: **false**: Allow insecure certification.
- `PAGING_NUM`: **10**: Number of webhook history events that are shown in one page.
- `PROXY_URL`: ****: Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
- `PROXY_HOSTS`: ****: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
- `PROXY_URL`: **\<empty\>**: Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy. If not given, will use global proxy setting.
- `PROXY_HOSTS`: **\<empty\>`**: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts. If not given, will use global proxy setting.

## Mailer (`mailer`)

Expand Down Expand Up @@ -950,6 +950,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
- `ALLOWED_DOMAINS`: **\<empty\>**: Domains allowlist for migrating repositories, default is blank. It means everything will be allowed. Multiple domains could be separated by commas.
- `BLOCKED_DOMAINS`: **\<empty\>**: Domains blocklist for migrating repositories, default is blank. Multiple domains could be separated by commas. When `ALLOWED_DOMAINS` is not blank, this option will be ignored.
- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291
- `SKIP_TLS_VERIFY`: **false**: Allow skip tls verify

## Mirror (`mirror`)

Expand Down Expand Up @@ -1023,6 +1024,19 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`.
- `MINIO_BASE_PATH`: **repo-archive/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio`
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio`

## Proxy (`proxy`)

- `PROXY_ENABLED`: **false**: Enable the proxy if true, all requests to external via HTTP will be affected, if false, no proxy will be used even environment http_proxy/https_proxy
- `PROXY_URL`: **\<empty\>**: Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
- `PROXY_HOSTS`: **\<empty\>**: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.

i.e.
```ini
PROXY_ENABLED = true
PROXY_URL = socks://127.0.0.1:1080
PROXY_HOSTS = *.github.com
```

## Other (`other`)

- `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer.
Expand Down
14 changes: 14 additions & 0 deletions docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ IS_INPUT_FILE = false
- `ALLOWED_DOMAINS`: **\<empty\>**: 迁移仓库的域名白名单,默认为空,表示允许从任意域名迁移仓库,多个域名用逗号分隔。
- `BLOCKED_DOMAINS`: **\<empty\>**: 迁移仓库的域名黑名单,默认为空,多个域名用逗号分隔。如果 `ALLOWED_DOMAINS` 不为空,此选项将会被忽略。
- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918
- `SKIP_TLS_VERIFY`: **false**: 允许忽略 TLS 认证

## LFS (`lfs`)

Expand Down Expand Up @@ -397,6 +398,19 @@ Repository archive 的存储配置。 如果 `STORAGE_TYPE` 为空,则此配
- `MINIO_BASE_PATH`: **repo-archive/**: Minio base path ,仅当 `STORAGE_TYPE``minio` 时有效。
- `MINIO_USE_SSL`: **false**: Minio 是否启用 ssl ,仅当 `STORAGE_TYPE``minio` 时有效。

## Proxy (`proxy`)

- `PROXY_ENABLED`: **false**: 是否启用全局代理。如果为否,则不使用代理,环境变量中的代理也不使用
- `PROXY_URL`: **\<empty\>**: 代理服务器地址,支持 http://, https//, socks://,为空则不启用代理而使用环境变量中的 http_proxy/https_proxy
- `PROXY_HOSTS`: **\<empty\>**: 逗号分隔的多个需要代理的网址,支持 * 号匹配符号, ** 表示匹配所有网站

i.e.
```ini
PROXY_ENABLED = true
PROXY_URL = socks://127.0.0.1:1080
PROXY_HOSTS = *.github.com
```

## Other (`other`)

- `SHOW_FOOTER_BRANDING`: 为真则在页面底部显示Gitea的字样。
Expand Down
51 changes: 37 additions & 14 deletions modules/git/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,47 @@ func (c *Command) RunInDirTimeoutEnvFullPipeline(env []string, timeout time.Dura
// RunInDirTimeoutEnvFullPipelineFunc executes the command in given directory with given timeout,
// it pipes stdout and stderr to given io.Writer and passes in an io.Reader as stdin. Between cmd.Start and cmd.Wait the passed in function is run.
func (c *Command) RunInDirTimeoutEnvFullPipelineFunc(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader, fn func(context.Context, context.CancelFunc) error) error {
if timeout == -1 {
timeout = defaultCommandExecutionTimeout
return c.RunWithContext(&RunContext{
Env: env,
Timeout: timeout,
Dir: dir,
Stdout: stdout,
Stderr: stderr,
Stdin: stdin,
PipelineFunc: fn,
})
}

// RunContext represents parameters to run the command
type RunContext struct {
Env []string
Timeout time.Duration
Dir string
Stdout, Stderr io.Writer
Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
}

// RunWithContext run the command with context
func (c *Command) RunWithContext(rc *RunContext) error {
if rc.Timeout == -1 {
rc.Timeout = defaultCommandExecutionTimeout
}

if len(dir) == 0 {
if len(rc.Dir) == 0 {
log.Debug("%s", c)
} else {
log.Debug("%s: %v", dir, c)
log.Debug("%s: %v", rc.Dir, c)
}

ctx, cancel := context.WithTimeout(c.parentContext, timeout)
ctx, cancel := context.WithTimeout(c.parentContext, rc.Timeout)
defer cancel()

cmd := exec.CommandContext(ctx, c.name, c.args...)
if env == nil {
if rc.Env == nil {
cmd.Env = os.Environ()
} else {
cmd.Env = env
cmd.Env = rc.Env
}

cmd.Env = append(
Expand All @@ -141,23 +164,23 @@ func (c *Command) RunInDirTimeoutEnvFullPipelineFunc(env []string, timeout time.
if goVersionLessThan115 {
cmd.Env = append(cmd.Env, "GODEBUG=asyncpreemptoff=1")
}
cmd.Dir = dir
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.Stdin = stdin
cmd.Dir = rc.Dir
cmd.Stdout = rc.Stdout
cmd.Stderr = rc.Stderr
cmd.Stdin = rc.Stdin
if err := cmd.Start(); err != nil {
return err
}

desc := c.desc
if desc == "" {
desc = fmt.Sprintf("%s %s %s [repo_path: %s]", GitExecutable, c.name, strings.Join(c.args, " "), dir)
desc = fmt.Sprintf("%s %s %s [repo_path: %s]", GitExecutable, c.name, strings.Join(c.args, " "), rc.Dir)
}
pid := process.GetManager().Add(desc, cancel)
defer process.GetManager().Remove(pid)

if fn != nil {
err := fn(ctx, cancel)
if rc.PipelineFunc != nil {
err := rc.PipelineFunc(ctx, cancel)
if err != nil {
cancel()
_ = cmd.Wait()
Expand Down
28 changes: 24 additions & 4 deletions modules/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import (
"bytes"
"context"
"fmt"
"io"
"net/url"
"os"
"path"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/proxy"
)

// GPGSettings represents the default GPG settings for this repository
Expand Down Expand Up @@ -99,12 +103,12 @@ type CloneRepoOptions struct {
}

// Clone clones original repository to target path.
func Clone(from, to string, opts CloneRepoOptions) (err error) {
func Clone(from, to string, opts CloneRepoOptions) error {
return CloneWithContext(DefaultContext, from, to, opts)
}

// CloneWithContext clones original repository to target path.
func CloneWithContext(ctx context.Context, from, to string, opts CloneRepoOptions) (err error) {
func CloneWithContext(ctx context.Context, from, to string, opts CloneRepoOptions) error {
cargs := make([]string, len(GlobalCommandArgs))
copy(cargs, GlobalCommandArgs)
return CloneWithArgs(ctx, from, to, cargs, opts)
Expand Down Expand Up @@ -146,8 +150,24 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
opts.Timeout = -1
}

_, err = cmd.RunTimeout(opts.Timeout)
return err
var envs = os.Environ()
u, err := url.Parse(from)
if err == nil && (strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https")) {
if proxy.Match(u.Host) {
envs = append(envs, fmt.Sprintf("https_proxy=%s", proxy.GetProxyURL()))
}
}

var stderr = new(bytes.Buffer)
if err = cmd.RunWithContext(&RunContext{
Timeout: opts.Timeout,
Env: envs,
Stdout: io.Discard,
Stderr: stderr,
}); err != nil {
return ConcatenateError(err, stderr.String())
}
return nil
}

// PullRemoteOptions options when pull from remote
Expand Down
4 changes: 2 additions & 2 deletions modules/lfs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ type Client interface {
}

// NewClient creates a LFS client
func NewClient(endpoint *url.URL) Client {
func NewClient(endpoint *url.URL, skipTLSVerify bool) Client {
if endpoint.Scheme == "file" {
return newFilesystemClient(endpoint)
}
return newHTTPClient(endpoint)
return newHTTPClient(endpoint, skipTLSVerify)
}
4 changes: 2 additions & 2 deletions modules/lfs/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (

func TestNewClient(t *testing.T) {
u, _ := url.Parse("file:///test")
c := NewClient(u)
c := NewClient(u, true)
assert.IsType(t, &FilesystemClient{}, c)

u, _ = url.Parse("https://test.com/lfs")
c = NewClient(u)
c = NewClient(u, true)
assert.IsType(t, &HTTPClient{}, c)
}
11 changes: 9 additions & 2 deletions modules/lfs/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package lfs
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"net/http"
Expand All @@ -15,6 +16,7 @@ import (

"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/proxy"
)

const batchSize = 20
Expand All @@ -32,8 +34,13 @@ func (c *HTTPClient) BatchSize() int {
return batchSize
}

func newHTTPClient(endpoint *url.URL) *HTTPClient {
hc := &http.Client{}
func newHTTPClient(endpoint *url.URL, skipTLSVerify bool) *HTTPClient {
hc := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: skipTLSVerify},
Proxy: proxy.Proxy(),
},
}

client := &HTTPClient{
client: hc,
Expand Down
22 changes: 21 additions & 1 deletion modules/migrations/gitea_downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package migrations

import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
Expand All @@ -17,6 +18,8 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"

gitea_sdk "code.gitea.io/sdk/gitea"
Expand Down Expand Up @@ -87,6 +90,12 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo
gitea_sdk.SetToken(token),
gitea_sdk.SetBasicAuth(username, password),
gitea_sdk.SetContext(ctx),
gitea_sdk.SetHTTPClient(&http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify},
Proxy: proxy.Proxy(),
},
}),
)
if err != nil {
log.Error(fmt.Sprintf("Failed to create NewGiteaDownloader for: %s. Error: %v", baseURL, err))
Expand Down Expand Up @@ -266,6 +275,13 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele
Created: rel.CreatedAt,
}

httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify},
Proxy: proxy.Proxy(),
},
}

for _, asset := range rel.Attachments {
size := int(asset.Size)
dlCount := int(asset.DownloadCount)
Expand All @@ -282,7 +298,11 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele
return nil, err
}
// FIXME: for a private download?
resp, err := http.Get(asset.DownloadURL)
req, err := http.NewRequest("GET", asset.DownloadURL, nil)
if err != nil {
return nil, err
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
Expand Down
14 changes: 12 additions & 2 deletions modules/migrations/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package migrations

import (
"context"
"crypto/tls"
"fmt"
"io"
"net/http"
Expand All @@ -17,6 +18,8 @@ import (

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"

Expand Down Expand Up @@ -90,7 +93,7 @@ func NewGithubDownloaderV3(ctx context.Context, baseURL, userName, password, tok
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(userName, password)
return nil, nil
return proxy.Proxy()(req)
},
},
}
Expand Down Expand Up @@ -269,6 +272,13 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease)
r.Published = rel.PublishedAt.Time
}

httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify},
Proxy: proxy.Proxy(),
},
}

for _, asset := range rel.Assets {
var assetID = *asset.ID // Don't optimize this, for closure we need a local variable
r.Assets = append(r.Assets, &base.ReleaseAsset{
Expand All @@ -295,7 +305,7 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
resp, err := httpClient.Do(req)
err1 := g.RefreshRate()
if err1 != nil {
log.Error("g.client.RateLimits: %s", err1)
Expand Down
Loading

0 comments on commit f9acad8

Please sign in to comment.