create prototype that contains all common fields
This commit is contained in:
127
pkg/onions/adproto/adproto.go
Normal file
127
pkg/onions/adproto/adproto.go
Normal file
@@ -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 "<hash>/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) }
|
||||||
61
pkg/onions/adproto/adproto_test.go
Normal file
61
pkg/onions/adproto/adproto_test.go
Normal file
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package splice
|
package splice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gookit/color"
|
"github.com/gookit/color"
|
||||||
"github.com/indra-labs/indra"
|
"github.com/indra-labs/indra"
|
||||||
@@ -10,7 +9,6 @@ import (
|
|||||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||||
magic2 "github.com/indra-labs/indra/pkg/engine/magic"
|
magic2 "github.com/indra-labs/indra/pkg/engine/magic"
|
||||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
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/indra-labs/indra/pkg/util/slice"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"net"
|
"net"
|
||||||
@@ -456,78 +454,78 @@ func (s *Splice) StoreCursor(c *int) *Splice {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Splice) String() (o string) {
|
//func (s *Splice) String() (o string) {
|
||||||
o = "splice:"
|
// o = "splice:"
|
||||||
seg := s.GetSlicesFromSegments()
|
// seg := s.GetSlicesFromSegments()
|
||||||
var prevString string
|
// var prevString string
|
||||||
for i := range seg {
|
// for i := range seg {
|
||||||
switch v := seg[i].(type) {
|
// switch v := seg[i].(type) {
|
||||||
case string:
|
// case string:
|
||||||
o += "\n" + v + " "
|
// o += "\n" + v + " "
|
||||||
prevString = v
|
// prevString = v
|
||||||
case slice.Bytes:
|
// case slice.Bytes:
|
||||||
if len(v) > 72 {
|
// if len(v) > 72 {
|
||||||
o += "\n "
|
// o += "\n "
|
||||||
}
|
// }
|
||||||
var oe string
|
// var oe string
|
||||||
for j := range v {
|
// for j := range v {
|
||||||
if (j)%4 == 0 && j != 0 {
|
// if (j)%4 == 0 && j != 0 {
|
||||||
oe += ""
|
// oe += ""
|
||||||
}
|
// }
|
||||||
if j == 0 {
|
// if j == 0 {
|
||||||
oe += ""
|
// oe += ""
|
||||||
}
|
// }
|
||||||
if v[j] >= '0' && v[j] <= '9' ||
|
// if v[j] >= '0' && v[j] <= '9' ||
|
||||||
v[j] >= 'a' && v[j] <= 'z' ||
|
// v[j] >= 'a' && v[j] <= 'z' ||
|
||||||
v[j] >= 'A' && v[j] <= 'Z' {
|
// v[j] >= 'A' && v[j] <= 'Z' {
|
||||||
oe += string(v[j])
|
// oe += string(v[j])
|
||||||
} else {
|
// } else {
|
||||||
oe += "."
|
// oe += "."
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if prevString == "magic" {
|
// if prevString == "magic" {
|
||||||
o += color.Red.Sprint(oe) + " "
|
// o += color.Red.Sprint(oe) + " "
|
||||||
} else {
|
// } else {
|
||||||
o += color.Gray.Sprint(oe) + " "
|
// o += color.Gray.Sprint(oe) + " "
|
||||||
}
|
// }
|
||||||
if prevString != "remainder" {
|
// if prevString != "remainder" {
|
||||||
hexed := hex.EncodeToString(v.ToBytes())
|
// hexed := hex.EncodeToString(v.ToBytes())
|
||||||
var oHexed string
|
// var oHexed string
|
||||||
var revHex string
|
// var revHex string
|
||||||
for {
|
// for {
|
||||||
if len(hexed) >= 8 {
|
// if len(hexed) >= 8 {
|
||||||
revHex, hexed = hexed[:8], hexed[8:]
|
// revHex, hexed = hexed[:8], hexed[8:]
|
||||||
oHexed += revHex + " "
|
// oHexed += revHex + " "
|
||||||
} else {
|
// } else {
|
||||||
oHexed += hexed
|
// oHexed += hexed
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
o += color.Gray.Sprint(color.Bold.Sprint(oHexed))
|
// o += color.Gray.Sprint(color.Bold.Sprint(oHexed))
|
||||||
}
|
// }
|
||||||
if prevString == "pubkey" {
|
// if prevString == "pubkey" {
|
||||||
var oo string
|
// var oo string
|
||||||
if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) {
|
// if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) {
|
||||||
o += "<error: " + s.E.Error() + " >"
|
// o += "<error: " + s.E.Error() + " >"
|
||||||
}
|
// }
|
||||||
oo = oo[3:]
|
// oo = oo[3:]
|
||||||
tmp := make(slice.Bytes, 0, len(oo))
|
// tmp := make(slice.Bytes, 0, len(oo))
|
||||||
tmp = append(tmp[:13], append([]byte("..."),
|
// tmp = append(tmp[:13], append([]byte("..."),
|
||||||
tmp[len(tmp)-8:]...)...)
|
// tmp[len(tmp)-8:]...)...)
|
||||||
oo = string(tmp)
|
// oo = string(tmp)
|
||||||
o += color.LightGreen.Sprint(" ", oo)
|
// o += color.LightGreen.Sprint(" ", oo)
|
||||||
}
|
// }
|
||||||
if prevString == "Keys" {
|
// if prevString == "Keys" {
|
||||||
var oo string
|
// var oo string
|
||||||
if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) {
|
// if oo, s.E = based32.Codec.Encode(v.ToBytes()); fails(s.E) {
|
||||||
o += "<error: " + s.E.Error() + " >"
|
// o += "<error: " + s.E.Error() + " >"
|
||||||
}
|
// }
|
||||||
o += color.LightBlue.Sprint(oo[:13])
|
// o += color.LightBlue.Sprint(oo[:13])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
|
|
||||||
func (s *Splice) Time(v time.Time) *Splice {
|
func (s *Splice) Time(v time.Time) *Splice {
|
||||||
slice.EncodeUint64(s.b[*s.c:s.c.Inc(slice.Uint64Len)], uint64(v.UnixNano()))
|
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
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Segments) String() (o string) {
|
//func (s Segments) String() (o string) {
|
||||||
for i := range s {
|
// for i := range s {
|
||||||
o += fmt.Sprintf("%s %d ", s[i].Name, s[i].Offset)
|
// o += fmt.Sprintf("%s %d ", s[i].Name, s[i].Offset)
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
|
|
||||||
func (s Segments) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s Segments) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|||||||
Reference in New Issue
Block a user