fd7361aa14
- 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
60 lines
1.0 KiB
Go
60 lines
1.0 KiB
Go
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)
|
|
}
|