Sprint 6: JSON file persistence + real SSH terminal + V1 crypto/knownhosts integration

- go.mod replace directive for git.tukangketik.id/swanadiva/hostkeeper → ../../v1
- store/ package: JSON file persistence for hosts, snippets, keys, settings
  (~/Library/Application Support/hostkeeper/v2/)
- model SSH fields: Hostname, Port, Username, AuthType, Password, KeyID
- sshconn/ package: real SSH client via golang.org/x/crypto/ssh
- Terminal WS: real SSH connection with fallback to mock shell
- Dynamic host list in terminal (server-rendered JSON script tag)
- All mock data defaults removed from model packages
- Settings persist via store/settings.go
This commit is contained in:
swanadiva
2026-07-07 13:53:50 +07:00
parent 04d9cfb096
commit fd7361aa14
21 changed files with 746 additions and 306 deletions
+59
View File
@@ -0,0 +1,59 @@
package store
import (
"encoding/json"
"math/rand"
"os"
"path/filepath"
"sync"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/crypto"
)
var dataDir string
var mu sync.RWMutex
func init() {
configDir, err := os.UserConfigDir()
if err != nil {
configDir = os.TempDir()
}
dataDir = filepath.Join(configDir, "hostkeeper", "v2")
os.MkdirAll(dataDir, 0755)
}
func readFile(name string, v any) error {
path := filepath.Join(dataDir, name)
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if len(data) == 0 {
return nil
}
if crypto.IsEncrypted(string(data)) {
return nil
}
return json.Unmarshal(data, v)
}
func writeFile(name string, v any) error {
path := filepath.Join(dataDir, name)
data, err := json.MarshalIndent(v, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, data, 0644)
}
func randID() string {
const letters = "abcdefghijklmnopqrstuvwxyz0123456789"
b := make([]byte, 8)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}