dc4bc/client/keystore.go

122 lines
2.8 KiB
Go

package client
import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/syndtr/goleveldb/leveldb"
)
const (
secretsKey = "secrets"
)
type KeyStore interface {
PutKeys(username string, keyPair *KeyPair) error
LoadKeys(userName, password string) (*KeyPair, error)
}
// LevelDBKeyStore is a temporary solution for keeping hot node keys.
// The target state is an encrypted storage with password authentication.
type LevelDBKeyStore struct {
keystoreDb *leveldb.DB
}
func NewLevelDBKeyStore(username, keystorePath string) (KeyStore, error) {
db, err := leveldb.OpenFile(keystorePath, nil)
if err != nil {
return nil, fmt.Errorf("failed to open keystore: %w", err)
}
keystore := &LevelDBKeyStore{
keystoreDb: db,
}
if _, err := keystore.keystoreDb.Get([]byte(secretsKey), nil); err != nil {
if err := keystore.initJsonKey(secretsKey, map[string]*KeyPair{}); err != nil {
return nil, fmt.Errorf("failed to init %s storage: %w", operationsKey, err)
}
}
return keystore, nil
}
func (s *LevelDBKeyStore) PutKeys(username string, keyPair *KeyPair) error {
bz, err := s.keystoreDb.Get([]byte(secretsKey), nil)
if err != nil {
return fmt.Errorf("failed to read keystore: %w", err)
}
var keyPairs = map[string]*KeyPair{}
if err := json.Unmarshal(bz, &keyPairs); err != nil {
return fmt.Errorf("failed to unmarshak key pairs: %w", err)
}
keyPairs[username] = keyPair
keyPairsBz, err := json.Marshal(keyPairs)
if err != nil {
return fmt.Errorf("failed to marshal key pair: %w", err)
}
err = s.keystoreDb.Put([]byte(secretsKey), keyPairsBz, nil)
if err != nil {
return fmt.Errorf("failed to put key pairs: %w", err)
}
return nil
}
func (s *LevelDBKeyStore) LoadKeys(userName, password string) (*KeyPair, error) {
bz, err := s.keystoreDb.Get([]byte(secretsKey), nil)
if err != nil {
return nil, fmt.Errorf("failed to read keystore: %w", err)
}
var keyPairs = map[string]*KeyPair{}
if err := json.Unmarshal(bz, &keyPairs); err != nil {
return nil, fmt.Errorf("failed to unmarshal key pairs: %w", err)
}
keyPair, ok := keyPairs[userName]
if !ok {
return nil, fmt.Errorf("no key pair found for user %s", userName)
}
return keyPair, nil
}
func (s *LevelDBKeyStore) initJsonKey(key string, data interface{}) error {
if _, err := s.keystoreDb.Get([]byte(key), nil); err != nil {
dataBz, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("failed to marshal storage structure: %w", err)
}
err = s.keystoreDb.Put([]byte(key), dataBz, nil)
if err != nil {
return fmt.Errorf("failed to init state: %w", err)
}
}
return nil
}
type KeyPair struct {
Pub ed25519.PublicKey
Priv ed25519.PrivateKey
}
func NewKeyPair() *KeyPair {
pub, priv, _ := ed25519.GenerateKey(nil)
return &KeyPair{
Pub: pub,
Priv: priv,
}
}
func (p *KeyPair) GetAddr() string {
return hex.EncodeToString(p.Pub)
}