Files
indra/pkg/onions/adintro/adintro.go

144 lines
2.8 KiB
Go

package adintro
import (
"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"
"net/netip"
"reflect"
"time"
"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/util/slice"
"github.com/indra-labs/indra/pkg/util/splice"
)
var (
log = log2.GetLogger()
fails = log.E.Chk
)
const (
Magic = "inad"
Len = adproto.Len + splice.AddrLen + 1 + slice.Uint16Len + slice.Uint32Len
)
type Ad struct {
adproto.Ad
AddrPort *netip.AddrPort // Introducer address.
Port uint16 // Well known port of protocol available.
RelayRate uint32 // mSat/Mb
}
var _ coding.Codec = &Ad{}
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).
ReadAddrPort(&x.AddrPort).
ReadUint32(&x.RelayRate).
ReadUint16(&x.Port).
ReadTime(&x.Expiry).
ReadSignature(&x.Sig)
return
}
func (x *Ad) Encode(s *splice.Splice) (e error) {
log.T.S("encoding", reflect.TypeOf(x), x)
x.Splice(s)
return
}
func (x *Ad) GetOnion() interface{} { return x }
func (x *Ad) Len() int { return Len }
func (x *Ad) Magic() string { return Magic }
func (x *Ad) Splice(s *splice.Splice) {
x.SpliceNoSig(s)
s.Signature(x.Sig)
}
func (x *Ad) SpliceNoSig(s *splice.Splice) {
IntroSplice(s, x.ID, x.Key, x.AddrPort, x.RelayRate, x.Port, x.Expiry)
}
func (x *Ad) Validate() bool {
s := splice.New(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) && x.Expiry.After(time.Now()) {
return true
}
return false
}
func IntroSplice(
s *splice.Splice,
id nonce.ID,
key *crypto.Pub,
ap *netip.AddrPort,
relayRate uint32,
port uint16,
expires time.Time,
) {
s.Magic(Magic).
ID(id).
Pubkey(key).
AddrPort(ap).
Uint32(relayRate).
Uint16(port).
Time(expires)
}
func New(
id nonce.ID,
key *crypto.Prv,
ap *netip.AddrPort,
relayRate uint32,
port uint16,
expires time.Time,
) (in *Ad) {
pk := crypto.DerivePub(key)
in = &Ad{
Ad: adproto.Ad{
ID: id,
Key: pk,
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
}
func init() { reg.Register(Magic, introGen) }
func introGen() coding.Codec { return &Ad{} }