diff --git a/bindings/authenticatedConnection.go b/bindings/authenticatedConnection.go index 33aac039b7bea7ff91e5f021103e22442bc615ba..3cd2fcd009b7d47160e9002b60b4844ff1d43ade 100644 --- a/bindings/authenticatedConnection.go +++ b/bindings/authenticatedConnection.go @@ -34,7 +34,6 @@ func (_ *AuthenticatedConnection) IsAuthenticated() bool { // ConnectWithAuthentication is called by the client (i.e., the one establishing // connection with the server). Once a connect.Connection has been established // with the server, it then authenticates their identity to the server. -// accepts a marshalled ReceptionIdentity and contact.Contact object func (c *Cmix) ConnectWithAuthentication(e2eId int, recipientContact, e2eParamsJSON []byte) (*AuthenticatedConnection, error) { if len(e2eParamsJSON) == 0 { diff --git a/bindings/backup.go b/bindings/backup.go index 2c5c24560184fe5d1f121e05b8df5de98ce1fc23..b7756fccb06b3df2b25f6ab5da3aa06f7d1e6313 100644 --- a/bindings/backup.go +++ b/bindings/backup.go @@ -55,7 +55,7 @@ type UpdateBackupFunc interface { // backup. Users of this function should delete the storage directory on error. // Users of this function should call LoadCmix as normal once this call succeeds. // -// Params +// Parameters: // - ndfJSON - JSON of the NDF. // - storageDir - directory for the storage files. // - sessionPassword - password to decrypt the data in the storageDir. @@ -92,10 +92,11 @@ func NewCmixFromBackup(ndfJSON, storageDir, backupPassphrase string, // InitializeBackup creates a bindings-layer Backup object. // -// Params +// Parameters: // - e2eID - ID of the E2e object in the e2e tracker. // - udID - ID of the UserDiscovery object in the ud tracker. -// - backupPassPhrase - backup passphrase provided by the user. Used to decrypt backup. +// - backupPassPhrase - backup passphrase provided by the user. Used to decrypt +// backup. // - cb - the callback to be called when a backup is triggered. func InitializeBackup(e2eID, udID int, backupPassPhrase string, cb UpdateBackupFunc) (*Backup, error) { @@ -129,7 +130,7 @@ func InitializeBackup(e2eID, udID int, backupPassPhrase string, // To start the backup for the first time or to use a new password, use // InitializeBackup. // -// Params +// Parameters: // - e2eID - ID of the E2e object in the e2e tracker. // - udID - ID of the UserDiscovery object in the ud tracker. // - cb - the callback to be called when a backup is triggered. diff --git a/bindings/broadcast.go b/bindings/broadcast.go index 62cce68bc271509b19f92aa4c44dac6f2c9ff7d9..6cea173b9000ede941c7c640727912c21f6e8cb0 100644 --- a/bindings/broadcast.go +++ b/bindings/broadcast.go @@ -19,18 +19,21 @@ import ( "gitlab.com/xx_network/primitives/id/ephemeral" ) -// Channel is a bindings-level struct encapsulating the broadcast.Channel client object. +// Channel is a bindings-level struct encapsulating the broadcast.Channel client +// object. type Channel struct { ch broadcast.Channel } -// ChannelDef is the bindings representation of an elixxir/crypto broadcast.Channel object. +// ChannelDef is the bindings representation of an elixxir/crypto +// broadcast.Channel object. // // Example JSON: -// {"Name": "My broadcast channel", -// "Description":"A broadcast channel for me to test things", -// "Salt":"gpUqW7N22sffMXsvPLE7BA==", -// "PubKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1DZ0NJUUN2YkZVckJKRFpqT3Y0Y0MvUHZZdXNvQkFtUTFkb3Znb044aHRuUjA2T3F3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0=" +// { +// "Name": "My broadcast channel", +// "Description": "A broadcast channel for me to test things", +// "Salt": "gpUqW7N22sffMXsvPLE7BA==", +// "PubKey": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1DZ0NJUUN2YkZVckJKRFpqT3Y0Y0MvUHZZdXNvQkFtUTFkb3Znb044aHRuUjA2T3F3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0=" // } type ChannelDef struct { Name string @@ -51,7 +54,8 @@ type BroadcastMessage struct { Payload []byte } -// BroadcastReport is the bindings representation of the info on how a broadcast message was sent +// BroadcastReport is the bindings representation of the info on how a broadcast +// message was sent // // Example JSON: // {"RoundID":42, @@ -72,7 +76,8 @@ type BroadcastListener interface { Callback([]byte, error) } -// NewBroadcastChannel creates a bindings-layer broadcast channel & starts listening for new messages +// NewBroadcastChannel creates a bindings-layer broadcast channel and starts +// listening for new messages. // // Parameters: // - cmixId - internal ID of cmix @@ -112,8 +117,8 @@ func NewBroadcastChannel(cmixId int, channelDefinition []byte) (*Channel, error) return &Channel{ch: ch}, nil } -// Listen registers a BroadcastListener for a given method. -// This allows users to handle incoming broadcast messages. +// Listen registers a BroadcastListener for a given method. This allows users to +// handle incoming broadcast messages. // // Parameters: // - l - BroadcastListener object @@ -139,7 +144,8 @@ func (c *Channel) Listen(l BroadcastListener, method int) error { // // Returns: // - []byte - the JSON marshalled bytes of the BroadcastReport object, which -// can be passed into WaitForRoundResult to see if the broadcast succeeded. +// can be passed into Cmix.WaitForRoundResult to see if the broadcast +// succeeded. func (c *Channel) Broadcast(payload []byte) ([]byte, error) { rid, eid, err := c.ch.Broadcast(payload, cmix.GetDefaultCMIXParams()) if err != nil { @@ -172,17 +178,20 @@ func (c *Channel) BroadcastAsymmetric(payload, pk []byte) ([]byte, error) { }) } -// MaxPayloadSize returns the maximum possible payload size which can be broadcast. +// MaxPayloadSize returns the maximum possible payload size which can be +// broadcast. func (c *Channel) MaxPayloadSize() int { return c.ch.MaxPayloadSize() } -// MaxAsymmetricPayloadSize returns the maximum possible payload size which can be broadcast. +// MaxAsymmetricPayloadSize returns the maximum possible payload size which can +// be broadcast. func (c *Channel) MaxAsymmetricPayloadSize() int { return c.ch.MaxAsymmetricPayloadSize() } -// Get returns the result of calling json.Marshal on a ChannelDef based on the underlying crypto broadcast.Channel. +// Get returns the result of calling json.Marshal on a ChannelDef based on the +// underlying crypto broadcast.Channel. func (c *Channel) Get() ([]byte, error) { def := c.ch.Get() return json.Marshal(&ChannelDef{ diff --git a/bindings/cmix.go b/bindings/cmix.go index 4b9d66cf31598178e56e387d429b390cb91356c4..71d5b1c64e19277498922c345edac1ab38997698 100644 --- a/bindings/cmix.go +++ b/bindings/cmix.go @@ -35,10 +35,10 @@ type Cmix struct { id int } -// NewCmix creates user storage, generates keys, connects, and registers -// with the network. Note that this does not register a username/identity, but -// merely creates a new cryptographic identity for adding such information -// at a later date. +// NewCmix creates user storage, generates keys, connects, and registers with +// the network. Note that this does not register a username/identity, but merely +// creates a new cryptographic identity for adding such information at a later +// date. // // Users of this function should delete the storage directory on error. func NewCmix(ndfJSON, storageDir string, password []byte, registrationCode string) error { @@ -49,8 +49,9 @@ func NewCmix(ndfJSON, storageDir string, password []byte, registrationCode strin return nil } -// LoadCmix will load an existing user storage from the storageDir using the password. -// This will fail if the user storage does not exist or the password is incorrect. +// LoadCmix will load an existing user storage from the storageDir using the +// password. This will fail if the user storage does not exist or the password +// is incorrect. // // The password is passed as a byte array so that it can be cleared from memory // and stored as securely as possible using the MemGuard library. @@ -82,6 +83,10 @@ func (c *Cmix) GetID() int { return c.id } +//////////////////////////////////////////////////////////////////////////////// +// cMix Tracker // +//////////////////////////////////////////////////////////////////////////////// + // cmixTracker is a singleton used to keep track of extant Cmix objects, // preventing race conditions created by passing it over the bindings. type cmixTracker struct { @@ -90,8 +95,8 @@ type cmixTracker struct { mux sync.RWMutex } -// make creates a Cmix from a xxdk.Cmix, assigns it a unique ID,and adds it to -// the cmixTracker. +// make creates a Cmix from a [xxdk.Cmix], assigns it a unique ID, and adds it +// to the cmixTracker. func (ct *cmixTracker) make(c *xxdk.Cmix) *Cmix { ct.mux.Lock() defer ct.mux.Unlock() diff --git a/bindings/connect.go b/bindings/connect.go index c097d0cb3a23c9366ff6057a690c2b92845bc2aa..912ee6ffa9744e12a5b44ae626a198cb6e9bb36e 100644 --- a/bindings/connect.go +++ b/bindings/connect.go @@ -48,7 +48,7 @@ func (c *Connection) GetId() int { // Parameters: // - e2eId - ID of the E2E object in the e2e tracker // - recipientContact - marshalled contact.Contact object -// - myIdentity - marshalled ReceptionIdentity object +// - e2eParamsJSON - JSON marshalled byte of xxdk.E2EParams object func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) ( *Connection, error) { if len(e2eParamsJSON) == 0 { @@ -83,7 +83,7 @@ func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) ( // // Returns: // - []byte - the JSON marshalled bytes of the E2ESendReport object, which can -// be passed into WaitForRoundResult to see if the send succeeded. +// be passed into Cmix.WaitForRoundResult to see if the send succeeded. func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) { rounds, mid, ts, err := c.connection.SendE2E(catalog.MessageType(mt), payload, c.params.Base) diff --git a/bindings/delivery.go b/bindings/delivery.go index 7d549ec7d397da9654ff5be8fccdd7122a6c3c2f..39df199c799b395cae42e0743debca49375a46c0 100644 --- a/bindings/delivery.go +++ b/bindings/delivery.go @@ -70,19 +70,21 @@ type MessageDeliveryCallback interface { EventCallback(delivered, timedOut bool, roundResults []byte) } -// WaitForRoundResult allows the caller to get notified if the rounds a -// message was sent in successfully completed. Under the hood, this uses an API -// that uses the internal round data, network historical round lookup, and -// waiting on network events to determine what has (or will) occur. -// -// The callbacks will return at timeoutMS if no state update occurs. +// WaitForRoundResult allows the caller to get notified if the rounds a message +// was sent in successfully completed. Under the hood, this uses an API that +// uses the internal round data, network historical round lookup, and waiting on +// network events to determine what has (or will) occur. // // This function takes the marshaled send report to ensure a memory leak does // not occur as a result of both sides of the bindings holding a reference to // the same pointer. // -// roundList is a JSON marshalled RoundsList or any JSON marshalled send report -// that inherits a RoundsList object. +// Parameters: +// - roundList - JSON marshalled bytes of RoundsList or JSON of any send report +// that inherits a [bindings.RoundsList] object +// - mdc - callback that adheres to the MessageDeliveryCallback interface +// - timeoutMS - timeout when the callback will return if no state update +// occurs, in milliseconds func (c *Cmix) WaitForRoundResult( roundList []byte, mdc MessageDeliveryCallback, timeoutMS int) error { jww.INFO.Printf("WaitForRoundResult(%s, _, %d)", roundList, timeoutMS) diff --git a/bindings/dummy.go b/bindings/dummy.go new file mode 100644 index 0000000000000000000000000000000000000000..6d6ee3c391c3edfb6812347f702d16bbc65dc443 --- /dev/null +++ b/bindings/dummy.go @@ -0,0 +1,86 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package bindings + +import ( + "gitlab.com/elixxir/client/dummy" + "time" +) + +// DummyTraffic is the bindings-layer dummy (or "cover") traffic manager. T +// The manager can be used to set and get the status of the thread responsible for +// sending dummy messages. +type DummyTraffic struct { + m *dummy.Manager +} + +// NewDummyTrafficManager creates a DummyTraffic manager and initialises the +// dummy traffic sending thread. Note that the manager does not start sending +// dummy traffic until true is passed into DummyTraffic.SetStatus. The time +// duration between each sending operation and the amount of messages sent each +// interval are randomly generated values with bounds defined by the given +// parameters below. +// +// Parameters: +// - cmixId - a Cmix object ID in the tracker. +// - maxNumMessages - the upper bound of the random number of messages sent +// each sending cycle. +// - avgSendDeltaMS - the average duration, in milliseconds, to wait between +// sends. +// - randomRangeMS - the upper bound of the interval between sending cycles, in +// milliseconds. Sends occur every avgSendDeltaMS +/- a random duration with +// an upper bound of randomRangeMS. +func NewDummyTrafficManager(cmixId, maxNumMessages, avgSendDeltaMS, + randomRangeMS int) (*DummyTraffic, error) { + + // Get user from singleton + net, err := cmixTrackerSingleton.get(cmixId) + if err != nil { + return nil, err + } + + avgSendDelta := time.Duration(avgSendDeltaMS) * time.Millisecond + randomRange := time.Duration(randomRangeMS) * time.Millisecond + + m := dummy.NewManager( + maxNumMessages, avgSendDelta, randomRange, net.api) + + return &DummyTraffic{m}, net.api.AddService(m.StartDummyTraffic) +} + +// SetStatus sets the state of the DummyTraffic manager's send thread by passing +// in a boolean parameter. There may be a small delay in between this call and +// the status of the sending thread to change accordingly. For example, passing +// false into this call while the sending thread is currently sending messages +// will not cancel nor halt the sending operation, but will pause the thread +// once that operation has completed. +// +// Parameters: +// - status - Input should be true if you want to send dummy messages and false +// if you want to pause dummy messages. +// +// Returns: +// - error - if the DummyTraffic.SetStatus is called too frequently, causing +// the internal status channel to fill. +func (dt *DummyTraffic) SetStatus(status bool) error { + return dt.m.SetStatus(status) +} + +// GetStatus returns the current state of the DummyTraffic manager's sending +// thread. Note that this function does not return the status set by the most +// recent call to SetStatus. Instead, this call returns the current status of +// the sending thread. This is due to the small delay that may occur between +// calling SetStatus and the sending thread taking into effect that status +// change. +// +// Returns: +// - bool - Returns true if sending thread is sending dummy messages and false +// if sending thread is paused/stopped and is not sending dummy messages. +func (dt *DummyTraffic) GetStatus() bool { + return dt.m.GetStatus() +} diff --git a/bindings/e2e.go b/bindings/e2e.go index 22438e73df9db897e20b785b871d78aadba73307..22bc2b7249c48ffff3aff0ce88102175282fd024 100644 --- a/bindings/e2e.go +++ b/bindings/e2e.go @@ -26,20 +26,20 @@ var e2eTrackerSingleton = &e2eTracker{ count: 0, } -// E2e wraps the xxdk.E2e, implementing additional functions -// to support the bindings E2e interface. +// E2e wraps the xxdk.E2e, implementing additional functions to support the +// bindings E2e interface. type E2e struct { api *xxdk.E2e id int } -// GetID returns the e2eTracker ID for the E2e object. +// GetID returns the ID for this E2e in the e2eTracker. func (e *E2e) GetID() int { return e.id } // Login creates and returns a new E2e object and adds it to the -// e2eTrackerSingleton. identity should be created via +// e2eTrackerSingleton. Identity should be created via // Cmix.MakeReceptionIdentity and passed in here. If callbacks is left nil, a // default auth.Callbacks will be used. func Login(cmixId int, callbacks AuthCallbacks, identity, @@ -80,7 +80,7 @@ func Login(cmixId int, callbacks AuthCallbacks, identity, } // LoginEphemeral creates and returns a new ephemeral E2e object and adds it to -// the e2eTrackerSingleton. identity should be created via +// the e2eTrackerSingleton. Identity should be created via // Cmix.MakeReceptionIdentity or Cmix.MakeLegacyReceptionIdentity and passed in // here. If callbacks is left nil, a default auth.Callbacks will be used. func LoginEphemeral(cmixId int, callbacks AuthCallbacks, identity, @@ -126,13 +126,15 @@ func (e *E2e) GetContact() []byte { return e.api.GetReceptionIdentity().GetContact().Marshal() } -// GetUdAddressFromNdf retrieve the User Discovery's network address fom the NDF. +// GetUdAddressFromNdf retrieve the User Discovery's network address fom the +// NDF. func (e *E2e) GetUdAddressFromNdf() string { return e.api.GetCmix().GetInstance().GetPartialNdf(). Get().UDB.Address } -// GetUdCertFromNdf retrieves the User Discovery's TLS certificate from the NDF. +// GetUdCertFromNdf retrieves the User Discovery's TLS certificate (in PEM +// format) from the NDF. func (e *E2e) GetUdCertFromNdf() []byte { return []byte(e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.Cert) } @@ -143,19 +145,26 @@ func (e *E2e) GetUdCertFromNdf() []byte { // Returns // - []byte - A byte marshalled contact.Contact. func (e *E2e) GetUdContactFromNdf() ([]byte, error) { - udIdData := e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.ID + // Retrieve data from E2e + netDef := e.api.GetCmix().GetInstance().GetPartialNdf().Get() + e2eGroup := e.api.GetE2E().GetGroup() + + // Unmarshal UD ID + udIdData := netDef.UDB.ID udId, err := id.Unmarshal(udIdData) if err != nil { return nil, err } - udDhPubKeyData := e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.DhPubKey - udDhPubKey := e.api.GetE2E().GetGroup().NewInt(1) + // Unmarshal DH pub key + udDhPubKeyData := netDef.UDB.DhPubKey + udDhPubKey := e2eGroup.NewInt(1) err = udDhPubKey.UnmarshalJSON(udDhPubKeyData) if err != nil { return nil, err } + // Construct contact udContact := contact.Contact{ ID: udId, DhPubKey: udDhPubKey, @@ -178,11 +187,11 @@ type authCallback struct { } // convertAuthCallbacks turns an auth.Callbacks into an AuthCallbacks. -func convertAuthCallbacks(requestor contact.Contact, +func convertAuthCallbacks(requester contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) ( contact []byte, receptionId []byte, ephemeralId int64, roundId int64) { - contact = requestor.Marshal() + contact = requester.Marshal() receptionId = receptionID.Source.Marshal() ephemeralId = int64(receptionID.EphId.UInt64()) roundId = int64(round.ID) @@ -207,6 +216,10 @@ func (a *authCallback) Reset(partner contact.Contact, a.bindingsCbs.Reset(convertAuthCallbacks(partner, receptionID, round)) } +//////////////////////////////////////////////////////////////////////////////// +// E2E Tracker // +//////////////////////////////////////////////////////////////////////////////// + // e2eTracker is a singleton used to keep track of extant E2e objects, // preventing race conditions created by passing it over the bindings. type e2eTracker struct { @@ -222,15 +235,15 @@ func (ct *e2eTracker) make(c *xxdk.E2e) *E2e { ct.mux.Lock() defer ct.mux.Unlock() - id := ct.count + e2eID := ct.count ct.count++ - ct.tracked[id] = &E2e{ + ct.tracked[e2eID] = &E2e{ api: c, - id: id, + id: e2eID, } - return ct.tracked[id] + return ct.tracked[e2eID] } // get an E2e from the e2eTracker given its ID. diff --git a/bindings/e2eAuth.go b/bindings/e2eAuth.go index b2277eb3e3c77ae54ab933dae3b23c9edee9ef25..cee5f04f4d0e1fafcaecc8c65ff5cdb56e3c9209 100644 --- a/bindings/e2eAuth.go +++ b/bindings/e2eAuth.go @@ -35,12 +35,12 @@ import ( // // Parameters: // - partnerContact - the marshalled bytes of the contact.Contact object. -// - myFacts - stringified list of fact.FactList. +// - factsListJson - the JSON marshalled bytes of [fact.FactList]. // // Returns: // - int64 - ID of the round (convert to uint64) func (e *E2e) Request(partnerContact, factsListJson []byte) (int64, error) { - var factsList []Fact + var factsList fact.FactList err := json.Unmarshal(factsListJson, &factsList) if err != nil { return 0, err @@ -51,15 +51,7 @@ func (e *E2e) Request(partnerContact, factsListJson []byte) (int64, error) { return 0, err } - myFacts := fact.FactList{} - for _, f := range factsList { - myFacts = append(myFacts, fact.Fact{ - Fact: f.Fact, - T: fact.FactType(f.Type), - }) - } - - roundID, err := e.api.GetAuth().Request(partner, myFacts) + roundID, err := e.api.GetAuth().Request(partner, factsList) return int64(roundID), err } @@ -179,8 +171,7 @@ func (e *E2e) DeleteSentRequests() error { return e.api.GetAuth().DeleteSentRequests() } -// DeleteReceiveRequests clears all received requests from auth -// storage. +// DeleteReceiveRequests clears all received requests from auth storage. func (e *E2e) DeleteReceiveRequests() error { return e.api.GetAuth().DeleteReceiveRequests() } diff --git a/bindings/e2eHandler.go b/bindings/e2eHandler.go index 83ca76d62341b62162fa97d19be63b5537c517d2..b71d6646d85eec5cea9a4450979d75003e20b9d2 100644 --- a/bindings/e2eHandler.go +++ b/bindings/e2eHandler.go @@ -24,9 +24,11 @@ import ( // SendE2E. // // Example E2ESendReport: -// {"Rounds":[1,5,9], +// { +// "Rounds":[1,5,9], // "MessageID":"51Yy47uZbP0o2Y9B/kkreDLTB6opUol3M3mYiY2dcdQ=", -// "Timestamp":1653582683183384000} +// "Timestamp":1653582683183384000 +// } type E2ESendReport struct { RoundsList MessageID []byte @@ -117,7 +119,7 @@ func (e *E2e) RemoveService(tag string) error { // // Returns: // - []byte - the JSON marshalled bytes of the E2ESendReport object, which can -// be passed into WaitForRoundResult to see if the send succeeded. +// be passed into Cmix.WaitForRoundResult to see if the send succeeded. func (e *E2e) SendE2E(messageType int, recipientId, payload, e2eParams []byte) ([]byte, error) { // Note that specifically these are the Base params from xxdk.E2EParams @@ -166,11 +168,9 @@ func (e *E2e) AddService(tag string, processor Processor) error { // - messageType - message type from the sender you want to listen for. // - newListener: A provider for a callback to hear a message. // Do not pass nil to this. -func (e *E2e) RegisterListener(senderID []byte, - messageType int, - newListener Listener) error { - jww.INFO.Printf("RegisterListener(%v, %d)", senderID, - messageType) +func (e *E2e) RegisterListener( + senderID []byte, messageType int, newListener Listener) error { + jww.INFO.Printf("RegisterListener(%v, %d)", senderID, messageType) // Convert senderID to id.Id object var uid *id.ID diff --git a/bindings/errors.go b/bindings/errors.go index 32c945c80c219626623b39ce12e3f299c1f73cef..c5f4edce5a03fd31ce40ca5c15c3e689fe16e174 100644 --- a/bindings/errors.go +++ b/bindings/errors.go @@ -46,14 +46,14 @@ const ( UnrecognizedMessage = UnrecognizedCode + "Unrecognized error from XX backend, please report" ) -// CreateUserFriendlyErrorMessage will convert the passed in error string -// to an error string that is user-friendly if a substring match is -// found to a common error. Common errors is a map which can be updated -// using UpdateCommonErrors. If the error is not common, some simple parsing -// is done on the error message to make it more user-accessible, removing -// backend specific jargon. +// CreateUserFriendlyErrorMessage will convert the passed in error string to an +// error string that is user-friendly if a substring match is found to a +// common error. Common errors is a map that can be updated using +// UpdateCommonErrors. If the error is not common, some simple parsing is done +// on the error message to make it more user-accessible, removing backend +// specific jargon. // -// Parameters +// Parameters: // - errStr - an error returned from the backend. // // Returns @@ -97,16 +97,18 @@ func CreateUserFriendlyErrorMessage(errStr string) string { return fmt.Sprintf("%s: %v", UnrecognizedCode, errStr) } -// UpdateCommonErrors updates the internal error mapping DB. This internal database -// maps errors returned from the backend to user-friendly error messages. +// UpdateCommonErrors updates the internal error mapping database. This internal +// database maps errors returned from the backend to user-friendly error +// messages. // -// Parameters +// Parameters: // - jsonFile - contents of a JSON file whose format conforms to the example below. +// // Example Input: -// { -// "Failed to Unmarshal Conversation": "Could not retrieve conversation", -// "Failed to unmarshal SentRequestMap": "Failed to pull up friend requests", -// "cannot create username when network is not health": "Cannot create username, unable to connect to network", +// { +// "Failed to Unmarshal Conversation": "Could not retrieve conversation", +// "Failed to unmarshal SentRequestMap": "Failed to pull up friend requests", +// "cannot create username when network is not health": "Cannot create username, unable to connect to network", // } func UpdateCommonErrors(jsonFile string) error { errorMux.Lock() diff --git a/bindings/fileTransfer.go b/bindings/fileTransfer.go index b0182ed6e2cb9c018a54ee716946e60cbb74f328..79a7d6bc7cbda08f0cc9b85341a82692bb834362 100644 --- a/bindings/fileTransfer.go +++ b/bindings/fileTransfer.go @@ -179,7 +179,6 @@ func InitFileTransfer(e2eID int, receiveFileCallback ReceiveFileCallback, // Parameters: // - payload - JSON marshalled FileSend // - recipientID - marshalled recipient id.ID -// - paramsJSON - JSON marshalled e2e.Params // - retry - number of retries allowed // - callback - callback that reports file sending progress // - period - duration to wait between progress callbacks triggering diff --git a/bindings/follow.go b/bindings/follow.go index 482bbd9cd83ab254ee2677a494d8e720df67c88d..6267a34125388a681827437d7a1e1cea1aa1c8dd 100644 --- a/bindings/follow.go +++ b/bindings/follow.go @@ -27,28 +27,28 @@ import ( // // Threads Started: // - Network Follower (/network/follow.go) -// tracks the network events and hands them off to workers for handling. +// tracks the network events and hands them off to workers for handling. // - Historical Round Retrieval (/network/rounds/historical.go) -// retrieves data about rounds that are too old to be stored by the client. +// retrieves data about rounds that are too old to be stored by the client. // - Message Retrieval Worker Group (/network/rounds/retrieve.go) -// requests all messages in a given round from the gateway of the last -// nodes. +// requests all messages in a given round from the gateway of the last +// nodes. // - Message Handling Worker Group (/network/message/handle.go) -// decrypts and partitions messages when signals via the Switchboard. +// decrypts and partitions messages when signals via the Switchboard. // - Health Tracker (/network/health), -// via the network instance, tracks the state of the network. +// via the network instance, tracks the state of the network. // - Garbled Messages (/network/message/garbled.go) -// can be signaled to check all recent messages that could be decoded. It -// uses a message store on disk for persistence. +// can be signaled to check all recent messages that could be decoded. It +// uses a message store on disk for persistence. // - Critical Messages (/network/message/critical.go) -// ensures all protocol layer mandatory messages are sent. It uses a -// message store on disk for persistence. +// ensures all protocol layer mandatory messages are sent. It uses a message +// store on disk for persistence. // - KeyExchange Trigger (/keyExchange/trigger.go) -// responds to sent rekeys and executes them. +// responds to sent rekeys and executes them. // - KeyExchange Confirm (/keyExchange/confirm.go) -// responds to confirmations of successful rekey operations. +// responds to confirmations of successful rekey operations. // - Auth Callback (/auth/callback.go) -// handles both auth confirm and requests. +// handles both auth confirm and requests. func (c *Cmix) StartNetworkFollower(timeoutMS int) error { timeout := time.Duration(timeoutMS) * time.Millisecond return c.api.StartNetworkFollower(timeout) @@ -58,7 +58,7 @@ func (c *Cmix) StartNetworkFollower(timeoutMS int) error { // an error if the follower is in the wrong state to stop or if it fails to stop // it. // -// if the network follower is running and this fails, the Cmix object will +// If the network follower is running and this fails, the Cmix object will // most likely be in an unrecoverable state and need to be trashed. func (c *Cmix) StopNetworkFollower() error { if err := c.api.StopNetworkFollower(); err != nil { @@ -84,11 +84,9 @@ func (c *Cmix) WaitForNetwork(timeoutMS int) bool { // NetworkFollowerStatus gets the state of the network follower. It returns a // status with the following values: -// -// Status: -// - Stopped - 0 -// - Running - 2000 -// - Stopping - 3000 +// Stopped - 0 +// Running - 2000 +// Stopping - 3000 func (c *Cmix) NetworkFollowerStatus() int { return int(c.api.NetworkFollowerStatus()) } @@ -103,10 +101,11 @@ type NodeRegistrationReport struct { // GetNodeRegistrationStatus returns the current state of node registration. // // Returns: -// - []bye - A marshalled NodeRegistrationReport containing the number of -// nodes the user is registered with and the number of nodes present in the NDF. -// - An error if it cannot get the node registration status. The most likely cause -// is that the network is unhealthy. +// - []byte - A marshalled NodeRegistrationReport containing the number of +// nodes the user is registered with and the number of nodes present in the +// NDF. +// - An error if it cannot get the node registration status. The most likely +// cause is that the network is unhealthy. func (c *Cmix) GetNodeRegistrationStatus() ([]byte, error) { numNodesRegistered, numNodes, err := c.api.GetNodeRegistrationStatus() if err != nil { diff --git a/bindings/group.go b/bindings/group.go index 00951c269e43843fd3bd05609f1bddc9562cb844..709a969091b8bbddd5a2d242e8ddab0e51312e9a 100644 --- a/bindings/group.go +++ b/bindings/group.go @@ -22,7 +22,7 @@ import ( ) //////////////////////////////////////////////////////////////////////////////// -// Group Singleton Tracker // +// Group Singleton Tracker // //////////////////////////////////////////////////////////////////////////////// // groupTrackerSingleton is used to track Group objects so that they can be @@ -129,16 +129,16 @@ func NewGroupChat(e2eID int, // IDs of members the user wants to add to the group. // - message - the initial message sent to all members in the group. This is an // optional parameter and may be nil. -// - tag - the name of the group decided by the creator. This is an optional +// - name - the name of the group decided by the creator. This is an optional // parameter and may be nil. If nil the group will be assigned the default // name. // // Returns: // - []byte - the JSON marshalled bytes of the GroupReport object, which can be -// passed into WaitForRoundResult to see if the group request message send -// succeeded. -func (g *GroupChat) MakeGroup(membershipBytes []byte, message, name []byte) ( - []byte, error) { +// passed into Cmix.WaitForRoundResult to see if the group request message +// send succeeded. +func (g *GroupChat) MakeGroup( + membershipBytes, message, name []byte) ([]byte, error) { // Unmarshal membership list into a list of []*id.Id var members []*id.ID @@ -246,17 +246,16 @@ func (g *GroupChat) LeaveGroup(groupId []byte) error { // Send is the bindings-level function for sending to a group. // // Parameters: -// - groupId - the byte data representing a group ID. -// This can be pulled from a marshalled GroupReport. +// - groupId - the byte data representing a group ID. This can be pulled from +// marshalled GroupReport. // - message - the message that the user wishes to send to the group. // - tag - the tag associated with the message. This tag may be empty. // // Returns: // - []byte - the JSON marshalled bytes of the GroupSendReport object, which -// can be passed into WaitForRoundResult to see if the group message send -// succeeded. -func (g *GroupChat) Send(groupId, - message []byte, tag string) ([]byte, error) { +// can be passed into Cmix.WaitForRoundResult to see if the group message +// send succeeded. +func (g *GroupChat) Send(groupId, message []byte, tag string) ([]byte, error) { groupID, err := id.Unmarshal(groupId) if err != nil { return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err) @@ -291,7 +290,7 @@ func (g *GroupChat) GetGroups() ([]byte, error) { // // Parameters: // - groupId - The byte data representing a group ID (a byte marshalled id.ID). -// This can be pulled from a marshalled GroupReport. +// This can be pulled from a marshalled GroupReport. // Returns: // - Group - The bindings-layer representation of a group. func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) { @@ -317,7 +316,7 @@ func (g *GroupChat) NumGroups() int { } //////////////////////////////////////////////////////////////////////////////// -// Group Structure +// Group Structure // //////////////////////////////////////////////////////////////////////////////// // Group structure contains the identifying and membership information of a @@ -332,12 +331,13 @@ func (g *Group) GetName() []byte { return g.g.Name } -// GetID return the 33-byte unique group ID. This represents the id.ID object +// GetID return the 33-byte unique group ID. This represents the id.ID object. func (g *Group) GetID() []byte { return g.g.ID.Bytes() } -// GetTrackedID returns the tracked ID of the Group object. This is used by the backend tracker. +// GetTrackedID returns the tracked ID of the Group object. This is used by the +// backend tracker. func (g *Group) GetTrackedID() int { return g.id } @@ -375,9 +375,9 @@ func (g *Group) Serialize() []byte { return g.g.Serialize() } -////////////////////////////////////////////////////////////////////////////////// -// Callbacks -////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Callbacks // +//////////////////////////////////////////////////////////////////////////////// // GroupRequest is a bindings-layer interface that handles a group reception. // diff --git a/bindings/identity.go b/bindings/identity.go index f1b56803184de8491f3c93ad43d89008f6227bd4..e3aa4abdc2362f80c7d12f103cea39e55bfc93e4 100644 --- a/bindings/identity.go +++ b/bindings/identity.go @@ -26,16 +26,18 @@ import ( // "RSAPrivatePem":"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNU15dTdhYjBJOS9UL1BFUUxtd2x3ejZHV3FjMUNYemVIVXhoVEc4bmg1WWRWSXMxCmJ2THpBVjNOMDJxdXN6K2s4TVFEWjBtejMzdkswUmhPczZIY0NUSFdzTEpXRkE5WWpzWWlCRi9qTDd1bmd1ckIKL2tvK1JJSnNrWGFWaEZaazRGdERoRXhTNWY4RnR0Qmk1NmNLZmdJQlVKT3ozZi9qQllTMkxzMlJ6cWV5YXM3SApjV2RaME9TclBTT3BiYlViU1FPbS9LWnlweGZHU21yZ2oxRUZuU1dZZ2xGZTdUOTRPbHF5MG14QTV5clVXbHorCk9sK3hHbXpCNUp4WUFSMU9oMFQrQTk4RWMrTUZHNm43L1MraDdzRDgybGRnVnJmbStFTzRCdmFKeTRESGZGMWgKNnp6QnVnY25NUVFGc0dLeDFYWC9COTVMdUpPVjdyeXlDbzZGbHdJREFRQUJBb0lCQVFDaUh6OGNlcDZvQk9RTAphUzBVRitHeU5VMnlVcVRNTWtTWThoUkh1c09CMmFheXoybHZVb3RLUHBPbjZRSWRWVTJrcE4vY2dtY0lSb2x5CkhBMDRUOHJBWVNaRlVqaVlRajkzKzRFREpJYXd2Z0YyVEs1bFoyb3oxVTdreStncU82V0RMR2Z0Q0wvODVQWEIKa210aXhnUXpRV3g1RWcvemtHdm03eURBalQxeDloNytsRjJwNFlBam5kT2xTS0dmQjFZeTR1RXBQd0kwc1lWdgpKQWc0MEFxbllZUmt4emJPbmQxWGNjdEJFN2Z1VDdrWXhoeSs3WXYrUTJwVy9BYmh6NGlHOEY1MW9GMGZwV0czCmlISDhsVXZFTkp2SUZEVHZ0UEpESlFZalBRN3lUbGlGZUdrMXZUQkcyQkpQNExzVzhpbDZOeUFuRktaY1hOQ24KeHVCendiSlJBb0dCQVBUK0dGTVJGRHRHZVl6NmwzZmg3UjJ0MlhrMysvUmpvR3BDUWREWDhYNERqR1pVd1RGVQpOS2tQTTNjS29ia2RBYlBDb3FpL0tOOVBibk9QVlZ3R3JkSE9vSnNibFVHYmJGamFTUzJQMFZnNUVhTC9rT2dUCmxMMUdoVFpIUWk1VUlMM0p4M1Z3T0ZRQ3RQOU1UQlQ0UEQvcEFLbDg3VTJXN3JTY1dGV1ZGbFNkQW9HQkFPOFUKVmhHWkRpVGFKTWVtSGZIdVYrNmtzaUlsam9aUVVzeGpmTGNMZ2NjV2RmTHBqS0ZWTzJNN3NqcEJEZ0w4NmFnegorVk14ZkQzZ1l0SmNWN01aMVcwNlZ6TlNVTHh3a1dRY1hXUWdDaXc5elpyYlhCUmZRNUVjMFBlblVoWWVwVzF5CkpkTC8rSlpQeDJxSzVrQytiWU5EdmxlNWdpcjlDSGVzTlR5enVyckRBb0dCQUl0cTJnN1RaazhCSVFUUVNrZ24Kb3BkRUtzRW4wZExXcXlBdENtVTlyaWpHL2l2eHlXczMveXZDQWNpWm5VVEp0QUZISHVlbXVTeXplQ2g5QmRkegoyWkRPNUdqQVBxVHlQS3NudFlNZkY4UDczZ1NES1VSWWVFbHFDejdET0c5QzRzcitPK3FoN1B3cCtqUmFoK1ZiCkNuWllNMDlBVDQ3YStJYUJmbWRkaXpLbEFvR0JBSmo1dkRDNmJIQnNISWlhNUNJL1RZaG5YWXUzMkVCYytQM0sKMHF3VThzOCtzZTNpUHBla2Y4RjVHd3RuUU4zc2tsMk1GQWFGYldmeVFZazBpUEVTb0p1cGJzNXA1enNNRkJ1bwpncUZrVnQ0RUZhRDJweTVwM2tQbDJsZjhlZXVwWkZScGE0WmRQdVIrMjZ4eWYrNEJhdlZJeld3NFNPL1V4Q3crCnhqbTNEczRkQW9HQWREL0VOa1BjU004c1BCM3JSWW9MQ2twcUV2U0MzbVZSbjNJd3c1WFAwcDRRVndhRmR1ckMKYUhtSE1EekNrNEUvb0haQVhFdGZ2S2tRaUI4MXVYM2c1aVo4amdYUVhXUHRteTVIcVVhcWJYUTlENkxWc3B0egpKL3R4SWJLMXp5c1o2bk9IY1VoUUwyVVF6SlBBRThZNDdjYzVzTThEN3kwZjJ0QURTQUZNMmN3PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==", // "Salt":"4kk02v0NIcGtlobZ/xkxqWz8uH/ams/gjvQm14QT0dI=", // "DHKeyPrivate":"eyJWYWx1ZSI6NDU2MDgzOTEzMjA0OTIyODA5Njg2MDI3MzQ0MzM3OTA0MzAyODYwMjM2NDk2NDM5NDI4NTcxMTMwNDMzOTQwMzgyMTIyMjY4OTQzNTMyMjIyMzc1MTkzNTEzMjU4MjA4MDA0NTczMDY4MjEwNzg2NDI5NjA1MjA0OTA3MjI2ODI5OTc3NTczMDkxODY0NTY3NDExMDExNjQxNCwiRmluZ2VycHJpbnQiOjE2ODAxNTQxNTExMjMzMDk4MzYzfQ==" -// } +// "E2eGrp": "eyJnZW4iOiIyIiwicHJpbWUiOiJlMmVlOTgzZDAzMWRjMWRiNmYxYTdhNjdkZjBlOWE4ZTU1NjFkYjhlOGQ0OTQxMzM5NGMwNDliN2E4YWNjZWRjMjk4NzA4ZjEyMTk1MWQ5Y2Y5MjBlYzVkMTQ2NzI3YWE0YWU1MzViMDkyMmM2ODhiNTViM2RkMmFlZGY2YzAxYzk0NzY0ZGFiOTM3OTM1YWE4M2JlMzZlNjc3NjA3MTNhYjQ0YTYzMzdjMjBlNzg2MTU3NWU3NDVkMzFmOGI5ZTlhZDg0MTIxMThjNjJhM2UyZTI5ZGY0NmIwODY0ZDBjOTUxYzM5NGE1Y2JiZGM2YWRjNzE4ZGQyYTNlMDQxMDIzZGJiNWFiMjNlYmI0NzQyZGU5YzE2ODdiNWIzNGZhNDhjMzUyMTYzMmM0YTUzMGU4ZmZiMWJjNTFkYWRkZjQ1M2IwYjI3MTdjMmJjNjY2OWVkNzZiNGJkZDVjOWZmNTU4ZTg4ZjI2ZTU3ODUzMDJiZWRiY2EyM2VhYzVhY2U5MjA5NmVlOGE2MDY0MmZiNjFlOGYzZDI0OTkwYjhjYjEyZWU0NDhlZWY3OGUxODRjNzI0MmRkMTYxYzc3MzhmMzJiZjI5YTg0MTY5ODk3ODgyNWI0MTExYjRiYzNlMWUxOTg0NTUwOTU5NTgzMzNkNzc2ZDhiMmJlZWVkM2ExYTFhMjIxYTZlMzdlNjY0YTY0YjgzOTgxYzQ2ZmZkZGMxYTQ1ZTNkNTIxMWFhZjhiZmJjMDcyNzY4YzRmNTBkN2Q3ODAzZDJkNGYyNzhkZTgwMTRhNDczMjM2MzFkN2UwNjRkZTgxYzBjNmJmYTQzZWYwZTY5OTg4NjBmMTM5MGI1ZDNmZWFjYWYxNjk2MDE1Y2I3OWMzZjljMmQ5M2Q5NjExMjBjZDBlNWYxMmNiYjY4N2VhYjA0NTI0MWY5Njc4OWMzOGU4OWQ3OTYxMzhlNjMxOWJlNjJlMzVkODdiMTA0OGNhMjhiZTM4OWI1NzVlOTk0ZGNhNzU1NDcxNTg0YTA5ZWM3MjM3NDJkYzM1ODczODQ3YWVmNDlmNjZlNDM4NzMifQ==" +// } type ReceptionIdentity struct { ID []byte // User ID (base64) RSAPrivatePem []byte // RSA Private key (PEM format) Salt []byte // Salt for identity (base64) DHKeyPrivate []byte // DH Private key + E2eGrp []byte } // StoreReceptionIdentity stores the given identity in Cmix storage with the -// given key. This is the ideal way to securely store identities, as the caller +// given key. This is the ideal way to securely store identities, as the caller // of this function is only required to store the given key separately rather // than the keying material. func StoreReceptionIdentity(key string, identity []byte, cmixId int) error { @@ -77,7 +79,8 @@ func (c *Cmix) MakeReceptionIdentity() ([]byte, error) { } // MakeLegacyReceptionIdentity generates the legacy identity for receiving -// messages. +// messages. As with all legacy calls, this should primarily be used +// for the xx messenger team. func (c *Cmix) MakeLegacyReceptionIdentity() ([]byte, error) { ident, err := xxdk.MakeLegacyReceptionIdentity(c.api) if err != nil { @@ -90,17 +93,23 @@ func (c *Cmix) MakeLegacyReceptionIdentity() ([]byte, error) { // GetReceptionRegistrationValidationSignature returns the signature provided by // the xx network. func (c *Cmix) GetReceptionRegistrationValidationSignature() []byte { - return c.api.GetStorage().GetReceptionRegistrationValidationSignature() + regSig := c.api.GetStorage().GetReceptionRegistrationValidationSignature() + return regSig } //////////////////////////////////////////////////////////////////////////////// // Contact Functions // //////////////////////////////////////////////////////////////////////////////// -// GetIDFromContact accepts a marshalled contact.Contact object and returns a -// marshalled id.ID object. -func GetIDFromContact(marshaled []byte) ([]byte, error) { - cnt, err := contact.Unmarshal(marshaled) +// GetIDFromContact returns the ID in the [contact.Contact] object. +// +// Parameters: +// - marshaledContact - JSON marshalled bytes of [contact.Contact] +// +// Returns: +// - []byte - bytes of the [id.ID] object +func GetIDFromContact(marshaledContact []byte) ([]byte, error) { + cnt, err := contact.Unmarshal(marshaledContact) if err != nil { return nil, err } @@ -108,10 +117,16 @@ func GetIDFromContact(marshaled []byte) ([]byte, error) { return cnt.ID.Marshal(), nil } -// GetPubkeyFromContact accepts a marshalled contact.Contact object and returns -// a JSON marshalled large.Int DH public key. -func GetPubkeyFromContact(marshaled []byte) ([]byte, error) { - cnt, err := contact.Unmarshal(marshaled) +// GetPubkeyFromContact returns the DH public key in the [contact.Contact] +// object. +// +// Parameters: +// - marshaledContact - JSON marshalled bytes of [contact.Contact] +// +// Returns: +// - []byte - JSON marshalled bytes of the [cyclic.Int] object +func GetPubkeyFromContact(marshaledContact []byte) ([]byte, error) { + cnt, err := contact.Unmarshal(marshaledContact) if err != nil { return nil, err } @@ -123,67 +138,44 @@ func GetPubkeyFromContact(marshaled []byte) ([]byte, error) { // Fact Functions // //////////////////////////////////////////////////////////////////////////////// -// Fact is an internal fact type for use in the bindings layer. -// -// JSON example: -// { -// "Fact": "Zezima", -// "Type": 0 -// } -type Fact struct { - Fact string - Type int -} - // SetFactsOnContact replaces the facts on the contact with the passed in facts // pass in empty facts in order to clear the facts. // // Parameters: -// - marshaled - JSON marshalled contact.Contact object -// - facts - JSON marshalled Fact object. -func SetFactsOnContact(marshaled []byte, facts []byte) ([]byte, error) { - cnt, err := contact.Unmarshal(marshaled) +// - marshaledContact - the JSON marshalled bytes of [contact.Contact] +// - factListJSON - the JSON marshalled bytes of [fact.FactList] +// +// Returns: +// - []byte - marshalled bytes of the modified [contact.Contact] +func SetFactsOnContact(marshaledContact []byte, factListJSON []byte) ([]byte, error) { + cnt, err := contact.Unmarshal(marshaledContact) if err != nil { return nil, err } - factsList := make([]Fact, 0) - err = json.Unmarshal(facts, &factsList) + var factsList fact.FactList + err = json.Unmarshal(factListJSON, &factsList) if err != nil { return nil, err } - realFactList := make(fact.FactList, 0, len(factsList)) - for i := range factsList { - realFactList = append(realFactList, fact.Fact{ - Fact: factsList[i].Fact, - T: fact.FactType(factsList[i].Type), - }) - } + cnt.Facts = factsList - cnt.Facts = realFactList return cnt.Marshal(), nil } -// GetFactsFromContact accepts a marshalled contact.Contact object and returns -// its marshalled list of Fact objects. -func GetFactsFromContact(marshaled []byte) ([]byte, error) { - cnt, err := contact.Unmarshal(marshaled) +// GetFactsFromContact returns the fact list in the [contact.Contact] object. +// +// Parameters: +// - marshaledContact - the JSON marshalled bytes of [contact.Contact] +// +// Returns: +// - []byte - the JSON marshalled bytes of [fact.FactList] +func GetFactsFromContact(marshaledContact []byte) ([]byte, error) { + cnt, err := contact.Unmarshal(marshaledContact) if err != nil { return nil, err } - factsList := make([]Fact, len(cnt.Facts)) - for i := range cnt.Facts { - factsList = append(factsList, Fact{ - Fact: cnt.Facts[i].Fact, - Type: int(cnt.Facts[i].T), - }) - } - - factsListMarshaled, err := json.Marshal(&factsList) - if err != nil { - return nil, err - } - return factsListMarshaled, nil + return json.Marshal(&cnt.Facts) } diff --git a/bindings/identity_test.go b/bindings/identity_test.go index 662f1f5c000021def40a17a50d9c9646b8a78779..3dda17691bc63fc1e049ff14cccbbe7888d55146 100644 --- a/bindings/identity_test.go +++ b/bindings/identity_test.go @@ -29,34 +29,21 @@ func TestIdentity_JSON(t *testing.T) { dhpk := dh.GeneratePrivateKey(64, grp, rng) dhpkJson, _ := dhpk.MarshalJSON() op := make([]byte, 64) + e2eGrp, _ := getGroup().MarshalJSON() _, _ = rng.Read(op) identity := ReceptionIdentity{ ID: uid.Marshal(), RSAPrivatePem: rsa.CreatePrivateKeyPem(pk), Salt: salt, DHKeyPrivate: dhpkJson, + E2eGrp: e2eGrp, } + im, _ := json.Marshal(identity) t.Log("Marshalled ReceptionIdentity object") t.Log(string(im)) } -func TestFacts_JSON(t *testing.T) { - fl := []Fact{ - { - Fact: "Zezima", - Type: 0, - }, - { - Fact: "Zezima@osrs.org", - Type: 2, - }, - } - flm, _ := json.Marshal(fl) - t.Log("Marshalled []Fact") - t.Log(string(flm)) -} - func getGroup() *cyclic.Group { return cyclic.NewGroup( large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D4941"+ diff --git a/bindings/logging.go b/bindings/logging.go index 6783d4b546f293862863110a85b16791dbf88baa..a4b1df6ae671f808ce5594f5ab1ae0e204d81cfc 100644 --- a/bindings/logging.go +++ b/bindings/logging.go @@ -10,7 +10,6 @@ package bindings import ( - "fmt" "log" "github.com/pkg/errors" @@ -34,7 +33,7 @@ import ( // The default log level without updates is INFO. func LogLevel(level int) error { if level < 0 || level > 6 { - return errors.New(fmt.Sprintf("log level is not valid: log level: %d", level)) + return errors.Errorf("log level is not valid: log level: %d", level) } threshold := jww.Threshold(level) diff --git a/bindings/notifications.go b/bindings/notifications.go new file mode 100644 index 0000000000000000000000000000000000000000..bbc79ca79c028ceac33a5ba1e972119f904aa4ba --- /dev/null +++ b/bindings/notifications.go @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package bindings + +// FIXME: This is the old NotificationsForMe code that needs to be fixed +/* +type NotificationForMeReport struct { + ForMe bool + Type string + Source []byte +} + +type ManyNotificationForMeReport struct { + Many []*NotificationForMeReport +} + +// NotificationsForMe Check if a notification received is for me +// It returns a NotificationForMeReport which contains a ForMe bool stating if it is for the caller, +// a Type, and a source. These are as follows: +// TYPE SOURCE DESCRIPTION +// "default" recipient user ID A message with no association +// "request" sender user ID A channel request has been received +// "reset" sender user ID A channel reset has been received +// "confirm" sender user ID A channel request has been accepted +// "silent" sender user ID A message which should not be notified on +// "e2e" sender user ID reception of an E2E message +// "group" group ID reception of a group chat message +// "endFT" sender user ID Last message sent confirming end of file transfer +// "groupRQ" sender user ID Request from sender to join a group chat +func NotificationsForMe(notifCSV, preimages string) (*ManyNotificationForMeReport, error) { + // Handle deserialization of preimages + var preimageList []edge.Preimage + if err := json.Unmarshal([]byte(preimages), &preimageList); err != nil { + return nil, errors.WithMessagef(err, "Failed to unmarshal the " + + "preimages list, cannot check if notification is for me") + } + + list, err := notifications.DecodeNotificationsCSV(notifCSV) + if err != nil { + return nil, err + } + + notifList := make([]*NotificationForMeReport, len(list)) + + for i, notifData := range list { + notifList[i] = &NotificationForMeReport{ + ForMe: false, + Type: "", + Source: nil, + } + // check if any preimages match with the passed in data + for _, preimage := range preimageList { + if fingerprint.CheckIdentityFpFromMessageHash(notifData.IdentityFP, notifData.MessageHash, preimage.Data) { + notifList[i] = &NotificationForMeReport{ + ForMe: true, + Type: preimage.Type, + Source: preimage.Source, + } + break + } + } + } + + return &ManyNotificationForMeReport{notifList}, nil +}*/ + +// RegisterForNotifications allows a client to register for push notifications. +// The token is a firebase messaging token. +// +// Parameters: +// - e2eId - ID of the E2E object in the E2E tracker +func RegisterForNotifications(e2eId int, token string) error { + user, err := e2eTrackerSingleton.get(e2eId) + if err != nil { + return err + } + + return user.api.RegisterForNotifications(token) +} + +// UnregisterForNotifications turns off notifications for this client. +// +// Parameters: +// - e2eId - ID of the E2E object in the E2E tracker +func UnregisterForNotifications(e2eId int) error { + user, err := e2eTrackerSingleton.get(e2eId) + if err != nil { + return err + } + + return user.api.UnregisterForNotifications() +} diff --git a/bindings/params.go b/bindings/params.go index 2b0cdd18c82d16c2a7a3f0b5570532d26bf87b23..151811be715db3ce2d612173b6d2b45bcfd84417 100644 --- a/bindings/params.go +++ b/bindings/params.go @@ -66,8 +66,8 @@ func GetDefaultSingleUseParams() []byte { } // GetDefaultE2eFileTransferParams returns a JSON serialized object with all the -// e2e file transfer parameters and their default values. Call this function and modify -// the JSON to change single use settings. +// E2E file transfer parameters and their default values. Call this function and +// modify the JSON to change single use settings. func GetDefaultE2eFileTransferParams() []byte { defaultParams := e2eFileTransfer.DefaultParams() data, err := defaultParams.MarshalJSON() diff --git a/bindings/restlike.go b/bindings/restlike.go index e3c87e1d8279f60833ae91a8e49f32597fcf8352..2fe52c8aa5df83a31f5f49be27e16c2d384705f0 100644 --- a/bindings/restlike.go +++ b/bindings/restlike.go @@ -107,7 +107,7 @@ func RestlikeRequest( // // Returns: // - []byte - JSON marshalled RestlikeMessage -func RestlikeRequestAuth(cmixId int, authConnectionID int, request, +func RestlikeRequestAuth(cmixId, authConnectionID int, request, e2eParamsJSON []byte) ([]byte, error) { if len(e2eParamsJSON) == 0 { jww.WARN.Printf("restlike params unspecified, using defaults") diff --git a/bindings/single.go b/bindings/single.go index bb1efe57b0821fb1f1445c0fbf06ae7ce8ec666a..a3bacbce28c6db129ae233ea0c684ad9b90a9817 100644 --- a/bindings/single.go +++ b/bindings/single.go @@ -62,14 +62,14 @@ func TransmitSingleUse(e2eID int, recipient []byte, tag string, payload, } sr := SingleUseSendReport{ EphID: eid.EphId.Int64(), - ReceptionID: eid.Source.Marshal(), + ReceptionID: eid.Source, RoundsList: makeRoundsList(rids...), } return json.Marshal(sr) } -// Listen starts a single-use listener on a given tag using the passed in e2e object -// and SingleUseCallback func. +// Listen starts a single-use listener on a given tag using the passed in E2e +// object and SingleUseCallback func. // // Parameters: // - e2eID - ID of the e2e object in the tracker @@ -85,11 +85,11 @@ func Listen(e2eID int, tag string, cb SingleUseCallback) (Stopper, error) { } suListener := singleUseListener{scb: cb} - dhpk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate() + dhPk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate() if err != nil { return nil, err } - l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhpk, + l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhPk, e2eCl.api.GetCmix(), e2eCl.api.GetStorage().GetE2EGroup(), suListener) return &stopper{l: l}, nil } @@ -102,12 +102,12 @@ func Listen(e2eID int, tag string, cb SingleUseCallback) (Stopper, error) { // JSON example: // { // "Rounds":[1,5,9], -// "EphID":{"EphId":[0,0,0,0,0,0,3,89], -// "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"} +// "EphID":1655533, +// "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"} // } type SingleUseSendReport struct { RoundsList - ReceptionID []byte + ReceptionID *id.ID EphID int64 } @@ -119,14 +119,14 @@ type SingleUseSendReport struct { // { // "Rounds":[1,5,9], // "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==", -// "ReceptionID":{"EphId":[0,0,0,0,0,0,3,89], -// "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}, -// "Err":null +// "EphID":1655533, +// "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}, +// "Err":"", // } type SingleUseResponseReport struct { RoundsList Payload []byte - ReceptionID []byte + ReceptionID *id.ID EphID int64 Err error } @@ -139,22 +139,23 @@ type SingleUseResponseReport struct { // "Rounds":[1,5,9], // "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==", // "Partner":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", -// "EphID":{"EphId":[0,0,0,0,0,0,3,89], -// "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"} +// "EphID":1655533, +// "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"} // } type SingleUseCallbackReport struct { RoundsList Payload []byte Partner *id.ID EphID int64 - ReceptionID []byte + ReceptionID *id.ID } //////////////////////////////////////////////////////////////////////////////// // Function Types // //////////////////////////////////////////////////////////////////////////////// -// Stopper is a public interface returned by Listen, allowing users to stop the registered listener. +// Stopper is a public interface returned by Listen, allowing users to stop the +// registered listener. type Stopper interface { Stop() } @@ -164,8 +165,8 @@ type Stopper interface { // // Parameters: // - callbackReport - the JSON marshalled bytes of the SingleUseCallbackReport -// object, which can be passed into WaitForRoundResult to see if the send -// succeeded. +// object, which can be passed into Cmix.WaitForRoundResult to see if the +// send operation succeeded. type SingleUseCallback interface { Callback(callbackReport []byte, err error) } @@ -175,8 +176,8 @@ type SingleUseCallback interface { // // Parameters: // - callbackReport - the JSON marshalled bytes of the SingleUseResponseReport -// object, which can be passed into WaitForRoundResult to see if the send -// succeeded. +// object, which can be passed into Cmix.WaitForRoundResult to see if the +// send operation succeeded. type SingleUseResponse interface { Callback(responseReport []byte, err error) } @@ -209,7 +210,7 @@ func (sl singleUseListener) Callback( RoundsList: makeRoundsList(rids...), Partner: req.GetPartner(), EphID: eid.EphId.Int64(), - ReceptionID: eid.Source.Marshal(), + ReceptionID: eid.Source, } sl.scb.Callback(json.Marshal(scr)) @@ -245,7 +246,7 @@ func (sr singleUseResponse) Callback(payload []byte, } sendReport := SingleUseResponseReport{ RoundsList: makeRoundsList(rids...), - ReceptionID: receptionID.Source.Marshal(), + ReceptionID: receptionID.Source, EphID: receptionID.EphId.Int64(), Payload: payload, Err: err, diff --git a/bindings/single_test.go b/bindings/single_test.go index a262a40738afe4ce73fc565ddaf259663f9d3a2e..c5424809add94e375336da1badd3a1a00696c36e 100644 --- a/bindings/single_test.go +++ b/bindings/single_test.go @@ -36,7 +36,7 @@ func TestSingleUseJsonMarshals(t *testing.T) { sendReport := SingleUseSendReport{ RoundsList: rl, EphID: ephId.EphId.Int64(), - ReceptionID: ephId.Source.Marshal(), + ReceptionID: ephId.Source, } srm, err := json.Marshal(sendReport) if err != nil { @@ -48,7 +48,7 @@ func TestSingleUseJsonMarshals(t *testing.T) { responseReport := SingleUseResponseReport{ RoundsList: rl, Payload: payload, - ReceptionID: ephId.Source.Marshal(), + ReceptionID: ephId.Source, EphID: ephId.EphId.Int64(), Err: nil, } @@ -64,7 +64,7 @@ func TestSingleUseJsonMarshals(t *testing.T) { Payload: payload, Partner: rid, EphID: ephId.EphId.Int64(), - ReceptionID: ephId.Source.Marshal(), + ReceptionID: ephId.Source, } crm, err := json.Marshal(callbackReport) if err != nil { diff --git a/bindings/ud.go b/bindings/ud.go index 6ce8f8b3af073057e210675ff3203ef5ba364746..3a3f21a0d43a4905ba5645d40cd38f4e82ed4854 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -105,34 +105,77 @@ type UdNetworkStatus interface { // Manager functions // //////////////////////////////////////////////////////////////////////////////// -// NewOrLoadUd loads an existing Manager from storage or creates a -// new one if there is no extant storage information. Parameters need be provided -// to specify how to connect to the User Discovery service. These parameters may be used -// to contact either the UD server hosted by the xx network team or a custom -// third-party operated server. For the former, all the information may be pulled from the -// NDF using the bindings. +// IsRegisteredWithUD is a function which checks the internal state +// files to determine if a user has registered with UD in the past. +// +// Parameters: +// - e2eID - REQUIRED. The tracked e2e object ID. This can be retrieved using [E2e.GetID]. +// +// Returns: +// - bool - A boolean representing true if the user has been registered with UD already +// or false if it has not been registered already. +// - error - An error should only be returned if the internal tracker failed to retrieve an +// E2e object given the e2eId. If an error was returned, the registration state check +// was not performed properly, and the boolean returned should be ignored. +func IsRegisteredWithUD(e2eId int) (bool, error) { + + // Get user from singleton + user, err := e2eTrackerSingleton.get(e2eId) + if err != nil { + return false, err + } + + return ud.IsRegistered(user.api.GetStorage().GetKV()), nil +} + +// NewOrLoadUd loads an existing UserDiscovery from storage or creates a new +// UserDiscovery if there is no storage data. Regardless of storage state, +// the UserDiscovery object returned will be registered with the +// User Discovery service. If the user is not already registered, a call +// to register will occur internally. If the user is already registered, +// this call will simply load state and return to you a UserDiscovery object. +// Some parameters are required for registering with the service, but are not required +// if the user is already registered. These will be noted in the parameters section as +// "SEMI-REQUIRED". +// +// Certain parameters are required every call to this function. These parameters are listed below +// as "REQUIRED". For example, parameters need be provided to specify how to connect to the +// User Discovery service. These parameters specifically may be used to contact either the UD +// server hosted by the xx network team or a custom third-party operated server. For the former, +// all the information may be fetched from the NDF using the bindings. These fetch +// methods are detailed in the parameters section. // // Params -// - e2eID - e2e object ID in the tracker -// - follower - network follower func wrapped in UdNetworkStatus -// - username - the username the user wants to register with UD. -// If the user is already registered, this field may be blank -// - networkValidationSig is a signature provided by the network (i.e. the client registrar). -// This may be nil, however UD may return an error in some cases (e.g. in a production level -// environment). -// - cert is the TLS certificate for the UD server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdCertFromNdf. -// - contactFile is the data within a marshalled contact.Contact. This represents the +// - e2eID - REQUIRED. The tracked e2e object ID. This is returned by [E2e.GetID]. +// - follower - REQUIRED. Network follower function. This will check if the network +// follower is running. +// - username - SEMI-REQUIRED. The username the user wants to register with UD. +// If the user is already registered, this field may be blank. If the user is not +// already registered, these field must be populated with a username that meets the +// requirements of the UD service. For example, in the xx network's UD service, +// the username must not be registered by another user. +// - registrationValidationSignature - SEMI-REQUIRED. A signature provided by the xx network +// (i.e. the client registrar). If the user is not already registered, this field is required +// in order to register with the xx network. This may be nil if the user is already registered +// or connecting to a third-party UD service unassociated with the xx network. +// - cert - REQUIRED. The TLS certificate for the UD server this call will connect with. +// If this is nil, you may not contact the UD server hosted by the xx network. +// Third-party services may vary. +// You may use the UD server run by the xx network team by using [E2e.GetUdCertFromNdf]. +// - contactFile - REQUIRED. The data within a marshalled [contact.Contact]. This represents the // contact file of the server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdContactFromNdf. -// - address is the IP address of the UD server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdAddressFromNdf. +// If this is nil, you may not contact the UD server hosted by the xx network. +// Third-party services may vary. +// You may use the UD server run by the xx network team by using [E2e.GetUdContactFromNdf]. +// - address - REQUIRED. The IP address of the UD server this call will connect with. +// You may use the UD server run by the xx network team by using [E2e.GetUdAddressFromNdf]. +// If this is nil, you may not contact the UD server hosted by the xx network. +// Third-party services may vary. // // Returns // - A Manager object which is registered to the specified UD service. -func NewOrLoadUd(e2eID int, follower UdNetworkStatus, - username string, registrationValidationSignature, - cert, contactFile []byte, address string) ( +func NewOrLoadUd(e2eID int, follower UdNetworkStatus, username string, + registrationValidationSignature, cert, contactFile []byte, address string) ( *UserDiscovery, error) { // Get user from singleton @@ -165,17 +208,24 @@ func NewOrLoadUd(e2eID int, follower UdNetworkStatus, // Parameters: // - e2eID - e2e object ID in the tracker // - follower - network follower func wrapped in UdNetworkStatus -// - emailFactJson - nullable JSON marshalled email fact.Fact -// - phoneFactJson - nullable JSON marshalled phone fact.Fact -// - cert is the TLS certificate for the UD server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdCertFromNdf. -// - contactFile is the data within a marshalled contact.Contact. This represents the -// contact file of the server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdContactFromNdf. -// - address is the IP address of the UD server this call will connect with. -// You may use the UD server run by the xx network team by using E2e.GetUdAddressFromNdf. -func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson, - phoneFactJson []byte, cert, contactFile []byte, address string) (*UserDiscovery, error) { +// - username - The username this user registered with initially. This should +// not be nullable, and be JSON marshalled as retrieved from +// UserDiscovery.GetFacts(). +// - emailFactJson - nullable JSON marshalled email [fact.Fact] +// - phoneFactJson - nullable JSON marshalled phone [fact.Fact] +// - cert - the TLS certificate for the UD server this call will connect with. +// You may use the UD server run by the xx network team by using +// E2e.GetUdCertFromNdf. +// - contactFile - the data within a marshalled contact.Contact. This +// represents the contact file of the server this call will connect with. You +// may use the UD server run by the xx network team by using +// E2e.GetUdContactFromNdf. +// - address - the IP address of the UD server this call will connect with. You +// may use the UD server run by the xx network team by using +// E2e.GetUdAddressFromNdf. +func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, + usernameJson, emailFactJson, phoneFactJson, + cert, contactFile []byte, address string) (*UserDiscovery, error) { // Get user from singleton user, err := e2eTrackerSingleton.get(e2eID) @@ -183,7 +233,9 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson, return nil, err } - var email, phone fact.Fact + var email, phone, username fact.Fact + + // Parse email if non-nil if emailFactJson != nil { err = json.Unmarshal(emailFactJson, &email) if err != nil { @@ -191,6 +243,7 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson, } } + // Parse phone if non-nil if phoneFactJson != nil { err = json.Unmarshal(phoneFactJson, &phone) if err != nil { @@ -198,13 +251,19 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson, } } + // Parse username + err = json.Unmarshal(usernameJson, &username) + if err != nil { + return nil, err + } + UdNetworkStatusFn := func() xxdk.Status { return xxdk.Status(follower.UdNetworkStatus()) } u, err := ud.NewManagerFromBackup( user.api, user.api.GetComms(), UdNetworkStatusFn, - email, phone, + username, email, phone, cert, contactFile, address) if err != nil { return nil, err @@ -213,7 +272,7 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson, return udTrackerSingleton.make(u), nil } -// GetFacts returns a JSON marshalled list of fact.Fact objects that exist +// GetFacts returns a JSON marshalled list of [fact.Fact] objects that exist // within the Store's registeredFacts map. func (ud *UserDiscovery) GetFacts() []byte { jsonData, err := json.Marshal(ud.api.GetFacts()) @@ -229,9 +288,9 @@ func (ud *UserDiscovery) GetContact() ([]byte, error) { return ud.api.GetContact().Marshal(), nil } -// ConfirmFact confirms a fact first registered via AddFact. The confirmation ID -// comes from AddFact while the code will come over the associated -// communications system. +// ConfirmFact confirms a fact first registered via SendRegisterFact. The +// confirmation ID comes from SendRegisterFact while the code will come over the +// associated communications system. func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error { return ud.api.ConfirmFact(confirmationID, code) } @@ -246,7 +305,7 @@ func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error { // along with the code to finalize the fact. // // Parameters: -// - factJson - a JSON marshalled fact.Fact +// - factJson - a JSON marshalled [fact.Fact] func (ud *UserDiscovery) SendRegisterFact(factJson []byte) (string, error) { var f fact.Fact err := json.Unmarshal(factJson, &f) @@ -262,7 +321,7 @@ func (ud *UserDiscovery) SendRegisterFact(factJson []byte) (string, error) { // be associated with this user. // // Parameters: -// - factJson - a JSON marshalled fact.Fact +// - factJson - a JSON marshalled [fact.Fact] func (ud *UserDiscovery) PermanentDeleteAccount(factJson []byte) error { var f fact.Fact err := json.Unmarshal(factJson, &f) @@ -277,7 +336,7 @@ func (ud *UserDiscovery) PermanentDeleteAccount(factJson []byte) error { // passed in is not UD service does not associate this fact with this user. // // Parameters: -// - factJson - a JSON marshalled fact.Fact +// - factJson - a JSON marshalled [fact.Fact] func (ud *UserDiscovery) RemoveFact(factJson []byte) error { var f fact.Fact err := json.Unmarshal(factJson, &f) @@ -309,13 +368,14 @@ type UdLookupCallback interface { // Parameters: // - e2eID - e2e object ID in the tracker // - udContact - the marshalled bytes of the contact.Contact object -// - lookupId - the marshalled bytes of the id.ID object for the user -// that LookupUD will look up. +// - lookupId - the marshalled bytes of the id.ID object for the user that +// LookupUD will look up. // - singleRequestParams - the JSON marshalled bytes of single.RequestParams // // Returns: // - []byte - the JSON marshalled bytes of the SingleUseSendReport object, -// which can be passed into WaitForRoundResult to see if the send succeeded. +// which can be passed into Cmix.WaitForRoundResult to see if the send +// succeeded. func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback, lookupId []byte, singleRequestParamsJSON []byte) ([]byte, error) { @@ -352,7 +412,7 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback, sr := SingleUseSendReport{ EphID: eid.EphId.Int64(), - ReceptionID: eid.Source.Marshal(), + ReceptionID: eid.Source, RoundsList: makeRoundsList(rids...), } @@ -369,8 +429,15 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback, // // Parameters: // - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil -// if an error occurs -// - err - any errors that occurred in the search +// if an error occurs. +// +// JSON Example: +// { +// "<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>", +// "<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>", +// "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>" +// } +// - err - any errors that occurred in the search. type UdSearchCallback interface { Callback(contactListJSON []byte, err error) } @@ -385,14 +452,15 @@ type UdSearchCallback interface { // - e2eID - e2e object ID in the tracker // - udContact - the marshalled bytes of the contact.Contact for the user // discovery server -// - factListJSON - the JSON marshalled bytes of fact.FactList +// - factListJSON - the JSON marshalled bytes of [fact.FactList] // - singleRequestParams - the JSON marshalled bytes of single.RequestParams // // Returns: // - []byte - the JSON marshalled bytes of the SingleUseSendReport object, -// which can be passed into WaitForRoundResult to see if the send succeeded. +// which can be passed into Cmix.WaitForRoundResult to see if the send +// operation succeeded. func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback, - factListJSON []byte, singleRequestParamsJSON []byte) ([]byte, error) { + factListJSON, singleRequestParamsJSON []byte) ([]byte, error) { // Get user from singleton user, err := e2eTrackerSingleton.get(e2eID) @@ -418,7 +486,20 @@ func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback, } callback := func(contactList []contact.Contact, err error) { - contactListJSON, err2 := json.Marshal(contactList) + marshaledContactList := make([][]byte, 0) + // fixme: it may be wiser to change this callback interface + // to simply do the work below when parsing the response from UD. + // that would change ud/search.go in two places: + // - searchCallback + // - parseContacts + // I avoid doing that as it changes interfaces w/o approval + for i := range contactList { + con := contactList[i] + marshaledContactList = append( + marshaledContactList, con.Marshal()) + } + + contactListJSON, err2 := json.Marshal(marshaledContactList) if err2 != nil { jww.FATAL.Panicf( "Failed to marshal list of contact.Contact: %+v", err2) @@ -434,7 +515,7 @@ func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback, sr := SingleUseSendReport{ EphID: eid.EphId.Int64(), - ReceptionID: eid.Source.Marshal(), + ReceptionID: eid.Source, RoundsList: makeRoundsList(rids...), } diff --git a/cmd/flags.go b/cmd/flags.go index 93b5d505d77f4846f80d1cda6b32bfa29a0ad3cf..edd40259a56eb227c267811c125ffab746ec0f67 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -80,7 +80,9 @@ const ( // Misc sendIdFlag = "sendid" profileCpuFlag = "profile-cpu" + profileMemFlag = "profile-mem" userIdPrefixFlag = "userid-prefix" + legacyFlag = "legacy" ///////////////// Broadcast subcommand flags ////////////////////////////// broadcastNameFlag = "name" diff --git a/cmd/init.go b/cmd/init.go index e78ef22bb78387d64210e9d7365bc76fa765fd94..00294f2c4a79d6bd38ce9c330df5b86466a608c3 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -45,16 +45,27 @@ var initCmd = &cobra.Command{ jww.FATAL.Panicf("%+v", err) } - identity, err := xxdk.MakeReceptionIdentity(net) + // Generate identity + var identity xxdk.ReceptionIdentity + if viper.GetBool(legacyFlag) { + identity, err = xxdk.MakeLegacyReceptionIdentity(net) + } else { + identity, err = xxdk.MakeReceptionIdentity(net) + + } + + // Panic if conditional branch fails if err != nil { jww.FATAL.Panicf("%+v", err) } + // Store identity err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, net) if err != nil { jww.FATAL.Panicf("%+v", err) } + // Write contact to file jww.INFO.Printf("User: %s", identity.ID) writeContact(identity.GetContact()) @@ -68,6 +79,11 @@ func init() { "Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.") bindFlagHelper(userIdPrefixFlag, initCmd) + initCmd.Flags().BoolP(legacyFlag, "", false, + "Generates a legacy identity if set. "+ + "If this flag is absent, a standard identity will be generated.") + bindFlagHelper(legacyFlag, initCmd) + rootCmd.AddCommand(initCmd) } diff --git a/cmd/root.go b/cmd/root.go index 837b68e1af7d13f8476844c3bb0f525be4bcbd63..3766d7cb53360d19598066788aaa42726c10aa2b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,7 +17,9 @@ import ( "io/ioutil" "log" "os" - "runtime/pprof" + + "github.com/pkg/profile" + "strconv" "strings" "sync" @@ -58,13 +60,17 @@ var rootCmd = &cobra.Command{ Short: "Runs a client for cMix anonymous communication platform", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - profileOut := viper.GetString(profileCpuFlag) - if profileOut != "" { - f, err := os.Create(profileOut) - if err != nil { - jww.FATAL.Panicf("%+v", err) - } - pprof.StartCPUProfile(f) + cpuProfileOut := viper.GetString(profileCpuFlag) + if cpuProfileOut != "" { + defer profile.Start(profile.CPUProfile, + profile.ProfilePath(cpuProfileOut), + profile.NoShutdownHook).Stop() + } + memProfileOut := viper.GetString(profileMemFlag) + if memProfileOut != "" { + defer profile.Start(profile.MemProfile, + profile.ProfilePath(memProfileOut), + profile.NoShutdownHook).Stop() } cmixParams, e2eParams := initParams() @@ -382,9 +388,6 @@ var rootCmd = &cobra.Command{ "Failed to cleanly close threads: %+v\n", err) } - if profileOut != "" { - pprof.StopCPUProfile() - } jww.INFO.Printf("Client exiting!") }, } @@ -1101,6 +1104,10 @@ func init() { "Enable cpu profiling to this file") viper.BindPFlag(profileCpuFlag, rootCmd.Flags().Lookup(profileCpuFlag)) + rootCmd.Flags().String(profileMemFlag, "", + "Enable memory profiling to this file") + viper.BindPFlag(profileMemFlag, rootCmd.Flags().Lookup(profileMemFlag)) + // Proto user flags rootCmd.Flags().String(protoUserPathFlag, "", "Path to proto user JSON file containing cryptographic primitives "+ diff --git a/cmix/client.go b/cmix/client.go index d164b4d2a60620176fe7fee12c5a26e95e351c99..d2dcee014faa90f9a1328db5bbd6ac1232703100 100644 --- a/cmix/client.go +++ b/cmix/client.go @@ -251,6 +251,9 @@ func (c *client) Follow(report ClientErrorReport) (stoppable.Stoppable, error) { // Start the processes for the identity handler multi.Add(c.Tracker.StartProcesses()) + //Start the critical processing thread + multi.Add(c.crit.startProcessies()) + return multi, nil } diff --git a/cmix/critical.go b/cmix/critical.go index 03ebfc7b56429b0fd0e8f588fa5ca2fe2e809491..719e6d9f0eff0774bdf083f01f07034a58ab6127 100644 --- a/cmix/critical.go +++ b/cmix/critical.go @@ -1,6 +1,8 @@ package cmix import ( + "time" + jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix/health" "gitlab.com/elixxir/client/stoppable" @@ -10,7 +12,6 @@ import ( "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" - "time" ) const criticalRawMessagesKey = "RawCriticalMessages" @@ -58,6 +59,12 @@ func newCritical(kv *versioned.KV, hm health.Monitor, return c } +func (c *critical) startProcessies() *stoppable.Single { + stop := stoppable.NewSingle("criticalStopper") + go c.runCriticalMessages(stop) + return stop +} + func (c *critical) runCriticalMessages(stop *stoppable.Single) { for { select { diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go index 961aac77627f0f5ef15ed35b839c2c5eaafa9b4b..8d9f8a6d2a168d27147f9fe280f2d777e0b9935c 100644 --- a/cmix/identity/tracker.go +++ b/cmix/identity/tracker.go @@ -55,7 +55,7 @@ type Tracker interface { } type manager struct { - tracked []TrackedID + tracked []*TrackedID ephemeral *receptionID.Store session storage.Session newIdentity chan TrackedID @@ -76,7 +76,7 @@ type TrackedID struct { func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager { // Initialization t := &manager{ - tracked: make([]TrackedID, 0), + tracked: make([]*TrackedID, 0), session: session, newIdentity: make(chan TrackedID, trackedIDChanSize), deleteIdentity: make(chan *id.ID, deleteIDChanSize), @@ -92,7 +92,7 @@ func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager jww.WARN.Printf("No tracked identities found, creating a new " + "tracked identity from legacy stored timestamp.") - t.tracked = append(t.tracked, TrackedID{ + t.tracked = append(t.tracked, &TrackedID{ // Make the next generation now so a generation triggers on // first run NextGeneration: netTime.Now(), @@ -155,7 +155,7 @@ func (t *manager) GetIdentity(get *id.ID) (TrackedID, error) { defer t.mux.Unlock() for i := range t.tracked { if get.Cmp(t.tracked[i].Source) { - return t.tracked[i], nil + return *t.tracked[i], nil } } return TrackedID{}, errors.Errorf("could not find id %s", get) @@ -201,7 +201,7 @@ func (t *manager) track(stop *stoppable.Single) { if !isOld { jww.DEBUG.Printf("Tracking new identity %s", newIdentity.Source) // Otherwise, add it to the list and run - t.tracked = append(t.tracked, newIdentity) + t.tracked = append(t.tracked, &newIdentity) } t.save() @@ -236,7 +236,8 @@ func (t *manager) processIdentities(addressSize uint8) time.Time { nextEvent := netTime.Now().Add(time.Duration(ephemeral.Period)) // Loop through every tracked ID and see if any operations are needed - for i, inQuestion := range t.tracked { + for i := range t.tracked { + inQuestion := t.tracked[i] // Generate new ephemeral if is time for it if netTime.Now().After(inQuestion.NextGeneration) { nextGeneration := t.generateIdentitiesOverRange(inQuestion, addressSize) @@ -267,7 +268,7 @@ func (t *manager) processIdentities(addressSize uint8) time.Time { // Process any deletions if len(toRemove) > 0 { - newTracked := make([]TrackedID, 0, len(t.tracked)) + newTracked := make([]*TrackedID, 0, len(t.tracked)) for i := range t.tracked { if _, remove := toRemove[i]; !remove { newTracked = append(newTracked, t.tracked[i]) @@ -305,7 +306,7 @@ func unmarshalTimestamp(lastTimestampObj *versioned.Object) (time.Time, error) { // generateIdentitiesOverRange generates and adds all not yet existing ephemeral Ids // and returns the timestamp of the next generation for the given TrackedID -func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, +func (t *manager) generateIdentitiesOverRange(inQuestion *TrackedID, addressSize uint8) time.Time { // Ensure that ephemeral IDs will not be generated after the // identity is invalid @@ -374,7 +375,7 @@ func (t *manager) save() { for i := range t.tracked { if t.tracked[i].Persistent { - persistent = append(persistent, t.tracked[i]) + persistent = append(persistent, *t.tracked[i]) } } diff --git a/cmix/identity/tracker_test.go b/cmix/identity/tracker_test.go index d16f64b5526f30e2d9719974ad1f82560b7f6b1f..dc9a895764c996abf1cf947c92139f2b7a23c71e 100644 --- a/cmix/identity/tracker_test.go +++ b/cmix/identity/tracker_test.go @@ -67,7 +67,7 @@ func TestManager_processIdentities(t *testing.T) { addrSpace.UpdateAddressSpace(18) session := storage.InitTestingSession(t) m := &manager{ - tracked: make([]TrackedID, 0), + tracked: make([]*TrackedID, 0), session: session, newIdentity: make(chan TrackedID, trackedIDChanSize), deleteIdentity: make(chan *id.ID, deleteIDChanSize), @@ -79,7 +79,7 @@ func TestManager_processIdentities(t *testing.T) { // Add some expired test IDs testId := id.NewIdFromUInt(0, id.User, t) validUntil := netTime.Now().Add(time.Minute) - m.tracked = append(m.tracked, TrackedID{ + m.tracked = append(m.tracked, &TrackedID{ NextGeneration: netTime.Now(), LastGeneration: time.Time{}, Source: testId, diff --git a/connect/authenticated.go b/connect/authenticated.go index 6a311978d78333ec9709151e7528c7da7f55657f..c45489fbc78ab87ab1115ab6da02d2b0fe5167f4 100644 --- a/connect/authenticated.go +++ b/connect/authenticated.go @@ -67,7 +67,7 @@ func ConnectWithAuthentication(recipient contact.Contact, user *xxdk.E2e, // Build the authenticated connection and return identity := user.GetReceptionIdentity() - privKey, err := identity.GetRSAPrivatePem() + privKey, err := identity.GetRSAPrivateKey() if err != nil { return nil, err } diff --git a/dummy/manager.go b/dummy/manager.go index 4832f3ef505ea37114c2f4d202c82604ddd7eab0..7bc4847134c5b95ebb776f81d04199ad0862878c 100644 --- a/dummy/manager.go +++ b/dummy/manager.go @@ -12,7 +12,7 @@ package dummy import ( "github.com/pkg/errors" - "gitlab.com/elixxir/client/interfaces" + "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/xxdk" @@ -21,20 +21,25 @@ import ( "time" ) +// Manager related thread handling constants. const ( + // The name of the Manager's stoppable.Stoppable dummyTrafficStoppableName = "DummyTraffic" - statusChanLen = 100 + + // The amount of statuses in queue that can be placed + // by Manager.SetStatus. + statusChanLen = 100 ) -// Thread status. +// The thread status values. const ( - notStarted uint32 = iota - running - paused - stopped + notStarted uint32 = iota // Sending thread has not been started + running // Sending thread is currently operating + paused // Sending thread is temporarily halted. + stopped // Sending thread is halted. ) -// Error messages. +// Error messages for Manager. const ( setStatusErr = "Failed to change status of dummy traffic send thread to %t: channel full" ) @@ -56,27 +61,41 @@ type Manager struct { // Pauses/Resumes the dummy send thread when triggered statusChan chan bool - // Cmix interfaces - net *xxdk.Cmix - store *storage.Session - networkManager interfaces.NetworkManager - rng *fastRNG.StreamGenerator + // Interfaces + net cmix.Client + store storage.Session + + // Generates + rng *fastRNG.StreamGenerator } -// NewManager creates a new dummy Manager with the specified average send delta -// and the range used for generating random durations. -func NewManager(maxNumMessages int, avgSendDelta, randomRange time.Duration, - net *xxdk.Cmix, manager interfaces.NetworkManager) *Manager { - clientStorage := net.GetStorage() - return newManager(maxNumMessages, avgSendDelta, randomRange, net, - &clientStorage, manager, net.GetRng()) +// NewManager creates a Manager object and initialises the +// dummy traffic sending thread. Note that the Manager does not start sending dummy +// traffic until `True` is passed into Manager.SetStatus. The time duration +// between each sending operation and the amount of messages sent each interval +// are randomly generated values with bounds defined by the +// given parameters below. +// +// Params: +// - maxNumMessages - the upper bound of the random number of messages sent +// each sending cycle. +// - avgSendDeltaMS - the average duration, in milliseconds, to wait +// between sends. +// - randomRangeMS - the upper bound of the interval between sending cycles, +// in milliseconds. Sends occur every avgSendDeltaMS +/- a random duration +// with an upper bound of randomRangeMS. +func NewManager(maxNumMessages int, + avgSendDelta, randomRange time.Duration, + net *xxdk.Cmix) *Manager { + + return newManager(maxNumMessages, avgSendDelta, randomRange, net.GetCmix(), + net.GetStorage(), net.GetRng()) } // newManager builds a new dummy Manager from fields explicitly passed in. This -// function is a helper function for NewManager to make it easier to test. +// function is a helper function for NewManager. func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration, - net *xxdk.Cmix, store *storage.Session, networkManager interfaces.NetworkManager, - rng *fastRNG.StreamGenerator) *Manager { + net cmix.Client, store storage.Session, rng *fastRNG.StreamGenerator) *Manager { return &Manager{ maxNumMessages: maxNumMessages, avgSendDelta: avgSendDelta, @@ -85,13 +104,12 @@ func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration, statusChan: make(chan bool, statusChanLen), net: net, store: store, - networkManager: networkManager, rng: rng, } } // StartDummyTraffic starts the process of sending dummy traffic. This function -// matches the xxdk.Service type. +// adheres to xxdk.Service. func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) { stop := stoppable.NewSingle(dummyTrafficStoppableName) go m.sendThread(stop) @@ -99,13 +117,19 @@ func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) { return stop, nil } -// SetStatus sets the state of the dummy traffic send thread, which determines -// if the thread is running or paused. The possible statuses are: -// true = send thread is sending dummy messages -// false = send thread is paused/stopped and not sending dummy messages -// Returns an error if the channel is full. -// Note that this function cannot change the status of the send thread if it has -// yet to be started via StartDummyTraffic or if it has been stopped. +// SetStatus sets the state of the dummy traffic send thread by passing in +// a boolean parameter. There may be a small delay in between this call +// and the status of the sending thread to change accordingly. For example, +// passing False into this call while the sending thread is currently sending messages +// will not cancel nor halt the sending operation, but will pause the thread once that +// operation has completed. +// +// Params: +// - boolean - Input should be true if you want to send dummy messages. +// Input should be false if you want to pause dummy messages. +// Returns: +// - error - if the Manager.SetStatus is called too frequently, causing the +// internal status channel to fill. func (m *Manager) SetStatus(status bool) error { select { case m.statusChan <- status: @@ -115,13 +139,16 @@ func (m *Manager) SetStatus(status bool) error { } } -// GetStatus returns the current state of the dummy traffic send thread. It has -// the following return values: -// true = send thread is sending dummy messages -// false = send thread is paused/stopped and not sending dummy messages -// Note that this function does not return the status set by SetStatus directly; -// it returns the current status of the send thread, which means any call to -// SetStatus will have a small delay before it is returned by GetStatus. +// GetStatus returns the current state of the Manager's sending thread. +// Note that this function does not return the status set by the most recent call to +// SetStatus. Instead, this call returns the current status of the sending thread. +// This is due to the small delay that may occur between calling SetStatus and the +// sending thread taking into effect that status change. +// +// Returns: +// - boolean - Returns true if sending thread is sending dummy messages. +// Returns false if sending thread is paused/stopped and is +// not sending dummy messages. func (m *Manager) GetStatus() bool { switch atomic.LoadUint32(&m.status) { case running: diff --git a/dummy/manager_test.go b/dummy/manager_test.go index 6a49bcc6a597ebf476ee8bbfb8f45a79045a4488..5ce9cdaee7792078681a22255e53a8039677f041 100644 --- a/dummy/manager_test.go +++ b/dummy/manager_test.go @@ -27,7 +27,7 @@ func Test_newManager(t *testing.T) { } received := newManager(expected.maxNumMessages, expected.avgSendDelta, - expected.randomRange, nil, nil, nil, nil) + expected.randomRange, nil, nil, nil) if statusChanLen != cap(received.statusChan) { t.Errorf("Capacity of status channel unexpected."+ @@ -45,7 +45,7 @@ func Test_newManager(t *testing.T) { // Tests that Manager.StartDummyTraffic sends dummy messages and that it stops // when the stoppable is closed. func TestManager_StartDummyTraffic(t *testing.T) { - m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) + m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t) err := m.SetStatus(true) if err != nil { @@ -59,7 +59,7 @@ func TestManager_StartDummyTraffic(t *testing.T) { msgChan := make(chan bool) go func() { - for m.networkManager.(*testNetworkManager).GetMsgListLen() == 0 { + for m.net.(*mockCmix).GetMsgListLen() == 0 { time.Sleep(5 * time.Millisecond) } msgChan <- true @@ -71,7 +71,7 @@ func TestManager_StartDummyTraffic(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived += m.net.(*mockCmix).GetMsgListLen() } err = stop.Close() @@ -86,7 +86,7 @@ func TestManager_StartDummyTraffic(t *testing.T) { msgChan = make(chan bool) go func() { - for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived { + for m.net.(*mockCmix).GetMsgListLen() == numReceived { time.Sleep(5 * time.Millisecond) } msgChan <- true @@ -104,7 +104,7 @@ func TestManager_StartDummyTraffic(t *testing.T) { // can be called multiple times with the same status without it affecting // anything. Also tests that the thread quits even when paused. func TestManager_SetStatus(t *testing.T) { - m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) + m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t) err := m.SetStatus(false) if err != nil { @@ -118,10 +118,10 @@ func TestManager_SetStatus(t *testing.T) { go func() { var numReceived int for i := 0; i < 2; i++ { - for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived { + for m.net.(*mockCmix).GetMsgListLen() == numReceived { time.Sleep(5 * time.Millisecond) } - numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived = m.net.(*mockCmix).GetMsgListLen() msgChan <- true } }() @@ -161,7 +161,7 @@ func TestManager_SetStatus(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived += m.net.(*mockCmix).GetMsgListLen() } // Setting status to true multiple times does not interrupt sending @@ -177,10 +177,10 @@ func TestManager_SetStatus(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived { + if m.net.(*mockCmix).GetMsgListLen() <= numReceived { t.Errorf("Failed to receive second send."+ "\nmessages on last receive: %d\nmessages on this receive: %d", - numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen()) + numReceived, m.net.(*mockCmix).GetMsgListLen()) } } @@ -213,7 +213,7 @@ func TestManager_SetStatus(t *testing.T) { // Error path: tests that Manager.SetStatus returns an error if the status // cannot be set. func TestManager_SetStatus_ChannelError(t *testing.T) { - m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) + m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t) // Send the max number of status changes on the channel for i := 0; i < statusChanLen; i++ { @@ -236,7 +236,7 @@ func TestManager_SetStatus_ChannelError(t *testing.T) { // Tests that Manager.GetStatus gets the correct status before the send thread // starts, while sending, while paused, and after it is stopped. func TestManager_GetStatus(t *testing.T) { - m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) + m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t) err := m.SetStatus(false) if err != nil { @@ -254,10 +254,10 @@ func TestManager_GetStatus(t *testing.T) { go func() { var numReceived int for i := 0; i < 2; i++ { - for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived { + for m.net.(*mockCmix).GetMsgListLen() == numReceived { time.Sleep(5 * time.Millisecond) } - numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived = m.net.(*mockCmix).GetMsgListLen() msgChan <- true } }() @@ -292,7 +292,7 @@ func TestManager_GetStatus(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived += m.net.(*mockCmix).GetMsgListLen() } // Setting status to true multiple times does not interrupt sending @@ -311,10 +311,10 @@ func TestManager_GetStatus(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived { + if m.net.(*mockCmix).GetMsgListLen() <= numReceived { t.Errorf("Failed to receive second send."+ "\nmessages on last receive: %d\nmessages on this receive: %d", - numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen()) + numReceived, m.net.(*mockCmix).GetMsgListLen()) } } diff --git a/dummy/mockCmix_test.go b/dummy/mockCmix_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f8211be97a777d23f59458416075154dd055e067 --- /dev/null +++ b/dummy/mockCmix_test.go @@ -0,0 +1,219 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package dummy + +import ( + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/gateway" + "gitlab.com/elixxir/client/cmix/identity" + "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/client/cmix/rounds" + "gitlab.com/elixxir/client/stoppable" + "gitlab.com/elixxir/comms/network" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "sync" + "time" +) + +// mockCmix is a testing structure that adheres to cmix.Client. +type mockCmix struct { + messages map[id.ID]format.Message + sync.RWMutex + payloadSize int +} + +func newMockCmix(payloadSize int) cmix.Client { + + return &mockCmix{ + messages: make(map[id.ID]format.Message), + payloadSize: payloadSize, + } +} + +func (m *mockCmix) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) { + m.Lock() + defer m.Unlock() + m.messages[*recipient] = generateMessage(m.payloadSize, fingerprint, service, payload, mac) + + return 0, ephemeral.Id{}, nil +} + +func (m *mockCmix) GetMsgListLen() int { + m.RLock() + defer m.RUnlock() + return len(m.messages) +} + +func (m *mockCmix) GetMsgList() map[id.ID]format.Message { + m.RLock() + defer m.RUnlock() + return m.messages +} + +func (m mockCmix) Follow(report cmix.ClientErrorReport) (stoppable.Stoppable, error) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetMaxMessageLength() int { + //TODO implement me + panic("implement me") +} + +func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (id.Round, []ephemeral.Id, error) { + //TODO implement me + panic("implement me") +} + +func (m *mockCmix) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) { + //TODO implement me + panic("implement me") +} + +func (m *mockCmix) RemoveIdentity(id *id.ID) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetIdentity(get *id.ID) (identity.TrackedID, error) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, mp message.Processor) error { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) DeleteClientFingerprints(identity *id.ID) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) AddService(clientID *id.ID, newService message.Service, response message.Processor) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) DeleteService(clientID *id.ID, toDelete message.Service, processor message.Processor) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) DeleteClientService(clientID *id.ID) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) TrackServices(tracker message.ServicesTracker) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) CheckInProgressMessages() { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) IsHealthy() bool { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) WasHealthy() bool { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) AddHealthCallback(f func(bool)) uint64 { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) RemoveHealthCallback(u uint64) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) HasNode(nid *id.ID) bool { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) NumRegisteredNodes() int { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) TriggerNodeRegistration(nid *id.ID) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) error { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) LookupHistoricalRound(rid id.Round, callback rounds.RoundResultCallback) error { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) SendToPreferred(targets []*id.ID, sendFunc gateway.SendToPreferredFunc, stop *stoppable.Single, timeout time.Duration) (interface{}, error) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) SetGatewayFilter(f gateway.Filter) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetHostParams() connect.HostParams { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetAddressSpace() uint8 { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) RegisterAddressSpaceNotification(tag string) (chan uint8, error) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) UnregisterAddressSpaceNotification(tag string) { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetInstance() *network.Instance { + //TODO implement me + panic("implement me") +} + +func (m mockCmix) GetVerboseRounds() string { + //TODO implement me + panic("implement me") +} diff --git a/dummy/random.go b/dummy/random.go index 8c8a87a6cc0328f136f2444125cde62c92972a0b..4190336b55ed461c4264ad259340876bc676afc7 100644 --- a/dummy/random.go +++ b/dummy/random.go @@ -10,42 +10,77 @@ package dummy import ( "encoding/binary" "github.com/pkg/errors" + "gitlab.com/elixxir/client/cmix/message" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/primitives/id" "time" ) // Error messages. +// Error constants for Manager.newRandomCmixMessage and it's helper functions.. const ( payloadSizeRngErr = "failed to generate random payload size: %+v" + payloadRngErr = "failed to generate random payload: %+v" + fingerprintRngErr = "failed to generate random fingerprint: %+v" + macRngErr = "failed to generate random MAC: %+v" + recipientRngErr = "failed to generate random recipient: %+v" ) -// intRng returns, as an int, a non-negative, non-zero random number in [1, n) -// from the csprng.Source. -func intRng(n int, rng csprng.Source) (int, error) { - v, err := csprng.Generate(8, rng) +// newRandomCmixMessage returns random format.Message data. +// +// Returns in order a: +// - Recipient (id.ID) +// - Message fingerprint (format.Fingerprint) +// - Message service (message.Service) +// - Payload ([]byte) +// - MAC ([]byte) +// - Error if there was an issue randomly generating any of the above data. +// The error will specify which of the above failed to be randomly generated. +func (m *Manager) newRandomCmixMessage(rng csprng.Source) ( + recipient *id.ID, fingerprint format.Fingerprint, + service message.Service, + payload, mac []byte, err error) { + + // Generate random recipient + recipient, err = id.NewRandomID(rng, id.User) if err != nil { - return 0, err + return nil, format.Fingerprint{}, message.Service{}, nil, nil, + errors.Errorf(recipientRngErr, err) } - return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil -} + // Generate random message payload + payloadSize := m.store.GetCmixGroup().GetP().ByteLen() + payload, err = newRandomPayload(payloadSize, rng) + if err != nil { + return nil, format.Fingerprint{}, message.Service{}, nil, nil, + errors.Errorf(payloadRngErr, err) + } -// durationRng returns a duration that is the base duration plus or minus a -// random duration of max randomRange. -func durationRng(base, randomRange time.Duration, rng csprng.Source) ( - time.Duration, error) { - delta, err := intRng(int(2*randomRange), rng) + // Generate random fingerprint + fingerprint, err = newRandomFingerprint(rng) if err != nil { - return 0, err + return nil, format.Fingerprint{}, message.Service{}, nil, nil, + errors.Errorf(fingerprintRngErr, err) } - return base + randomRange - time.Duration(delta), nil + // Generate random MAC + mac, err = newRandomMAC(rng) + if err != nil { + return nil, format.Fingerprint{}, message.Service{}, nil, nil, + errors.Errorf(macRngErr, err) + } + + // Generate random service + service = message.GetRandomService(rng) + + return } -// newRandomPayload generates a random payload of a random length. +// newRandomPayload generates a random payload of a random length +// within the maxPayloadSize. func newRandomPayload(maxPayloadSize int, rng csprng.Source) ([]byte, error) { // Generate random payload size - randomPayloadSize, err := intRng(maxPayloadSize, rng) + randomPayloadSize, err := randomInt(maxPayloadSize, rng) if err != nil { return nil, errors.Errorf(payloadSizeRngErr, err) } @@ -86,3 +121,32 @@ func newRandomMAC(rng csprng.Source) ([]byte, error) { return mac, nil } + +////////////////////////////////////////////////////////////////////////////////// +// Miscellaneous +////////////////////////////////////////////////////////////////////////////////// + +// randomDuration returns a duration that is the base duration plus or minus a +// random duration of max randomRange. +func randomDuration(base, randomRange time.Duration, rng csprng.Source) ( + time.Duration, error) { + + // Generate a random duration + delta, err := randomInt(int(2*randomRange), rng) + if err != nil { + return 0, err + } + + return base + randomRange - time.Duration(delta), nil +} + +// randomInt returns, as an int, a non-negative, non-zero random number in [1, n) +// from the csprng.Source. +func randomInt(n int, rng csprng.Source) (int, error) { + v, err := csprng.Generate(8, rng) + if err != nil { + return 0, err + } + + return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil +} diff --git a/dummy/random_test.go b/dummy/random_test.go index 661986a0416993e211209d009a023c451dd3ff60..3303425c884da1febf5ddecc9b3850b8221e1e33 100644 --- a/dummy/random_test.go +++ b/dummy/random_test.go @@ -13,7 +13,7 @@ import ( "time" ) -// Consistency test: tests that intRng returns the expected int when using a +// Consistency test: tests that randomInt returns the expected int when using a // PRNG and that the result is not larger than the max. func Test_intRng_Consistency(t *testing.T) { expectedInts := []int{15, 1, 35, 13, 42, 52, 57, 3, 48} @@ -22,9 +22,9 @@ func Test_intRng_Consistency(t *testing.T) { max := 64 for i, expected := range expectedInts { - v, err := intRng(max, prng) + v, err := randomInt(max, prng) if err != nil { - t.Errorf("intRng returned an error (%d): %+v", i, err) + t.Errorf("randomInt returned an error (%d): %+v", i, err) } if v != expected { @@ -40,7 +40,7 @@ func Test_intRng_Consistency(t *testing.T) { } } -// Consistency test: tests that durationRng returns the expected int when using +// Consistency test: tests that randomDuration returns the expected int when using // a PRNG and that the result is within the allowed range. func Test_durationRng_Consistency(t *testing.T) { expectedDurations := []time.Duration{ @@ -52,9 +52,9 @@ func Test_durationRng_Consistency(t *testing.T) { base, randomRange := time.Minute, 15*time.Second for i, expected := range expectedDurations { - v, err := durationRng(base, randomRange, prng) + v, err := randomDuration(base, randomRange, prng) if err != nil { - t.Errorf("durationRng returned an error (%d): %+v", i, err) + t.Errorf("randomDuration returned an error (%d): %+v", i, err) } if v != expected { diff --git a/dummy/send.go b/dummy/send.go index 84271b67ea4310bf91af057a58ffe2256520460a..06561c941434643f6f77af8105f78323b4d3c47b 100644 --- a/dummy/send.go +++ b/dummy/send.go @@ -8,192 +8,137 @@ package dummy import ( + "gitlab.com/elixxir/client/cmix" + "gitlab.com/xx_network/crypto/csprng" "sync" "sync/atomic" "time" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/stoppable" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/crypto/csprng" - "gitlab.com/xx_network/primitives/id" ) -// Error messages. +// Error messages for the Manager.sendThread and its helper functions. const ( - numMsgsRngErr = "failed to generate random number of messages to send: %+v" - payloadRngErr = "failed to generate random payload: %+v" - recipientRngErr = "failed to generate random recipient: %+v" - fingerprintRngErr = "failed to generate random fingerprint: %+v" - macRngErr = "failed to generate random MAC: %+v" + numMsgsRngErr = "failed to generate random number of messages to send: %+v" ) // sendThread is a thread that sends the dummy messages at random intervals. func (m *Manager) sendThread(stop *stoppable.Single) { - jww.DEBUG.Print("Starting dummy traffic sending thread.") + jww.INFO.Print("Starting dummy traffic sending thread.") nextSendChan := make(<-chan time.Time) nextSendChanPtr := &(nextSendChan) for { select { - case <-stop.Quit(): - m.stopSendThread(stop) - return case status := <-m.statusChan: if status { atomic.StoreUint32(&m.status, running) - nextSendChanPtr = &(m.randomTimer().C) + // Generate random duration + rng := m.rng.GetStream() + duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng) + if err != nil { + rng.Close() + jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err) + } + rng.Close() + + // Create timer + nextSendChanPtr = &(time.NewTimer(duration).C) + } else { atomic.StoreUint32(&m.status, paused) nextSendChan = make(<-chan time.Time) nextSendChanPtr = &nextSendChan } case <-*nextSendChanPtr: - nextSendChanPtr = &(m.randomTimer().C) - - go func() { - // get list of random messages and recipients - rng := m.rng.GetStream() - msgs, err := m.newRandomMessages(rng) - if err != nil { - jww.FATAL.Panicf("Failed to generate dummy messages: %+v", err) - } + // Generate random duration + rng := m.rng.GetStream() + duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng) + if err != nil { rng.Close() + jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err) + } + rng.Close() + + // Create timer + nextSendChanPtr = &(time.NewTimer(duration).C) - err = m.sendMessages(msgs) + // Send messages + go func() { + err := m.sendMessages() if err != nil { - jww.FATAL.Panicf("Failed to send dummy messages: %+v", err) + jww.ERROR.Printf("Failed to send dummy messages: %+v", err) } }() + case <-stop.Quit(): + m.stopSendThread(stop) + return } } } -// stopSendThread is triggered when the stoppable is triggered. It prints a -// debug message, sets the thread status to stopped, and sets the status of the -// stoppable to stopped. -func (m *Manager) stopSendThread(stop *stoppable.Single) { - jww.DEBUG.Print( - "Stopping dummy traffic sending thread: stoppable triggered") - atomic.StoreUint32(&m.status, stopped) - stop.ToStopped() -} - // sendMessages generates and sends random messages. -func (m *Manager) sendMessages(msgs map[id.ID]format.Message) error { - var sent, i int64 +func (m *Manager) sendMessages() error { + var sent int64 var wg sync.WaitGroup - for recipient, msg := range msgs { - wg.Add(1) + // Randomly generate amount of messages to send + rng := m.rng.GetStream() + defer rng.Close() + numMessages, err := randomInt(m.maxNumMessages+1, rng) + if err != nil { + return errors.Errorf(numMsgsRngErr, err) + } - go func(i int64, recipient id.ID, msg format.Message) { + for i := 0; i < numMessages; i++ { + wg.Add(1) + go func(localIndex, totalMessages int) { defer wg.Done() - // Fill the preimage with random data to ensure it is not repeatable - p := cmix.GetDefaultParams() - // FIXME: these fields no longer available - // through these params objects - // p.IdentityPreimage = make([]byte, 32) - // rng := m.rng.GetStream() - // if _, err := rng.Read(p.IdentityPreimage); err != nil { - // jww.FATAL.Panicf("Failed to generate data for random identity "+ - // "preimage in e2e send: %+v", err) - // } - // rng.Close() - // p.DebugTag = "dummy" - _, _, err := m.networkManager.SendCMIX(msg, &recipient, p) + err = m.sendMessage(localIndex, totalMessages, rng) if err != nil { - jww.WARN.Printf("Failed to send dummy message %d/%d via "+ - "Send: %+v", i, len(msgs), err) - } else { - atomic.AddInt64(&sent, 1) + jww.ERROR.Printf("Failed to send message %d/%d: %+v", + localIndex, numMessages, err) } - }(i, recipient, msg) - - i++ + // Add to counter of successful sends + atomic.AddInt64(&sent, 1) + }(i, numMessages) } wg.Wait() - - jww.INFO.Printf("Sent %d/%d dummy messages.", sent, len(msgs)) - + jww.INFO.Printf("Sent %d/%d dummy messages.", sent, numMessages) return nil } -// newRandomMessages returns a map of a random recipients and random messages of -// a randomly generated length in [1, Manager.maxNumMessages]. -func (m *Manager) newRandomMessages(rng csprng.Source) ( - map[id.ID]format.Message, error) { - numMessages, err := intRng(m.maxNumMessages+1, rng) - if err != nil { - return nil, errors.Errorf(numMsgsRngErr, err) - } - - msgs := make(map[id.ID]format.Message, numMessages) - - for i := 0; i < numMessages; i++ { - // Generate random recipient - recipient, err := id.NewRandomID(rng, id.User) - if err != nil { - return nil, errors.Errorf(recipientRngErr, err) - } - - msgs[*recipient], err = m.newRandomCmixMessage(rng) - if err != nil { - return nil, err - } - } - - return msgs, nil -} - -// newRandomCmixMessage returns a new cMix message filled with a randomly -// generated payload, fingerprint, and MAC. -func (m *Manager) newRandomCmixMessage(rng csprng.Source) (format.Message, error) { - // Create new empty cMix message - clientStorage := *m.store - cMixMsg := format.NewMessage(clientStorage.GetCmixGroup().GetP().ByteLen()) - - // Generate random message - randomMsg, err := newRandomPayload(cMixMsg.ContentsSize(), rng) +// sendMessage is a helper function which generates a sends a single random format.Message +// to a random recipient. +func (m *Manager) sendMessage(index, totalMessages int, rng csprng.Source) error { + // Generate message data + recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(rng) if err != nil { - return format.Message{}, errors.Errorf(payloadRngErr, err) + return errors.Errorf("Failed to create random data: %+v", err) } - // Generate random fingerprint - fingerprint, err := newRandomFingerprint(rng) + // Send message + p := cmix.GetDefaultCMIXParams() + _, _, err = m.net.Send(recipient, fp, service, payload, mac, p) if err != nil { - return format.Message{}, errors.Errorf(fingerprintRngErr, err) + return errors.Errorf("Failed to send message: %+v", err) } - // Generate random MAC - mac, err := newRandomMAC(rng) - if err != nil { - return format.Message{}, errors.Errorf(macRngErr, err) - } - - // Set contents, fingerprint, and MAC, of the cMix message - cMixMsg.SetContents(randomMsg) - cMixMsg.SetKeyFP(fingerprint) - cMixMsg.SetMac(mac) - - return cMixMsg, nil + return nil } -// randomTimer generates a timer that will trigger after a random duration. -func (m *Manager) randomTimer() *time.Timer { - rng := m.rng.GetStream() - - duration, err := durationRng(m.avgSendDelta, m.randomRange, rng) - if err != nil { - jww.FATAL.Panicf("Failed to generate random duration to wait to send "+ - "dummy messages: %+v", err) - } - - return time.NewTimer(duration) +// stopSendThread is triggered when the stoppable is triggered. It prints a +// debug message, sets the thread status to stopped, and sets the status of the +// stoppable to stopped. +func (m *Manager) stopSendThread(stop *stoppable.Single) { + jww.DEBUG.Print( + "Stopping dummy traffic sending thread: stoppable triggered") + atomic.StoreUint32(&m.status, stopped) + stop.ToStopped() } diff --git a/dummy/send_test.go b/dummy/send_test.go index 9af8ee8796e4d76faa7d45188c60db271d772335..ef776b17ba9084fe07d34ab453ed890ab9b9f0f4 100644 --- a/dummy/send_test.go +++ b/dummy/send_test.go @@ -9,7 +9,6 @@ package dummy import ( "bytes" - "encoding/base64" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" @@ -21,7 +20,7 @@ import ( // Tests that Manager.sendThread sends multiple sets of messages. func TestManager_sendThread(t *testing.T) { - m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) + m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t) stop := stoppable.NewSingle("sendThreadTest") go m.sendThread(stop) @@ -40,10 +39,10 @@ func TestManager_sendThread(t *testing.T) { go func() { var numReceived int for i := 0; i < 2; i++ { - for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived { + for m.net.(*mockCmix).GetMsgListLen() == numReceived { time.Sleep(5 * time.Millisecond) } - numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived = m.net.(*mockCmix).GetMsgListLen() msgChan <- true } }() @@ -54,7 +53,7 @@ func TestManager_sendThread(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen() + numReceived += m.net.(*mockCmix).GetMsgListLen() } select { @@ -62,10 +61,10 @@ func TestManager_sendThread(t *testing.T) { t.Errorf("Timed out after %s waiting for messages to be sent.", 3*m.avgSendDelta) case <-msgChan: - if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived { + if m.net.(*mockCmix).GetMsgListLen() <= numReceived { t.Errorf("Failed to receive second send."+ "\nmessages on last receive: %d\nmessages on this receive: %d", - numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen()) + numReceived, m.net.(*mockCmix).GetMsgListLen()) } } @@ -86,36 +85,37 @@ func TestManager_sendThread(t *testing.T) { } -// Tests that Manager.sendMessages sends all the messages with the correct -// recipient. -func TestManager_sendMessages(t *testing.T) { - m := newTestManager(100, 0, 0, false, t) - prng := NewPrng(42) +// Tests that sendMessage generates random message data using pseudo-RNGs. +func TestManager_sendMessage(t *testing.T) { + m := newTestManager(100, 0, 0, t) + + // Generate two identical RNGs, one for generating expected data (newRandomCmixMessage) + // and one for received data (sendMessage) + prngOne := NewPrng(42) + prngTwo := NewPrng(42) // Generate map of recipients and messages msgs := make(map[id.ID]format.Message, m.maxNumMessages) for i := 0; i < m.maxNumMessages; i++ { - recipient, err := id.NewRandomID(prng, id.User) + // Generate random data + recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(prngOne) if err != nil { - t.Errorf("Failed to generate random recipient ID (%d): %+v", i, err) + t.Fatalf("Failed to generate random cMix message (%d): %+v", i, err) } - msg, err := m.newRandomCmixMessage(prng) + payloadSize := m.store.GetCmixGroup().GetP().ByteLen() + msgs[*recipient] = generateMessage(payloadSize, fp, service, payload, mac) + + // Send the messages + err = m.sendMessage(i, m.maxNumMessages, prngTwo) if err != nil { - t.Errorf("Failed to generate random cMix message (%d): %+v", i, err) + t.Errorf("sendMessages returned an error: %+v", err) } - msgs[*recipient] = msg - } - - // Send the messages - err := m.sendMessages(msgs) - if err != nil { - t.Errorf("sendMessages returned an error: %+v", err) } // get sent messages - receivedMsgs := m.networkManager.(*testNetworkManager).GetMsgList() + receivedMsgs := m.net.(*mockCmix).GetMsgList() // Test that all messages were received if len(receivedMsgs) != len(msgs) { @@ -127,60 +127,46 @@ func TestManager_sendMessages(t *testing.T) { for recipient, msg := range msgs { receivedMsg, exists := receivedMsgs[recipient] if !exists { - t.Errorf("Failed to receive message from %s: %+v", &recipient, msg) - } else if !reflect.DeepEqual(msg, receivedMsg) { + t.Errorf("Failed to receive message from %s: %+v", &recipient, msg.Marshal()) + } else if !reflect.DeepEqual(msg.Marshal(), receivedMsg.Marshal()) { + // In mockCmix.Send, we map recipientId to the passed fingerprint. t.Errorf("Received unexpected message for recipient %s."+ "\nexpected: %+v\nreceived: %+v", &recipient, msg, receivedMsg) } } } -// Tests that Manager.newRandomMessages creates a non-empty map of messages and -// that each message is unique. -func TestManager_newRandomMessages(t *testing.T) { - m := newTestManager(10, 0, 0, false, t) +// Tests that newRandomCmixMessage generates cMix message data with +// populated recipient, payload, fingerprint, and MAC. +func TestManager_newRandomCmixMessage(t *testing.T) { + m := newTestManager(0, 0, 0, t) prng := NewPrng(42) - msgMap, err := m.newRandomMessages(prng) + // Generate data + recipient, fp, _, payload, mac, err := m.newRandomCmixMessage(prng) if err != nil { - t.Errorf("newRandomMessages returned an error: %+v", err) - } - - if len(msgMap) == 0 { - t.Error("Message map is empty.") + t.Fatalf("newRandomCmixMessage returned an error: %+v", err) } - marshalledMsgs := make(map[string]format.Message, len(msgMap)) - for _, msg := range msgMap { - msgString := base64.StdEncoding.EncodeToString(msg.Marshal()) - if _, exists := marshalledMsgs[msgString]; exists { - t.Errorf("Message not unique.") - } else { - marshalledMsgs[msgString] = msg - } + // Check that recipient is not empty data + if bytes.Equal(recipient.Bytes(), make([]byte, id.ArrIDLen)) { + t.Errorf("Recipient ID not set") } -} - -// Tests that Manager.newRandomCmixMessage generates a cMix message with -// populated contents, fingerprint, and MAC. -func TestManager_newRandomCmixMessage(t *testing.T) { - m := newTestManager(0, 0, 0, false, t) - prng := NewPrng(42) - cMixMsg, err := m.newRandomCmixMessage(prng) - if err != nil { - t.Errorf("newRandomCmixMessage returned an error: %+v", err) - } - - if bytes.Equal(cMixMsg.GetContents(), make([]byte, len(cMixMsg.GetContents()))) { + // Check that payload is not empty data + payloadSize := m.store.GetCmixGroup().GetP().ByteLen() + if bytes.Equal(payload, make([]byte, payloadSize)) { t.Error("cMix message contents not set.") } - if cMixMsg.GetKeyFP() == (format.Fingerprint{}) { + // Check that fingerprint is not empty data + if fp == (format.Fingerprint{}) { t.Error("cMix message fingerprint not set.") } - if bytes.Equal(cMixMsg.GetMac(), make([]byte, format.MacLen)) { + // Check that mac is not empty data + if bytes.Equal(mac, make([]byte, format.MacLen)) { t.Error("cMix message MAC not set.") } + } diff --git a/dummy/utils_test.go b/dummy/utils_test.go index bc838731f5f42b345c4fbdfd849750b4551c0ef5..a3780867a513a6c497157bd17ccfceef89f2a5ec 100644 --- a/dummy/utils_test.go +++ b/dummy/utils_test.go @@ -8,27 +8,13 @@ package dummy import ( - "github.com/pkg/errors" - "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/gateway" "gitlab.com/elixxir/client/cmix/message" - "gitlab.com/elixxir/client/event" - "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/comms/network" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/csprng" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/id/ephemeral" - "gitlab.com/xx_network/primitives/ndf" "io" "math/rand" - "sync" "testing" "time" ) @@ -51,201 +37,35 @@ func (s *Prng) SetSeed([]byte) error { return nil } // newTestManager creates a new Manager that has groups stored for testing. One // of the groups in the list is also returned. func newTestManager(maxNumMessages int, avgSendDelta, randomRange time.Duration, - sendErr bool, t *testing.T) *Manager { + t *testing.T) *Manager { store := storage.InitTestingSession(t) + payloadSize := store.GetCmixGroup().GetP().ByteLen() m := &Manager{ maxNumMessages: maxNumMessages, avgSendDelta: avgSendDelta, randomRange: randomRange, statusChan: make(chan bool, statusChanLen), - store: &store, - networkManager: newTestNetworkManager(sendErr, t), + store: store, + net: newMockCmix(payloadSize), rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG), } return m } -// //////////////////////////////////////////////////////////////////////////////// -// // Test Network State // -// //////////////////////////////////////////////////////////////////////////////// - -// // testNetworkManager is a test implementation of NetworkManager interface. -type testNetworkManager struct { - instance *network.Instance - messages map[id.ID]format.Message - sendErr bool - sync.RWMutex -} - -func newTestNetworkManager(sendErr bool, t *testing.T) interfaces.NetworkManager { - instanceComms := &connect.ProtoComms{ - Manager: connect.NewManagerTesting(t), - } - - thisInstance, err := network.NewInstanceTesting(instanceComms, getNDF(), - getNDF(), nil, nil, t) - if err != nil { - t.Fatalf("Failed to create new test instance: %v", err) - } - - return &testNetworkManager{ - instance: thisInstance, - messages: make(map[id.ID]format.Message), - sendErr: sendErr, - } -} - -func (tnm *testNetworkManager) GetMsgListLen() int { - tnm.RLock() - defer tnm.RUnlock() - return len(tnm.messages) -} - -func (tnm *testNetworkManager) GetMsgList() map[id.ID]format.Message { - tnm.RLock() - defer tnm.RUnlock() - return tnm.messages -} - -func (tnm *testNetworkManager) GetMsg(recipient id.ID) format.Message { - tnm.RLock() - defer tnm.RUnlock() - return tnm.messages[recipient] -} - -// TEST -func (tnm *testNetworkManager) SendE2E() ( - []id.Round, e2e.MessageID, time.Time, error) { - return nil, e2e.MessageID{}, time.Time{}, nil -} - -// TEST -func (tnm *testNetworkManager) SendUnsafe() ([]id.Round, error) { - return []id.Round{}, nil -} - -func (tnm *testNetworkManager) SendCMIX(message format.Message, - recipient *id.ID, _ cmix.Params) (id.Round, ephemeral.Id, error) { - tnm.Lock() - defer tnm.Unlock() - - if tnm.sendErr { - return 0, ephemeral.Id{}, errors.New("Send error") - } +// generateMessage is a utility function which generates a format.Message +// given message data. +func generateMessage(payloadSize int, + fingerprint format.Fingerprint, + service message.Service, + payload, mac []byte) format.Message { - tnm.messages[*recipient] = message + // Build message. Will panic if inputs are not correct. + msg := format.NewMessage(payloadSize) + msg.SetContents(payload) + msg.SetKeyFP(fingerprint) + msg.SetSIH(service.Hash(msg.GetContents())) + msg.SetMac(mac) - return 0, ephemeral.Id{}, nil -} - -func (tnm *testNetworkManager) SendManyCMIX([]cmix.TargetedCmixMessage, cmix.Params) ( - id.Round, []ephemeral.Id, error) { - return 0, nil, nil -} - -type dummyEventMgr struct{} - -func (d *dummyEventMgr) Report(int, string, string, string) {} -func (tnm *testNetworkManager) GetEventManager() event.Reporter { - return &dummyEventMgr{} -} - -func (tnm *testNetworkManager) GetInstance() *network.Instance { return tnm.instance } -func (tnm *testNetworkManager) GetAddressSpace() uint8 { return 0 } -func (tnm *testNetworkManager) GetHostParams() connect.HostParams { return connect.HostParams{} } -func (tnm *testNetworkManager) GetHealthTracker() interfaces.HealthTracker { return nil } -func (tnm *testNetworkManager) Follow(interfaces.ClientErrorReport) (stoppable.Stoppable, error) { - return nil, nil -} -func (tnm *testNetworkManager) CheckGarbledMessages() {} -func (tnm *testNetworkManager) CheckInProgressMessages() {} -func (tnm *testNetworkManager) InProgressRegistrations() int { return 0 } -func (tnm *testNetworkManager) GetSender() *gateway.Sender { return nil } -func (tnm *testNetworkManager) GetAddressSize() uint8 { return 0 } -func (tnm *testNetworkManager) RegisterAddressSizeNotification(string) (chan uint8, error) { - return nil, nil -} -func (tnm *testNetworkManager) UnregisterAddressSizeNotification(string) {} -func (tnm *testNetworkManager) SetPoolFilter(gateway.Filter) {} -func (tnm *testNetworkManager) GetVerboseRounds() string { return "" } -func (tnm *testNetworkManager) HasNode(*id.ID) bool { return false } -func (tnm *testNetworkManager) LookupHistoricalRound(id.Round, func(*mixmessages.RoundInfo, bool)) error { - return nil -} -func (tnm *testNetworkManager) NumRegisteredNodes() int { return 0 } -func (tnm *testNetworkManager) RegisterAddressSpaceNotification(string) (chan uint8, error) { - return nil, nil -} -func (tnm *testNetworkManager) SendToAny(func(*connect.Host) (interface{}, error), *stoppable.Single) (interface{}, error) { - return nil, nil -} -func (tnm *testNetworkManager) SendToPreferred([]*id.ID, func(*connect.Host, *id.ID, time.Duration) (interface{}, error), *stoppable.Single, time.Duration) (interface{}, error) { - return nil, nil -} -func (tnm *testNetworkManager) SetGatewayFilter(func(map[id.ID]int, *ndf.NetworkDefinition) map[id.ID]int) { -} -func (tnm *testNetworkManager) TrackServices(message.ServicesTracker) {} -func (tnm *testNetworkManager) TriggerNodeRegistration(*id.ID) {} -func (tnm *testNetworkManager) UnregisterAddressSpaceNotification(string) {} - -func (tnm *testNetworkManager) AddFingerprint(*id.ID, format.Fingerprint, message.Processor) error { - return nil -} -func (tnm *testNetworkManager) DeleteFingerprint(*id.ID, format.Fingerprint) {} -func (tnm *testNetworkManager) DeleteClientFingerprints(*id.ID) {} - -func (tnm *testNetworkManager) AddIdentity(*id.ID, time.Time, bool) error { return nil } -func (tnm *testNetworkManager) RemoveIdentity(*id.ID) {} - -func (tnm *testNetworkManager) AddTrigger(*id.ID, message.Service, message.Processor) {} -func (tnm *testNetworkManager) DeleteTrigger(*id.ID, interfaces.Preimage, message.Processor) error { - return nil -} -func (tnm *testNetworkManager) DeleteClientTriggers(*id.ID) {} - -// //////////////////////////////////////////////////////////////////////////////// -// // NDF Primes // -// //////////////////////////////////////////////////////////////////////////////// - -func getNDF() *ndf.NetworkDefinition { - return &ndf.NetworkDefinition{ - E2E: ndf.Group{ - Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A" + - "8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3D" + - "D2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E78615" + - "75E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC" + - "6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C" + - "4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F2" + - "6E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE" + - "448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E" + - "198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FF" + - "DDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323" + - "631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C" + - "3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E63" + - "19BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC3" + - "5873847AEF49F66E43873", - Generator: "2", - }, - CMIX: ndf.Group{ - Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642" + - "F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757" + - "264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F" + - "9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091E" + - "B51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D" + - "0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D3" + - "92145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A" + - "2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7" + - "995FAD5AABBCFBE3EDA2741E375404AE25B", - Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E2480" + - "9670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D" + - "1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A33" + - "8661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361" + - "C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B28" + - "5DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD929" + - "59859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D83" + - "2186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8" + - "B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - }, - } + return msg } diff --git a/go.sum b/go.sum index 3898f13b2d9af37a8e82268407d8423e1badb09a..9ddad24c184a4ed3b3074e6cf902a8ea1e2e9352 100644 --- a/go.sum +++ b/go.sum @@ -337,6 +337,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM= +github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go deleted file mode 100644 index 2139e9597c6a4cdc51714e47308d6aa91d3481c5..0000000000000000000000000000000000000000 --- a/interfaces/networkManager.go +++ /dev/null @@ -1,244 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// 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 ( - "time" - - "gitlab.com/elixxir/comms/network" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/ndf" - - "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/message" - "gitlab.com/elixxir/client/stoppable" - "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/id/ephemeral" -) - -type NetworkManager interface { - // Follow starts the tracking of the network in a new thread. - // Errors that occur are reported on the ClientErrorReport function if - // passed. The returned stopable can be used to stop the follower. - // Only one follower may run at a time. - Follow(report ClientErrorReport) (stoppable.Stoppable, error) - - /*===Sending==========================================================*/ - - // SendCMIX sends a "raw" CMIX message payload to the provided - // recipient. Returns the round ID of the round the payload - // was sent or an error if it fails. - SendCMIX(message format.Message, recipient *id.ID, p cmix.Params) ( - id.Round, ephemeral.Id, error) - - // SendManyCMIX sends many "raw" cMix message payloads to each - // of the provided recipients. Used to send messages in group - // chats. Metadata is NOT as well protected with this call and - // can leak data about yourself. Should be replaced with - // 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 - SendManyCMIX(messages []cmix.TargetedCmixMessage, p cmix.Params) ( - id.Round, []ephemeral.Id, error) - - /*===Message Reception================================================*/ - /* Identities are all network identities which the client is currently - trying to pick up message on. An identity must be added - to receive messages, fake ones will be used to poll the network - if none are present. On creation of the network handler, the identity in - session storage will be automatically added*/ - - // AddIdentity adds an identity to be tracked - // If persistent is false, the identity will not be stored to disk and - // will be dropped on reload. - AddIdentity(id *id.ID, validUntil time.Time, persistent bool) error - // RemoveIdentity removes a currently tracked identity. - RemoveIdentity(id *id.ID) - - /* Fingerprints are the primary mechanism of identifying a - picked up message over cMix. They are a unique one time use - 255 bit vector generally associated with a specific encryption - key, but can be used for an alternative protocol.When - registering a fingerprint, a MessageProcessor is registered to - handle the message.*/ - - // AddFingerprint - Adds a fingerprint which will be handled by a - // specific processor for messages received by the given identity - AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, - mp message.Processor) error - - // DeleteFingerprint deletes a single fingerprint associated - // with the given identity if it exists - - DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) - // DeleteClientFingerprints deletes al fingerprint associated - // with the given identity if it exists - DeleteClientFingerprints(identity *id.ID) - - /* trigger - predefined hash based tags appended to all cMix messages - which, though trial hashing, are used to determine if a message applies - to this client - - Triggers are used for 2 purposes - They can be processed by the - notifications system, or can be used to implement custom non fingerprint - processing of payloads. I.E. key negotiation, broadcast negotiation - - A tag is appended to the message of the format tag = - H(H(messageContents), preimage) and trial hashing is used to - 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. 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 be used for notifications. Multiple - // triggers can be registered for the same preimage. - // preimage - the preimage which is triggered on - // type - a descriptive string of the trigger. Generally - // used in notifications - // source - a byte buffer of related data. Generally used in - // notifications. - // Example: Sender ID - AddTrigger(identity *id.ID, newTrigger message.Service, - response message.Processor) - - // DeleteTrigger - If only a single response is associated with the - // 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, all triggers for the preimage will be removed - DeleteTrigger(identity *id.ID, preimage Preimage, - response message.Processor) error - - // DeleteClientTriggers - deletes all triggers assoseated with - // the given identity - DeleteClientTriggers(identity *id.ID) - - // TrackServices - Registers a callback which will get called - // every time triggers change. - // It will receive the triggers list every time it is modified. - // Will only get callbacks while the Network Follower is running. - // Multiple trackTriggers can be registered - TrackServices(message.ServicesTracker) - - /* In inProcess */ - // it is possible to receive a message over cMix before the - // fingerprints or triggers are registered. As a result, when - // handling fails, messages are put in the inProcess que for a - // set number of retries. - - // CheckInProgressMessages - retry processing all messages in check in - // progress messages. Call this after adding fingerprints or triggers - //while the follower is running. - CheckInProgressMessages() - - /*===Nodes============================================================*/ - /* Keys must be registed with nodes in order to send messages - 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 node. - HasNode(nid *id.ID) bool - - // NumRegisteredNodes Returns the total number of nodes we have a keying - // relationship with - NumRegisteredNodes() int - - // TriggerNodeRegistration triggers the generation of a keying - // relationship with a given node - TriggerNodeRegistration(nid *id.ID) - - /*===Historical Rounds================================================*/ - /* 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 - is the system internal to the Network Manager to do this. - It can be used externally as well.*/ - - // LookupHistoricalRound - looks up the passed historical round on the - // network - LookupHistoricalRound(rid id.Round, - callback func(info *mixmessages.RoundInfo, - success bool)) error - - /*===Sender===========================================================*/ - /* The sender handles sending comms to the network. It tracks - connections to gateways and handles proxying to gateways for - targeted comms. It can be used externally to contact gateway - directly, bypassing the majority of the network package*/ - - // 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) - - // SendToPreferred sends to a specific gateway, doing so through another - // gateway as a proxy if not directly connected. - SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host, - target *id.ID, timeout time.Duration) (interface{}, error), - stop *stoppable.Single, timeout time.Duration) (interface{}, - error) - - // SetGatewayFilter sets a function which will be used to - // filter gateways before connecting. - SetGatewayFilter(f func(map[id.ID]int, - *ndf.NetworkDefinition) map[id.ID]int) - - // GetHostParams - returns the host params used when - // connectign to gateways - GetHostParams() connect.HostParams - - /*===Address Space====================================================*/ - // The network compasses identities into a smaller address - // space to cause collisions and hide the actual recipient of - // messages. These functions allow for the tracking of this - // 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 address size is known. - GetAddressSpace() uint8 - - // RegisterAddressSpaceNotification returns a channel that - // will trigger for every address space size update. The - // provided tag is the unique ID for the channel. Returns an - // error if the tag is already used. - RegisterAddressSpaceNotification(tag string) (chan uint8, error) - - // UnregisterAddressSpaceNotification stops broadcasting - // address space size updates on the channel with the - // specified tag. - UnregisterAddressSpaceNotification(tag string) - - /*===Accessors========================================================*/ - - // GetInstance returns the network instance object, which tracks the - // state of the network - GetInstance() *network.Instance - - // GetHealthTracker returns the health tracker, which using a polling or - // event api lets you determine if network following is functioning - GetHealthTracker() HealthTracker - - // GetVerboseRounds returns stringification of verbose round info - GetVerboseRounds() string -} - -type Preimage [32]byte diff --git a/registration/register.go b/registration/register.go index 57b6cf8f2003b0323d96d9b53aff9dc6e0f1ac2c..97c1f3d6d9ef121ca3d4efa8e71c6070d85614a0 100644 --- a/registration/register.go +++ b/registration/register.go @@ -62,14 +62,6 @@ func register(comms registrationMessageSender, host *connect.Host, "reception confirmation message") } - transmissionConfirmation := &pb.ClientRegistrationConfirmation{} - err = proto.Unmarshal(response.GetClientReceptionConfirmation(). - ClientRegistrationConfirmation, transmissionConfirmation) - if err != nil { - return nil, nil, 0, errors.WithMessage(err, "Failed to unmarshal "+ - "transmission confirmation message") - } - // Verify reception signature receptionSignature := response.GetClientReceptionConfirmation(). GetRegistrarSignature().Signature @@ -80,6 +72,15 @@ func register(comms registrationMessageSender, host *connect.Host, return nil, nil, 0, errors.WithMessage(err, "Failed to verify reception signature") } + // Unmarshal transmission confirmation + transmissionConfirmation := &pb.ClientRegistrationConfirmation{} + err = proto.Unmarshal(response.GetClientTransmissionConfirmation(). + ClientRegistrationConfirmation, transmissionConfirmation) + if err != nil { + return nil, nil, 0, errors.WithMessage(err, "Failed to unmarshal "+ + "transmission confirmation message") + } + // Verify transmission signature transmissionSignature := response.GetClientTransmissionConfirmation(). GetRegistrarSignature().Signature diff --git a/storage/versioned/kv.go b/storage/versioned/kv.go index 2b8b7ae2129d5a67fdf576297a4318e229c91ff8..13f05e82c7449282c669453eefbff1a6bb03ad46 100644 --- a/storage/versioned/kv.go +++ b/storage/versioned/kv.go @@ -164,3 +164,9 @@ func (v *KV) GetFullKey(key string, version uint64) string { func (v *KV) makeKey(key string, version uint64) string { return fmt.Sprintf("%s%s_%d", v.prefix, key, version) } + +// Exists returns false if the error indicates the element doesn't +// exist. +func (v *KV) Exists(err error) bool { + return ekv.Exists(err) +} diff --git a/ud/addFact.go b/ud/addFact.go index 719e7d137ab1f9c3e5ce4d414c9db08876d668a4..2022b82e03482dbbe5d172ff6fc95a533c1d87d2 100644 --- a/ud/addFact.go +++ b/ud/addFact.go @@ -40,7 +40,7 @@ func (m *Manager) addFact(inFact fact.Fact, myId *id.ID, fHash := factID.Fingerprint(f) // Sign our inFact for putting into the request - privKey, err := m.user.GetReceptionIdentity().GetRSAPrivatePem() + privKey, err := m.user.GetReceptionIdentity().GetRSAPrivateKey() if err != nil { return "", err } diff --git a/ud/confirmFact.go b/ud/confirmFact.go index a55da37566945a03b5c0a276f92b7e30ec220f4d..1d77f357c8a1a53f7b8ed5bf6899ce696c2def01 100644 --- a/ud/confirmFact.go +++ b/ud/confirmFact.go @@ -6,8 +6,8 @@ import ( pb "gitlab.com/elixxir/comms/mixmessages" ) -// ConfirmFact confirms a fact first registered via AddFact. The -// confirmation ID comes from AddFact while the code will come over the +// ConfirmFact confirms a fact first registered via SendRegisterFact. The +// confirmation ID comes from SendRegisterFact while the code will come over the // associated communications system. func (m *Manager) ConfirmFact(confirmationID, code string) error { jww.INFO.Printf("ud.ConfirmFact(%s, %s)", confirmationID, code) diff --git a/ud/manager.go b/ud/manager.go index 0a4247fb809d876b4c0659639827bc2929ba3b83..d431da78c9f961ac7112923203eb54f51dae9564 100644 --- a/ud/manager.go +++ b/ud/manager.go @@ -66,18 +66,34 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus, jww.INFO.Println("ud.NewOrLoad()") - // Construct manager - m, err := loadOrNewManager(user, comms, follower) - if err != nil { - return nil, err + if follower() != xxdk.Running { + return nil, errors.New( + "cannot start UD Manager when network follower is not running.") + } + + // Initialize manager + m := &Manager{ + user: user, + comms: comms, } // Set user discovery - err = m.setUserDiscovery(cert, contactFile, address) + err := m.setUserDiscovery(cert, contactFile, address) if err != nil { return nil, err } + // Initialize store + m.store, err = store.NewOrLoadStore(m.getKv()) + if err != nil { + return nil, errors.Errorf("Failed to initialize store: %v", err) + } + + // If already registered, return + if IsRegistered(m.getKv()) { + return m, nil + } + // Register manager rng := m.getRng().GetStream() defer rng.Close() @@ -86,6 +102,13 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus, return nil, err } + usernameFact, err := fact.NewFact(fact.Username, username) + if err != nil { + return nil, err + } + + err = m.store.StoreUsername(usernameFact) + return m, nil } @@ -111,7 +134,8 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus, // Returns // - A Manager object which is registered to the specified UD service. func NewManagerFromBackup(user udE2e, comms Comms, follower udNetworkStatus, - email, phone fact.Fact, cert, contactFile []byte, address string) (*Manager, error) { + username, email, phone fact.Fact, + cert, contactFile []byte, address string) (*Manager, error) { jww.INFO.Println("ud.NewManagerFromBackup()") if follower() != xxdk.Running { return nil, errors.New( @@ -133,7 +157,7 @@ func NewManagerFromBackup(user udE2e, comms Comms, follower udNetworkStatus, } // Put any passed in missing facts into store - err = m.store.BackUpMissingFacts(email, phone) + err = m.store.BackUpMissingFacts(username, email, phone) if err != nil { return nil, errors.WithMessage(err, "Failed to restore UD store "+ "from backup") @@ -164,7 +188,7 @@ func InitStoreFromBackup(kv *versioned.KV, } // Put any passed in missing facts into store - err = udStore.BackUpMissingFacts(email, phone) + err = udStore.BackUpMissingFacts(username, email, phone) if err != nil { return errors.WithMessage(err, "Failed to restore UD store "+ "from backup") @@ -197,41 +221,6 @@ func (m *Manager) GetContact() contact.Contact { return m.ud.contact } -// loadOrNewManager is a helper function which loads from storage or -// creates a new Manager object. -func loadOrNewManager(user udE2e, comms Comms, - follower udNetworkStatus) (*Manager, error) { - if follower() != xxdk.Running { - return nil, errors.New( - "cannot start UD Manager when network follower is not running.") - } - - // Initialize manager - m := &Manager{ - user: user, - comms: comms, - } - - if m.isRegistered() { - // Load manager if already registered - var err error - m.store, err = store.NewOrLoadStore(m.getKv()) - if err != nil { - return nil, errors.Errorf("Failed to initialize store: %v", err) - } - return m, nil - } - - // Initialize store - var err error - m.store, err = store.NewOrLoadStore(m.getKv()) - if err != nil { - return nil, errors.Errorf("Failed to initialize store: %v", err) - } - - return m, nil -} - //////////////////////////////////////////////////////////////////////////////// // Internal Getters // //////////////////////////////////////////////////////////////////////////////// @@ -242,7 +231,7 @@ func (m *Manager) getCmix() udCmix { return m.user.GetCmix() } -// getKv returns a versioned.KV used for isRegistered and setRegistered. +// getKv returns a versioned.KV used for IsRegistered and setRegistered. // This is separated from store operations as store's kv // has a different prefix which breaks backwards compatibility. func (m *Manager) getKv() *versioned.KV { diff --git a/ud/register.go b/ud/register.go index 495d50da5e1fb51dd0e9d0e9d0211547d3314946..48074cf1ac491fb5496d1160d1ef7cda54138edb 100644 --- a/ud/register.go +++ b/ud/register.go @@ -19,7 +19,7 @@ func (m *Manager) register(username string, networkSignature []byte, // Retrieve data used for registration identity := m.user.GetReceptionIdentity() - privKey, err := identity.GetRSAPrivatePem() + privKey, err := identity.GetRSAPrivateKey() if err != nil { return err } diff --git a/ud/registered.go b/ud/registered.go index 06dba95886e3d92717ae9d8143fbd3ca8bd3189c..77742fc17923e1b0a30c03622db40e797e76ec36 100644 --- a/ud/registered.go +++ b/ud/registered.go @@ -11,10 +11,10 @@ import ( const isRegisteredKey = "isRegisteredKey" const isRegisteredVersion = 0 -// isRegistered loads from storage if the user is registered with user +// IsRegistered loads from storage if the user is registered with user // discovery. -func (m *Manager) isRegistered() bool { - _, err := m.getKv().Get(isRegisteredKey, isRegisteredVersion) +func IsRegistered(kv *versioned.KV) bool { + _, err := kv.Get(isRegisteredKey, isRegisteredVersion) if err != nil { return false } diff --git a/ud/remove.go b/ud/remove.go index ebb809c0022ab0bbc81237c092c106bcbf946bd2..691d9792f4468093ed2468b654b829ec60353c35 100644 --- a/ud/remove.go +++ b/ud/remove.go @@ -40,7 +40,7 @@ func (m *Manager) removeFact(f fact.Fact, // Sign our inFact for putting into the request identity := m.user.GetReceptionIdentity() - privKey, err := identity.GetRSAPrivatePem() + privKey, err := identity.GetRSAPrivateKey() if err != nil { return err } @@ -78,7 +78,7 @@ func (m *Manager) PermanentDeleteAccount(f fact.Fact) error { "a username. Cannot remove fact %q", f.Fact)) } identity := m.user.GetReceptionIdentity() - privKey, err := identity.GetRSAPrivatePem() + privKey, err := identity.GetRSAPrivateKey() if err != nil { return err } diff --git a/ud/store/facts.go b/ud/store/facts.go index 202d8814bf5748ad5c7f8bf77c68ca26344fa842..d0ac3112616de9c9336555ea9126ec059df8ff1d 100644 --- a/ud/store/facts.go +++ b/ud/store/facts.go @@ -42,6 +42,42 @@ func (s *Store) RestoreFromBackUp(backupData fact.FactList) error { return s.save() } +// StoreUsername forces the storage of a username fact.Fact into the +// Store's confirmedFacts map. The passed in fact.Fact must be of +// type fact.Username or this will not store the username. +func (s *Store) StoreUsername(f fact.Fact) error { + s.mux.Lock() + defer s.mux.Unlock() + + if f.T != fact.Username { + return errors.Errorf("Fact (%s) is not of type username", f.Stringify()) + } + + s.confirmedFacts[f] = struct{}{} + + return s.saveUnconfirmedFacts() +} + +// GetUsername retrieves the username from the Store object. +// If it is not directly in the Store's username field, it is +// searched for in the map. +func (s *Store) GetUsername() (string, error) { + s.mux.RLock() + defer s.mux.RUnlock() + + // todo: refactor this in the future so that + // it's an O(1) lookup (place this object in another map + // or have it's own field) + for f := range s.confirmedFacts { + if f.T == fact.Username { + return f.Fact, nil + } + } + + return "", errors.New("Could not find username in store") + +} + // StoreUnconfirmedFact stores a fact that has been added to UD but has not been // confirmed by the user. It is keyed on the confirmation ID given by UD. func (s *Store) StoreUnconfirmedFact(confirmationId string, f fact.Fact) error { @@ -84,11 +120,11 @@ func (s *Store) ConfirmFact(confirmationId string) error { // If you attempt to back up a fact type that has already been backed up, // an error will be returned and nothing will be backed up. // Otherwise, it adds the fact and returns whether the Store saved successfully. -func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error { +func (s *Store) BackUpMissingFacts(username, email, phone fact.Fact) error { s.mux.Lock() defer s.mux.Unlock() - modifiedEmail, modifiedPhone := false, false + modified := false // Handle email if it is not zero (empty string) if !isFactZero(email) { @@ -102,10 +138,12 @@ func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error { // If an email exists in memory, return an error return errors.Errorf(factTypeExistsErr, email, fact.Email) } else { - modifiedEmail = true + s.confirmedFacts[email] = struct{}{} + modified = true } } + // Handle phone if it is not an empty string if !isFactZero(phone) { // check if fact is expected type if phone.T != fact.Phone { @@ -117,19 +155,24 @@ func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error { // If a phone exists in memory, return an error return errors.Errorf(factTypeExistsErr, phone, fact.Phone) } else { - modifiedPhone = true + s.confirmedFacts[phone] = struct{}{} + modified = true } } - if modifiedPhone || modifiedEmail { - if modifiedEmail { - s.confirmedFacts[email] = struct{}{} - } - - if modifiedPhone { - s.confirmedFacts[phone] = struct{}{} + if !isFactZero(username) { + // Check if fact type is already in map. You should not be able to + // overwrite your username. + if isFactTypeInMap(fact.Username, s.confirmedFacts) { + // If a username exists in memory, return an error + return errors.Errorf(factTypeExistsErr, username, fact.Username) + } else { + s.confirmedFacts[username] = struct{}{} + modified = true } + } + if modified { return s.saveConfirmedFacts() } diff --git a/ud/store/facts_test.go b/ud/store/facts_test.go index 332b5289da335390d76df7f41adbb49f2bd2d975..7cdac5fd81667f6da119a0ce2fc6333bd8eef895 100644 --- a/ud/store/facts_test.go +++ b/ud/store/facts_test.go @@ -203,7 +203,12 @@ func TestStore_BackUpMissingFacts(t *testing.T) { T: fact.Phone, } - err = expectedStore.BackUpMissingFacts(email, phone) + username := fact.Fact{ + Fact: "admin", + T: fact.Username, + } + + err = expectedStore.BackUpMissingFacts(username, email, phone) if err != nil { t.Fatalf("BackUpMissingFacts() produced an error: %v", err) } @@ -238,18 +243,23 @@ func TestStore_BackUpMissingFacts_DuplicateFactType(t *testing.T) { T: fact.Phone, } - err = expectedStore.BackUpMissingFacts(email, phone) + username := fact.Fact{ + Fact: "admin", + T: fact.Username, + } + + err = expectedStore.BackUpMissingFacts(username, email, phone) if err != nil { t.Fatalf("BackUpMissingFacts() produced an error: %v", err) } - err = expectedStore.BackUpMissingFacts(email, fact.Fact{}) + err = expectedStore.BackUpMissingFacts(username, email, fact.Fact{}) if err == nil { t.Fatalf("BackUpMissingFacts() should not allow backing up an "+ "email when an email has already been backed up: %v", err) } - err = expectedStore.BackUpMissingFacts(fact.Fact{}, phone) + err = expectedStore.BackUpMissingFacts(username, fact.Fact{}, phone) if err == nil { t.Fatalf("BackUpMissingFacts() should not allow backing up a "+ "phone number when a phone number has already been backed up: %v", err) @@ -272,7 +282,12 @@ func TestStore_GetFacts(t *testing.T) { emptyFact := fact.Fact{} - err = testStore.BackUpMissingFacts(emailFact, emptyFact) + username := fact.Fact{ + Fact: "admin", + T: fact.Username, + } + + err = testStore.BackUpMissingFacts(username, emailFact, emptyFact) if err != nil { t.Fatalf("Faild to add fact %v: %v", emailFact, err) } @@ -282,12 +297,12 @@ func TestStore_GetFacts(t *testing.T) { T: fact.Phone, } - err = testStore.BackUpMissingFacts(emptyFact, phoneFact) + err = testStore.BackUpMissingFacts(emptyFact, emptyFact, phoneFact) if err != nil { t.Fatalf("Faild to add fact %v: %v", phoneFact, err) } - expectedFacts := []fact.Fact{emailFact, phoneFact} + expectedFacts := []fact.Fact{username, emailFact, phoneFact} receivedFacts := testStore.GetFacts() @@ -318,10 +333,14 @@ func TestStore_GetFactStrings(t *testing.T) { Fact: "josh@elixxir.io", T: fact.Email, } + username := fact.Fact{ + Fact: "admin", + T: fact.Username, + } emptyFact := fact.Fact{} - err = testStore.BackUpMissingFacts(emailFact, emptyFact) + err = testStore.BackUpMissingFacts(username, emailFact, emptyFact) if err != nil { t.Fatalf("Faild to add fact %v: %v", emailFact, err) } @@ -331,12 +350,12 @@ func TestStore_GetFactStrings(t *testing.T) { T: fact.Phone, } - err = testStore.BackUpMissingFacts(emptyFact, phoneFact) + err = testStore.BackUpMissingFacts(emptyFact, emptyFact, phoneFact) if err != nil { t.Fatalf("Faild to add fact %v: %v", phoneFact, err) } - expectedFacts := []string{emailFact.Stringify(), phoneFact.Stringify()} + expectedFacts := []string{username.Stringify(), emailFact.Stringify(), phoneFact.Stringify()} receivedFacts := testStore.GetStringifiedFacts() sort.SliceStable(receivedFacts, func(i, j int) bool { diff --git a/ud/ud.go b/ud/ud.go index 5fb27e619de9d5196b24022b35277f1f26c37837..fd4633483eb34b52a9106a00cbc3b8c342bec5fd 100644 --- a/ud/ud.go +++ b/ud/ud.go @@ -4,7 +4,6 @@ import ( "github.com/pkg/errors" "gitlab.com/elixxir/crypto/contact" "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/id" "time" ) @@ -23,35 +22,26 @@ func (m *Manager) setUserDiscovery(cert, params.AuthEnabled = false params.SendTimeout = 20 * time.Second - udIdBytes, dhPubKeyBytes, err := contact.ReadContactFromFile(contactFile) - if err != nil { - return err - } - - udID, err := id.Unmarshal(udIdBytes) + // Unmarshal the new contact + con, err := contact.Unmarshal(contactFile) if err != nil { return err } // Add a new host and return it if it does not already exist - host, err := m.comms.AddHost(udID, address, + host, err := m.comms.AddHost(con.ID, address, cert, params) if err != nil { return errors.WithMessage(err, "User Discovery host object could "+ "not be constructed.") } - dhPubKey := m.user.GetE2E().GetGroup().NewInt(1) - err = dhPubKey.UnmarshalJSON(dhPubKeyBytes) - if err != nil { - return err - } - + // Set the user discovery object within the manager m.ud = &userDiscovery{ host: host, contact: contact.Contact{ - ID: udID, - DhPubKey: dhPubKey, + ID: con.ID, + DhPubKey: con.DhPubKey, }, } diff --git a/xxdk/cmix.go b/xxdk/cmix.go index 539c2610d55f23f3b26ed7aad70e0f563148cc39..a6a715d575e35422a7c224a8b78a5b579aa7a284 100644 --- a/xxdk/cmix.go +++ b/xxdk/cmix.go @@ -341,28 +341,28 @@ func (c *Cmix) GetErrorsChannel() <-chan interfaces.ClientError { // // Threads Started: // - Network Follower (/network/follow.go) -// tracks the network events and hands them off to workers for handling. +// tracks the network events and hands them off to workers for handling. // - Historical Round Retrieval (/network/rounds/historical.go) -// retrieves data about rounds that are too old to be stored by the client. +// retrieves data about rounds that are too old to be stored by the client. // - Message Retrieval Worker Group (/network/rounds/retrieve.go) -// requests all messages in a given round from the gateway of the last -// nodes. +// requests all messages in a given round from the gateway of the last +// nodes. // - Message Handling Worker Group (/network/message/handle.go) -// decrypts and partitions messages when signals via the Switchboard. +// decrypts and partitions messages when signals via the Switchboard. // - Health Tracker (/network/health), -// via the network instance, tracks the state of the network. +// via the network instance, tracks the state of the network. // - Garbled Messages (/network/message/garbled.go) -// can be signaled to check all recent messages that could be decoded. It -// uses a message store on disk for persistence. +// can be signaled to check all recent messages that could be decoded. It +// uses a message store on disk for persistence. // - Critical Messages (/network/message/critical.go) -// ensures all protocol layer mandatory messages are sent. It uses a -// message store on disk for persistence. +// ensures all protocol layer mandatory messages are sent. It uses a +// message store on disk for persistence. // - KeyExchange Trigger (/keyExchange/trigger.go) -// responds to sent rekeys and executes them. +// responds to sent rekeys and executes them. // - KeyExchange Confirm (/keyExchange/confirm.go) -// responds to confirmations of successful rekey operations. +// responds to confirmations of successful rekey operations. // - Auth Callback (/auth/callback.go) -// handles both auth confirm and requests. +// handles both auth confirm and requests. func (c *Cmix) StartNetworkFollower(timeout time.Duration) error { jww.INFO.Printf( "StartNetworkFollower() \n\tTransmissionID: %s \n\tReceptionID: %s", @@ -375,7 +375,7 @@ func (c *Cmix) StartNetworkFollower(timeout time.Duration) error { // an error if the follower is in the wrong state to stop or if it fails to stop // it. // -// if the network follower is running and this fails, the client object will +// If the network follower is running and this fails, the client object will // most likely be in an unrecoverable state and need to be trashed. func (c *Cmix) StopNetworkFollower() error { jww.INFO.Printf("StopNetworkFollower()") diff --git a/xxdk/e2e.go b/xxdk/e2e.go index 4c2b9e22ca2e800e77489f69690092e13f6db6bc..cd0d7f00c2931b192d20ba6206e4b21067e6740f 100644 --- a/xxdk/e2e.go +++ b/xxdk/e2e.go @@ -102,7 +102,7 @@ func loginLegacy(net *Cmix, callbacks AuthCallbacks, return nil, err } - rsaKey, err := identity.GetRSAPrivatePem() + rsaKey, err := identity.GetRSAPrivateKey() if err != nil { return nil, err } @@ -116,7 +116,7 @@ func login(net *Cmix, callbacks AuthCallbacks, identity ReceptionIdentity, kv *versioned.KV, params E2EParams) (m *E2e, err error) { // Verify the passed-in ReceptionIdentity matches its properties - privatePem, err := identity.GetRSAPrivatePem() + privatePem, err := identity.GetRSAPrivateKey() if err != nil { return nil, err } @@ -246,7 +246,7 @@ func (m *E2e) ConstructProtoUserFile() ([]byte, error) { transIdentity := m.Cmix.GetTransmissionIdentity() receptionIdentity := m.GetReceptionIdentity() - privatePem, err := receptionIdentity.GetRSAPrivatePem() + privatePem, err := receptionIdentity.GetRSAPrivateKey() if err != nil { return nil, err } diff --git a/xxdk/identity.go b/xxdk/identity.go index 9d646785fd71c713398036fd4dc8ae66ecbbc447..1b2dd605dfa9f6bd63daeff49967dcdcd9fb459e 100644 --- a/xxdk/identity.go +++ b/xxdk/identity.go @@ -80,8 +80,8 @@ func (r ReceptionIdentity) GetDHKeyPrivate() (*cyclic.Int, error) { return dhKeyPriv, err } -// GetRSAPrivatePem returns the RSAPrivatePem. -func (r ReceptionIdentity) GetRSAPrivatePem() (*rsa.PrivateKey, error) { +// GetRSAPrivateKey returns the RSAPrivatePem. +func (r ReceptionIdentity) GetRSAPrivateKey() (*rsa.PrivateKey, error) { return rsa.LoadPrivateKeyFromPem(r.RSAPrivatePem) }