Support SSH for go get (#24664)

fix #12192 Support SSH for go get

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: mfk <mfk@hengwei.com.cn>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
rune 2023-05-12 17:44:37 +08:00 committed by GitHub
parent 49808136c5
commit 4b80813341
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 15 deletions

View File

@ -940,6 +940,9 @@ ROUTER = console
;; Force ssh:// clone url instead of scp-style uri when default SSH port is used ;; Force ssh:// clone url instead of scp-style uri when default SSH port is used
;USE_COMPAT_SSH_URI = false ;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 ;; 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. ;; 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 = ;DISABLED_REPO_UNITS =

View File

@ -95,6 +95,8 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
HTTP protocol. HTTP protocol.
- `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when - `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when
default SSH port is used. 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`: **\<empty\>**: Value for Access-Control-Allow-Origin header, - `ACCESS_CONTROL_ALLOW_ORIGIN`: **\<empty\>**: Value for Access-Control-Allow-Origin header,
default is not to present. **WARNING**: This maybe harmful to you website if you do not default is not to present. **WARNING**: This maybe harmful to you website if you do not
give it a right value. give it a right value.

View File

@ -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)) return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo))
} }
func (repo *Repository) cloneLink(isWiki bool) *CloneLink { func ComposeSSHCloneURL(ownerName, repoName string) string {
repoName := repo.Name
if isWiki {
repoName += ".wiki"
}
sshUser := setting.SSH.User sshUser := setting.SSH.User
cl := new(CloneLink)
// if we have a ipv6 literal we need to put brackets around it // if we have a ipv6 literal we need to put brackets around it
// for the git cloning to work. // for the git cloning to work.
sshDomain := setting.SSH.Domain sshDomain := setting.SSH.Domain
@ -566,12 +559,25 @@ func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
} }
if setting.SSH.Port != 22 { 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)) return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser,
} else if setting.Repository.UseCompatSSHURI { net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)),
cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) url.PathEscape(ownerName),
} else { url.PathEscape(repoName))
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.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) cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName)
return cl return cl
} }

View File

@ -319,7 +319,14 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
ctx.PlainText(http.StatusBadRequest, "invalid repository path") ctx.PlainText(http.StatusBadRequest, "invalid repository path")
return 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(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent)) htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
ctx.PlainText(http.StatusOK, htmlMeta) ctx.PlainText(http.StatusOK, htmlMeta)
} }

View File

@ -36,6 +36,7 @@ var (
DisableHTTPGit bool DisableHTTPGit bool
AccessControlAllowOrigin string AccessControlAllowOrigin string
UseCompatSSHURI bool UseCompatSSHURI bool
GoGetCloneURLProtocol string
DefaultCloseIssuesViaCommitsInAnyBranch bool DefaultCloseIssuesViaCommitsInAnyBranch bool
EnablePushCreateUser bool EnablePushCreateUser bool
EnablePushCreateOrg bool EnablePushCreateOrg bool
@ -273,6 +274,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("repository") sec := rootCfg.Section("repository")
Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool() Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").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.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch) Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
RepoRootPath = sec.Key("ROOT").MustString(path.Join(AppDataPath, "gitea-repositories")) RepoRootPath = sec.Key("ROOT").MustString(path.Join(AppDataPath, "gitea-repositories"))

View File

@ -66,7 +66,14 @@ func goGet(ctx *context.Context) {
} }
goGetImport := context.ComposeGoGetImport(ownerName, trimmedRepoName) 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*/) 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) goGetCli := fmt.Sprintf("go get %s%s", insecure, goGetImport)

View File

@ -33,3 +33,29 @@ func TestGoGet(t *testing.T) {
assert.Equal(t, expected, resp.Body.String()) 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(`<!doctype html>
<html>
<head>
<meta name="go-import" content="%[1]s:%[2]s/blah/glah git ssh://git@%[4]s:%[5]d/blah/glah.git">
<meta name="go-source" content="%[1]s:%[2]s/blah/glah _ %[3]sblah/glah/src/branch/master{/dir} %[3]sblah/glah/src/branch/master{/dir}/{file}#L{line}">
</head>
<body>
go get --insecure %[1]s:%[2]s/blah/glah
</body>
</html>`, setting.Domain, setting.HTTPPort, setting.AppURL, setting.SSH.Domain, setting.SSH.Port)
assert.Equal(t, expected, resp.Body.String())
}