@@ -20,6 +20,7 @@ import (
20
20
user_model "code.gitea.io/gitea/models/user"
21
21
"code.gitea.io/gitea/modules/base"
22
22
"code.gitea.io/gitea/modules/git"
23
+ gitUrl "code.gitea.io/gitea/modules/git/url"
23
24
"code.gitea.io/gitea/modules/httplib"
24
25
"code.gitea.io/gitea/modules/log"
25
26
"code.gitea.io/gitea/modules/markup"
@@ -635,14 +636,26 @@ type CloneLink struct {
635
636
}
636
637
637
638
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
638
- func ComposeHTTPSCloneURL (owner , repo string ) string {
639
- return fmt .Sprintf ("%s%s/%s.git" , setting . AppURL , url .PathEscape (owner ), url .PathEscape (repo ))
639
+ func ComposeHTTPSCloneURL (ctx context. Context , owner , repo string ) string {
640
+ return fmt .Sprintf ("%s%s/%s.git" , httplib . GuessCurrentAppURL ( ctx ) , url .PathEscape (owner ), url .PathEscape (repo ))
640
641
}
641
642
642
- func ComposeSSHCloneURL (ownerName , repoName string ) string {
643
+ func ComposeSSHCloneURL (doer * user_model. User , ownerName , repoName string ) string {
643
644
sshUser := setting .SSH .User
644
645
sshDomain := setting .SSH .Domain
645
646
647
+ if sshUser == "(DOER_USERNAME)" {
648
+ // Some users use SSH reverse-proxy and need to use the current signed-in username as the SSH user
649
+ // to make the SSH reverse-proxy could prepare the user's public keys ahead.
650
+ // For most cases we have the correct "doer", then use it as the SSH user.
651
+ // If we can't get the doer, then use the built-in SSH user.
652
+ if doer != nil {
653
+ sshUser = doer .Name
654
+ } else {
655
+ sshUser = setting .SSH .BuiltinServerUser
656
+ }
657
+ }
658
+
646
659
// non-standard port, it must use full URI
647
660
if setting .SSH .Port != 22 {
648
661
sshHost := net .JoinHostPort (sshDomain , strconv .Itoa (setting .SSH .Port ))
@@ -660,21 +673,20 @@ func ComposeSSHCloneURL(ownerName, repoName string) string {
660
673
return fmt .Sprintf ("%s@%s:%s/%s.git" , sshUser , sshHost , url .PathEscape (ownerName ), url .PathEscape (repoName ))
661
674
}
662
675
663
- func (repo * Repository ) cloneLink (isWiki bool ) * CloneLink {
664
- repoName := repo .Name
665
- if isWiki {
666
- repoName += ".wiki"
667
- }
668
-
676
+ func (repo * Repository ) cloneLink (ctx context.Context , doer * user_model.User , repoPathName string ) * CloneLink {
669
677
cl := new (CloneLink )
670
- cl .SSH = ComposeSSHCloneURL (repo .OwnerName , repoName )
671
- cl .HTTPS = ComposeHTTPSCloneURL (repo .OwnerName , repoName )
678
+ cl .SSH = ComposeSSHCloneURL (doer , repo .OwnerName , repoPathName )
679
+ cl .HTTPS = ComposeHTTPSCloneURL (ctx , repo .OwnerName , repoPathName )
672
680
return cl
673
681
}
674
682
675
683
// CloneLink returns clone URLs of repository.
676
- func (repo * Repository ) CloneLink () (cl * CloneLink ) {
677
- return repo .cloneLink (false )
684
+ func (repo * Repository ) CloneLink (ctx context.Context , doer * user_model.User ) (cl * CloneLink ) {
685
+ return repo .cloneLink (ctx , doer , repo .Name )
686
+ }
687
+
688
+ func (repo * Repository ) CloneLinkGeneral (ctx context.Context ) (cl * CloneLink ) {
689
+ return repo .cloneLink (ctx , nil /* no doer, use a general git user */ , repo .Name )
678
690
}
679
691
680
692
// GetOriginalURLHostname returns the hostname of a URL or the URL
@@ -770,47 +782,66 @@ func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repo
770
782
return & repo , err
771
783
}
772
784
773
- // getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url
774
- func getRepositoryURLPathSegments (repoURL string ) []string {
775
- if strings .HasPrefix (repoURL , setting .AppURL ) {
776
- return strings .Split (strings .TrimPrefix (repoURL , setting .AppURL ), "/" )
785
+ func parseRepositoryURL (ctx context.Context , repoURL string ) (ret struct {
786
+ OwnerName , RepoName , RemainingPath string
787
+ },
788
+ ) {
789
+ // possible urls for git:
790
+ // https://my.domain/sub-path/<owner>/<repo>[.git]
791
+ // git+ssh://[email protected] /<owner>/<repo>[.git]
792
+ // ssh://[email protected] /<owner>/<repo>[.git]
793
+ // [email protected] :<owner>/<repo>[.git]
794
+
795
+ fillPathParts := func (s string ) {
796
+ s = strings .TrimPrefix (s , "/" )
797
+ fields := strings .SplitN (s , "/" , 3 )
798
+ if len (fields ) >= 2 {
799
+ ret .OwnerName = fields [0 ]
800
+ ret .RepoName = strings .TrimSuffix (fields [1 ], ".git" )
801
+ if len (fields ) == 3 {
802
+ ret .RemainingPath = "/" + fields [2 ]
803
+ }
804
+ }
777
805
}
778
806
779
- sshURLVariants := [4 ]string {
780
- setting .SSH .Domain + ":" ,
781
- setting .SSH .User + "@" + setting .SSH .Domain + ":" ,
782
- "git+ssh://" + setting .SSH .Domain + "/" ,
783
- "git+ssh://" + setting .SSH .User + "@" + setting .SSH .Domain + "/" ,
807
+ parsed , err := gitUrl .ParseGitURL (repoURL )
808
+ if err != nil {
809
+ return ret
784
810
}
785
-
786
- for _ , sshURL := range sshURLVariants {
787
- if strings .HasPrefix (repoURL , sshURL ) {
788
- return strings .Split (strings .TrimPrefix (repoURL , sshURL ), "/" )
811
+ if parsed .URL .Scheme == "http" || parsed .URL .Scheme == "https" {
812
+ if ! httplib .IsCurrentGiteaSiteURL (ctx , repoURL ) {
813
+ return ret
814
+ }
815
+ fillPathParts (strings .TrimPrefix (parsed .URL .Path , setting .AppSubURL ))
816
+ return ret
817
+ }
818
+ if parsed .URL .Scheme == "ssh" || parsed .URL .Scheme == "git+ssh" {
819
+ domainApp := setting .Domain
820
+ domainCur := httplib .GuessCurrentHostDomain (ctx )
821
+ urlDomain , _ , _ := net .SplitHostPort (parsed .URL .Host )
822
+ urlDomain = util .IfZero (urlDomain , parsed .URL .Host )
823
+ if urlDomain == "" {
824
+ return ret
789
825
}
826
+ // check whether URL domain is the App domain
827
+ domainMatches := domainApp == urlDomain
828
+ // check whether URL domain is current domain from context
829
+ domainMatches = domainMatches || (domainCur != "" && domainCur == urlDomain )
830
+ if domainMatches {
831
+ fillPathParts (parsed .URL .Path )
832
+ }
833
+ return ret
790
834
}
791
-
792
- return nil
835
+ return ret
793
836
}
794
837
795
838
// GetRepositoryByURL returns the repository by given url
796
839
func GetRepositoryByURL (ctx context.Context , repoURL string ) (* Repository , error ) {
797
- // possible urls for git:
798
- // https://my.domain/sub-path/<owner>/<repo>.git
799
- // https://my.domain/sub-path/<owner>/<repo>
800
- // git+ssh://[email protected] /<owner>/<repo>.git
801
- // git+ssh://[email protected] /<owner>/<repo>
802
- // [email protected] :<owner>/<repo>.git
803
- // [email protected] :<owner>/<repo>
804
-
805
- pathSegments := getRepositoryURLPathSegments (repoURL )
806
-
807
- if len (pathSegments ) != 2 {
840
+ ret := parseRepositoryURL (ctx , repoURL )
841
+ if ret .OwnerName == "" {
808
842
return nil , fmt .Errorf ("unknown or malformed repository URL" )
809
843
}
810
-
811
- ownerName := pathSegments [0 ]
812
- repoName := strings .TrimSuffix (pathSegments [1 ], ".git" )
813
- return GetRepositoryByOwnerAndName (ctx , ownerName , repoName )
844
+ return GetRepositoryByOwnerAndName (ctx , ret .OwnerName , ret .RepoName )
814
845
}
815
846
816
847
// GetRepositoryByID returns the repository by given id if exists.
0 commit comments