diff options
Diffstat (limited to 'internal/ssh/ssh.go')
-rw-r--r-- | internal/ssh/ssh.go | 76 |
1 files changed, 53 insertions, 23 deletions
diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go index dfbd2281..9fbd4a69 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -5,6 +5,7 @@ package ssh import ( + "context" "fmt" "io" "net" @@ -12,13 +13,17 @@ import ( "os/exec" "path/filepath" "strings" + "syscall" + "github.com/pkg/errors" + "github.com/sourcegraph/run" "github.com/unknwon/com" "golang.org/x/crypto/ssh" log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/db" + "gogs.io/gogs/internal/osutil" ) func cleanCommand(cmd string) string { @@ -144,8 +149,8 @@ func listen(config *ssh.ServerConfig, host string, port int) { log.Trace("SSH: Handshaking for %s", conn.RemoteAddr()) sConn, chans, reqs, err := ssh.NewServerConn(conn, config) if err != nil { - if err == io.EOF { - log.Warn("SSH: Handshaking was terminated: %v", err) + if err == io.EOF || errors.Is(err, syscall.ECONNRESET) { + log.Trace("SSH: Handshaking was terminated: %v", err) } else { log.Error("SSH: Error on handshaking: %v", err) } @@ -161,11 +166,11 @@ func listen(config *ssh.ServerConfig, host string, port int) { } // Listen starts a SSH server listens on given port. -func Listen(host string, port int, ciphers, macs []string) { +func Listen(opts conf.SSHOpts, appDataPath string) { config := &ssh.ServerConfig{ Config: ssh.Config{ - Ciphers: ciphers, - MACs: macs, + Ciphers: opts.ServerCiphers, + MACs: opts.ServerMACs, }, PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { pkey, err := db.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))) @@ -177,27 +182,52 @@ func Listen(host string, port int, ciphers, macs []string) { }, } - keyPath := filepath.Join(conf.Server.AppDataPath, "ssh", "gogs.rsa") - if !com.IsExist(keyPath) { - if err := os.MkdirAll(filepath.Dir(keyPath), os.ModePerm); err != nil { - panic(err) - } - _, stderr, err := com.ExecCmd(conf.SSH.KeygenPath, "-f", keyPath, "-t", "rsa", "-m", "PEM", "-N", "") - if err != nil { - panic(fmt.Sprintf("Failed to generate private key: %v - %s", err, stderr)) - } - log.Trace("SSH: New private key is generateed: %s", keyPath) - } - - privateBytes, err := os.ReadFile(keyPath) + keys, err := setupHostKeys(appDataPath, opts.ServerAlgorithms) if err != nil { - panic("SSH: Failed to load private key: " + err.Error()) + log.Fatal("SSH: Failed to setup host keys: %v", err) } - private, err := ssh.ParsePrivateKey(privateBytes) + for _, key := range keys { + config.AddHostKey(key) + } + + go listen(config, opts.ListenHost, opts.ListenPort) +} + +func setupHostKeys(appDataPath string, algorithms []string) ([]ssh.Signer, error) { + dir := filepath.Join(appDataPath, "ssh") + err := os.MkdirAll(dir, os.ModePerm) if err != nil { - panic("SSH: Failed to parse private key: " + err.Error()) + return nil, errors.Wrapf(err, "create host key directory") } - config.AddHostKey(private) - go listen(config, host, port) + var hostKeys []ssh.Signer + for _, algo := range algorithms { + keyPath := filepath.Join(dir, "gogs."+algo) + if !osutil.IsExist(keyPath) { + args := []string{ + conf.SSH.KeygenPath, + "-t", algo, + "-f", keyPath, + "-m", "PEM", + "-N", run.Arg(""), + } + err = run.Cmd(context.Background(), args...).Run().Wait() + if err != nil { + return nil, errors.Wrapf(err, "generate host key with args %v", args) + } + log.Trace("SSH: New private key is generated: %s", keyPath) + } + + keyData, err := os.ReadFile(keyPath) + if err != nil { + return nil, errors.Wrapf(err, "read host key %q", keyPath) + } + signer, err := ssh.ParsePrivateKey(keyData) + if err != nil { + return nil, errors.Wrapf(err, "parse host key %q", keyPath) + } + + hostKeys = append(hostKeys, signer) + } + return hostKeys, nil } |