diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index c89bd221efbf503410151c991c87bc825dd393e5..34ab130eaaae9e1953cb936262f2f2b1a713a91f 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -8,7 +8,6 @@ package interfaces import ( - "encoding/base64" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/interfaces/params" "gitlab.com/elixxir/client/network/gateway" @@ -151,15 +150,8 @@ type IdentityParams struct { Ephemeral bool } -type Preimage []byte - -// key returns the key used to identify the Preimage in a map. -func (pi Preimage) String() string { - return base64.StdEncoding.EncodeToString(pi) -} - type Trigger struct { - Preimage Preimage + Preimage []byte Type string Source []byte } @@ -172,6 +164,7 @@ type MessageProcessorFP interface { type MessageProcessorTrigger interface { Process(message format.Message, preimage []byte, Type string, source []byte) Equals(trigger MessageProcessorTrigger) bool + String() string } //type Ratchet interface { diff --git a/network/triggers.go b/network/triggers.go index 2e61ee188de4c7ec6cb97f2dd0d6a38165221d64..5b758c70c722ea0f7859f6797040a2fb1b2a1096 100644 --- a/network/triggers.go +++ b/network/triggers.go @@ -8,11 +8,33 @@ package network import ( + "encoding/base64" "github.com/pkg/errors" "gitlab.com/elixxir/client/interfaces" + fingerprint2 "gitlab.com/elixxir/crypto/fingerprint" "sync" ) +/* 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 - 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 preiamge is known by an adversary, they can determine which messages +are for the client. + +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 ephemeral to the session. When starting a new client, all triggers must be +re-added before StartNetworkFollower is called. +*/ + type Triggers struct { triggers map[string][]*Trigger sync.RWMutex @@ -29,10 +51,22 @@ func NewTriggers() *Triggers { } func (t *Triggers) Lookup(identityFp, - ecrMsgContents []byte) (*Trigger, bool) { + ecrMsgContents []byte) ([]*Trigger, bool) { t.RLock() defer t.RUnlock() + for preimage, triggers := range t.triggers { + preimageBytes, err := unmarshalPreimage(preimage) + if err != nil { + // fixme: panic here, this error would mean bad data is in the map + } + + if fingerprint2.CheckIdentityFP(identityFp, ecrMsgContents, preimageBytes) { + return triggers, true + } + } + + return nil, false } // Add - Adds a trigger which can call a message @@ -47,19 +81,20 @@ func (t *Triggers) Add(trigger interfaces.Trigger, t.Lock() defer t.Unlock() - preimage := trigger.Preimage.String() + marshalledPreimage := marshalPreimage(trigger.Preimage) newTrigger := &Trigger{ Trigger: trigger, MessageProcessorTrigger: response, } - if existingTriggers, exists := t.triggers[preimage]; exists { - t.triggers[preimage] = append(existingTriggers, newTrigger) + if existingTriggers, exists := t.triggers[marshalledPreimage]; exists { + // fixme Should there be a check if this response exists already? + t.triggers[marshalledPreimage] = append(existingTriggers, newTrigger) return nil } - t.triggers[preimage] = []*Trigger{newTrigger} + t.triggers[marshalledPreimage] = []*Trigger{newTrigger} return nil } @@ -68,26 +103,45 @@ func (t *Triggers) Add(trigger interfaces.Trigger, // 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. -func (t *Triggers) RemoveTrigger(preimage interfaces.Preimage, +func (t *Triggers) RemoveTrigger(preimage []byte, response interfaces.MessageProcessorTrigger) error { t.Lock() defer t.Unlock() - triggers, exists := t.triggers[preimage.String()] + marshalledPreimage := marshalPreimage(preimage) + + triggers, exists := t.triggers[marshalledPreimage] if !exists { - return errors.Errorf("No triggers exist with preimage %q", preimage.String()) + return errors.Errorf("No trigger with preimage %q found", + marshalledPreimage) } if response == nil { - delete(t.triggers, preimage.String()) + delete(t.triggers, marshalledPreimage) return nil } for _, trigger := range triggers { if trigger.Equals(response) { - delete(t.triggers, trigger.Preimage.String()) + delete(t.triggers, marshalPreimage(trigger.Preimage)) + return nil } } - return nil + return errors.Errorf("No response (%q) exists with preimage %q", + response.String(), marshalledPreimage) +} + +// fixme: maybe make preimage a type or struct and place this in primitives? +func marshalPreimage(pi []byte) string { + return base64.StdEncoding.EncodeToString(pi) +} + +func unmarshalPreimage(data string) ([]byte, error) { + decoded, err := base64.StdEncoding.DecodeString(data) + if err != nil { + return nil, err + } + + return decoded, nil } diff --git a/network/triggers_test.go b/network/triggers_test.go new file mode 100644 index 0000000000000000000000000000000000000000..60caace571619a36dba468204a2d6dda540a0129 --- /dev/null +++ b/network/triggers_test.go @@ -0,0 +1,8 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package network