aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-02-16 00:32:46 +0800
committerRunxi Yu <me@runxiyu.org>2025-02-16 00:33:04 +0800
commit2cd785fc9e7d25e7504fa552cd94607d250665b0 (patch)
tree8c72000e687ad1841358353aae87693e05e266cf
parentREADME.md: Add Libera channel (diff)
downloadforge-2cd785fc9e7d25e7504fa552cd94607d250665b0.tar.gz
forge-2cd785fc9e7d25e7504fa552cd94607d250665b0.tar.zst
forge-2cd785fc9e7d25e7504fa552cd94607d250665b0.zip
ssh_*: Use pure go-git SSH handling (receive and upload)
-rw-r--r--misc.go18
-rw-r--r--ssh_handle_receive_pack.go49
-rw-r--r--ssh_handle_upload_pack.go49
-rw-r--r--ssh_server.go39
4 files changed, 132 insertions, 23 deletions
diff --git a/misc.go b/misc.go
index a43f20a..5077b83 100644
--- a/misc.go
+++ b/misc.go
@@ -1,6 +1,24 @@
package main
+import (
+ "errors"
+ "strings"
+)
+
type name_desc_t struct {
Name string
Description string
}
+
+var err_environ_no_separator = errors.New("No separator found in environ line")
+
+func environ_to_map(environ_strings []string) (result map[string]string, err error) {
+ for _, environ_string := range environ_strings {
+ key, value, found := strings.Cut(environ_string, "=")
+ if !found {
+ return result, err_environ_no_separator
+ }
+ result[key] = value
+ }
+ return result, err_environ_no_separator
+}
diff --git a/ssh_handle_receive_pack.go b/ssh_handle_receive_pack.go
new file mode 100644
index 0000000..69af8f5
--- /dev/null
+++ b/ssh_handle_receive_pack.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ glider_ssh "github.com/gliderlabs/ssh"
+ "github.com/go-git/go-billy/v5/osfs"
+ "github.com/go-git/go-git/v5/plumbing/protocol/packp"
+ "github.com/go-git/go-git/v5/plumbing/transport"
+ transport_server "github.com/go-git/go-git/v5/plumbing/transport/server"
+)
+
+func ssh_handle_receive_pack(session glider_ssh.Session, repo_identifier string) (err error) {
+ repo_path, err := get_repo_path_from_ssh_path(session.Context(), repo_identifier)
+ if err != nil {
+ return err
+ }
+ endpoint, err := transport.NewEndpoint("/")
+ if err != nil {
+ return err
+ }
+ billy_fs := osfs.New(repo_path)
+ fs_loader := transport_server.NewFilesystemLoader(billy_fs)
+ transport := transport_server.NewServer(fs_loader)
+ receive_pack_session, err := transport.NewReceivePackSession(endpoint, nil)
+ if err != nil {
+ return err
+ }
+ advertised_references, err := receive_pack_session.AdvertisedReferencesContext(session.Context())
+ if err != nil {
+ return err
+ }
+ err = advertised_references.Encode(session)
+ if err != nil {
+ return err
+ }
+ reference_update_request := packp.NewReferenceUpdateRequest()
+ err = reference_update_request.Decode(session)
+ if err != nil {
+ return err
+ }
+ report_status, err := receive_pack_session.ReceivePack(session.Context(), reference_update_request)
+ if err != nil {
+ return err
+ }
+ err = report_status.Encode(session)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/ssh_handle_upload_pack.go b/ssh_handle_upload_pack.go
new file mode 100644
index 0000000..8f7d9c9
--- /dev/null
+++ b/ssh_handle_upload_pack.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ glider_ssh "github.com/gliderlabs/ssh"
+ "github.com/go-git/go-billy/v5/osfs"
+ "github.com/go-git/go-git/v5/plumbing/protocol/packp"
+ "github.com/go-git/go-git/v5/plumbing/transport"
+ "github.com/go-git/go-git/v5/plumbing/transport/server"
+)
+
+func ssh_handle_upload_pack(session glider_ssh.Session, repo_identifier string) (err error) {
+ repo_path, err := get_repo_path_from_ssh_path(session.Context(), repo_identifier)
+ if err != nil {
+ return err
+ }
+ endpoint, err := transport.NewEndpoint("/")
+ if err != nil {
+ return err
+ }
+ billy_fs := osfs.New(repo_path)
+ fs_loader := server.NewFilesystemLoader(billy_fs)
+ transport := server.NewServer(fs_loader)
+ upload_pack_session, err := transport.NewUploadPackSession(endpoint, nil)
+ if err != nil {
+ return err
+ }
+ advertised_references, err := upload_pack_session.AdvertisedReferencesContext(session.Context())
+ if err != nil {
+ return err
+ }
+ err = advertised_references.Encode(session)
+ if err != nil {
+ return err
+ }
+ reference_update_request := packp.NewUploadPackRequest()
+ err = reference_update_request.Decode(session)
+ if err != nil {
+ return err
+ }
+ report_status, err := upload_pack_session.UploadPack(session.Context(), reference_update_request)
+ if err != nil {
+ return err
+ }
+ err = report_status.Encode(session)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/ssh_server.go b/ssh_server.go
index 0dde4b4..b3a6a52 100644
--- a/ssh_server.go
+++ b/ssh_server.go
@@ -4,7 +4,6 @@ import (
"fmt"
"net"
"os"
- "os/exec"
"strings"
glider_ssh "github.com/gliderlabs/ssh"
@@ -51,33 +50,27 @@ func serve_ssh(listener net.Listener) error {
return
}
- if cmd[0] != "git-upload-pack" {
- fmt.Fprintln(session.Stderr(), "Unsupported command\r")
+ switch cmd[0] {
+ case "git-upload-pack":
+ if len(cmd) > 2 {
+ fmt.Fprintln(session.Stderr(), "Too many arguments\r")
+ return
+ }
+ err = ssh_handle_upload_pack(session, cmd[1])
+ case "git-receive-pack":
+ if len(cmd) > 2 {
+ fmt.Fprintln(session.Stderr(), "Too many arguments\r")
+ return
+ }
+ err = ssh_handle_receive_pack(session, cmd[1])
+ default:
+ fmt.Fprintln(session.Stderr(), "Unsupported command: "+cmd[0]+"\r")
return
}
-
- fs_path, err := get_repo_path_from_ssh_path(session.Context(), cmd[1])
if err != nil {
- fmt.Fprintln(session.Stderr(), "Error while getting repo path:", err, "\r")
+ fmt.Fprintln(session.Stderr(), err.Error())
return
}
-
- proc := exec.CommandContext(session.Context(), cmd[0], fs_path)
- proc.Stdin = session
- proc.Stdout = session
- proc.Stderr = session.Stderr()
-
- err = proc.Start()
- if err != nil {
- fmt.Fprintln(session.Stderr(), "Error while starting process:", err)
- return
- }
- err = proc.Wait()
- if exit_error, ok := err.(*exec.ExitError); ok {
- fmt.Fprintln(session.Stderr(), "Process exited with error", exit_error.ExitCode())
- } else if err != nil {
- fmt.Fprintln(session.Stderr(), "Error while waiting for process:", err)
- }
},
PublicKeyHandler: func(ctx glider_ssh.Context, key glider_ssh.PublicKey) bool { return true },
KeyboardInteractiveHandler: func(ctx glider_ssh.Context, challenge go_ssh.KeyboardInteractiveChallenge) bool { return true },