diff --git a/cmix/client.go b/cmix/client.go index 9df2adce41927f91a692b0d55b2043610ebf0471..d164b4d2a60620176fe7fee12c5a26e95e351c99 100644 --- a/cmix/client.go +++ b/cmix/client.go @@ -189,7 +189,6 @@ func (c *client) initialize(ndf *ndf.NetworkDefinition) error { // Set up critical message tracking (sendCmix only) critSender := func(msg format.Message, recipient *id.ID, params CMIXParams, ) (id.Round, ephemeral.Id, error) { - // TODO: Does this need to be reworked to take in a message compiler? This has ramifications down the stack in critical messaging compiler := func(round id.Round) (format.Message, error) { return msg, nil } diff --git a/cmix/interface.go b/cmix/interface.go index a5db8b3cfe2089e94d03861769785ab99bd4390a..717dbb0bbe8b26a288aaa79427bc6d2ed07a30a6 100644 --- a/cmix/interface.go +++ b/cmix/interface.go @@ -290,6 +290,14 @@ type Client interface { type ClientErrorReport func(source, message, trace string) +// MessageAssembler func accepts a round ID, returning fingerprint, service, payload & mac. +// This allows users to pass in a paylaod which will contain the round ID over which the message is sent. +type MessageAssembler func(rid id.Round) (fingerprint format.Fingerprint, service message.Service, payload, mac []byte) + +// messageAssembler is an internal wrapper around MessageAssembler which returns a format.message +// This is necessary to preserve the interaction between sendCmixHelper and critical messages +type messageAssembler func(rid id.Round) (format.Message, error) + type clientCommsInterface interface { followNetworkComms SendCmixCommsInterface diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go index 0742a6fe30f554e70b57d97a1577d151411f9171..648e1ef1c8691211f40bf11fc76e86bc17e5dfe7 100644 --- a/cmix/sendCmix.go +++ b/cmix/sendCmix.go @@ -57,25 +57,48 @@ import ( func (c *client) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams CMIXParams) ( id.Round, ephemeral.Id, error) { - compiler := func(rid id.Round) (format.Fingerprint, message.Service, []byte, []byte) { + // create an internal assembler function to pass to sendWithAssembler + assembler := func(rid id.Round) (format.Fingerprint, message.Service, []byte, []byte) { return fingerprint, service, payload, mac } - return c.SendWithCompiler(recipient, compiler, cmixParams) + return c.sendWithAssembler(recipient, assembler, cmixParams) } -type Compiler func(rid id.Round) (fingerprint format.Fingerprint, service message.Service, payload, mac []byte) - -type messageCompiler func(rid id.Round) (format.Message, error) +// SendWithAssembler sends a variable cmix payload to the provided recipient. +// The payload sent is based on the Complier function passed in, which accepts +// a round ID and returns the necessary payload data. +// Returns the round ID of the round the payload was sent or an error if it +// fails. +// This does not have end-to-end encryption on it and is used exclusively as +// a send for higher order cryptographic protocols. Do not use unless +// implementing a protocol on top. +// recipient - cMix ID of the recipient. +// assembler - MessageAssembler function, accepting round ID and returning fingerprint +// format.Fingerprint, service message.Service, payload, mac []byte +// Will return an error if the network is unhealthy or if it fails to send +// (along with the reason). Blocks until successful sends or errors. +// WARNING: Do not roll your own crypto. +func (c *client) SendWithAssembler(recipient *id.ID, assembler MessageAssembler, cmixParams CMIXParams) ( + id.Round, ephemeral.Id, error) { + // Critical messaging and assembler-based message payloads are not compatible + if cmixParams.Critical { + return 0, ephemeral.Id{}, errors.New("Cannot send critical messages with a message assembler") + } + return c.sendWithAssembler(recipient, assembler, cmixParams) +} -func (c *client) SendWithCompiler(recipient *id.ID, compiler Compiler, cmixParams CMIXParams) ( +// sendWithAssembler wraps the passed in MessageAssembler in a messageAssembler for sendCmixHelper, +// and sets up critical message handling where applicable. +func (c *client) sendWithAssembler(recipient *id.ID, assembler MessageAssembler, cmixParams CMIXParams) ( id.Round, ephemeral.Id, error) { if !c.Monitor.IsHealthy() { return 0, ephemeral.Id{}, errors.New( "Cannot send cmix message when the network is not healthy") } - compilerFunc := func(rid id.Round) (format.Message, error) { - fingerprint, service, payload, mac := compiler(rid) + // Create an internal messageAssembler which returns a format.Message + assemblerFunc := func(rid id.Round) (format.Message, error) { + fingerprint, service, payload, mac := assembler(rid) if len(payload) != c.maxMsgLen { return format.Message{}, errors.Errorf( @@ -100,7 +123,7 @@ func (c *client) SendWithCompiler(recipient *id.ID, compiler Compiler, cmixParam return msg, nil } - rid, ephID, msg, rtnErr := sendCmixHelper(c.Sender, compilerFunc, recipient, cmixParams, + rid, ephID, msg, rtnErr := sendCmixHelper(c.Sender, assemblerFunc, recipient, cmixParams, c.instance, c.session.GetCmixGroup(), c.Registrar, c.rng, c.events, c.session.GetTransmissionID(), c.comms) @@ -121,7 +144,7 @@ func (c *client) SendWithCompiler(recipient *id.ID, compiler Compiler, cmixParam // If the message is successfully sent, the ID of the round sent it is returned, // which can be registered with the network instance to get a callback on its // status. -func sendCmixHelper(sender gateway.Sender, msgCompiler messageCompiler, recipient *id.ID, +func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient *id.ID, cmixParams CMIXParams, instance *network.Instance, grp *cyclic.Group, nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Reporter, senderId *id.ID, comms SendCmixCommsInterface) (id.Round, ephemeral.Id, format.Message, error) { @@ -198,7 +221,7 @@ func sendCmixHelper(sender gateway.Sender, msgCompiler messageCompiler, recipien continue } - msg, err := msgCompiler(id.Round(bestRound.ID)) + msg, err := assembler(id.Round(bestRound.ID)) if err != nil { jww.ERROR.Printf("Failed to compile message: %+v", err) return 0, ephemeral.Id{}, format.Message{}, err