diff --git a/auth/confirm.go b/auth/confirm.go index fc6c5b69c90fa6c5533fd26e570ad31c10e8e4a6..d4ab60744cdc6fb261580287cb3ed06ab0ee1fd0 100644 --- a/auth/confirm.go +++ b/auth/confirm.go @@ -36,13 +36,6 @@ import ( // If the request must be resent, use ReplayConfirm func (s *state) Confirm(partner contact.Contact) ( id.Round, error) { - - // check that messages can be sent over the network - if !s.net.IsHealthy() { - return 0, errors.New("Cannot confirm authenticated message " + - "when the network is not healthy") - } - return s.confirm(partner, s.params.ConfirmTag) } @@ -133,7 +126,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) ( partner.ID, s.e2e.GetReceptionID(), format.DigestContents(baseFmt.Marshal())) - //service used for noticiation only + //service used for notification only /*send message*/ if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(), diff --git a/auth/receivedRequest.go b/auth/receivedRequest.go index 45fe574d225814e324c456cc1a9ae91bc1b86354..a512c12e437ca5f84071ba30f3d138352e98a81d 100644 --- a/auth/receivedRequest.go +++ b/auth/receivedRequest.go @@ -18,7 +18,7 @@ import ( "strings" ) -const dummyerr = "dummy error so we dont delete the request" +const dummyErr = "dummy error so we dont delete the request" type receivedRequestService struct { s *state @@ -27,7 +27,6 @@ type receivedRequestService struct { func (rrs *receivedRequestService) Process(message format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { - state := rrs.s // check if the timestamp is before the id was created and therefore @@ -201,7 +200,7 @@ func (rrs *receivedRequestService) Process(message format.Message, // return an error so the store layer does not delete the request // because the other side will confirm it bail = true - return errors.Errorf(dummyerr) + return errors.Errorf(dummyErr) } jww.INFO.Printf("Received AuthRequest from %s to %s,"+ diff --git a/connect/connect.go b/connect/connect.go new file mode 100644 index 0000000000000000000000000000000000000000..764fc1ea1094d188389ccd53f6b9a9078859147a --- /dev/null +++ b/connect/connect.go @@ -0,0 +1,191 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package connect + +import ( + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/auth" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/identity/receptionID" + "gitlab.com/elixxir/client/cmix/rounds" + clientE2e "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/e2e/ratchet/partner" + "gitlab.com/elixxir/client/e2e/receive" + "gitlab.com/elixxir/client/event" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/contact" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/e2e" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/ekv" + "gitlab.com/xx_network/primitives/id" + "io" + "time" +) + +// Connection is a wrapper for the E2E and auth packages +// and automatically establishes an E2E partnership with a partner. +// You can then use this interface to send to and receive from the newly-established partner. +type Connection interface { + // Closer deletes this Connection's partner.Manager and releases resources + io.Closer + + // GetPartner returns the partner.Manager for this Connection + GetPartner() partner.Manager + + // SendE2E is a wrapper for sending specifically to the Connection's partner.Manager + SendE2E(mt catalog.MessageType, payload []byte, params clientE2e.Params) ( + []id.Round, e2e.MessageID, time.Time, error) + + // RegisterListener is used for E2E reception + // and allows for reading data sent from the partner.Manager + RegisterListener(messageType catalog.MessageType, + newListener receive.Listener) receive.ListenerID + // Unregister listener for E2E reception + Unregister(listenerID receive.ListenerID) +} + +// handler provides an implementation for the Connection interface +type handler struct { + partner partner.Manager + net cmix.Client + e2e clientE2e.Handler + params Params +} + +// Params for managing Connection objects +type Params struct { + auth auth.Param + event event.Reporter +} + +// GetDefaultParams returns a usable set of default Connection parameters +func GetDefaultParams() Params { + return Params{ + auth: auth.GetDefaultParams(), + event: nil, + } +} + +// Connect performs auth key negotiation with the given recipient, +// and returns a Connection object for the newly-created partner.Manager +// This function is to be used sender-side and will block until the partner.Manager is confirmed +func Connect(recipient contact.Contact, myID *id.ID, rng *fastRNG.StreamGenerator, + grp *cyclic.Group, net cmix.Client, p Params) (Connection, error) { + + // Build an ephemeral KV + kv := versioned.NewKV(ekv.MakeMemstore()) + + // Build E2e handler + e2eHandler, err := clientE2e.Load(kv, net, myID, grp, rng, p.event) + if err != nil { + return nil, err + } + + // Build callback for E2E negotiation + callback := GetConnectionCallback() + + // Build auth object for E2E negotiation + authState, err := auth.NewState(kv, net, e2eHandler, + rng, p.event, p.auth, callback, nil) + if err != nil { + return nil, err + } + + // Perform the auth request + _, err = authState.Request(recipient, nil) + if err != nil { + return nil, err + } + + // Block waiting for auth to confirm + jww.DEBUG.Printf("Connection waiting for auth request for %s to be confirmed...", recipient.ID.String()) + <-callback.confirmPartner + jww.DEBUG.Printf("Connection auth request for %s confirmed", recipient.ID.String()) + + // After confirmation, get the new partner + newPartner, err := e2eHandler.GetPartner(recipient.ID) + if err != nil { + return nil, err + } + + return &handler{ + partner: newPartner, + params: p, + net: net, + e2e: e2eHandler, + }, nil +} + +// ConnectWithPartner assembles a Connection object on the reception-side +// after an E2E partnership has already been confirmed +func ConnectWithPartner(partner partner.Manager, + e2eHandler clientE2e.Handler, net cmix.Client, p Params) Connection { + return &handler{ + partner: partner, + params: p, + net: net, + e2e: e2eHandler, + } +} + +// Close deletes this Connection's partner.Manager and releases resources +func (h *handler) Close() error { + return h.e2e.DeletePartner(h.partner.PartnerId()) +} + +// GetPartner returns the partner.Manager for this Connection +func (h *handler) GetPartner() partner.Manager { + return h.partner +} + +// SendE2E is a wrapper for sending specifically to the Connection's partner.Manager +func (h *handler) SendE2E(mt catalog.MessageType, payload []byte, params clientE2e.Params) ( + []id.Round, e2e.MessageID, time.Time, error) { + return h.e2e.SendE2E(mt, h.partner.PartnerId(), payload, params) +} + +// RegisterListener is used for E2E reception +// and allows for reading data sent from the partner.Manager +func (h *handler) RegisterListener(messageType catalog.MessageType, newListener receive.Listener) receive.ListenerID { + return h.e2e.RegisterListener(h.partner.PartnerId(), messageType, newListener) +} + +// Unregister listener for E2E reception +func (h *handler) Unregister(listenerID receive.ListenerID) { + h.e2e.Unregister(listenerID) +} + +// ConnectionCallback provides callback functionality for interfacing between auth.State and Connection +// This is used both for blocking creation of a Connection object until the auth Request is confirmed +// and for dynamically building new Connection objects when an auth Request is received. +type ConnectionCallback struct { + // Used for signaling confirmation of E2E partnership + confirmPartner chan *id.ID +} + +// GetConnectionCallback returns a callback interface to be passed into the creation of an auth.State object. +func GetConnectionCallback() ConnectionCallback { + return ConnectionCallback{ + confirmPartner: make(chan *id.ID, 1), + } +} + +// Confirm will be called when an auth Confirm message is processed +func (c ConnectionCallback) Confirm(requestor contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) { + // Signal to a listening thread that the partnership is confirmed + c.confirmPartner <- requestor.ID +} + +// Request will be called when an auth Request message is processed +func (c ConnectionCallback) Request(requestor contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) { +} + +// Reset will be called when an auth Reset operation occurs +func (c ConnectionCallback) Reset(requestor contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) { +} diff --git a/e2e/interface.go b/e2e/interface.go index 43644636361a97c310f60ca0cf2ca1651fee1078..a24f285ce3b2046b8d838aa2826775b167f47bf9 100644 --- a/e2e/interface.go +++ b/e2e/interface.go @@ -45,10 +45,10 @@ type Handler interface { // The name is used for debug printing and not checked for // uniqueness // - // user: 0 for all, or any user ID to listen for messages from - // a particular user. 0 can be id.ZeroUser or id.ZeroID - // messageType: 0 for all, or any message type to listen for - // messages of that type. 0 can be Message.AnyType + // user: id.ZeroUser for all, or any user ID to listen for + // messages from a particular user. + // messageType: catalog.NoType for all, or any message type to + // listen for messages of that type. // newListener: something implementing the Listener // interface. Do not pass nil to this. // @@ -66,10 +66,10 @@ type Handler interface { // name is used for debug printing and not checked for // uniqueness // - // user: 0 for all, or any user ID to listen for messages from - // a particular user. 0 can be id.ZeroUser or id.ZeroID - // messageType: 0 for all, or any message type to listen for - // messages of that type. 0 can be Message.AnyType + // user: id.ZeroUser for all, or any user ID to listen for + // messages from a particular user. + // messageType: catalog.NoType for all, or any message type to + // listen for messages of that type. // newListener: a function implementing the ListenerFunc // function type. Do not pass nil to this. // @@ -115,7 +115,6 @@ type Handler interface { receiveParams session.Params) (partner.Manager, error) // GetPartner returns the partner per its ID, if it exists - // myID is your ID in the relationship GetPartner(partnerID *id.ID) (partner.Manager, error) // DeletePartner removes the associated contact from the E2E store @@ -133,8 +132,8 @@ type Handler interface { // be sent to using the tag fields in the Params Object // Passing nil for the processor allows you to create a // service which is never called but will be visible by - // notifications Processes added this way are generally not - // end ot end encrypted messages themselves, but other + // notifications. Processes added this way are generally not + // end-to-end encrypted messages themselves, but other // protocols which piggyback on e2e relationships to start // communication AddService(tag string, processor message.Processor) error diff --git a/e2e/manager.go b/e2e/manager.go index 7565deb402e86dec5a2b61e25ebf28f8553ff555..885748a08e35a57bbabb610abf874df5180b40cc 100644 --- a/e2e/manager.go +++ b/e2e/manager.go @@ -39,7 +39,7 @@ const e2eRekeyParamsKey = "e2eRekeyParams" const e2eRekeyParamsVer = 0 // Init Creates stores. After calling, use load -// Passes a the ID public key which is used for the relationship +// Passes the ID public key which is used for the relationship // uses the passed ID to modify the kv prefix for a unique storage path func Init(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int, grp *cyclic.Group, rekeyParams rekey.Params) error { diff --git a/e2e/manager_test.go b/e2e/manager_test.go index 54a04e1ec096c0106cc5711982c46eb0524ed8e3..af4736d0ddb1fee413be96e026dbb4ea05c75109 100644 --- a/e2e/manager_test.go +++ b/e2e/manager_test.go @@ -101,7 +101,7 @@ func TestLoadLegacy(t *testing.T) { // t.Fatalf( // "Failed to create storage session: %+v", err) //} - kv := versioned.NewKV(ekv.Memstore{}) + kv := versioned.NewKV(&ekv.Memstore{}) err := ratchet.New(kv, myId, myPrivKey, grp) if err != nil {