Skip to content
Snippets Groups Projects
Commit e956c580 authored by Richard T. Carback III's avatar Richard T. Carback III
Browse files

WIP api conversion

parent 30f1e3f2
Branches
Tags
4 merge requests!510Release,!207WIP: Client Restructure,!203Symmetric broadcast,!197WIP: Convert API to use new restructure
...@@ -9,9 +9,10 @@ package api ...@@ -9,9 +9,10 @@ package api
import ( import (
"encoding/binary" "encoding/binary"
"gitlab.com/elixxir/client/catalog"
"math/rand" "math/rand"
"gitlab.com/elixxir/client/catalog"
"github.com/cloudflare/circl/dh/sidh" "github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
...@@ -36,7 +37,7 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact, ...@@ -36,7 +37,7 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
message string) (id.Round, error) { message string) (id.Round, error) {
jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID) jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID)
if !c.network.GetHealthTracker().IsHealthy() { if !c.network.HealthTracker().IsHealthy() {
return 0, errors.New("Cannot request authenticated channel " + return 0, errors.New("Cannot request authenticated channel " +
"creation when the network is not healthy") "creation when the network is not healthy")
} }
......
This diff is collapsed.
...@@ -8,15 +8,19 @@ ...@@ -8,15 +8,19 @@
package api package api
import ( import (
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/client/interfaces/params" "gitlab.com/elixxir/client/interfaces/params"
"gitlab.com/elixxir/crypto/e2e" e2eCrypto "gitlab.com/elixxir/crypto/e2e"
"gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/id/ephemeral"
"time"
) )
//This holds all functions to send messages over the network //This holds all functions to send messages over the network
...@@ -24,11 +28,12 @@ import ( ...@@ -24,11 +28,12 @@ import (
// SendE2E sends an end-to-end payload to the provided recipient with // SendE2E sends an end-to-end payload to the provided recipient with
// the provided msgType. Returns the list of rounds in which parts of // the provided msgType. Returns the list of rounds in which parts of
// the message were sent or an error if it fails. // the message were sent or an error if it fails.
func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, func (c *Client) SendE2E(mt catalog.MessageType, recipient *id.ID,
e2e.MessageID, time.Time, error) { payload []byte, param e2e.Params) ([]id.Round,
jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient, e2eCrypto.MessageID, time.Time, error) {
m.MessageType, m.Payload) jww.INFO.Printf("SendE2E(%s, %d. %v)", recipient,
return c.network.SendE2E(m, param, nil) mt, payload)
return c.e2e.SendE2E(mt, recipient, payload, param)
} }
// SendUnsafe sends an unencrypted payload to the provided recipient // SendUnsafe sends an unencrypted payload to the provided recipient
...@@ -36,11 +41,12 @@ func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, ...@@ -36,11 +41,12 @@ func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round,
// of the message were sent or an error if it fails. // of the message were sent or an error if it fails.
// NOTE: Do not use this function unless you know what you are doing. // NOTE: Do not use this function unless you know what you are doing.
// This function always produces an error message in client logging. // This function always produces an error message in client logging.
func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round, func (c *Client) SendUnsafe(mt catalog.MessageType, recipient *id.ID,
payload []byte, param e2e.Params) ([]id.Round, time.Time,
error) { error) {
jww.INFO.Printf("SendUnsafe(%s, %d. %v)", m.Recipient, jww.INFO.Printf("SendUnsafe(%s, %d. %v)", recipient,
m.MessageType, m.Payload) mt, payload)
return c.network.SendUnsafe(m, param) return c.e2e.SendUnsafe(mt, recipient, payload, param)
} }
// SendCMIX sends a "raw" CMIX message payload to the provided // SendCMIX sends a "raw" CMIX message payload to the provided
...@@ -48,9 +54,11 @@ func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round, ...@@ -48,9 +54,11 @@ func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round,
// Returns the round ID of the round the payload was sent or an error // Returns the round ID of the round the payload was sent or an error
// if it fails. // if it fails.
func (c *Client) SendCMIX(msg format.Message, recipientID *id.ID, func (c *Client) SendCMIX(msg format.Message, recipientID *id.ID,
param params.CMIX) (id.Round, ephemeral.Id, error) { param cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
jww.INFO.Printf("Send(%s)", string(msg.GetContents())) jww.INFO.Printf("Send(%s)", string(msg.GetContents()))
return c.network.SendCMIX(msg, recipientID, param) return c.network.Send(recipientID, msg.GetKeyFP(),
message.GetDefaultService(recipientID),
msg.GetContents(), msg.GetMac(), param)
} }
// SendManyCMIX sends many "raw" CMIX message payloads to each of the // SendManyCMIX sends many "raw" CMIX message payloads to each of the
......
...@@ -9,19 +9,20 @@ package api ...@@ -9,19 +9,20 @@ package api
import ( import (
"encoding/binary" "encoding/binary"
"math/rand"
"regexp"
"runtime"
"strings"
"sync"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces/user" "gitlab.com/elixxir/client/storage/user"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/crypto/xx"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"math/rand"
"regexp"
"runtime"
"strings"
"sync"
) )
const ( const (
...@@ -30,7 +31,8 @@ const ( ...@@ -30,7 +31,8 @@ const (
) )
// createNewUser generates an identity for cMix // createNewUser generates an identity for cMix
func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.Info { func createNewUser(rng *fastRNG.StreamGenerator, cmix,
e2e *cyclic.Group) user.Info {
// CMIX Keygen // CMIX Keygen
var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey
...@@ -65,12 +67,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.I ...@@ -65,12 +67,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.I
stream.Close() stream.Close()
transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User) transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(),
transmissionSalt, id.User)
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User) receptionID, err := xx.NewID(receptionRsaKey.GetPublic(),
receptionSalt, id.User)
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
...@@ -98,13 +102,17 @@ func createDhKeys(rng *fastRNG.StreamGenerator, ...@@ -98,13 +102,17 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
go func() { go func() {
defer wg.Done() defer wg.Done()
var err error var err error
// DH Keygen rngStream := rng.GetStream()
// FIXME: Why 256 bits? -- this is spec but not explained, it has prime := e2e.GetPBytes()
// to do with optimizing operations on one side and still preserves // FIXME: Why 256 bits? -- this is spec but not
// decent security -- cite this. Why valid for BOTH e2e and cmix? // explained, it has to do with optimizing operations
stream := rng.GetStream() // on one side and still preserves decent security --
e2eKeyBytes, err = csprng.GenerateInGroup(e2e.GetPBytes(), 256, stream) // cite this. Why valid for BOTH e2e and cmix?
stream.Close() //keyLen := len(prime)
keyLen := 256
e2eKeyBytes, err = csprng.GenerateInGroup(prime, keyLen,
rngStream)
rngStream.Close()
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
...@@ -115,7 +123,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, ...@@ -115,7 +123,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
defer wg.Done() defer wg.Done()
var err error var err error
stream := rng.GetStream() stream := rng.GetStream()
transmissionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen) transmissionRsaKey, err = rsa.GenerateKey(stream,
rsa.DefaultRSABitLen)
stream.Close() stream.Close()
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
...@@ -126,7 +135,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, ...@@ -126,7 +135,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
defer wg.Done() defer wg.Done()
var err error var err error
stream := rng.GetStream() stream := rng.GetStream()
receptionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen) receptionRsaKey, err = rsa.GenerateKey(stream,
rsa.DefaultRSABitLen)
stream.Close() stream.Close()
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
...@@ -140,7 +150,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, ...@@ -140,7 +150,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
// TODO: Add precanned user code structures here. // TODO: Add precanned user code structures here.
// creates a precanned user // creates a precanned user
func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.Group) user.Info { func createPrecannedUser(precannedID uint, rng csprng.Source, cmix,
e2e *cyclic.Group) user.Info {
// DH Keygen // DH Keygen
// FIXME: Why 256 bits? -- this is spec but not explained, it has // FIXME: Why 256 bits? -- this is spec but not explained, it has
// to do with optimizing operations on one side and still preserves // to do with optimizing operations on one side and still preserves
...@@ -178,7 +189,8 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic. ...@@ -178,7 +189,8 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.
// createNewVanityUser generates an identity for cMix // createNewVanityUser generates an identity for cMix
// The identity's ReceptionID is not random but starts with the supplied prefix // The identity's ReceptionID is not random but starts with the supplied prefix
func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.Info { func createNewVanityUser(rng csprng.Source, cmix,
e2e *cyclic.Group, prefix string) user.Info {
// DH Keygen // DH Keygen
// FIXME: Why 256 bits? -- this is spec but not explained, it has // FIXME: Why 256 bits? -- this is spec but not explained, it has
// to do with optimizing operations on one side and still preserves // to do with optimizing operations on one side and still preserves
...@@ -203,7 +215,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri ...@@ -203,7 +215,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
if n != SaltSize { if n != SaltSize {
jww.FATAL.Panicf("transmissionSalt size too small: %d", n) jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
} }
transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User) transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(),
transmissionSalt, id.User)
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
...@@ -213,7 +226,9 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri ...@@ -213,7 +226,9 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID // just in case more than one go routine tries to access
// receptionSalt and receptionID
var mu sync.Mutex
done := make(chan struct{}) done := make(chan struct{})
found := make(chan bool) found := make(chan bool)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
...@@ -234,7 +249,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri ...@@ -234,7 +249,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
if match == false { if match == false {
jww.FATAL.Panicf("Prefix contains non-Base64 characters") jww.FATAL.Panicf("Prefix contains non-Base64 characters")
} }
jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores) jww.INFO.Printf("Vanity userID generation started. Prefix: %s "+
"Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores)
for w := 0; w < cores; w++ { for w := 0; w < cores; w++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
...@@ -245,14 +261,20 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri ...@@ -245,14 +261,20 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
defer wg.Done() defer wg.Done()
return return
default: default:
n, err = csprng.NewSystemRNG().Read(rSalt) n, err = csprng.NewSystemRNG().Read(
rSalt)
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
if n != SaltSize { if n != SaltSize {
jww.FATAL.Panicf("receptionSalt size too small: %d", n) jww.FATAL.Panicf(
} "receptionSalt size "+
rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User) "too small: %d",
n)
}
rID, err := xx.NewID(
receptionRsaKey.GetPublic(),
rSalt, id.User)
if err != nil { if err != nil {
jww.FATAL.Panicf(err.Error()) jww.FATAL.Panicf(err.Error())
} }
...@@ -273,7 +295,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri ...@@ -273,7 +295,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
} }
}() }()
} }
// wait for a solution then close the done channel to signal the workers to exit // wait for a solution then close the done channel to signal
// the workers to exit
<-found <-found
close(done) close(done)
wg.Wait() wg.Wait()
......
...@@ -60,4 +60,19 @@ type State interface { ...@@ -60,4 +60,19 @@ type State interface {
// CallAllReceivedRequests will iterate through all pending contact requests // CallAllReceivedRequests will iterate through all pending contact requests
// and replay them on the callbacks. // and replay them on the callbacks.
CallAllReceivedRequests() CallAllReceivedRequests()
// DeleteRequest deletes sent or received requests for a
// specific partner ID.
DeleteRequest(partnerID *id.ID) error
// DeleteAllRequests clears all requests from client's auth storage.
DeleteAllRequests() error
// DeleteSentRequests clears all sent requests from client's auth
// storage.
DeleteSentRequests() error
// DeleteReceiveRequests clears all received requests from client's auth
// storage.
DeleteReceiveRequests() error
} }
...@@ -9,6 +9,9 @@ package auth ...@@ -9,6 +9,9 @@ package auth
import ( import (
"fmt" "fmt"
"io"
"strings"
"github.com/cloudflare/circl/dh/sidh" "github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
...@@ -23,8 +26,6 @@ import ( ...@@ -23,8 +26,6 @@ import (
"gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/fact"
"gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"io"
"strings"
) )
const terminator = ";" const terminator = ";"
...@@ -199,3 +200,19 @@ func createRequestAuth(sender *id.ID, payload, ownership []byte, myDHPriv, ...@@ -199,3 +200,19 @@ func createRequestAuth(sender *id.ID, payload, ownership []byte, myDHPriv,
return &baseFmt, mac, nil return &baseFmt, mac, nil
} }
func (s *state) DeleteRequest(partnerID *id.ID) error {
return s.store.DeleteRequest(partnerID)
}
func (s *state) DeleteAllRequests() error {
return s.store.DeleteAllRequests()
}
func (s *state) DeleteSentRequests() error {
return s.store.DeleteSentRequests()
}
func (s *state) DeleteReceiveRequests() error {
return s.store.DeleteReceiveRequests()
}
...@@ -11,6 +11,11 @@ package cmix ...@@ -11,6 +11,11 @@ package cmix
// and intra-client state are accessible through the context object. // and intra-client state are accessible through the context object.
import ( import (
"math"
"strconv"
"sync/atomic"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/elixxir/client/cmix/address" "gitlab.com/elixxir/client/cmix/address"
"gitlab.com/elixxir/client/cmix/gateway" "gitlab.com/elixxir/client/cmix/gateway"
...@@ -30,10 +35,6 @@ import ( ...@@ -30,10 +35,6 @@ import (
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/id/ephemeral"
"gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/ndf"
"math"
"strconv"
"sync/atomic"
"time"
) )
// fakeIdentityRange indicates the range generated between 0 (most current) and // fakeIdentityRange indicates the range generated between 0 (most current) and
...@@ -94,7 +95,8 @@ func NewClient(params Params, comms *commClient.Comms, session storage.Session, ...@@ -94,7 +95,8 @@ func NewClient(params Params, comms *commClient.Comms, session storage.Session,
// Start network instance // Start network instance
instance, err := commNetwork.NewInstance( instance, err := commNetwork.NewInstance(
comms.ProtoComms, ndf, nil, nil, commNetwork.None, params.FastPolling) comms.ProtoComms, ndf, nil, nil, commNetwork.None,
params.FastPolling)
if err != nil { if err != nil {
return nil, errors.WithMessage( return nil, errors.WithMessage(
err, "failed to create network client") err, "failed to create network client")
......
...@@ -9,10 +9,11 @@ package event ...@@ -9,10 +9,11 @@ package event
import ( import (
"fmt" "fmt"
"sync"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/stoppable"
"sync"
) )
// ReportableEvent is used to surface events to client users. // ReportableEvent is used to surface events to client users.
...@@ -35,7 +36,7 @@ type eventManager struct { ...@@ -35,7 +36,7 @@ type eventManager struct {
eventCbs sync.Map eventCbs sync.Map
} }
func newEventManager() *eventManager { func NewEventManager() Manager {
return &eventManager{ return &eventManager{
eventCh: make(chan reportableEvent, 1000), eventCh: make(chan reportableEvent, 1000),
} }
...@@ -77,7 +78,7 @@ func (e *eventManager) UnregisterEventCallback(name string) { ...@@ -77,7 +78,7 @@ func (e *eventManager) UnregisterEventCallback(name string) {
e.eventCbs.Delete(name) e.eventCbs.Delete(name)
} }
func (e *eventManager) eventService() (stoppable.Stoppable, error) { func (e *eventManager) EventService() (stoppable.Stoppable, error) {
stop := stoppable.NewSingle("EventReporting") stop := stoppable.NewSingle("EventReporting")
go e.reportEventsHandler(stop) go e.reportEventsHandler(stop)
return stop, nil return stop, nil
......
...@@ -25,7 +25,7 @@ func TestEventReporting(t *testing.T) { ...@@ -25,7 +25,7 @@ func TestEventReporting(t *testing.T) {
evts = append(evts, evt) evts = append(evts, evt)
} }
evtMgr := newEventManager() evtMgr := NewEventManager()
stop, _ := evtMgr.eventService() stop, _ := evtMgr.eventService()
// Register a callback // Register a callback
err := evtMgr.RegisterEventCallback("test", myCb) err := evtMgr.RegisterEventCallback("test", myCb)
......
...@@ -7,10 +7,13 @@ ...@@ -7,10 +7,13 @@
package event package event
import "gitlab.com/elixxir/client/stoppable"
// Callback defines the callback functions for client event reports // Callback defines the callback functions for client event reports
type Callback func(priority int, category, evtType, details string) type Callback func(priority int, category, evtType, details string)
// Manager reporting api (used internally) // Manager reporting api (used internally)
type Manager interface { type Manager interface {
Report(priority int, category, evtType, details string) Report(priority int, category, evtType, details string)
EventService() (stoppable.Stoppable, error)
} }
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
package interfaces package interfaces
import ( import (
"time"
"gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/comms/network"
"gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/ndf"
"time"
"gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/interfaces/params" "gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/stoppable"
"gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/format"
...@@ -29,24 +30,26 @@ type NetworkManager interface { ...@@ -29,24 +30,26 @@ type NetworkManager interface {
// Only one follower may run at a time. // Only one follower may run at a time.
Follow(report ClientErrorReport) (stoppable.Stoppable, error) Follow(report ClientErrorReport) (stoppable.Stoppable, error)
/*===Sending==============================================================*/ /*===Sending==========================================================*/
// SendCMIX sends a "raw" CMIX message payload to the provided recipient. // SendCMIX sends a "raw" CMIX message payload to the provided
// Returns the round ID of the round the payload was sent or an error // recipient. Returns the round ID of the round the payload
// if it fails. // was sent or an error if it fails.
SendCMIX(message format.Message, recipient *id.ID, p params.CMIX) ( SendCMIX(message format.Message, recipient *id.ID, p cmix.Params) (
id.Round, ephemeral.Id, error) id.Round, ephemeral.Id, error)
// SendManyCMIX sends many "raw" cMix message payloads to each of the provided // SendManyCMIX sends many "raw" cMix message payloads to each
// recipients. Used to send messages in group chats. Metadata is NOT as well // of the provided recipients. Used to send messages in group
// protected with this call and can leak data about yourself. Should be // chats. Metadata is NOT as well protected with this call and
// replaced with multiple uses of SendCmix in most cases. Returns the round // can leak data about yourself. Should be replaced with
// ID of the round the payload was sent or an error if it fails. // multiple uses of SendCmix in most cases. Returns the round
// ID of the round the payload was sent or an error if it
// fails.
// WARNING: Potentially Unsafe // WARNING: Potentially Unsafe
SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) ( SendManyCMIX(messages []cmix.TargetedCmixMessage, p cmix.Params) (
id.Round, []ephemeral.Id, error) id.Round, []ephemeral.Id, error)
/*===Message Reception====================================================*/ /*===Message Reception================================================*/
/* Identities are all network identites which the client is currently /* Identities are all network identites which the client is currently
trying to pick up message on. An identity must be added trying to pick up message on. An identity must be added
to receive messages, fake ones will be used to poll the network to receive messages, fake ones will be used to poll the network
...@@ -60,23 +63,24 @@ type NetworkManager interface { ...@@ -60,23 +63,24 @@ type NetworkManager interface {
// RemoveIdentity removes a currently tracked identity. // RemoveIdentity removes a currently tracked identity.
RemoveIdentity(id *id.ID) RemoveIdentity(id *id.ID)
/* Fingerprints are the primary mechanism of identifying a picked up /* Fingerprints are the primary mechanism of identifying a
message over cMix. They are a unique one time use 255 bit vector generally picked up message over cMix. They are a unique one time use
associated with a specific encryption key, but can be used for an 255 bit vector generally associated with a specific encryption
alternative protocol.When registering a fingerprint, a MessageProcessor key, but can be used for an alternative protocol.When
is registered to handle the message.*/ registering a fingerprint, a MessageProcessor is registered to
handle the message.*/
// AddFingerprint - Adds a fingerprint which will be handled by a // AddFingerprint - Adds a fingerprint which will be handled by a
// specific processor for messages received by the given identity // specific processor for messages received by the given identity
AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
mp MessageProcessor) error mp message.Processor) error
// DeleteFingerprint deletes a single fingerprint associated with the given // DeleteFingerprint deletes a single fingerprint associated
// identity if it exists // with the given identity if it exists
DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
// DeleteClientFingerprints deletes al fingerprint associated with the given // DeleteClientFingerprints deletes al fingerprint associated
// identity if it exists // with the given identity if it exists
DeleteClientFingerprints(identity *id.ID) DeleteClientFingerprints(identity *id.ID)
/* trigger - predefined hash based tags appended to all cMix messages /* trigger - predefined hash based tags appended to all cMix messages
...@@ -87,60 +91,72 @@ type NetworkManager interface { ...@@ -87,60 +91,72 @@ type NetworkManager interface {
notifications system, or can be used to implement custom non fingerprint notifications system, or can be used to implement custom non fingerprint
processing of payloads. I.E. key negotiation, broadcast negotiation processing of payloads. I.E. key negotiation, broadcast negotiation
A tag is appended to the message of the format tag = H(H(messageContents), A tag is appended to the message of the format tag =
preimage) and trial hashing is used to determine if a message adheres to a H(H(messageContents), preimage) and trial hashing is used to
tag. determine if a message adheres to a tag.
WARNING: If a preimage is known by an adversary, they can determine which
messages are for the client on reception (which is normally hidden due to
collision between ephemeral IDs.
Due to the extra overhead of trial hashing, triggers are processed after fingerprints. WARNING: If a preimage is known by an adversary, they can
If a fingerprint match occurs on the message, triggers will not be handled. determine which messages are for the client on reception
(which is normally hidden due to collision between ephemeral
IDs.
Triggers are address to the session. When starting a new client, all triggers must be Due to the extra overhead of trial hashing, triggers are
re-added before StartNetworkFollower is called. processed after fingerprints. If a fingerprint match occurs
on the message, triggers will not be handled.
Triggers are address to the session. When starting a new
client, all triggers must be re-added before
StartNetworkFollower is called.
*/ */
// AddTrigger - Adds a trigger which can call a message handing function or // AddTrigger - Adds a trigger which can call a message
// be used for notifications. Multiple triggers can be registered for the // handing function or be used for notifications. Multiple
// same preimage. // triggers can be registered for the same preimage.
// preimage - the preimage which is triggered on // preimage - the preimage which is triggered on
// type - a descriptive string of the trigger. Generally used in notifications // type - a descriptive string of the trigger. Generally
// source - a byte buffer of related data. Generally used in notifications. // used in notifications
// source - a byte buffer of related data. Generally used in
// notifications.
// Example: Sender ID // Example: Sender ID
AddTrigger(identity *id.ID, newTrigger Trigger, response MessageProcessor) AddTrigger(identity *id.ID, newTrigger message.Service,
response message.Processor)
// DeleteTrigger - If only a single response is associated with the // DeleteTrigger - If only a single response is associated with the
// preimage, the entire preimage is removed. If there is more than one // preimage, the entire preimage is removed. If there is more than one
// response, only the given response is removed if nil is passed in for // response, only the given response is removed if nil is passed in for
// response, all triggers for the preimage will be removed // response, all triggers for the preimage will be removed
DeleteTrigger(identity *id.ID, preimage Preimage, response MessageProcessor) error DeleteTrigger(identity *id.ID, preimage Preimage,
response message.Processor) error
// DeleteClientTriggers - deletes all triggers assoseated with the given identity // DeleteClientTriggers - deletes all triggers assoseated with
// the given identity
DeleteClientTriggers(identity *id.ID) DeleteClientTriggers(identity *id.ID)
// TrackTriggers - Registers a callback which will get called every time triggers change. // TrackTriggers - Registers a callback which will get called
// every time triggers change.
// It will receive the triggers list every time it is modified. // It will receive the triggers list every time it is modified.
// Will only get callbacks while the Network Follower is running. // Will only get callbacks while the Network Follower is running.
// Multiple trackTriggers can be registered // Multiple trackTriggers can be registered
TrackTriggers(TriggerTracker) TrackServices(message.ServicesTracker)
/* In inProcess */ /* In inProcess */
// it is possible to receive a message over cMix before the fingerprints or // it is possible to receive a message over cMix before the
// triggers are registered. As a result, when handling fails, messages are // fingerprints or triggers are registered. As a result, when
// put in the inProcess que for a set number of retries. // handling fails, messages are put in the inProcess que for a
// set number of retries.
// CheckInProgressMessages - retry processing all messages in check in // CheckInProgressMessages - retry processing all messages in check in
// progress messages. Call this after adding fingerprints or triggers // progress messages. Call this after adding fingerprints or triggers
//while the follower is running. //while the follower is running.
CheckInProgressMessages() CheckInProgressMessages()
/*===Nodes================================================================*/ /*===Nodes============================================================*/
/* Keys must be registed with nodes in order to send messages throug them. /* Keys must be registed with nodes in order to send messages
this process is in general automatically handled by the Network Manager*/ throug them. this process is in general automatically handled
by the Network Manager*/
// HasNode can be used to determine if a keying relationship exists with a // HasNode can be used to determine if a keying relationship
// node. // exists with a node.
HasNode(nid *id.ID) bool HasNode(nid *id.ID) bool
// NumRegisteredNodes Returns the total number of nodes we have a keying // NumRegisteredNodes Returns the total number of nodes we have a keying
...@@ -150,7 +166,7 @@ type NetworkManager interface { ...@@ -150,7 +166,7 @@ type NetworkManager interface {
// Triggers the generation of a keying relationship with a given node // Triggers the generation of a keying relationship with a given node
TriggerNodeRegistration(nid *id.ID) TriggerNodeRegistration(nid *id.ID)
/*===Historical Rounds====================================================*/ /*===Historical Rounds================================================*/
/* A complete set of round info is not kept on the client, and sometimes /* A complete set of round info is not kept on the client, and sometimes
the network will need to be queried to get round info. Historical rounds the network will need to be queried to get round info. Historical rounds
is the system internal to the Network Manager to do this. is the system internal to the Network Manager to do this.
...@@ -158,52 +174,59 @@ type NetworkManager interface { ...@@ -158,52 +174,59 @@ type NetworkManager interface {
// LookupHistoricalRound - looks up the passed historical round on the // LookupHistoricalRound - looks up the passed historical round on the
// network // network
LookupHistoricalRound(rid id.Round, callback func(info *mixmessages.RoundInfo, LookupHistoricalRound(rid id.Round,
callback func(info *mixmessages.RoundInfo,
success bool)) error success bool)) error
/*===Sender===============================================================*/ /*===Sender===========================================================*/
/* The sender handles sending comms to the network. It tracks connections to /* The sender handles sending comms to the network. It tracks
gateways and handles proxying to gateways for targeted comms. It can be connections to gateways and handles proxying to gateways for
used externally to contact gateway directly, bypassing the majority of targeted comms. It can be used externally to contact gateway
the network package*/ directly, bypassing the majority of the network package*/
// SendToAny can be used to send the comm to any gateway in the network. // SendToAny can be used to send the comm to any gateway in the network.
SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error) SendToAny(sendFunc func(host *connect.Host) (interface{}, error),
stop *stoppable.Single) (interface{}, error)
// SendToPreferred sends to a specific gateway, doing so through another // SendToPreferred sends to a specific gateway, doing so through another
// gateway as a proxy if not directly connected. // gateway as a proxy if not directly connected.
SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host, SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host,
target *id.ID, timeout time.Duration) (interface{}, error), target *id.ID, timeout time.Duration) (interface{}, error),
stop *stoppable.Single, timeout time.Duration) (interface{}, error) stop *stoppable.Single, timeout time.Duration) (interface{},
error)
// SetGatewayFilter sets a function which will be used to filter gateways // SetGatewayFilter sets a function which will be used to
// before connecting. // filter gateways before connecting.
SetGatewayFilter(f func(map[id.ID]int, SetGatewayFilter(f func(map[id.ID]int,
*ndf.NetworkDefinition) map[id.ID]int) *ndf.NetworkDefinition) map[id.ID]int)
// GetHostParams - returns the host params used when connectign to gateways // GetHostParams - returns the host params used when
// connectign to gateways
GetHostParams() connect.HostParams GetHostParams() connect.HostParams
/*===Address Space========================================================*/ /*===Address Space====================================================*/
// The network compasses identities into a smaller address space to cause // The network compasses identities into a smaller address
// collisions and hide the actual recipient of messages. These functions // space to cause collisions and hide the actual recipient of
// allow for the tracking of this addresses space. In general, address space // messages. These functions allow for the tracking of this
// issues are completely handled by the network package // addresses space. In general, address space issues are
// completely handled by the network package
// GetAddressSpace GetAddressSize returns the current address size of IDs. Blocks until an // GetAddressSpace GetAddressSize returns the current address
// address size is known. // size of IDs. Blocks until an address size is known.
GetAddressSpace() uint8 GetAddressSpace() uint8
// RegisterAddressSpaceNotification returns a channel that will trigger for // RegisterAddressSpaceNotification returns a channel that
// every address space size update. The provided tag is the unique ID for // will trigger for every address space size update. The
// the channel. Returns an error if the tag is already used. // provided tag is the unique ID for the channel. Returns an
// error if the tag is already used.
RegisterAddressSpaceNotification(tag string) (chan uint8, error) RegisterAddressSpaceNotification(tag string) (chan uint8, error)
// UnregisterAddressSpaceNotification stops broadcasting address space size // UnregisterAddressSpaceNotification stops broadcasting
// updates on the channel with the specified tag. // address space size updates on the channel with the
// specified tag.
UnregisterAddressSpaceNotification(tag string) UnregisterAddressSpaceNotification(tag string)
/*===Accessors============================================================*/ /*===Accessors========================================================*/
// GetInstance returns the network instance object, which tracks the // GetInstance returns the network instance object, which tracks the
// state of the network // state of the network
...@@ -218,8 +241,3 @@ type NetworkManager interface { ...@@ -218,8 +241,3 @@ type NetworkManager interface {
} }
type Preimage [32]byte type Preimage [32]byte
type ClientErrorReport func(source, message, trace string)
//for use in key exchange which needs to be callable inside of network
///type SendE2E func(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error)
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package interfaces
import (
"gitlab.com/elixxir/client/interfaces/message"
"gitlab.com/elixxir/client/switchboard"
"gitlab.com/xx_network/primitives/id"
)
// public switchboard interface which only allows registration and does not
// allow speaking messages
type Switchboard interface {
// Registers a new listener. Returns the ID of the new listener.
// Keep this around if you want to be able to delete the listener later.
//
// name is used for debug printing and not checked for uniqueness
//
// user: 0 for all, or any user ID to listen for messages from a particular
// user. 0 can be id.ZeroUser or id.ZeroID
// messageType: 0 for all, or any message type to listen for messages of
// that type. 0 can be Receive.AnyType
// newListener: something implementing the Listener interface. Do not
// pass nil to this.
//
// If a message matches multiple listeners, all of them will hear the
// message.
RegisterListener(user *id.ID, messageType message.Type,
newListener switchboard.Listener) switchboard.ListenerID
// Registers a new listener built around the passed function.
// Returns the ID of the new listener.
// Keep this around if you want to be able to delete the listener later.
//
// name is used for debug printing and not checked for uniqueness
//
// user: 0 for all, or any user ID to listen for messages from a particular
// user. 0 can be id.ZeroUser or id.ZeroID
// messageType: 0 for all, or any message type to listen for messages of
// that type. 0 can be Receive.AnyType
// newListener: a function implementing the ListenerFunc function type.
// Do not pass nil to this.
//
// If a message matches multiple listeners, all of them will hear the
// message.
RegisterFunc(name string, user *id.ID, messageType message.Type,
newListener switchboard.ListenerFunc) switchboard.ListenerID
// Registers a new listener built around the passed channel.
// Returns the ID of the new listener.
// Keep this around if you want to be able to delete the listener later.
//
// name is used for debug printing and not checked for uniqueness
//
// user: 0 for all, or any user ID to listen for messages from a particular
// user. 0 can be id.ZeroUser or id.ZeroID
// messageType: 0 for all, or any message type to listen for messages of
// that type. 0 can be Receive.AnyType
// newListener: an item channel.
// Do not pass nil to this.
//
// If a message matches multiple listeners, all of them will hear the
// message.
RegisterChannel(name string, user *id.ID, messageType message.Type,
newListener chan message.Receive) switchboard.ListenerID
// Unregister removes the listener with the specified ID so it will no
// longer get called
Unregister(listenerID switchboard.ListenerID)
}
...@@ -17,10 +17,10 @@ func TestSession_SetGetNDF(t *testing.T) { ...@@ -17,10 +17,10 @@ func TestSession_SetGetNDF(t *testing.T) {
testNdf := getNDF() testNdf := getNDF()
sess.SetNDF(testNdf) sess.SetNDF(testNdf)
if !reflect.DeepEqual(testNdf, sess.ndf) { if !reflect.DeepEqual(testNdf, sess.GetNDF()) {
t.Errorf("SetNDF error: "+ t.Errorf("SetNDF error: "+
"Unexpected value after setting ndf:"+ "Unexpected value after setting ndf:"+
"Expected: %v\n\tReceived: %v", testNdf, sess.ndf) "Expected: %v\n\tReceived: %v", testNdf, sess.GetNDF())
} }
receivedNdf := sess.GetNDF() receivedNdf := sess.GetNDF()
......
...@@ -10,15 +10,15 @@ ...@@ -10,15 +10,15 @@
package storage package storage
import ( import (
"gitlab.com/elixxir/client/storage/utility"
"gitlab.com/xx_network/crypto/large"
"sync" "sync"
"testing" "testing"
"time" "time"
"gitlab.com/elixxir/client/storage/utility"
"gitlab.com/xx_network/crypto/large"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
userInterface "gitlab.com/elixxir/client/interfaces/user"
"gitlab.com/elixxir/client/storage/clientVersion" "gitlab.com/elixxir/client/storage/clientVersion"
"gitlab.com/elixxir/client/storage/user" "gitlab.com/elixxir/client/storage/user"
"gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/client/storage/versioned"
...@@ -60,7 +60,7 @@ type Session interface { ...@@ -60,7 +60,7 @@ type Session interface {
IsPrecanned() bool IsPrecanned() bool
SetUsername(username string) error SetUsername(username string) error
GetUsername() (string, error) GetUsername() (string, error)
PortableUserInfo() userInterface.Info PortableUserInfo() user.Info
GetTransmissionRegistrationValidationSignature() []byte GetTransmissionRegistrationValidationSignature() []byte
GetReceptionRegistrationValidationSignature() []byte GetReceptionRegistrationValidationSignature() []byte
GetRegistrationTimestamp() time.Time GetRegistrationTimestamp() time.Time
...@@ -103,7 +103,7 @@ func initStore(baseDir, password string) (*session, error) { ...@@ -103,7 +103,7 @@ func initStore(baseDir, password string) (*session, error) {
} }
// Creates new UserData in the session // Creates new UserData in the session
func New(baseDir, password string, u userInterface.Info, func New(baseDir, password string, u user.Info,
currentVersion version.Version, cmixGrp, e2eGrp *cyclic.Group) (Session, error) { currentVersion version.Version, cmixGrp, e2eGrp *cyclic.Group) (Session, error) {
s, err := initStore(baseDir, password) s, err := initStore(baseDir, password)
......
package user
import "gitlab.com/elixxir/client/interfaces/user"
func (u *User) PortableUserInfo() user.Info {
ci := u.CryptographicIdentity
return user.Info{
TransmissionID: ci.GetTransmissionID().DeepCopy(),
TransmissionSalt: copySlice(ci.GetTransmissionSalt()),
TransmissionRSA: ci.GetTransmissionRSA(),
ReceptionID: ci.GetReceptionID().DeepCopy(),
RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(),
ReceptionSalt: copySlice(ci.GetReceptionSalt()),
ReceptionRSA: ci.GetReceptionRSA(),
Precanned: ci.IsPrecanned(),
//fixme: set these in the e2e layer, the command line layer
//needs more logical seperation so this can be removed
E2eDhPrivateKey: nil,
E2eDhPublicKey: nil,
}
}
func copySlice(s []byte) []byte {
n := make([]byte, len(s))
copy(n, s)
return n
}
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package user
import (
"gitlab.com/elixxir/crypto/backup"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/primitives/fact"
"gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id"
)
type Proto struct {
//General Identity
TransmissionID *id.ID
TransmissionSalt []byte
TransmissionRSA *rsa.PrivateKey
ReceptionID *id.ID
ReceptionSalt []byte
ReceptionRSA *rsa.PrivateKey
Precanned bool
// Timestamp in which user has registered with the network
RegistrationTimestamp int64
RegCode string
TransmissionRegValidationSig []byte
ReceptionRegValidationSig []byte
//e2e Identity
E2eDhPrivateKey *cyclic.Int
E2eDhPublicKey *cyclic.Int
}
type Info struct {
//General Identity
TransmissionID *id.ID
TransmissionSalt []byte
TransmissionRSA *rsa.PrivateKey
ReceptionID *id.ID
ReceptionSalt []byte
ReceptionRSA *rsa.PrivateKey
Precanned bool
// Timestamp in which user has registered with the network
RegistrationTimestamp int64
//e2e Identity
E2eDhPrivateKey *cyclic.Int
E2eDhPublicKey *cyclic.Int
}
func (u Info) GetContact() contact.Contact {
return contact.Contact{
ID: u.ReceptionID.DeepCopy(),
DhPubKey: u.E2eDhPublicKey,
Facts: make([]fact.Fact, 0),
}
}
func NewUserFromProto(proto *Proto) Info {
return Info{
TransmissionID: proto.TransmissionID,
TransmissionSalt: proto.TransmissionSalt,
TransmissionRSA: proto.TransmissionRSA,
ReceptionID: proto.ReceptionID,
ReceptionSalt: proto.ReceptionSalt,
ReceptionRSA: proto.ReceptionRSA,
Precanned: proto.Precanned,
RegistrationTimestamp: proto.RegistrationTimestamp,
E2eDhPrivateKey: proto.E2eDhPrivateKey,
E2eDhPublicKey: proto.E2eDhPublicKey,
}
}
func NewUserFromBackup(backup *backup.Backup) Info {
return Info{
TransmissionID: backup.TransmissionIdentity.ComputedID,
TransmissionSalt: backup.TransmissionIdentity.Salt,
TransmissionRSA: backup.TransmissionIdentity.RSASigningPrivateKey,
ReceptionID: backup.ReceptionIdentity.ComputedID,
ReceptionSalt: backup.ReceptionIdentity.Salt,
ReceptionRSA: backup.ReceptionIdentity.RSASigningPrivateKey,
Precanned: false,
RegistrationTimestamp: backup.RegistrationTimestamp,
E2eDhPrivateKey: backup.ReceptionIdentity.DHPrivateKey,
E2eDhPublicKey: backup.ReceptionIdentity.DHPublicKey,
}
}
func (u *User) PortableUserInfo() Info {
ci := u.CryptographicIdentity
return Info{
TransmissionID: ci.GetTransmissionID().DeepCopy(),
TransmissionSalt: copySlice(ci.GetTransmissionSalt()),
TransmissionRSA: ci.GetTransmissionRSA(),
ReceptionID: ci.GetReceptionID().DeepCopy(),
RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(),
ReceptionSalt: copySlice(ci.GetReceptionSalt()),
ReceptionRSA: ci.GetReceptionRSA(),
Precanned: ci.IsPrecanned(),
//fixme: set these in the e2e layer, the command line layer
//needs more logical seperation so this can be removed
E2eDhPrivateKey: nil,
E2eDhPublicKey: nil,
}
}
func copySlice(s []byte) []byte {
n := make([]byte, len(s))
copy(n, s)
return n
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment