Lindenii Project Forge
Commit info | |
---|---|
ID | 2cd785fc9e7d25e7504fa552cd94607d250665b0 |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Sun, 16 Feb 2025 00:32:46 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Sun, 16 Feb 2025 00:33:04 +0800 |
Actions | Get patch |
ssh_*: Use pure go-git SSH handling (receive and upload)
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 }
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 }
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 }
package main import ( "fmt" "net" "os"
"os/exec"
"strings" glider_ssh "github.com/gliderlabs/ssh" "go.lindenii.runxiyu.org/lindenii-common/clog" go_ssh "golang.org/x/crypto/ssh" ) var ( server_public_key_string string server_public_key_fingerprint string server_public_key go_ssh.PublicKey ) func serve_ssh(listener net.Listener) error { host_key_bytes, err := os.ReadFile(config.SSH.Key) if err != nil { return err } host_key, err := go_ssh.ParsePrivateKey(host_key_bytes) if err != nil { return err } server_public_key = host_key.PublicKey() server_public_key_string = string(go_ssh.MarshalAuthorizedKey(server_public_key)) server_public_key_fingerprint = string(go_ssh.FingerprintSHA256(server_public_key)) 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)) } clog.Info("Incoming SSH: " + session.RemoteAddr().String() + " " + strings.TrimSuffix(client_public_key_string, "\n") + " " + session.RawCommand()) fmt.Fprintln(session.Stderr(), "Lindenii Forge "+VERSION+", source at "+strings.TrimSuffix(config.HTTP.Root, "/")+"/:/source/\r") cmd := session.Command() if len(cmd) < 2 { fmt.Fprintln(session.Stderr(), "Insufficient arguments\r") return }
if cmd[0] != "git-upload-pack" { fmt.Fprintln(session.Stderr(), "Unsupported command\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")
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 }
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)
fmt.Fprintln(session.Stderr(), err.Error())
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 }, // It is intentional that we do not check any credentials and accept all connections. // This allows all users to connect and clone repositories; when pushing is added later, // we will check their public key in the session handler, not in the auth handlers. } server.AddHostKey(host_key) go func() { err = server.Serve(listener) if err != nil { clog.Fatal(1, "Serving SSH: "+err.Error()) } }() return nil }