Merge pull request 'Allow pushmirror to use publickey authentication' (#4819) from ironmagma/forgejo:publickey-auth-push-mirror into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4819 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
commit
5dbacb70f4
24 changed files with 648 additions and 66 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue