diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/convert/mirror.go | 1 | ||||
-rw-r--r-- | services/forms/repo_form.go | 16 | ||||
-rw-r--r-- | services/migrations/migrate.go | 2 | ||||
-rw-r--r-- | services/mirror/mirror_push.go | 41 |
4 files changed, 54 insertions, 6 deletions
diff --git a/services/convert/mirror.go b/services/convert/mirror.go index 249ce2f968..85e0d1c856 100644 --- a/services/convert/mirror.go +++ b/services/convert/mirror.go @@ -22,5 +22,6 @@ func ToPushMirror(ctx context.Context, pm *repo_model.PushMirror) (*api.PushMirr LastError: pm.LastError, Interval: pm.Interval.String(), SyncOnCommit: pm.SyncOnCommit, + PublicKey: pm.GetPublicKey(), }, nil } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index e18bcfdd8d..c3d9c3edc9 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -6,8 +6,10 @@ package forms import ( + "fmt" "net/http" "net/url" + "regexp" "strings" "code.gitea.io/gitea/models" @@ -88,6 +90,9 @@ func (f *MigrateRepoForm) Validate(req *http.Request, errs binding.Errors) bindi return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } +// scpRegex matches the SCP-like addresses used by Git to access repositories over SSH. +var scpRegex = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) + // ParseRemoteAddr checks if given remote address is valid, // and returns composed URL with needed username and password. func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) { @@ -103,7 +108,15 @@ func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, err if len(authUsername)+len(authPassword) > 0 { u.User = url.UserPassword(authUsername, authPassword) } - remoteAddr = u.String() + return u.String(), nil + } + + // Detect SCP-like remote addresses and return host. + if m := scpRegex.FindStringSubmatch(remoteAddr); m != nil { + // Match SCP-like syntax and convert it to a URL. + // Eg, "git@forgejo.org:user/repo" becomes + // "ssh://git@forgejo.org/user/repo". + return fmt.Sprintf("ssh://%s@%s/%s", url.User(m[1]), m[2], m[3]), nil } return remoteAddr, nil @@ -127,6 +140,7 @@ type RepoSettingForm struct { PushMirrorPassword string PushMirrorSyncOnCommit bool PushMirrorInterval string + PushMirrorUseSSH bool Private bool Template bool EnablePrune bool diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index de90c5e98f..6854a56284 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -71,7 +71,7 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error { return &models.ErrInvalidCloneAddr{Host: u.Host, IsURLError: true} } - if u.Opaque != "" || u.Scheme != "" && u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "git" { + if u.Opaque != "" || u.Scheme != "" && u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "git" && u.Scheme != "ssh" { return &models.ErrInvalidCloneAddr{Host: u.Host, IsProtocolInvalid: true, IsPermissionDenied: true, IsURLError: true} } diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go index 8303c9fb0c..3a9644c3a1 100644 --- a/services/mirror/mirror_push.go +++ b/services/mirror/mirror_push.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "io" + "os" "regexp" "strings" "time" @@ -169,11 +170,43 @@ func runPushSync(ctx context.Context, m *repo_model.PushMirror) error { log.Trace("Pushing %s mirror[%d] remote %s", path, m.ID, m.RemoteName) + // OpenSSH isn't very intuitive when you want to specify a specific keypair. + // Therefore, we need to create a temporary file that stores the private key, so that OpenSSH can use it. + // We delete the the temporary file afterwards. + privateKeyPath := "" + if m.PublicKey != "" { + f, err := os.CreateTemp(os.TempDir(), m.RemoteName) + if err != nil { + log.Error("os.CreateTemp: %v", err) + return errors.New("unexpected error") + } + + defer func() { + f.Close() + if err := os.Remove(f.Name()); err != nil { + log.Error("os.Remove: %v", err) + } + }() + + privateKey, err := m.Privatekey() + if err != nil { + log.Error("Privatekey: %v", err) + return errors.New("unexpected error") + } + + if _, err := f.Write(privateKey); err != nil { + log.Error("f.Write: %v", err) + return errors.New("unexpected error") + } + + privateKeyPath = f.Name() + } if err := git.Push(ctx, path, git.PushOptions{ - Remote: m.RemoteName, - Force: true, - Mirror: true, - Timeout: timeout, + Remote: m.RemoteName, + Force: true, + Mirror: true, + Timeout: timeout, + PrivateKeyPath: privateKeyPath, }); err != nil { log.Error("Error pushing %s mirror[%d] remote %s: %v", path, m.ID, m.RemoteName, err) |