chat over ssh, powered by atproto
at main 55 lines 1.1 kB view raw
1package main 2 3import ( 4 "crypto/sha256" 5 "encoding/json" 6 "fmt" 7 "os" 8 "sync" 9 10 "github.com/charmbracelet/ssh" 11) 12 13// --- key store: maps SSH pubkey fingerprint -> atproto handle --- 14 15type keyStore struct { 16 mu sync.Mutex 17 path string 18 keys map[string]string // fingerprint -> handle 19} 20 21func newKeyStore(path string) *keyStore { 22 ks := &keyStore{path: path, keys: make(map[string]string)} 23 data, err := os.ReadFile(path) 24 if err == nil { 25 json.Unmarshal(data, &ks.keys) 26 } 27 return ks 28} 29 30func (ks *keyStore) lookup(pubkey ssh.PublicKey) string { 31 if pubkey == nil { 32 return "" 33 } 34 ks.mu.Lock() 35 defer ks.mu.Unlock() 36 fp := fingerprint(pubkey) 37 return ks.keys[fp] 38} 39 40func (ks *keyStore) save(pubkey ssh.PublicKey, handle string) { 41 if pubkey == nil { 42 return 43 } 44 ks.mu.Lock() 45 defer ks.mu.Unlock() 46 ks.keys[fingerprint(pubkey)] = handle 47 data, _ := json.MarshalIndent(ks.keys, "", " ") 48 os.MkdirAll(keysDir, 0700) 49 os.WriteFile(ks.path, data, 0600) 50} 51 52func fingerprint(pubkey ssh.PublicKey) string { 53 h := sha256.Sum256(pubkey.Marshal()) 54 return fmt.Sprintf("%x", h) 55}