diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 63eca484a51d4..60d109666738c 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -26,6 +26,7 @@ import ( "time" "code.gitea.io/gitea/models" + teagit "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" @@ -80,7 +81,7 @@ func runPR() { setting.RunUser = curUser.Username log.Printf("[PR] Loading fixtures data ...\n") - setting.CheckLFSVersion() + teagit.CheckLFSVersion() //models.LoadConfigs() /* setting.Database.Type = "sqlite3" diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 35f1bfaeabf2a..3359175c5fff6 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1302,3 +1302,11 @@ STORAGE_TYPE = local ;MINIO_LOCATION = us-east-1 ; 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 +PROXY_URL = +; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts. +PROXY_HOSTS = \ No newline at end of file diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 088b56fedd312..15fbb4ceee86d 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -523,8 +523,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`: ****: 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`: ****: 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`) @@ -902,6 +902,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ALLOWED_DOMAINS`: **\**: Domains allowlist for migrating repositories, default is blank. It means everything will be allowed. Multiple domains could be separated by commas. - `BLOCKED_DOMAINS`: **\**: 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`) @@ -958,6 +959,19 @@ MINIO_USE_SSL = false And used by `[attachment]`, `[lfs]` and etc. as `STORAGE_TYPE`. +## Proxy (`proxy`) + +- `PROXY_ENABLED`: **true**: 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`: ****: 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. + +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. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 1f7ae10c5daa4..2e77d3b249e97 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -326,7 +326,8 @@ IS_INPUT_FILE = false - `RETRY_BACKOFF`: **3**: 等待下一次重试的时间,单位秒。 - `ALLOWED_DOMAINS`: **\**: 迁移仓库的域名白名单,默认为空,表示允许从任意域名迁移仓库,多个域名用逗号分隔。 - `BLOCKED_DOMAINS`: **\**: 迁移仓库的域名黑名单,默认为空,多个域名用逗号分隔。如果 `ALLOWED_DOMAINS` 不为空,此选项将会被忽略。 -- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918 +- `ALLOW_LOCALNETWORKS`: **false**: 允许访问私有地址,定义在 RFC 1918 +- `SKIP_TLS_VERIFY`: **false**: 允许忽略 TLS 认证 ## LFS (`lfs`) @@ -377,6 +378,19 @@ MINIO_USE_SSL = false 然后你在 `[attachment]`, `[lfs]` 等中可以把这个名字用作 `STORAGE_TYPE` 的值。 +## Proxy (`proxy`) + +- `PROXY_ENABLED`: **true**: 是否启用全局代理。如果为否,则不使用代理,环境变量中的代理也不使用 +- `PROXY_URL`: ****: 代理服务器地址,支持 http://, https//, socks://,为空则不启用代理而使用环境变量中的 http_proxy/https_proxy +- `PROXY_HOSTS`: ****: 逗号分隔的多个需要代理的网址,支持 * 号匹配符号, ** 表示匹配所有网站 + +i.e. +```ini +PROXY_ENABLED = true +PROXY_URL = socks://127.0.0.1:1080 +PROXY_HOSTS = *.github.com +``` + ## Other (`other`) - `SHOW_FOOTER_BRANDING`: 为真则在页面底部显示Gitea的字样。 diff --git a/integrations/git_test.go b/integrations/git_test.go index 13a60076a7e9e..a9848eaa4c309 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -143,7 +143,7 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { t.Run("LFS", func(t *testing.T) { defer PrintCurrentTest(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -213,7 +213,7 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - setting.CheckLFSVersion() + git.CheckLFSVersion() if setting.LFS.StartServer { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -255,7 +255,7 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - setting.CheckLFSVersion() + git.CheckLFSVersion() if setting.LFS.StartServer { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 74227416c4be5..34b63f8612bdd 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/queue" @@ -163,7 +164,7 @@ func initIntegrationTest() { setting.SetCustomPathAndConf("", "", "") setting.NewContext() util.RemoveAll(models.LocalCopyPath()) - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() if err := storage.Init(); err != nil { fmt.Printf("Init storage failed: %v", err) diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 789c7572a77e5..6bfa805be3dc4 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -13,6 +13,7 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/routes" @@ -90,7 +91,7 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt func TestGetLFSSmall(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -103,7 +104,7 @@ func TestGetLFSSmall(t *testing.T) { func TestGetLFSLarge(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -119,7 +120,7 @@ func TestGetLFSLarge(t *testing.T) { func TestGetLFSGzip(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -140,7 +141,7 @@ func TestGetLFSGzip(t *testing.T) { func TestGetLFSZip(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -163,7 +164,7 @@ func TestGetLFSZip(t *testing.T) { func TestGetLFSRangeNo(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -176,7 +177,7 @@ func TestGetLFSRangeNo(t *testing.T) { func TestGetLFSRange(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 852c0b737c2da..209ff5a058f43 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -61,7 +62,7 @@ func initMigrationTest(t *testing.T) func() { assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() setting.NewLogServices(true) return deferFn diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index 641d972b8b377..26066580d8978 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -55,7 +56,7 @@ func TestMain(m *testing.M) { setting.SetCustomPathAndConf("", "", "") setting.NewContext() - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() setting.NewLogServices(true) diff --git a/modules/git/command.go b/modules/git/command.go index fe258954628e0..848dd674a8cde 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -109,24 +109,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, + CancelFunc: 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 + CancelFunc 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(c.String()) } else { - log("%s: %v", dir, c) + log("%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 = append(os.Environ(), fmt.Sprintf("LC_ALL=%s", DefaultLocale)) } else { - cmd.Env = env + cmd.Env = rc.Env cmd.Env = append(cmd.Env, fmt.Sprintf("LC_ALL=%s", DefaultLocale)) } @@ -134,23 +157,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.CancelFunc != nil { + err := rc.CancelFunc(ctx, cancel) if err != nil { cancel() _ = cmd.Wait() diff --git a/modules/git/git.go b/modules/git/git.go index 6b15138a5c748..c056c0ed4487f 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -14,6 +14,7 @@ import ( "time" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" "github.com/hashicorp/go-version" ) @@ -122,10 +123,45 @@ func SetExecutablePath(path string) error { return nil } +// VersionInfo returns git version information +func VersionInfo() string { + var format = "Git Version: %s" + var args = []interface{}{gitVersion.Original()} + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + format += ", Wire Protocol %s Enabled" + args = append(args, "Version 2") // for focus color + } + + return fmt.Sprintf(format, args...) +} + // Init initializes git module func Init(ctx context.Context) error { DefaultContext = ctx + DefaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second + + if err := SetExecutablePath(setting.Git.Path); err != nil { + return err + } + + // force cleanup args + GlobalCommandArgs = []string{} + + if CheckGitVersionAtLeast("2.9") == nil { + // Explicitly disable credential helper, otherwise Git credentials might leak + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "credential.helper=") + } + + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "protocol.version=2") + } + + CommitsRangeSize = setting.Git.CommitsRangeSize + BranchesRangeSize = setting.Git.BranchesRangeSize + // Save current git version on init to gitVersion otherwise it would require an RWMutex if err := LoadGitVersion(); err != nil { return err diff --git a/modules/git/lfs.go b/modules/git/lfs.go new file mode 100644 index 0000000000000..79049c98245ad --- /dev/null +++ b/modules/git/lfs.go @@ -0,0 +1,37 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "sync" + + logger "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +var once sync.Once + +// CheckLFSVersion will check lfs version, if not satisfied, then disable it. +func CheckLFSVersion() { + if setting.LFS.StartServer { + //Disable LFS client hooks if installed for the current OS user + //Needs at least git v2.1.2 + + err := LoadGitVersion() + if err != nil { + logger.Fatal("Error retrieving git version: %v", err) + } + + if CheckGitVersionAtLeast("2.1.2") != nil { + setting.LFS.StartServer = false + logger.Error("LFS server support needs at least Git v2.1.2") + } else { + once.Do(func() { + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "filter.lfs.required=", + "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") + }) + } + } +} diff --git a/modules/git/repo.go b/modules/git/repo.go index 515899ab04984..80be108ca7249 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -10,11 +10,14 @@ import ( "container/list" "context" "fmt" + "net/url" "os" "path" "strconv" "strings" "time" + + "code.gitea.io/gitea/modules/proxy" ) // GPGSettings represents the default GPG settings for this repository @@ -147,8 +150,22 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo opts.Timeout = -1 } - _, err = cmd.RunTimeout(opts.Timeout) - return err + var envs []string + u, err := url.Parse(from) + if err == nil && (strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https")) { + if proxy.Match(u.Host) { + envs = []string{fmt.Sprintf("https_proxy=%s", proxy.GetProxy())} + } + } + + var stderr = new(bytes.Buffer) + err = cmd.RunWithContext(&RunContext{ + Timeout: opts.Timeout, + Env: envs, + Stdout: new(bytes.Buffer), + Stderr: stderr, + }) + return ConcatenateError(err, stderr.String()) } // PullRemoteOptions options when pull from remote diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 40820ae3759ce..27d5dff9e7c9c 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -6,6 +6,7 @@ package migrations import ( "context" + "crypto/tls" "errors" "fmt" "io" @@ -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" @@ -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.SystemProxy(), + }, + }), ) if err != nil { log.Error(fmt.Sprintf("Failed to create NewGiteaDownloader for: %s. Error: %v", baseURL, err)) diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 282e3b4786151..720dc7253592d 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -16,6 +16,7 @@ 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/structs" "code.gitea.io/gitea/modules/util" @@ -89,7 +90,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.SystemProxy()(req) }, }, } diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index a697075ff892b..5e46bfc90ec8d 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -6,6 +6,7 @@ package migrations import ( "context" + "crypto/tls" "errors" "fmt" "io" @@ -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" "github.com/xanzy/go-gitlab" @@ -77,7 +80,12 @@ type GitlabDownloader struct { // Use either a username/password, personal token entered into the username field, or anonymous/public access // Note: Public access only allows very basic access func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GitlabDownloader, error) { - gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL)) + gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL), gitlab.WithHTTPClient(&http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify}, + Proxy: proxy.SystemProxy(), + }, + })) // Only use basic auth if token is blank and password is NOT // Basic auth will fail with empty strings, but empty token will allow anonymous public API usage if token == "" && password != "" { diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index b616907938ff4..2a9edcaf2d404 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -6,6 +6,7 @@ package migrations import ( "context" + "crypto/tls" "fmt" "net/http" "net/url" @@ -14,6 +15,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" "github.com/gogs/go-gogs-client" @@ -95,9 +98,10 @@ func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, downloader.userName = token } else { downloader.transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify}, Proxy: func(req *http.Request) (*url.URL, error) { req.SetBasicAuth(userName, password) - return nil, nil + return proxy.SystemProxy()(req) }, } diff --git a/modules/proxy/proxy.go b/modules/proxy/proxy.go new file mode 100644 index 0000000000000..126f68aba8ea9 --- /dev/null +++ b/modules/proxy/proxy.go @@ -0,0 +1,83 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "net/http" + "net/url" + "os" + "sync" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/gobwas/glob" +) + +var ( + once sync.Once + hostMatchers []glob.Glob +) + +// GetProxy returns proxy +func GetProxy() string { + if !setting.Proxy.Enabled { + return "" + } + + if setting.Proxy.ProxyURL == "" { + if os.Getenv("http_proxy") != "" { + return os.Getenv("http_proxy") + } + return os.Getenv("https_proxy") + } + return setting.Proxy.ProxyURL +} + +// Match return true if url needs to be proxied +func Match(u string) bool { + if !setting.Proxy.Enabled { + return false + } + + // enforce do once + SystemProxy() + + for _, v := range hostMatchers { + if v.Match(u) { + return true + } + } + return false +} + +// SystemProxy returns the system proxy +func SystemProxy() func(req *http.Request) (*url.URL, error) { + if !setting.Proxy.Enabled { + return nil + } + if setting.Proxy.ProxyURL == "" { + return http.ProxyFromEnvironment + } + + once.Do(func() { + for _, h := range setting.Proxy.ProxyHosts { + if g, err := glob.Compile(h); err == nil { + hostMatchers = append(hostMatchers, g) + } else { + log.Error("glob.Compile %s failed: %v", h, err) + } + } + }) + + return func(req *http.Request) (*url.URL, error) { + for _, v := range hostMatchers { + if v.Match(req.URL.Host) { + return http.ProxyURL(setting.Proxy.ProxyURLFixed)(req) + } + } + return http.ProxyFromEnvironment(req) + } +} diff --git a/modules/setting/git.go b/modules/setting/git.go index 308d94894ba72..36ac1e0a3ae9b 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -7,7 +7,6 @@ package setting import ( "time" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" ) @@ -54,7 +53,7 @@ var ( Pull int GC int `ini:"GC"` }{ - Default: int(git.DefaultCommandExecutionTimeout / time.Second), + Default: 360, Migrate: 600, Mirror: 300, Clone: 300, @@ -68,35 +67,4 @@ func newGit() { if err := Cfg.Section("git").MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) } - if err := git.SetExecutablePath(Git.Path); err != nil { - log.Fatal("Failed to initialize Git settings: %v", err) - } - git.DefaultCommandExecutionTimeout = time.Duration(Git.Timeout.Default) * time.Second - - version, err := git.LocalVersion() - if err != nil { - log.Fatal("Error retrieving git version: %v", err) - } - - // force cleanup args - git.GlobalCommandArgs = []string{} - - if git.CheckGitVersionAtLeast("2.9") == nil { - // Explicitly disable credential helper, otherwise Git credentials might leak - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") - } - - var format = "Git Version: %s" - var args = []interface{}{version.Original()} - // Since git wire protocol has been released from git v2.18 - if Git.EnableAutoGitWireProtocol && git.CheckGitVersionAtLeast("2.18") == nil { - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "protocol.version=2") - format += ", Wire Protocol %s Enabled" - args = append(args, "Version 2") // for focus color - } - - git.CommitsRangeSize = Git.CommitsRangeSize - git.BranchesRangeSize = Git.BranchesRangeSize - - log.Info(format, args...) } diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index ab475bbeb4b31..eaa8e71b71de8 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -11,7 +11,6 @@ import ( "time" "code.gitea.io/gitea/modules/generate" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" @@ -88,24 +87,3 @@ func newLFSService() { } } } - -// CheckLFSVersion will check lfs version, if not satisfied, then disable it. -func CheckLFSVersion() { - if LFS.StartServer { - //Disable LFS client hooks if installed for the current OS user - //Needs at least git v2.1.2 - - err := git.LoadGitVersion() - if err != nil { - log.Fatal("Error retrieving git version: %v", err) - } - - if git.CheckGitVersionAtLeast("2.1.2") != nil { - LFS.StartServer = false - log.Error("LFS server support needs at least Git v2.1.2") - } else { - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=", - "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") - } - } -} diff --git a/modules/setting/migrations.go b/modules/setting/migrations.go index 7808df5280756..b663b52f896f3 100644 --- a/modules/setting/migrations.go +++ b/modules/setting/migrations.go @@ -16,6 +16,7 @@ var ( AllowedDomains []string BlockedDomains []string AllowLocalNetworks bool + SkipTLSVerify bool }{ MaxAttempts: 3, RetryBackoff: 3, @@ -37,4 +38,5 @@ func newMigrationsService() { } Migrations.AllowLocalNetworks = sec.Key("ALLOW_LOCALNETWORKS").MustBool(false) + Migrations.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool(false) } diff --git a/modules/setting/proxy.go b/modules/setting/proxy.go new file mode 100644 index 0000000000000..6fe4d87f422ad --- /dev/null +++ b/modules/setting/proxy.go @@ -0,0 +1,40 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import ( + "net/url" + + "code.gitea.io/gitea/modules/log" +) + +var ( + // Proxy settings + Proxy = struct { + Enabled bool + ProxyURL string + ProxyURLFixed *url.URL + ProxyHosts []string + }{ + Enabled: false, + ProxyURL: "", + ProxyHosts: []string{}, + } +) + +func newProxyService() { + sec := Cfg.Section("proxy") + Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false) + Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("") + if Proxy.ProxyURL != "" { + var err error + Proxy.ProxyURLFixed, err = url.Parse(Proxy.ProxyURL) + if err != nil { + log.Error("Global PROXY_URL is not valid") + Proxy.ProxyURL = "" + } + } + Proxy.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",") +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7963776fd0644..e0756c3dd9939 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1171,6 +1171,7 @@ func NewServices() { newMailService() newRegisterMailService() newNotifyMailService() + newProxyService() newWebhookService() newMigrationsService() newIndexerService() diff --git a/routers/init.go b/routers/init.go index f5dbfc87d2721..ddabeb13b7f1f 100644 --- a/routers/init.go +++ b/routers/init.go @@ -130,7 +130,9 @@ func GlobalInit(ctx context.Context) { if err := git.Init(ctx); err != nil { log.Fatal("Git module init failed: %v", err) } - setting.CheckLFSVersion() + log.Info(git.VersionInfo()) + + git.CheckLFSVersion() log.Trace("AppPath: %s", setting.AppPath) log.Trace("AppWorkPath: %s", setting.AppWorkPath) log.Trace("Custom path: %s", setting.CustomPath) diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go index 8ac7d8c192467..c6f7ac55e252e 100644 --- a/services/webhook/deliver.go +++ b/services/webhook/deliver.go @@ -20,7 +20,9 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/setting" + "github.com/gobwas/glob" ) @@ -239,7 +241,7 @@ var ( func webhookProxy() func(req *http.Request) (*url.URL, error) { if setting.Webhook.ProxyURL == "" { - return http.ProxyFromEnvironment + return proxy.SystemProxy() } once.Do(func() { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 5aeed4a30f493..01ef92bb24502 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -17158,4 +17158,4 @@ "TOTPHeader": [] } ] -} +} \ No newline at end of file