aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-02-12 17:08:27 +0800
committerRunxi Yu <me@runxiyu.org>2025-02-12 17:08:27 +0800
commit78ef3b19d40aa6f63412ba961ab5c8bf0939237e (patch)
treed7758dc2071a8cedf02eeba9d731af4ea8ad5c3b
parentrouter.go: Fix out-of-bounds read on /: (diff)
downloadforge-78ef3b19d40aa6f63412ba961ab5c8bf0939237e.tar.gz
forge-78ef3b19d40aa6f63412ba961ab5c8bf0939237e.tar.zst
forge-78ef3b19d40aa6f63412ba961ab5c8bf0939237e.zip
ssh.go: Add anonymous SSH cloning
-rw-r--r--config.go5
-rw-r--r--forge.scfg6
-rw-r--r--go.mod4
-rw-r--r--main.go5
-rw-r--r--ssh.go82
5 files changed, 101 insertions, 1 deletions
diff --git a/config.go b/config.go
index 2445d88..bf4e571 100644
--- a/config.go
+++ b/config.go
@@ -19,6 +19,11 @@ var config struct {
Net string `scfg:"net"`
Addr string `scfg:"addr"`
} `scfg:"http"`
+ SSH struct {
+ Net string `scfg:"net"`
+ Addr string `scfg:"addr"`
+ Key string `scfg:"key"`
+ } `scfg:"ssh"`
Git struct {
Root string `scfg:"root"`
} `scfg:"git"`
diff --git a/forge.scfg b/forge.scfg
index b414410..194c046 100644
--- a/forge.scfg
+++ b/forge.scfg
@@ -3,6 +3,12 @@ http {
addr :8080
}
+ssh {
+ net ssh
+ addr :2222
+ key /etc/ssh/ssh_host_ed25519_key
+}
+
db {
type postgres
conn postgresql:///lindenii-forge?host=/var/run/postgresql
diff --git a/go.mod b/go.mod
index 14fe392..2b46fbc 100644
--- a/go.mod
+++ b/go.mod
@@ -4,18 +4,21 @@ go 1.23.5
require (
github.com/alecthomas/chroma/v2 v2.15.0
+ github.com/gliderlabs/ssh v0.3.8
github.com/go-git/go-git/v5 v5.13.2
github.com/jackc/pgx/v5 v5.7.2
github.com/microcosm-cc/bluemonday v1.0.27
github.com/niklasfasching/go-org v1.7.0
github.com/yuin/goldmark v1.7.8
go.lindenii.runxiyu.org/lindenii-common v0.0.0-20250211153243-8946fae17bd0
+ golang.org/x/crypto v0.33.0
)
require (
dario.cat/mergo v1.0.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.5 // indirect
+ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/cloudflare/circl v1.6.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
@@ -34,7 +37,6 @@ require (
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- golang.org/x/crypto v0.33.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
diff --git a/main.go b/main.go
index cb59438..0e0f91e 100644
--- a/main.go
+++ b/main.go
@@ -31,6 +31,11 @@ func main() {
clog.Fatal(1, "Listening: "+err.Error())
}
+ err = serve_ssh()
+ if err != nil {
+ clog.Fatal(1, "Listening SSH: "+err.Error())
+ }
+
err = http.Serve(listener, &http_router_t{})
if err != nil {
clog.Fatal(1, "Serving: "+err.Error())
diff --git a/ssh.go b/ssh.go
new file mode 100644
index 0000000..e1b9ff1
--- /dev/null
+++ b/ssh.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "os/exec"
+
+ glider_ssh "github.com/gliderlabs/ssh"
+ "go.lindenii.runxiyu.org/lindenii-common/clog"
+ go_ssh "golang.org/x/crypto/ssh"
+)
+
+func serve_ssh() error {
+ hostKeyBytes, err := os.ReadFile(config.SSH.Key)
+ if err != nil {
+ return err
+ }
+
+ hostKey, err := go_ssh.ParsePrivateKey(hostKeyBytes)
+ if err != nil {
+ return err
+ }
+
+ server := &glider_ssh.Server{
+ Handler: func(session glider_ssh.Session) {
+ client_public_key := session.PublicKey()
+ var client_public_key_string string
+ if client_public_key != nil {
+ client_public_key_string = string(go_ssh.MarshalAuthorizedKey(client_public_key))
+ }
+ _ = client_public_key_string
+
+ cmd := session.Command()
+
+ if len(cmd) < 2 {
+ fmt.Fprintln(session.Stderr(), "Insufficient arguments")
+ return
+ }
+
+ if cmd[0] != "git-upload-pack" {
+ fmt.Fprintln(session.Stderr(), "Unsupported command")
+ return
+ }
+
+ proc := exec.CommandContext(session.Context(), cmd[0], "/home/runxiyu/git/forge.git")
+ 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 exitError, ok := err.(*exec.ExitError); ok {
+ fmt.Fprintln(session.Stderr(), "Process exited with error", exitError.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 },
+ }
+
+ server.AddHostKey(hostKey)
+
+ listener, err := net.Listen("tcp", ":2222")
+ if err != nil {
+ return err
+ }
+
+ go func() {
+ err = server.Serve(listener)
+ if err != nil {
+ clog.Fatal(1, "Serving SSH: "+err.Error())
+ }
+ }()
+
+ return nil
+}