diff --git a/.run/go test git-indra.lan_indra-labs_indra_pkg (1).run.xml b/.run/go test git-indra.lan_indra-labs_indra_pkg_CI.run.xml similarity index 100% rename from .run/go test git-indra.lan_indra-labs_indra_pkg (1).run.xml rename to .run/go test git-indra.lan_indra-labs_indra_pkg_CI.run.xml diff --git a/pkg/onions/adproto/adproto.go b/pkg/onions/adproto/adproto.go new file mode 100644 index 00000000..196ffb34 --- /dev/null +++ b/pkg/onions/adproto/adproto.go @@ -0,0 +1,127 @@ +package adproto + +import ( + "github.com/indra-labs/indra" + "github.com/indra-labs/indra/pkg/ad" + "github.com/indra-labs/indra/pkg/crypto" + "github.com/indra-labs/indra/pkg/crypto/nonce" + "github.com/indra-labs/indra/pkg/crypto/sha256" + "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/reg" + log2 "github.com/indra-labs/indra/pkg/proc/log" + "github.com/indra-labs/indra/pkg/util/qu" + "github.com/indra-labs/indra/pkg/util/slice" + "github.com/indra-labs/indra/pkg/util/splice" + "reflect" + "time" +) + +var ( + log = log2.GetLogger(indra.PathBase) + fails = log.E.Chk +) + +const ( + Magic = "prot" + Len = magic.Len + + nonce.IDLen + + crypto.PubKeyLen + + slice.Uint64Len + + crypto.SigLen +) + +// Ad entries are stored with an index generated by concatenating the bytes +// of the public key with a string path "/address/N" where N is the index of the +// address. This means hidden service introducers for values over zero. +// Hidden services have no value in the zero index, which is "/address/0". +type Ad struct { + ID nonce.ID // To ensure no repeating message + Key *crypto.Pub + Expiry time.Time + Sig crypto.SigBytes +} + +func (x *Ad) Decode(s *splice.Splice) (e error) { + if e = magic.TooShort(s.Remaining(), Len-magic.Len, + Magic); fails(e) { + + return + } + s.ReadID(&x.ID). + ReadPubkey(&x.Key). + ReadTime(&x.Expiry). + ReadSignature(&x.Sig) + return +} + +func (x *Ad) Encode(s *splice.Splice) (e error) { + log.T.S("encoding", reflect.TypeOf(x), + x.ID, x.Sig, + ) + x.Splice(s) + return +} + +func (x *Ad) GetOnion() interface{} { return x } + +func (x *Ad) Gossip(sm *sess.Manager, c qu.C) { + log.D.F("propagating peer info for %s", + x.Key.ToBased32Abbreviated()) + ad.Gossip(x, sm, c) + log.T.Ln("finished broadcasting peer info") +} + +func (x *Ad) Len() int { return Len } + +func (x *Ad) Magic() string { return Magic } + +func (x *Ad) Splice(s *splice.Splice) { + x.SpliceWithoutSig(s) + s.Signature(x.Sig) +} + +func (x *Ad) SpliceWithoutSig(s *splice.Splice) { + s.Magic(Magic). + ID(x.ID). + Pubkey(x.Key). + Time(x.Expiry) +} + +func (x *Ad) Validate() bool { + s := splice.New(Len - magic.Len) + x.SpliceWithoutSig(s) + hash := sha256.Single(s.GetUntil(s.GetCursor())) + key, e := x.Sig.Recover(hash) + if fails(e) { + return false + } + if key.Equals(x.Key) { + return true + } + return false +} + +func NewAddressAd(id nonce.ID, key *crypto.Prv, + expiry time.Time) (peerAd *Ad) { + + pub := crypto.DerivePub(key) + peerAd = &Ad{ + ID: id, + Key: pub, + Expiry: expiry, + } + s := splice.New(Len - magic.Len) + peerAd.SpliceWithoutSig(s) + hash := sha256.Single(s.GetUntil(s.GetCursor())) + var e error + if peerAd.Sig, e = crypto.Sign(key, hash); fails(e) { + return nil + } + return +} + +func protGen() coding.Codec { return &Ad{} } + +func init() { reg.Register(Magic, protGen) } diff --git a/pkg/onions/adproto/adproto_test.go b/pkg/onions/adproto/adproto_test.go new file mode 100644 index 00000000..d0af0317 --- /dev/null +++ b/pkg/onions/adproto/adproto_test.go @@ -0,0 +1,61 @@ +package adproto + +import ( + "github.com/indra-labs/indra" + "github.com/indra-labs/indra/pkg/crypto" + "github.com/indra-labs/indra/pkg/crypto/nonce" + "github.com/indra-labs/indra/pkg/engine/coding" + "github.com/indra-labs/indra/pkg/onions/reg" + log2 "github.com/indra-labs/indra/pkg/proc/log" + "github.com/indra-labs/indra/pkg/util/splice" + "testing" + "time" +) + +func TestProtoAd(t *testing.T) { + if indra.CI == "false" { + log2.SetLogLevel(log2.Trace) + } + var e error + pr, _, _ := crypto.NewSigner() + id := nonce.NewID() + aa := NewAddressAd(id, pr, time.Now().Add(time.Hour)) + log.D.S("ad", aa) + s := splice.New(aa.Len()) + if e = aa.Encode(s); fails(e) { + t.FailNow() + } + s.SetCursor(0) + var onc coding.Codec + if onc = reg.Recognise(s); onc == nil { + t.Error("did not unwrap") + t.FailNow() + } + if e = onc.Decode(s); fails(e) { + t.Error("did not decode") + t.FailNow() + } + log.D.S(onc) + var ad *Ad + var ok bool + if ad, ok = onc.(*Ad); !ok { + t.Error("did not unwrap expected type") + t.FailNow() + } + if ad.ID != aa.ID { + t.Errorf("ID did not decode correctly") + t.FailNow() + } + if ad.Expiry == aa.Expiry { + t.Errorf("expiry did not decode correctly") + t.FailNow() + } + if !ad.Key.Equals(crypto.DerivePub(pr)) { + t.Errorf("public key did not decode correctly") + t.FailNow() + } + if !ad.Validate() { + t.Errorf("received ad did not validate") + t.FailNow() + } +} diff --git a/pkg/util/splice/eng_splice.go b/pkg/util/splice/eng_splice.go index 54696be7..ebefd30c 100644 --- a/pkg/util/splice/eng_splice.go +++ b/pkg/util/splice/eng_splice.go @@ -1,7 +1,6 @@ package splice import ( - "encoding/hex" "fmt" "github.com/gookit/color" "github.com/indra-labs/indra" @@ -10,7 +9,6 @@ import ( "github.com/indra-labs/indra/pkg/crypto/sha256" magic2 "github.com/indra-labs/indra/pkg/engine/magic" log2 "github.com/indra-labs/indra/pkg/proc/log" - "github.com/indra-labs/indra/pkg/util/b32/based32" "github.com/indra-labs/indra/pkg/util/slice" "github.com/lightningnetwork/lnd/lnwire" "net" @@ -456,78 +454,78 @@ func (s *Splice) StoreCursor(c *int) *Splice { return s } -func (s *Splice) String() (o string) { - o = "splice:" - seg := s.GetSlicesFromSegments() - var prevString string - for i := range seg { - switch v := seg[i].(type) { - case string: - o += "\n" + v + " " - prevString = v - case slice.Bytes: - if len(v) > 72 { - o += "\n " - } - var oe string - for j := range v { - if (j)%4 == 0 && j != 0 { - oe += "" - } - if j == 0 { - oe += "" - } - if v[j] >= '0' && v[j] <= '9' || - v[j] >= 'a' && v[j] <= 'z' || - v[j] >= 'A' && v[j] <= 'Z' { - oe += string(v[j]) - } else { - oe += "." - } - } - if prevString == "magic" { - o += color.Red.Sprint(oe) + " " - } else { - o += color.Gray.Sprint(oe) + " " - } - if prevString != "remainder" { - hexed := hex.EncodeToString(v.ToBytes()) - var oHexed string - var revHex string - for { - if len(hexed) >= 8 { - revHex, hexed = hexed[:8], hexed[8:] - oHexed += revHex + " " - } else { - oHexed += hexed - break - } - } - o += color.Gray.Sprint(color.Bold.Sprint(oHexed)) - } - if prevString == "pubkey" { - var oo string - if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) { - o += "" - } - oo = oo[3:] - tmp := make(slice.Bytes, 0, len(oo)) - tmp = append(tmp[:13], append([]byte("..."), - tmp[len(tmp)-8:]...)...) - oo = string(tmp) - o += color.LightGreen.Sprint(" ", oo) - } - if prevString == "Keys" { - var oo string - if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) { - o += "" - } - o += color.LightBlue.Sprint(oo[:13]) - } - } - } - return -} +//func (s *Splice) String() (o string) { +// o = "splice:" +// seg := s.GetSlicesFromSegments() +// var prevString string +// for i := range seg { +// switch v := seg[i].(type) { +// case string: +// o += "\n" + v + " " +// prevString = v +// case slice.Bytes: +// if len(v) > 72 { +// o += "\n " +// } +// var oe string +// for j := range v { +// if (j)%4 == 0 && j != 0 { +// oe += "" +// } +// if j == 0 { +// oe += "" +// } +// if v[j] >= '0' && v[j] <= '9' || +// v[j] >= 'a' && v[j] <= 'z' || +// v[j] >= 'A' && v[j] <= 'Z' { +// oe += string(v[j]) +// } else { +// oe += "." +// } +// } +// if prevString == "magic" { +// o += color.Red.Sprint(oe) + " " +// } else { +// o += color.Gray.Sprint(oe) + " " +// } +// if prevString != "remainder" { +// hexed := hex.EncodeToString(v.ToBytes()) +// var oHexed string +// var revHex string +// for { +// if len(hexed) >= 8 { +// revHex, hexed = hexed[:8], hexed[8:] +// oHexed += revHex + " " +// } else { +// oHexed += hexed +// break +// } +// } +// o += color.Gray.Sprint(color.Bold.Sprint(oHexed)) +// } +// if prevString == "pubkey" { +// var oo string +// if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) { +// o += "" +// } +// oo = oo[3:] +// tmp := make(slice.Bytes, 0, len(oo)) +// tmp = append(tmp[:13], append([]byte("..."), +// tmp[len(tmp)-8:]...)...) +// oo = string(tmp) +// o += color.LightGreen.Sprint(" ", oo) +// } +// if prevString == "Keys" { +// var oo string +// if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) { +// o += "" +// } +// o += color.LightBlue.Sprint(oo[:13]) +// } +// } +// } +// return +//} func (s *Splice) Time(v time.Time) *Splice { slice.EncodeUint64(s.b[*s.c:s.c.Inc(slice.Uint64Len)], uint64(v.UnixNano())) @@ -562,11 +560,11 @@ func (s *Splice) Uint64(v uint64) *Splice { return s } -func (s Segments) String() (o string) { - for i := range s { - o += fmt.Sprintf("%s %d ", s[i].Name, s[i].Offset) - } - return -} +//func (s Segments) String() (o string) { +// for i := range s { +// o += fmt.Sprintf("%s %d ", s[i].Name, s[i].Offset) +// } +// return +//} func (s Segments) Swap(i, j int) { s[i], s[j] = s[j], s[i] }