aboutsummaryrefslogtreecommitdiff
path: root/internal/ssh/ssh.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ssh/ssh.go')
-rw-r--r--internal/ssh/ssh.go76
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
}