package storage import ( "context" "fmt" "time" "errors" "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" ) var ErrNotFound error = errors.New("Not found") 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 { _, err := n.GetPassword(k) if err != nil { return ErrNotFound } 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 }