Lindenii Project Forge
Commit info | |
---|---|
ID | 78ef3b19d40aa6f63412ba961ab5c8bf0939237e |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Wed, 12 Feb 2025 17:08:27 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Wed, 12 Feb 2025 17:08:27 +0800 |
Actions | Get patch |
ssh.go: Add anonymous SSH cloning
package main import ( "bufio" "context" "errors" "os" "github.com/jackc/pgx/v5/pgxpool" "go.lindenii.runxiyu.org/lindenii-common/scfg" ) var database *pgxpool.Pool var err_unsupported_database_type = errors.New("Unsupported database type") var config struct { HTTP 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"` DB struct { Type string `scfg:"type"` Conn string `scfg:"conn"` } `scfg:"db"` } func load_config(path string) (err error) { config_file, err := os.Open(path) if err != nil { return err } defer config_file.Close() decoder := scfg.NewDecoder(bufio.NewReader(config_file)) err = decoder.Decode(&config) if err != nil { return err } if config.DB.Type != "postgres" { return err_unsupported_database_type } database, err = pgxpool.New(context.Background(), config.DB.Conn) if err != nil { return err } return nil }
http { net tcp 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 } git { root /srv/git }
module go.lindenii.runxiyu.org/forge 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 github.com/dlclark/regexp2 v1.11.4 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect 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 golang.org/x/text v0.22.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect )
package main import ( "flag" "net" "net/http" "go.lindenii.runxiyu.org/lindenii-common/clog" ) func main() { config_path := flag.String( "config", "/etc/lindenii/forge.scfg", "path to configuration file", ) flag.Parse() err := load_config(*config_path) if err != nil { clog.Fatal(1, "Loading configuration: "+err.Error()) } err = load_templates() if err != nil { clog.Fatal(1, "Loading templates: "+err.Error()) } listener, err := net.Listen(config.HTTP.Net, config.HTTP.Addr) if err != nil { 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()) } }
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 }