summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/convert/mirror.go1
-rw-r--r--services/forms/repo_form.go16
-rw-r--r--services/migrations/migrate.go2
-rw-r--r--services/mirror/mirror_push.go41
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)