chat over ssh, powered by atproto
at main 65 lines 1.5 kB view raw
1package main 2 3import ( 4 "context" 5 "fmt" 6 "net/url" 7 "time" 8 9 "github.com/charmbracelet/ssh" 10 "github.com/charmbracelet/wish" 11 12 "github.com/bluesky-social/indigo/atproto/identity" 13 "github.com/bluesky-social/indigo/atproto/syntax" 14) 15 16func checkPDSAllowed(handle string) error { 17 dir := identity.DefaultDirectory() 18 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 19 defer cancel() 20 h, err := syntax.ParseHandle(handle) 21 if err != nil { 22 return fmt.Errorf("invalid handle: %w", err) 23 } 24 ident, err := dir.LookupHandle(ctx, h) 25 if err != nil { 26 return fmt.Errorf("identity lookup: %w", err) 27 } 28 pdsURL := ident.PDSEndpoint() 29 if pdsURL == "" { 30 return fmt.Errorf("no PDS endpoint found") 31 } 32 parsed, err := url.Parse(pdsURL) 33 if err != nil { 34 return fmt.Errorf("invalid PDS URL: %w", err) 35 } 36 host := parsed.Hostname() 37 for _, allowed := range allowedPDS { 38 if host == allowed { 39 return nil 40 } 41 } 42 return fmt.Errorf("PDS %s is not on the allowlist", host) 43} 44 45func pdsGateMiddleware() wish.Middleware { 46 return func(next ssh.Handler) ssh.Handler { 47 return func(s ssh.Session) { 48 handle := s.User() 49 if err := checkPDSAllowed(handle); err != nil { 50 fmt.Fprintf(s, "\033[31mAccess denied: %s\033[0m\r\n", err) 51 return 52 } 53 next(s) 54 } 55 } 56} 57 58func goodbyeMiddleware() wish.Middleware { 59 return func(next ssh.Handler) ssh.Handler { 60 return func(s ssh.Session) { 61 next(s) 62 fmt.Fprintf(s, "Goodbye!\r\n") 63 } 64 } 65}