improve ssh handling #277

Merged
6543 merged 13 commits from noerw/tea:improve-ssh-handling into master 2020-12-11 13:42:42 +00:00
Showing only changes of commit 8b2b5c991b - Show all commits

View File

@ -6,17 +6,21 @@ package config
import (
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"code.gitea.io/tea/modules/utils"
"golang.org/x/crypto/ssh"
"code.gitea.io/sdk/gitea"
)
@ -97,6 +101,68 @@ func (l *Login) GenerateToken(user, pass string) (string, error) {
return t.Token, err
}
// FindSSHKey retrieves the ssh keys registered in gitea, and tries to find
// a matching private key in ~/.ssh/. If no match is found, path is empty.
func (l *Login) FindSSHKey() (string, error) {
// get keys registered on gitea instance
keys, _, err := l.Client().ListMyPublicKeys(gitea.ListPublicKeysOptions{})
if err != nil || len(keys) == 0 {
return "", err
}
// enumerate ~/.ssh/*.pub files
glob, err := utils.AbsPathWithExpansion("~/.ssh/*.pub")
6543 marked this conversation as resolved Outdated
Outdated
Review

But this require users to keep private keys with public keys on ~/.ssh.

But this require users to keep private keys with public keys on `~/.ssh`.
Outdated
Review

Anybody who has a different setup can still use the --ssh-key flag to override.
Also I have never seen any location different from ~/.ssh ?

Anybody who has a different setup can still use the `--ssh-key` flag to override. Also I have never seen any location different from `~/.ssh` ?
Outdated
Review

Ah, I misunderstood; you're talking about having private keys next to pubkeys.
That's a valid concern I guess. hmm

Ah, I misunderstood; you're talking about having private keys next to pubkeys. That's a valid concern I guess. hmm
Outdated
Review

So to summarize: Once we remove the check if the privkey file is next to the pubkey, it works for most cases:

  • ssh mode for new remotes is enabled, if a matching pubkey is found in ~/.ssh/
  • if ssh-agent is running & privkey isn't next to pubkey, ssh auth works as expected
  • if ssh-agent is not running & privkey is next to pubkey, ssh auth works as expected
  • if ssh-agent is not running & privkey isn't next to pubkey, ssh auth is broken.

To recover that last case, we could additionally search ~/.ssh/config for the gitea hostname, I'm not sure that is worth it, don't know if people actually have a setup like this

So to summarize: Once we remove the check if the privkey file is next to the pubkey, it works for most cases: - ssh mode for new remotes is enabled, if a matching pubkey is found in ~/.ssh/ - if ssh-agent is running & privkey isn't next to pubkey, ssh auth works as expected - if ssh-agent is not running & privkey is next to pubkey, ssh auth works as expected - if ssh-agent is not running & privkey isn't next to pubkey, ssh auth is broken. To recover that last case, we could additionally search `~/.ssh/config` for the gitea hostname, I'm not sure that is worth it, don't know if people actually have a setup like this
Outdated
Review

@noerw I did that set up and never used ssh-agent . :(

@noerw I did that set up and never used ssh-agent . :(
Outdated
Review

@lunny me too :D

@lunny me too :D
if err != nil {
return "", err
}
localPubkeyPaths, err := filepath.Glob(glob)
if err != nil {
return "", err
}
// parse each local key with present privkey & compare fingerprints to online keys
for _, pubkeyPath := range localPubkeyPaths {
var pubkeyFile []byte
pubkeyFile, err = ioutil.ReadFile(pubkeyPath)
if err != nil {
continue
}
fields := strings.Split(string(pubkeyFile), " ")
if len(fields) < 2 { // first word is key type, second word is key material
continue
}
var keymaterial []byte
keymaterial, err = base64.StdEncoding.DecodeString(fields[1])
if err != nil {
continue
}
var pubkey ssh.PublicKey
pubkey, err = ssh.ParsePublicKey(keymaterial)
if err != nil {
continue
}
privkeyPath := strings.TrimSuffix(pubkeyPath, ".pub")
var exists bool
exists, err = utils.FileExist(privkeyPath)
if err != nil || !exists {
continue
}
// if pubkey fingerprints match, return path to corresponding privkey.
fingerprint := ssh.FingerprintSHA256(pubkey)
for _, key := range keys {
if fingerprint == key.Fingerprint {
return privkeyPath, nil
}
}
}
return "", err
}
// GetDefaultLogin return the default login
func GetDefaultLogin() (*Login, error) {
if len(Config.Logins) == 0 {
@ -194,6 +260,14 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
// so we just use the hostname
login.SSHHost = serverURL.Hostname()
if len(sshKey) == 0 {
login.SSHKey, err = login.FindSSHKey()
fmt.Println(login.SSHKey)
noerw marked this conversation as resolved Outdated
Outdated
Review

Please remove trace code.

Please remove trace code.
if err != nil {
fmt.Printf("Warning: problem while finding a SSH key: %s\n", err)
}
}
// save login to global var
Config.Logins = append(Config.Logins, login)