repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

commit
dfcdebc
parent
dfcdebc
author
Eric Bower
date
2024-03-19 21:17:20 -0400 EDT
feat: init
4 files changed,  +216, -0
A go.mod
A go.sum
A .gitignore
+15, -0
 1@@ -0,0 +1,15 @@
 2+*.log
 3+*.swp
 4+.env
 5+.envrc
 6+.env.prod
 7+build/*
 8+!build/.gitkeep
 9+*.bak
10+data/*
11+!data/.gitkeep
12+ssh_data
13+.storage
14+__debug_bin
15+.bin
16+/public/
A go.mod
+38, -0
 1@@ -0,0 +1,38 @@
 2+module github.com/picosh/pico-git
 3+
 4+go 1.22.1
 5+
 6+require (
 7+	github.com/charmbracelet/ssh v0.0.0-20240301204039-e79ff702f5b3
 8+	github.com/charmbracelet/wish v1.3.2
 9+	github.com/picosh/ptun v0.0.0-20240313192814-d0ca401937fe
10+)
11+
12+require (
13+	github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
14+	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
15+	github.com/charmbracelet/bubbletea v0.25.0 // indirect
16+	github.com/charmbracelet/keygen v0.5.0 // indirect
17+	github.com/charmbracelet/lipgloss v0.10.0 // indirect
18+	github.com/charmbracelet/log v0.3.1 // indirect
19+	github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 // indirect
20+	github.com/charmbracelet/x/exp/term v0.0.0-20240229115032-4b79243a3516 // indirect
21+	github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
22+	github.com/creack/pty v1.1.21 // indirect
23+	github.com/go-logfmt/logfmt v0.6.0 // indirect
24+	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
25+	github.com/mattn/go-isatty v0.0.20 // indirect
26+	github.com/mattn/go-localereader v0.0.1 // indirect
27+	github.com/mattn/go-runewidth v0.0.15 // indirect
28+	github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
29+	github.com/muesli/cancelreader v0.2.2 // indirect
30+	github.com/muesli/reflow v0.3.0 // indirect
31+	github.com/muesli/termenv v0.15.2 // indirect
32+	github.com/rivo/uniseg v0.4.7 // indirect
33+	golang.org/x/crypto v0.21.0 // indirect
34+	golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
35+	golang.org/x/sync v0.6.0 // indirect
36+	golang.org/x/sys v0.18.0 // indirect
37+	golang.org/x/term v0.18.0 // indirect
38+	golang.org/x/text v0.14.0 // indirect
39+)
A go.sum
+71, -0
 1@@ -0,0 +1,71 @@
 2+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
 3+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
 4+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
 5+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
 6+github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
 7+github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
 8+github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc=
 9+github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8=
10+github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
11+github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
12+github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
13+github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
14+github.com/charmbracelet/ssh v0.0.0-20240301204039-e79ff702f5b3 h1:BI6Vno579jK/NKUwrvboHtMfF2On6kh6mU1cguf5+vQ=
15+github.com/charmbracelet/ssh v0.0.0-20240301204039-e79ff702f5b3/go.mod h1:wUZ0VTrLI5ixIbYOSRHrqrZnfj8EXgLZOOvQYAQ2f18=
16+github.com/charmbracelet/wish v1.3.2 h1:9+32OZnfebIw59Mcx0Yhsj6uke727bJVGJb6WolxsxQ=
17+github.com/charmbracelet/wish v1.3.2/go.mod h1:aulqcv2nEoW14yC3tlkrmIbVN7qDjeH+pzIO239VGTA=
18+github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 h1:3RXpZWGWTOeVXCTv0Dnzxdv/MhNUkBfEcbaTY0zrTQI=
19+github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
20+github.com/charmbracelet/x/exp/term v0.0.0-20240229115032-4b79243a3516 h1:wL/PiybPudKHv/LDgAUqS9eoPQr3pOAmzShMPG99cXA=
21+github.com/charmbracelet/x/exp/term v0.0.0-20240229115032-4b79243a3516/go.mod h1:ntNL6rRIDmBHKUmo6ZKt344wCTcrPsSrfVj72qT8A5U=
22+github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
23+github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
24+github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
25+github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
26+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
27+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
28+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
29+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
30+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
31+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
32+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
33+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
34+github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
35+github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
36+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
37+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
38+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
39+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
40+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
41+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
42+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
43+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
44+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
45+github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
46+github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
47+github.com/picosh/ptun v0.0.0-20240313192814-d0ca401937fe h1:FmDSB2z/4iQ1m1WEVWQaDEwXiXlehd9Csqb8evWCMpY=
48+github.com/picosh/ptun v0.0.0-20240313192814-d0ca401937fe/go.mod h1:uQfDebjN3JJPsI3PAx8T5rmJwdpfmjvdRe7fXY33Kbw=
49+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
50+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
51+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
52+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
53+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
54+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
55+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
56+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
57+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
58+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
59+golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
60+golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
61+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
62+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
63+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
64+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
65+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
66+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
67+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
68+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
69+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
70+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
71+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
72+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
A main.go
+92, -0
 1@@ -0,0 +1,92 @@
 2+package main
 3+
 4+import (
 5+	"context"
 6+	"fmt"
 7+	"log/slog"
 8+	"net/http"
 9+	"os"
10+	"os/signal"
11+	"syscall"
12+	"time"
13+
14+	"github.com/charmbracelet/ssh"
15+	"github.com/charmbracelet/wish"
16+	"github.com/picosh/ptun"
17+)
18+
19+func authHandler(ctx ssh.Context, key ssh.PublicKey) bool {
20+	return true
21+}
22+
23+func serveMux(ctx ssh.Context) http.Handler {
24+	clientName := ctx.User()
25+	router := http.NewServeMux()
26+
27+	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
28+		_, err := w.Write([]byte(fmt.Sprintf("Hello %s!", clientName)))
29+		if err != nil {
30+			fmt.Println(err)
31+		}
32+	})
33+
34+	return router
35+}
36+
37+func GitServerMiddleware() wish.Middleware {
38+	return func(next ssh.Handler) ssh.Handler {
39+		return func(sesh ssh.Session) {
40+			_, _, activePty := sesh.Pty()
41+			if activePty {
42+				next(sesh)
43+				return
44+			}
45+
46+			args := sesh.Command()
47+			fmt.Println(args)
48+		}
49+	}
50+}
51+
52+func main() {
53+	host := os.Getenv("SSH_HOST")
54+	if host == "" {
55+		host = "0.0.0.0"
56+	}
57+	port := os.Getenv("SSH_PORT")
58+	if port == "" {
59+		port = "2222"
60+	}
61+
62+	logger := slog.Default()
63+	s, err := wish.NewServer(
64+		wish.WithAddress(fmt.Sprintf("%s:%s", host, port)),
65+		wish.WithHostKeyPath("ssh_data/term_info_ed25519"),
66+		wish.WithPublicKeyAuth(authHandler),
67+		ptun.WithWebTunnel(ptun.NewWebTunnelHandler(serveMux, logger)),
68+		wish.WithMiddleware(GitServerMiddleware()),
69+	)
70+
71+	if err != nil {
72+		logger.Error("could not create server", "err", err)
73+	}
74+
75+	done := make(chan os.Signal, 1)
76+	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
77+	logger.Info("starting SSH server", "host", host, "port", port)
78+	go func() {
79+		if err = s.ListenAndServe(); err != nil {
80+			logger.Error("serve error", "err", err)
81+			os.Exit(1)
82+		}
83+	}()
84+
85+	<-done
86+	logger.Info("stopping SSH server")
87+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
88+	defer func() { cancel() }()
89+	if err := s.Shutdown(ctx); err != nil {
90+		logger.Error("shutdown", "err", err)
91+		os.Exit(1)
92+	}
93+}