From 4b808133414e39348f56d691883426947bf2d322 Mon Sep 17 00:00:00 2001 From: rune Date: Fri, 12 May 2023 17:44:37 +0800 Subject: [PATCH] Support SSH for go get (#24664) fix #12192 Support SSH for go get --------- Co-authored-by: Lunny Xiao Co-authored-by: Giteabot Co-authored-by: mfk Co-authored-by: silverwind --- custom/conf/app.example.ini | 3 ++ .../config-cheat-sheet.en-us.md | 2 ++ models/repo/repo.go | 32 +++++++++++-------- modules/context/repo.go | 9 +++++- modules/setting/repository.go | 2 ++ routers/web/goget.go | 9 +++++- tests/integration/goget_test.go | 26 +++++++++++++++ 7 files changed, 68 insertions(+), 15 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 3ceb53dcd0..e279b67ded 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -940,6 +940,9 @@ ROUTER = console ;; Force ssh:// clone url instead of scp-style uri when default SSH port is used ;USE_COMPAT_SSH_URI = false ;; +;; Value for the "go get" request returns the repository url as https or ssh, default is https +;GO_GET_CLONE_URL_PROTOCOL = https +;; ;; Close issues as long as a commit on any branch marks it as fixed ;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions. ;DISABLED_REPO_UNITS = diff --git a/docs/content/doc/administration/config-cheat-sheet.en-us.md b/docs/content/doc/administration/config-cheat-sheet.en-us.md index c1befed489..470e299a18 100644 --- a/docs/content/doc/administration/config-cheat-sheet.en-us.md +++ b/docs/content/doc/administration/config-cheat-sheet.en-us.md @@ -95,6 +95,8 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build HTTP protocol. - `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when default SSH port is used. +- `GO_GET_CLONE_URL_PROTOCOL`: **https**: Value for the "go get" request returns the repository url as https or ssh + default is https. - `ACCESS_CONTROL_ALLOW_ORIGIN`: **\**: Value for Access-Control-Allow-Origin header, default is not to present. **WARNING**: This maybe harmful to you website if you do not give it a right value. diff --git a/models/repo/repo.go b/models/repo/repo.go index 2e8c28cbb3..7cbd5867b7 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -547,16 +547,9 @@ func ComposeHTTPSCloneURL(owner, repo string) string { return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo)) } -func (repo *Repository) cloneLink(isWiki bool) *CloneLink { - repoName := repo.Name - if isWiki { - repoName += ".wiki" - } - +func ComposeSSHCloneURL(ownerName, repoName string) string { sshUser := setting.SSH.User - cl := new(CloneLink) - // if we have a ipv6 literal we need to put brackets around it // for the git cloning to work. sshDomain := setting.SSH.Domain @@ -566,12 +559,25 @@ func (repo *Repository) cloneLink(isWiki bool) *CloneLink { } if setting.SSH.Port != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) - } else if setting.Repository.UseCompatSSHURI { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) - } else { - cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) + return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, + net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), + url.PathEscape(ownerName), + url.PathEscape(repoName)) } + if setting.Repository.UseCompatSSHURI { + return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName)) + } + return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName)) +} + +func (repo *Repository) cloneLink(isWiki bool) *CloneLink { + repoName := repo.Name + if isWiki { + repoName += ".wiki" + } + + cl := new(CloneLink) + cl.SSH = ComposeSSHCloneURL(repo.OwnerName, repoName) cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName) return cl } diff --git a/modules/context/repo.go b/modules/context/repo.go index 84e07ab422..b20ea26e4e 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -319,7 +319,14 @@ func EarlyResponseForGoGetMeta(ctx *Context) { ctx.PlainText(http.StatusBadRequest, "invalid repository path") return } - goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), repo_model.ComposeHTTPSCloneURL(username, reponame)) + + var cloneURL string + if setting.Repository.GoGetCloneURLProtocol == "ssh" { + cloneURL = repo_model.ComposeSSHCloneURL(username, reponame) + } else { + cloneURL = repo_model.ComposeHTTPSCloneURL(username, reponame) + } + goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), cloneURL) htmlMeta := fmt.Sprintf(``, html.EscapeString(goImportContent)) ctx.PlainText(http.StatusOK, htmlMeta) } diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 56e7e6f4ac..153307a0b6 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -36,6 +36,7 @@ var ( DisableHTTPGit bool AccessControlAllowOrigin string UseCompatSSHURI bool + GoGetCloneURLProtocol string DefaultCloseIssuesViaCommitsInAnyBranch bool EnablePushCreateUser bool EnablePushCreateOrg bool @@ -273,6 +274,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("repository") Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool() Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool() + Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https") Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch) RepoRootPath = sec.Key("ROOT").MustString(path.Join(AppDataPath, "gitea-repositories")) diff --git a/routers/web/goget.go b/routers/web/goget.go index fb8afae999..c5b8b6cbc0 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -66,7 +66,14 @@ func goGet(ctx *context.Context) { } goGetImport := context.ComposeGoGetImport(ownerName, trimmedRepoName) - goImportContent := fmt.Sprintf("%s git %s", goGetImport, repo_model.ComposeHTTPSCloneURL(ownerName, repoName) /*CloneLink*/) + + var cloneURL string + if setting.Repository.GoGetCloneURLProtocol == "ssh" { + cloneURL = repo_model.ComposeSSHCloneURL(ownerName, repoName) + } else { + cloneURL = repo_model.ComposeHTTPSCloneURL(ownerName, repoName) + } + goImportContent := fmt.Sprintf("%s git %s", goGetImport, cloneURL /*CloneLink*/) goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/) goGetCli := fmt.Sprintf("go get %s%s", insecure, goGetImport) diff --git a/tests/integration/goget_test.go b/tests/integration/goget_test.go index fab3911464..854f8d7a2d 100644 --- a/tests/integration/goget_test.go +++ b/tests/integration/goget_test.go @@ -33,3 +33,29 @@ func TestGoGet(t *testing.T) { assert.Equal(t, expected, resp.Body.String()) } + +func TestGoGetForSSH(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + old := setting.Repository.GoGetCloneURLProtocol + defer func() { + setting.Repository.GoGetCloneURLProtocol = old + }() + setting.Repository.GoGetCloneURLProtocol = "ssh" + + req := NewRequest(t, "GET", "/blah/glah/plah?go-get=1") + resp := MakeRequest(t, req, http.StatusOK) + + expected := fmt.Sprintf(` + + + + + + + go get --insecure %[1]s:%[2]s/blah/glah + +`, setting.Domain, setting.HTTPPort, setting.AppURL, setting.SSH.Domain, setting.SSH.Port) + + assert.Equal(t, expected, resp.Body.String()) +}