263 lines
5.0 KiB
Go
263 lines
5.0 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/ipfs/go-datastore/query"
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
ds "github.com/ipfs/go-datastore"
|
|
|
|
crdt "github.com/ipfs/go-ds-crdt"
|
|
|
|
agelib "filippo.io/age"
|
|
password "github.com/k4lipso/pentapass/internal/crypto"
|
|
"github.com/k4lipso/pentapass/internal/crypto/age"
|
|
. "github.com/k4lipso/pentapass/internal/log"
|
|
)
|
|
|
|
type Vault struct {
|
|
ID string
|
|
Datastore *crdt.Datastore
|
|
//Registry *sharedKeyRegistry
|
|
CancelFunc context.CancelFunc
|
|
ctx context.Context
|
|
Key *agelib.X25519Identity
|
|
TrustedPeers []Peer
|
|
}
|
|
|
|
func (n *Vault) AddPeer(peer Peer) {
|
|
for _, CurrentPeer := range n.TrustedPeers {
|
|
if CurrentPeer.Id == peer.Id && CurrentPeer.Key == peer.Key {
|
|
return
|
|
}
|
|
}
|
|
|
|
n.TrustedPeers = append(n.TrustedPeers, peer)
|
|
}
|
|
|
|
func (n *Vault) RemovePeer(peer Peer) {
|
|
var Peers []Peer
|
|
for _, CurrentPeer := range n.TrustedPeers {
|
|
if CurrentPeer.Id == peer.Id && CurrentPeer.Key == peer.Key {
|
|
continue
|
|
}
|
|
|
|
Peers = append(Peers, CurrentPeer)
|
|
}
|
|
|
|
n.TrustedPeers = Peers
|
|
}
|
|
|
|
func (n *Vault) GetRecipients() []string {
|
|
var result []string
|
|
|
|
for _, peer := range n.TrustedPeers {
|
|
result = append(result, peer.Key)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (n *Vault) Put(k string, v string) error {
|
|
key := ds.NewKey(k)
|
|
err := n.Datastore.Put(n.ctx, key, []byte(v))
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (n *Vault) Delete(k string) error {
|
|
key := ds.NewKey(k)
|
|
err := n.Datastore.Delete(n.ctx, key)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (n *Vault) GetPassword(k string) (password.Password, error) {
|
|
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
|
|
if err != nil {
|
|
printErr(err)
|
|
return password.Password{}, err
|
|
}
|
|
|
|
val, err := age.Decrypt(v, n.Key)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
return password.Password{}, err
|
|
}
|
|
|
|
pw, err := password.GetPasswordFromJson(val)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
return password.Password{}, err
|
|
}
|
|
|
|
return pw, nil
|
|
}
|
|
|
|
|
|
func (n *Vault) Get(k string) (string, error) {
|
|
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
|
|
if err != nil {
|
|
printErr(err)
|
|
return "", err
|
|
}
|
|
|
|
return string(v), nil
|
|
}
|
|
|
|
func (n *Vault) GetAllNames() []string {
|
|
q := query.Query{}
|
|
results, err := n.Datastore.Query(n.ctx, q)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
|
|
var result []string
|
|
for r := range results.Next() {
|
|
if r.Error != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
result = append(result, r.Key)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (n *Vault) List() {
|
|
q := query.Query{}
|
|
results, err := n.Datastore.Query(n.ctx, q)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
|
|
for r := range results.Next() {
|
|
if r.Error != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
val, err := age.Decrypt(r.Value, n.Key)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
Logger.Infof("[%s] -> %s\n", r.Key, string(val))
|
|
}
|
|
}
|
|
|
|
func (n *Vault) GetAllPasswords() ([]password.Password, error) {
|
|
q := query.Query{}
|
|
results, err := n.Datastore.Query(n.ctx, q)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error during GetAllPasswords: %s", err)
|
|
}
|
|
|
|
var result []password.Password
|
|
|
|
for r := range results.Next() {
|
|
if r.Error != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
val, err := age.Decrypt(r.Value, n.Key)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
pw, err := password.GetPasswordFromJson(val)
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
continue
|
|
}
|
|
|
|
result = append(result, pw)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (n *Vault) Close() {
|
|
n.CancelFunc()
|
|
n.Datastore.Close()
|
|
}
|
|
|
|
func CreateVault(ID string, storageHandler *StorageHandler) (*Vault, error) {
|
|
Logger.Infof("Creating Vault %s\n", ID)
|
|
err := storageHandler.PubSub.RegisterTopicValidator(
|
|
ID, //== topicName
|
|
func(ctx context.Context, id peer.ID, msg *pubsub.Message) bool {
|
|
if id == storageHandler.Host.ID() {
|
|
return true
|
|
}
|
|
|
|
Logger.Debugf("PubSubmsg TOPIC: %s, PEER: %s\n", ID, id)
|
|
trusted := IsTrustedPeer(ctx, id, ID, storageHandler.Config)
|
|
if !trusted {
|
|
Logger.Debugf("discarded pubsub message from non trusted source %s\n", id)
|
|
}
|
|
return trusted
|
|
},
|
|
)
|
|
if err != nil {
|
|
Logger.Errorf("error registering topic validator: %s", err)
|
|
}
|
|
|
|
psubCtx, psubCancel := context.WithCancel(storageHandler.Ctx)
|
|
pubsubBC, err := crdt.NewPubSubBroadcaster(psubCtx, storageHandler.PubSub, ID)
|
|
if err != nil {
|
|
Logger.Fatal(err)
|
|
}
|
|
|
|
opts := crdt.DefaultOptions()
|
|
//opts.Logger = Logger
|
|
opts.RebroadcastInterval = 5 * time.Second
|
|
opts.PutHook = func(k ds.Key, v []byte) {
|
|
Logger.Infof("Added: [%s]\n", k)
|
|
}
|
|
opts.DeleteHook = func(k ds.Key) {
|
|
Logger.Infof("Removed: [%s]\n", k)
|
|
}
|
|
|
|
crdt, err := crdt.New(storageHandler.Store, ds.NewKey(ID), storageHandler.Ipfs, pubsubBC, opts)
|
|
if err != nil {
|
|
Logger.Fatal(err)
|
|
psubCancel()
|
|
return nil, err
|
|
}
|
|
|
|
PeerMap := GetTrustedPeers(storageHandler.Config)
|
|
|
|
val, ok := PeerMap[ID]
|
|
|
|
if !ok {
|
|
Logger.Debug("vault config does not contain any peers")
|
|
}
|
|
|
|
return &Vault{ID: ID, Datastore: crdt, CancelFunc: psubCancel, ctx: storageHandler.Ctx, Key: storageHandler.Key, TrustedPeers: val}, nil
|
|
}
|
|
|