Use wish middleware

Toby Padilla created

Change summary

go.mod                               |   6 
go.sum                               |  20 ++
main.go                              |  18 +-
server/middleware/bubbletea/tea.go   |  24 ----
server/middleware/git/git.go         | 170 ------------------------------
server/middleware/logging/logging.go |  20 ---
server/middleware/middleware.go      |   5 
server/server.go                     |  57 ----------
8 files changed, 30 insertions(+), 290 deletions(-)

Detailed changes

go.mod 🔗

@@ -8,14 +8,14 @@ replace github.com/charmbracelet/bubbletea => ../bubbletea
 
 require (
 	github.com/charmbracelet/bubbles v0.8.0
-	github.com/charmbracelet/bubbletea v0.14.0
-	github.com/charmbracelet/charm v0.8.6
+	github.com/charmbracelet/bubbletea v0.14.1
 	github.com/charmbracelet/glamour v0.3.0
 	github.com/charmbracelet/lipgloss v0.3.0
+	github.com/charmbracelet/wish v0.0.0-20210816211645-088e4d8b1b04
 	github.com/dustin/go-humanize v1.0.0
 	github.com/gliderlabs/ssh v0.3.3
 	github.com/go-git/go-git/v5 v5.4.2
 	github.com/meowgorithm/babyenv v1.3.0
 	github.com/muesli/termenv v0.8.1
-	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
+	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
 )

go.sum 🔗

@@ -32,18 +32,23 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/calmh/randomart v1.1.0 h1:evl+iwc10LXtHdMZhzLxmsCQVmWnkXs44SbC6Uk0Il8=
 github.com/calmh/randomart v1.1.0/go.mod h1:DQUbPVyP+7PAs21w/AnfMKG5NioxS3TbZ2F9MSK/jFM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/charmbracelet/bubbles v0.7.5/go.mod h1:IRTORFvhEI6OUH7WhN2Ks8Z8miNGimk1BE6cmHijOkM=
 github.com/charmbracelet/bubbles v0.8.0 h1:+l2op90Ag37Vn+30O1hbg/0wBl+e+sxHhgY1F/rvdHs=
 github.com/charmbracelet/bubbles v0.8.0/go.mod h1:5WX1sSSjNCgCrzvRMN/z23HxvWaa+AI16Ch0KPZPeDs=
+github.com/charmbracelet/charm v0.8.6 h1:/U6rxGj4J6zZ1Ex8+wTr4hNMr4ESBzNZbC1UyrJPVbg=
+github.com/charmbracelet/charm v0.8.6/go.mod h1:8dE3uX+TYSpa7Q6e/CmjN6WSd7koSAKNQTGWugFREx4=
 github.com/charmbracelet/glamour v0.3.0 h1:3H+ZrKlSg8s+WU6V7eF2eRVYt8lCueffbi7r2+ffGkc=
 github.com/charmbracelet/glamour v0.3.0/go.mod h1:TzF0koPZhqq0YVBNL100cPHznAAjVj7fksX2RInwjGw=
 github.com/charmbracelet/lipgloss v0.1.2/go.mod h1:5D8zradw52m7QmxRF6QgwbwJi9je84g8MkWiGN07uKg=
-github.com/charmbracelet/lipgloss v0.2.1 h1:knjqLRtlcDsxss6i0CUhNLuXrNW3TQhFDXlXII2UaZA=
 github.com/charmbracelet/lipgloss v0.2.1/go.mod h1:uiZUfrHLQN14I0lJ5591WtcHyY1X76pOIPSaRKPY6dE=
 github.com/charmbracelet/lipgloss v0.3.0 h1:5MysOD6sHr4RP4jkZNWGVIul5GKoOsP12NgbgXPvAlA=
 github.com/charmbracelet/lipgloss v0.3.0/go.mod h1:VkhdBS2eNAmRkTwRKLJCFhCOVkjntMusBDxv7TXahuk=
+github.com/charmbracelet/wish v0.0.0-20210816211645-088e4d8b1b04 h1:0jw7kvrrhf3a+GSD1AQwQCPxU4GIQL3jsK5nDrcXsXI=
+github.com/charmbracelet/wish v0.0.0-20210816211645-088e4d8b1b04/go.mod h1:vhGzR3x3nG4Rb9Msb5rZJ8zu81nhEOKdXqHveyAPr+U=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
 github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE=
@@ -65,6 +70,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgraph-io/badger/v3 v3.2011.1/go.mod h1:0rLLrQpKVQAL0or/lBLMQznhr6dWWX7h5AKnmnqx268=
 github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d/go.mod h1:tv2ec8nA7vRpSYX7/MbP52ihrUMXIHit54CQMq8npXQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -120,13 +126,14 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -168,7 +175,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -179,9 +186,9 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
-github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
 github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
@@ -198,11 +205,15 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mmcloughlin/avo v0.0.0-20201105074841-5d2f697d268f/go.mod h1:6aKT4zZIrpGqB3RpFU14ByCSSyKY6LfJz4J/JJChHfI=
+github.com/muesli/go-app-paths v0.2.1 h1:Qi+2igkDX2aPqyRddp7P0sMQIBwBqhkfQfNcjdGjL6Y=
 github.com/muesli/go-app-paths v0.2.1/go.mod h1:SxS3Umca63pcFcLtbjVb+J0oD7cl4ixQWoBKhGEtEho=
+github.com/muesli/reflow v0.1.0/go.mod h1:I9bWAt7QTg/que/qmUCJBGlj7wEq8OAFBjPNjc6xK4I=
 github.com/muesli/reflow v0.2.0/go.mod h1:qT22vjVmM9MIUeLgsVYe/Ye7eZlbv9dZjL3dVhUqLX8=
 github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk=
 github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
+github.com/muesli/sasquatch v0.0.0-20200811221207-66979d92330a h1:Hw/15RYEOUD6T9UCRkUmNBa33kJkH33Fui6hE4sRLKU=
 github.com/muesli/sasquatch v0.0.0-20200811221207-66979d92330a/go.mod h1:+XG0ne5zXWBTSbbe7Z3/RWxaT8PZY6zaZ1dX6KjprYY=
+github.com/muesli/termenv v0.7.4/go.mod h1:pZ7qY9l3F7e5xsAOS0zCew2tME+p7bWeBkotCEcIIcc=
 github.com/muesli/termenv v0.8.1 h1:9q230czSP3DHVpkaPDXGp0TOfAwyjyYwXlUCQxQSaBk=
 github.com/muesli/termenv v0.8.1/go.mod h1:kzt/D/4a88RoheZmwfqorY3A+tnsSMA9HJC/fQSFKo0=
 github.com/muesli/toktok v0.0.0-20201007181047-c74187025f3f/go.mod h1:FmV+MTLqgtVrOUfvwWxUZXyoiCGzYt8siG4BqrY4Mb8=
@@ -351,6 +362,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

main.go 🔗

@@ -1,19 +1,22 @@
 package main
 
 import (
+	"fmt"
 	"log"
-	"smoothie/server"
-	bm "smoothie/server/middleware/bubbletea"
-	gm "smoothie/server/middleware/git"
-	lm "smoothie/server/middleware/logging"
 	"smoothie/tui"
 	"time"
 
+	"github.com/charmbracelet/wish"
+	bm "github.com/charmbracelet/wish/bubbletea"
+	gm "github.com/charmbracelet/wish/git"
+	lm "github.com/charmbracelet/wish/logging"
+
 	"github.com/meowgorithm/babyenv"
 )
 
 type Config struct {
 	Port         int    `env:"SMOOTHIE_PORT" default:"23231"`
+	Host         string `env:"SMOOTHIE_HOST" default:""`
 	KeyPath      string `env:"SMOOTHIE_KEY_PATH" default:".ssh/smoothie_server_ed25519"`
 	RepoAuth     string `env:"SMOOTHIE_REPO_KEYS" default:""`
 	RepoAuthFile string `env:"SMOOTHIE_REPO_KEYS_PATH" default:".ssh/smoothie_git_authorized_keys"`
@@ -26,8 +29,8 @@ func main() {
 	if err != nil {
 		log.Fatalln(err)
 	}
-	s, err := server.NewServer(
-		cfg.Port,
+	s, err := wish.NewServer(
+		fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
 		cfg.KeyPath,
 		bm.Middleware(tui.SessionHandler(cfg.RepoPath, time.Second*5)),
 		gm.Middleware(cfg.RepoPath, cfg.RepoAuth, cfg.RepoAuthFile),
@@ -36,7 +39,8 @@ func main() {
 	if err != nil {
 		log.Fatalln(err)
 	}
-	err = s.Start()
+	log.Printf("Starting SSH server on %s:%d\n", cfg.Host, cfg.Port)
+	err = s.ListenAndServe()
 	if err != nil {
 		log.Fatalln(err)
 	}

server/middleware/bubbletea/tea.go 🔗

@@ -1,24 +0,0 @@
-package bubbletea
-
-import (
-	"smoothie/server/middleware"
-
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/gliderlabs/ssh"
-)
-
-type BubbleTeaHandler func(ssh.Session) (tea.Model, []tea.ProgramOption)
-
-func Middleware(bth BubbleTeaHandler) middleware.Middleware {
-	return func(sh ssh.Handler) ssh.Handler {
-		return func(s ssh.Session) {
-			m, opts := bth(s)
-			if m != nil {
-				opts = append(opts, tea.WithInput(s), tea.WithOutput(s))
-				p := tea.NewProgram(m, opts...)
-				_ = p.Start()
-			}
-			sh(s)
-		}
-	}
-}

server/middleware/git/git.go 🔗

@@ -1,170 +0,0 @@
-package git
-
-import (
-	"bufio"
-	"context"
-	"fmt"
-	"log"
-	"os"
-	"os/exec"
-	"smoothie/server/middleware"
-	"strings"
-
-	"github.com/gliderlabs/ssh"
-)
-
-func gitMiddleware(repoDir string, authedKeys []ssh.PublicKey) middleware.Middleware {
-	return func(sh ssh.Handler) ssh.Handler {
-		return func(s ssh.Session) {
-			cmd := s.Command()
-			if len(cmd) == 2 {
-				switch cmd[0] {
-				case "git-upload-pack", "git-upload-archive", "git-receive-pack":
-					if len(authedKeys) > 0 && cmd[0] == "git-receive-pack" {
-						authed := false
-						for _, pk := range authedKeys {
-							if ssh.KeysEqual(pk, s.PublicKey()) {
-								authed = true
-							}
-						}
-						if !authed {
-							fatalGit(s, fmt.Errorf("you are not authorized to do this"))
-							break
-						}
-					}
-					r := cmd[1]
-					rp := fmt.Sprintf("%s%s", repoDir, r)
-					ctx := s.Context()
-					err := ensureRepo(ctx, repoDir, r)
-					if err != nil {
-						fatalGit(s, err)
-						break
-					}
-					c := exec.CommandContext(ctx, cmd[0], rp)
-					c.Dir = "./"
-					c.Stdout = s
-					c.Stdin = s
-					err = c.Run()
-					if err != nil {
-						fatalGit(s, err)
-						break
-					}
-				}
-			}
-			sh(s)
-		}
-	}
-}
-
-func Middleware(repoDir, authorizedKeys, authorizedKeysFile string) middleware.Middleware {
-	ak1, err := parseKeysFromString(authorizedKeys)
-	if err != nil {
-		log.Fatal(err)
-	}
-	ak2, err := parseKeysFromFile(authorizedKeysFile)
-	if err != nil {
-		log.Fatal(err)
-	}
-	authedKeys := append(ak1, ak2...)
-	return gitMiddleware(repoDir, authedKeys)
-}
-
-func MiddlewareWithKeys(repoDir, authorizedKeys string) middleware.Middleware {
-	return Middleware(repoDir, authorizedKeys, "")
-}
-
-func MiddlewareWithKeyPath(repoDir, authorizedKeysFile string) middleware.Middleware {
-	return Middleware(repoDir, "", authorizedKeysFile)
-}
-
-func parseKeysFromFile(path string) ([]ssh.PublicKey, error) {
-	authedKeys := make([]ssh.PublicKey, 0)
-	hasAuth, err := fileExists(path)
-	if err != nil {
-		return nil, err
-	}
-	if hasAuth {
-		f, err := os.Open(path)
-		if err != nil {
-			log.Fatal(err)
-		}
-		defer f.Close()
-		scanner := bufio.NewScanner(f)
-		err = addKeys(scanner, &authedKeys)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return authedKeys, nil
-}
-
-func parseKeysFromString(keys string) ([]ssh.PublicKey, error) {
-	authedKeys := make([]ssh.PublicKey, 0)
-	scanner := bufio.NewScanner(strings.NewReader(keys))
-	err := addKeys(scanner, &authedKeys)
-	if err != nil {
-		return nil, err
-	}
-	return authedKeys, nil
-}
-
-func addKeys(s *bufio.Scanner, keys *[]ssh.PublicKey) error {
-	for s.Scan() {
-		pt := s.Text()
-		log.Printf("Adding authorized key: %s", pt)
-		pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pt))
-		if err != nil {
-			return err
-		}
-		*keys = append(*keys, pk)
-	}
-	if err := s.Err(); err != nil {
-		return err
-	}
-	return nil
-}
-
-func fileExists(path string) (bool, error) {
-	_, err := os.Stat(path)
-	if err == nil {
-		return true, nil
-	}
-	if os.IsNotExist(err) {
-		return false, nil
-	}
-	return true, err
-}
-
-func fatalGit(s ssh.Session, err error) {
-	// hex length includes 4 byte length prefix and ending newline
-	msg := err.Error()
-	pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg)
-	_, _ = s.Write([]byte(pktLine))
-	s.Exit(1)
-}
-
-func ensureRepo(ctx context.Context, dir string, repo string) error {
-	exists, err := fileExists(dir)
-	if err != nil {
-		return err
-	}
-	if !exists {
-		err = os.MkdirAll(dir, os.ModeDir|os.FileMode(0700))
-		if err != nil {
-			return err
-		}
-	}
-	rp := fmt.Sprintf("%s%s", dir, repo)
-	exists, err = fileExists(rp)
-	if err != nil {
-		return err
-	}
-	if !exists {
-		c := exec.CommandContext(ctx, "git", "init", "--bare", rp)
-		err = c.Run()
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}

server/middleware/logging/logging.go 🔗

@@ -1,20 +0,0 @@
-package logging
-
-import (
-	"log"
-	"smoothie/server/middleware"
-
-	"github.com/gliderlabs/ssh"
-)
-
-func Middleware() middleware.Middleware {
-	return func(sh ssh.Handler) ssh.Handler {
-		return func(s ssh.Session) {
-			hpk := s.PublicKey() != nil
-			pty, _, _ := s.Pty()
-			log.Printf("%s connect %v %v %s %v %v\n", s.RemoteAddr().String(), hpk, s.Command(), pty.Term, pty.Window.Width, pty.Window.Height)
-			sh(s)
-			log.Printf("%s disconnect\n", s.RemoteAddr().String())
-		}
-	}
-}

server/server.go 🔗

@@ -1,57 +0,0 @@
-package server
-
-import (
-	"fmt"
-	"log"
-	"path/filepath"
-	"smoothie/server/middleware"
-	"strings"
-
-	"github.com/charmbracelet/charm/keygen"
-	"github.com/gliderlabs/ssh"
-	gossh "golang.org/x/crypto/ssh"
-)
-
-type Server struct {
-	server *ssh.Server
-	key    gossh.PublicKey
-}
-
-func NewServer(port int, keyPath string, mw ...middleware.Middleware) (*Server, error) {
-	s := &Server{server: &ssh.Server{}}
-	s.server.Version = "OpenSSH_7.6p1"
-	s.server.Addr = fmt.Sprintf(":%d", port)
-	s.server.PasswordHandler = s.passHandler
-	s.server.PublicKeyHandler = s.authHandler
-	kps := strings.Split(keyPath, string(filepath.Separator))
-	kp := strings.Join(kps[:len(kps)-1], string(filepath.Separator))
-	n := strings.TrimRight(kps[len(kps)-1], "_ed25519")
-	_, err := keygen.NewSSHKeyPair(kp, n, nil, "ed25519")
-	if err != nil {
-		return nil, err
-	}
-	k := ssh.HostKeyFile(keyPath)
-	err = s.server.SetOption(k)
-	if err != nil {
-		return nil, err
-	}
-	h := func(s ssh.Session) {}
-	for _, m := range mw {
-		h = m(h)
-	}
-	s.server.Handler = h
-	return s, nil
-}
-
-func (srv *Server) authHandler(ctx ssh.Context, key ssh.PublicKey) bool {
-	return true
-}
-
-func (srv *Server) passHandler(ctx ssh.Context, pass string) bool {
-	return true
-}
-
-func (srv *Server) Start() error {
-	log.Printf("Starting SSH server on %s\n", srv.server.Addr)
-	return srv.server.ListenAndServe()
-}