diff options
author | jan <git@wiegelmann.net> | 2024-04-13 15:01:34 +0200 |
---|---|---|
committer | Matěj Cepl <mcepl@cepl.eu> | 2024-07-15 10:45:09 +0200 |
commit | ead30c5b454faf2e79951e0967a0dc5afc8ecc7c (patch) | |
tree | 3a16a77b5fee38c5ae03c8c921076b84904b924d /repository/gogit.go | |
parent | bc92f93b5f78cbf88f73e57469fae124bde9662b (diff) | |
download | git-bug-ead30c5b454faf2e79951e0967a0dc5afc8ecc7c.tar.gz |
fix ssh authenticate
Diffstat (limited to 'repository/gogit.go')
-rw-r--r-- | repository/gogit.go | 82 |
1 files changed, 78 insertions, 4 deletions
diff --git a/repository/gogit.go b/repository/gogit.go index 96d62665..a271ab8b 100644 --- a/repository/gogit.go +++ b/repository/gogit.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "sort" "strings" "sync" @@ -21,6 +22,7 @@ import ( "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/filemode" "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" "golang.org/x/sync/errgroup" "golang.org/x/sys/execabs" @@ -383,14 +385,31 @@ func (repo *GoGitRepo) FetchRefs(remote string, prefixes ...string) (string, err buf := bytes.NewBuffer(nil) - err := repo.r.Fetch(&gogit.FetchOptions{ + fetchOptions := &gogit.FetchOptions{ RemoteName: remote, RefSpecs: refSpecs, Progress: buf, - }) + } + + publicKeys, err := repo.SSHAuth(remote) + if err != nil { + return "", err + } + + err = repo.r.Fetch(fetchOptions) if err == gogit.NoErrAlreadyUpToDate { return "already up-to-date", nil } + // ssh-agent is required if ssh or scp-like url is configured in repository config + // we can not fetch if the ssh-agent has invalid keys or ssh-agent is not running + // retry to fetch again if we can retreive public keys from the users home directory + if err != nil && publicKeys != nil { + fetchOptions.Auth = publicKeys + err = repo.r.Fetch(fetchOptions) + if err == gogit.NoErrAlreadyUpToDate { + return "already up-to-date", nil + } + } if err != nil { return "", err } @@ -436,14 +455,31 @@ func (repo *GoGitRepo) PushRefs(remote string, prefixes ...string) (string, erro buf := bytes.NewBuffer(nil) - err = remo.Push(&gogit.PushOptions{ + pushOptions := &gogit.PushOptions{ RemoteName: remote, RefSpecs: refSpecs, Progress: buf, - }) + } + + publicKeys, err := repo.SSHAuth(remote) + if err != nil { + return "", err + } + + err = repo.r.Push(pushOptions) if err == gogit.NoErrAlreadyUpToDate { return "already up-to-date", nil } + // ssh-agent is required if ssh or scp-like url is configured in repository config + // we can not push if the ssh-agent has invalid keys or ssh-agent is not running + // retry to push again if we can retreive public keys from the users home directory + if err != nil && publicKeys != nil { + pushOptions.Auth = publicKeys + err = repo.r.Push(pushOptions) + if err == gogit.NoErrAlreadyUpToDate { + return "already up-to-date", nil + } + } if err != nil { return "", err } @@ -451,6 +487,44 @@ func (repo *GoGitRepo) PushRefs(remote string, prefixes ...string) (string, erro return buf.String(), nil } +// SSHAuth will attempt to read public keys for SSH auth +// if the repository remote contains a ssh or scp-like url +func (repo *GoGitRepo) SSHAuth(remote string) (*ssh.PublicKeys, error) { + // get the repository config + config, err := repo.r.Config() + if err != nil { + return nil, err + } + + // check if the repository config has at least one remote url + remotes, found := config.Remotes[remote] + if !found || len(remotes.URLs) < 1 { + return nil, fmt.Errorf("remote %s url not found in repository config", remote) + } + + schemeRegexp := regexp.MustCompile(`^[^:]+://`) + scpLikeRegexp := regexp.MustCompile(`^(?:(?P<user>[^@]+)@)?(?P<host>)`) + + // try to load public keys from the users home directory + // if the repository remote contains a ssh or scp-like url + if strings.HasPrefix(remotes.URLs[0], "ssh://") || (scpLikeRegexp.MatchString(remotes.URLs[0]) && !schemeRegexp.MatchString(remotes.URLs[0])) { + home, err := os.UserHomeDir() + if err != nil { + return nil, err + } + + // try to find and load valid public keys from the users home directory + attemptKeys := []string{"id_rsa", "id_ecdsa", "id_ecdsa_sk", "id_ed25519", "id_ed25519_sk", "id_xmss", "id_dsa"} + for _, key := range attemptKeys { + authMethod, err := ssh.NewPublicKeysFromFile("git", filepath.Join(home, ".ssh", key), "") + if err == nil { + return authMethod, nil + } + } + } + return nil, nil +} + // StoreData will store arbitrary data and return the corresponding hash func (repo *GoGitRepo) StoreData(data []byte) (Hash, error) { obj := repo.r.Storer.NewEncodedObject() |