diff --git a/pkg/engine/peerstore.go b/pkg/engine/peerstore.go index 40ad83f2..89d959b1 100644 --- a/pkg/engine/peerstore.go +++ b/pkg/engine/peerstore.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/indra-labs/indra/pkg/ad" "github.com/indra-labs/indra/pkg/onions/adload" "github.com/indra-labs/indra/pkg/util/slice" "github.com/libp2p/go-libp2p/core/peer" @@ -67,61 +68,67 @@ func (ng *Engine) HandleAd(p *pubsub.Message, ctx context.Context) (e error) { if e = c.Decode(s); fails(e) { return } + var ok bool switch c.(type) { case *adaddress.Ad: log.D.Ln("received", reflect.TypeOf(c), "from gossip network") - if addr, ok := c.(*adaddress.Ad); !ok { + var addr *adaddress.Ad + if addr, ok = c.(*adaddress.Ad); !ok { return fmt.Errorf(ErrWrongTypeDecode, adaddress.Magic, reflect.TypeOf(c).String()) - } else { - // If we got to here now we can add to the PeerStore. - log.D.S("new ad for address:", c) - var id peer.ID - if id, e = peer.IDFromPublicKey(addr.Key); fails(e) { - return - } - if e = ng.Listener.Host. - Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { - return - } + } else if !addr.Validate() { + return errors.New("addr ad failed validation") + } + // If we got to here now we can add to the PeerStore. + log.D.S("new ad for address:", c) + var id peer.ID + if id, e = peer.IDFromPublicKey(addr.Key); fails(e) { + return + } + if e = ng.Listener.Host. + Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { + return } case *adintro.Ad: log.D.Ln("received", reflect.TypeOf(c), "from gossip network") - if intr, ok := c.(*adintro.Ad); !ok { + var intr *adintro.Ad + if intr, ok = c.(*adintro.Ad); !ok { return fmt.Errorf(ErrWrongTypeDecode, adintro.Magic, reflect.TypeOf(c).String()) - } else { - // If we got to here now we can add to the PeerStore. - log.D.S("new ad for intro:", c) - var id peer.ID - if id, e = peer.IDFromPublicKey(intr.Key); fails(e) { - return - } - if e = ng.Listener.Host. - Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { - return - } + } else if !intr.Validate() { + return errors.New("intro ad failed validation") + } + // If we got to here now we can add to the PeerStore. + log.D.S("new ad for intro:", c) + var id peer.ID + if id, e = peer.IDFromPublicKey(intr.Key); fails(e) { + return + } + if e = ng.Listener.Host. + Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { + return } case *adload.Ad: log.D.Ln("received", reflect.TypeOf(c), "from gossip network") - if lod, ok := c.(*adload.Ad); !ok { + var lod *adload.Ad + if lod, ok = c.(*adload.Ad); !ok { return fmt.Errorf(ErrWrongTypeDecode, adaddress.Magic, reflect.TypeOf(c).String()) - } else { - // If we got to here now we can add to the PeerStore. - log.D.S("new ad for load:", c) - var id peer.ID - if id, e = peer.IDFromPublicKey(lod.Key); fails(e) { - return - } - if e = ng.Listener.Host. - Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { - return - } + } else if !lod.Validate() { + return errors.New("load ad failed validation") + } + // If we got to here now we can add to the PeerStore. + log.D.S("new ad for load:", c) + var id peer.ID + if id, e = peer.IDFromPublicKey(lod.Key); fails(e) { + return + } + if e = ng.Listener.Host. + Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { + return } case *adpeer.Ad: log.D.Ln("received", reflect.TypeOf(c), "from gossip network") - var ok bool var pa *adpeer.Ad if pa, ok = c.(*adpeer.Ad); !ok { return fmt.Errorf(ErrWrongTypeDecode, @@ -141,21 +148,61 @@ func (ng *Engine) HandleAd(p *pubsub.Message, ctx context.Context) (e error) { } case *adservices.Ad: log.D.Ln("received", reflect.TypeOf(c), "from gossip network") - if serv, ok := c.(*adservices.Ad); !ok { + var sa *adservices.Ad + if sa, ok = c.(*adservices.Ad); !ok { return fmt.Errorf(ErrWrongTypeDecode, adservices.Magic, reflect.TypeOf(c).String()) - } else { - // If we got to here now we can add to the PeerStore. - log.D.S("new ad for services:", c) - var id peer.ID - if id, e = peer.IDFromPublicKey(serv.Key); fails(e) { - return - } - if e = ng.Listener.Host. - Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { - return - } + } else if !sa.Validate() { + return errors.New("services ad failed validation") + } + // If we got to here now we can add to the PeerStore. + log.D.S("new ad for services:", c) + var id peer.ID + if id, e = peer.IDFromPublicKey(sa.Key); fails(e) { + return + } + if e = ng.Listener.Host. + Peerstore().Put(id, "services", s.GetAll().ToBytes()); fails(e) { + return } } return } + +func (ng *Engine) GetPeerRecord(id peer.ID, key string) (add ad.Ad, e error) { + var a interface{} + if a, e = ng.Listener.Host.Peerstore().Get(id, key); fails(e) { + return + } + + var ok bool + var adb slice.Bytes + if adb, ok = a.(slice.Bytes); !ok { + e = errors.New("peer record did not decode slice.Bytes") + return + } + s := splice.NewFrom(adb) + c := reg.Recognise(s) + if c == nil { + e = errors.New("message not recognised") + return + } + if e = c.Decode(s); fails(e) { + return + } + if add, ok = c.(ad.Ad); !ok { + e = errors.New("peer record did not decode as Ad") + } + return +} + +func (ng *Engine) ClearPeerRecord(id peer.ID, key string) (add ad.Ad, e error) { + if _, e = ng.Listener.Host.Peerstore().Get(id, key); fails(e) { + return + } + if e = ng.Listener.Host. + Peerstore().Put(id, key, []byte{}); fails(e) { + return + } + return +} diff --git a/pkg/onions/adaddress/adaddress.go b/pkg/onions/adaddress/adaddress.go index 2caa9628..d8a6ac18 100644 --- a/pkg/onions/adaddress/adaddress.go +++ b/pkg/onions/adaddress/adaddress.go @@ -87,11 +87,11 @@ func (x *Ad) Len() int { return Len } func (x *Ad) Magic() string { return Magic } func (x *Ad) Splice(s *splice.Splice) { - x.SpliceWithoutSig(s) + x.SpliceNoSig(s) s.Signature(x.Sig) } -func (x *Ad) SpliceWithoutSig(s *splice.Splice) { +func (x *Ad) SpliceNoSig(s *splice.Splice) { var e error var ap netip.AddrPort if ap, e = multi.AddrToAddrPort(x.Addr); fails(e) { @@ -107,13 +107,13 @@ func (x *Ad) SpliceWithoutSig(s *splice.Splice) { func (x *Ad) Validate() bool { s := splice.New(Len - magic.Len) - x.SpliceWithoutSig(s) + x.SpliceNoSig(s) hash := sha256.Single(s.GetUntil(s.GetCursor())) key, e := x.Sig.Recover(hash) if fails(e) { return false } - if key.Equals(x.Key) { + if key.Equals(x.Key) && x.Expiry.After(time.Now()) { return true } return false @@ -133,7 +133,7 @@ func New(id nonce.ID, key *crypto.Prv, Addr: ma, } s := splice.New(Len) - peerAd.SpliceWithoutSig(s) + peerAd.SpliceNoSig(s) hash := sha256.Single(s.GetUntil(s.GetCursor())) var e error if peerAd.Sig, e = crypto.Sign(key, hash); fails(e) { diff --git a/pkg/onions/adintro/adintro.go b/pkg/onions/adintro/adintro.go index 27749f9f..d44aca50 100644 --- a/pkg/onions/adintro/adintro.go +++ b/pkg/onions/adintro/adintro.go @@ -125,25 +125,24 @@ func New( ) (in *Ad) { pk := crypto.DerivePub(key) - s := splice.New(Len) - IntroSplice(s, id, pk, ap, relayRate, port, expires) - hash := sha256.Single(s.GetUntil(s.GetCursor())) - var e error - var sign crypto.SigBytes - if sign, e = crypto.Sign(key, hash); fails(e) { - return nil - } + in = &Ad{ Ad: adproto.Ad{ ID: id, Key: pk, - Expiry: time.Now().Add(adproto.TTL), - Sig: sign, + Expiry: expires, }, AddrPort: ap, RelayRate: relayRate, Port: port, } + s := splice.New(in.Len()) + in.SpliceNoSig(s) + hash := sha256.Single(s.GetUntil(s.GetCursor())) + var e error + if in.Sig, e = crypto.Sign(key, hash); fails(e) { + return nil + } return } diff --git a/pkg/onions/adload/adload.go b/pkg/onions/adload/adload.go index 0ebc8dc0..2870109a 100644 --- a/pkg/onions/adload/adload.go +++ b/pkg/onions/adload/adload.go @@ -7,7 +7,6 @@ import ( "github.com/indra-labs/indra/pkg/engine/coding" "github.com/indra-labs/indra/pkg/engine/magic" "github.com/indra-labs/indra/pkg/engine/sess" - "github.com/indra-labs/indra/pkg/onions/adintro" "github.com/indra-labs/indra/pkg/onions/adproto" "github.com/indra-labs/indra/pkg/onions/reg" log2 "github.com/indra-labs/indra/pkg/proc/log" @@ -24,7 +23,7 @@ var ( const ( Magic = "load" - Len = adproto.Len +1 + Len = adproto.Len + 1 ) // Ad stores a specification for the fee rate and existence of a peer. @@ -39,24 +38,22 @@ var _ coding.Codec = &Ad{} func New(id nonce.ID, key *crypto.Prv, load byte, expiry time.Time) (sv *Ad) { - s := splice.New(adintro.Len) k := crypto.DerivePub(key) - Splice(s, id, k, load, expiry) - hash := sha256.Single(s.GetUntil(s.GetCursor())) - var e error - var sign crypto.SigBytes - if sign, e = crypto.Sign(key, hash); fails(e) { - return nil - } sv = &Ad{ Ad: adproto.Ad{ ID: id, Key: k, - Expiry: time.Now().Add(adproto.TTL), - Sig: sign, + Expiry: expiry, }, Load: load, } + s := splice.New(sv.Len()) + sv.SpliceNoSig(s) + hash := sha256.Single(s.GetUntil(s.GetCursor())) + var e error + if sv.Sig, e = crypto.Sign(key, hash); fails(e) { + return nil + } return } @@ -83,17 +80,6 @@ func (x *Ad) Len() int { return Len } func (x *Ad) Magic() string { return "" } -func (x *Ad) Sign(prv *crypto.Prv) (e error) { - s := splice.New(x.Len()) - x.SpliceNoSig(s) - var b crypto.SigBytes - if b, e = crypto.Sign(prv, sha256.Single(s.GetUntil(s.GetCursor()))); fails(e) { - return - } - copy(x.Sig[:], b[:]) - return nil -} - func (x *Ad) Splice(s *splice.Splice) { x.SpliceNoSig(s) s.Signature(x.Sig) @@ -104,14 +90,14 @@ func (x *Ad) SpliceNoSig(s *splice.Splice) { } func (x *Ad) Validate() (valid bool) { - s := splice.New(adintro.Len - magic.Len) + s := splice.New(x.Len() - magic.Len) x.SpliceNoSig(s) hash := sha256.Single(s.GetUntil(s.GetCursor())) key, e := x.Sig.Recover(hash) if fails(e) { return false } - if key.Equals(x.Key) { + if key.Equals(x.Key) && x.Expiry.After(time.Now()) { return true } return false diff --git a/pkg/onions/adproto/adproto.go b/pkg/onions/adproto/adproto.go index d7e922e8..4705f774 100644 --- a/pkg/onions/adproto/adproto.go +++ b/pkg/onions/adproto/adproto.go @@ -76,11 +76,11 @@ func (x *Ad) Len() int { return Len } func (x *Ad) Magic() string { return Magic } func (x *Ad) Splice(s *splice.Splice) { - x.SpliceWithoutSig(s) + x.SpliceNoSig(s) s.Signature(x.Sig) } -func (x *Ad) SpliceWithoutSig(s *splice.Splice) { +func (x *Ad) SpliceNoSig(s *splice.Splice) { s.Magic(Magic). ID(x.ID). Pubkey(x.Key). @@ -89,7 +89,7 @@ func (x *Ad) SpliceWithoutSig(s *splice.Splice) { func (x *Ad) Validate() bool { s := splice.New(Len) - x.SpliceWithoutSig(s) + x.SpliceNoSig(s) hash := sha256.Single(s.GetUntil(s.GetCursor())) key, e := x.Sig.Recover(hash) if fails(e) { @@ -111,7 +111,7 @@ func New(id nonce.ID, key *crypto.Prv, Expiry: expiry, } s := splice.New(Len - magic.Len) - protoAd.SpliceWithoutSig(s) + protoAd.SpliceNoSig(s) hash := sha256.Single(s.GetUntil(s.GetCursor())) var e error if protoAd.Sig, e = crypto.Sign(key, hash); fails(e) { diff --git a/pkg/onions/adservices/adservices.go b/pkg/onions/adservices/adservices.go index 4d9b4ab4..965fbf07 100644 --- a/pkg/onions/adservices/adservices.go +++ b/pkg/onions/adservices/adservices.go @@ -49,24 +49,22 @@ var _ coding.Codec = &Ad{} func New(id nonce.ID, key *crypto.Prv, services []Service, expiry time.Time) (sv *Ad) { - s := splice.New(adintro.Len) k := crypto.DerivePub(key) - ServiceSplice(s, id, k, services, expiry) - hash := sha256.Single(s.GetUntil(s.GetCursor())) - var e error - var sign crypto.SigBytes - if sign, e = crypto.Sign(key, hash); fails(e) { - return nil - } sv = &Ad{ Ad: adproto.Ad{ ID: id, Key: k, Expiry: time.Now().Add(adproto.TTL), - Sig: sign, }, Services: services, } + s := splice.New(adintro.Len) + sv.SpliceNoSig(s) + hash := sha256.Single(s.GetUntil(s.GetCursor())) + var e error + if sv.Sig, e = crypto.Sign(key, hash); fails(e) { + return nil + } return }