Skip to content
Snippets Groups Projects
Commit a45b827b authored by Jake Taylor's avatar Jake Taylor
Browse files

Built the connection interface which wraps e2e and auth objects and manages a...

Built the connection interface which wraps e2e and auth objects and manages a connection with a partner
parent ceadb4af
No related branches found
No related tags found
4 merge requests!510Release,!207WIP: Client Restructure,!206Built the connection interface which wraps e2e and auth objects and manages a...,!203Symmetric broadcast
...@@ -36,13 +36,6 @@ import ( ...@@ -36,13 +36,6 @@ import (
// If the request must be resent, use ReplayConfirm // If the request must be resent, use ReplayConfirm
func (s *state) Confirm(partner contact.Contact) ( func (s *state) Confirm(partner contact.Contact) (
id.Round, error) { 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) return s.confirm(partner, s.params.ConfirmTag)
} }
...@@ -133,7 +126,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) ( ...@@ -133,7 +126,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) (
partner.ID, s.e2e.GetReceptionID(), partner.ID, s.e2e.GetReceptionID(),
format.DigestContents(baseFmt.Marshal())) format.DigestContents(baseFmt.Marshal()))
//service used for noticiation only //service used for notification only
/*send message*/ /*send message*/
if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(), if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(),
......
...@@ -18,7 +18,7 @@ import ( ...@@ -18,7 +18,7 @@ import (
"strings" "strings"
) )
const dummyerr = "dummy error so we dont delete the request" const dummyErr = "dummy error so we dont delete the request"
type receivedRequestService struct { type receivedRequestService struct {
s *state s *state
...@@ -27,7 +27,6 @@ type receivedRequestService struct { ...@@ -27,7 +27,6 @@ type receivedRequestService struct {
func (rrs *receivedRequestService) Process(message format.Message, func (rrs *receivedRequestService) Process(message format.Message,
receptionID receptionID.EphemeralIdentity, round rounds.Round) { receptionID receptionID.EphemeralIdentity, round rounds.Round) {
state := rrs.s state := rrs.s
// check if the timestamp is before the id was created and therefore // check if the timestamp is before the id was created and therefore
...@@ -201,7 +200,7 @@ func (rrs *receivedRequestService) Process(message format.Message, ...@@ -201,7 +200,7 @@ func (rrs *receivedRequestService) Process(message format.Message,
// return an error so the store layer does not delete the request // return an error so the store layer does not delete the request
// because the other side will confirm it // because the other side will confirm it
bail = true bail = true
return errors.Errorf(dummyerr) return errors.Errorf(dummyErr)
} }
jww.INFO.Printf("Received AuthRequest from %s to %s,"+ jww.INFO.Printf("Received AuthRequest from %s to %s,"+
......
////////////////////////////////////////////////////////////////////////////////
// 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) {
}
...@@ -45,10 +45,10 @@ type Handler interface { ...@@ -45,10 +45,10 @@ type Handler interface {
// The name is used for debug printing and not checked for // The name is used for debug printing and not checked for
// uniqueness // uniqueness
// //
// user: 0 for all, or any user ID to listen for messages from // user: id.ZeroUser for all, or any user ID to listen for
// a particular user. 0 can be id.ZeroUser or id.ZeroID // messages from a particular user.
// messageType: 0 for all, or any message type to listen for // messageType: catalog.NoType for all, or any message type to
// messages of that type. 0 can be Message.AnyType // listen for messages of that type.
// newListener: something implementing the Listener // newListener: something implementing the Listener
// interface. Do not pass nil to this. // interface. Do not pass nil to this.
// //
...@@ -66,10 +66,10 @@ type Handler interface { ...@@ -66,10 +66,10 @@ type Handler interface {
// name is used for debug printing and not checked for // name is used for debug printing and not checked for
// uniqueness // uniqueness
// //
// user: 0 for all, or any user ID to listen for messages from // user: id.ZeroUser for all, or any user ID to listen for
// a particular user. 0 can be id.ZeroUser or id.ZeroID // messages from a particular user.
// messageType: 0 for all, or any message type to listen for // messageType: catalog.NoType for all, or any message type to
// messages of that type. 0 can be Message.AnyType // listen for messages of that type.
// newListener: a function implementing the ListenerFunc // newListener: a function implementing the ListenerFunc
// function type. Do not pass nil to this. // function type. Do not pass nil to this.
// //
...@@ -115,7 +115,6 @@ type Handler interface { ...@@ -115,7 +115,6 @@ type Handler interface {
receiveParams session.Params) (partner.Manager, error) receiveParams session.Params) (partner.Manager, error)
// GetPartner returns the partner per its ID, if it exists // GetPartner returns the partner per its ID, if it exists
// myID is your ID in the relationship
GetPartner(partnerID *id.ID) (partner.Manager, error) GetPartner(partnerID *id.ID) (partner.Manager, error)
// DeletePartner removes the associated contact from the E2E store // DeletePartner removes the associated contact from the E2E store
...@@ -133,8 +132,8 @@ type Handler interface { ...@@ -133,8 +132,8 @@ type Handler interface {
// be sent to using the tag fields in the Params Object // be sent to using the tag fields in the Params Object
// Passing nil for the processor allows you to create a // Passing nil for the processor allows you to create a
// service which is never called but will be visible by // service which is never called but will be visible by
// notifications Processes added this way are generally not // notifications. Processes added this way are generally not
// end ot end encrypted messages themselves, but other // end-to-end encrypted messages themselves, but other
// protocols which piggyback on e2e relationships to start // protocols which piggyback on e2e relationships to start
// communication // communication
AddService(tag string, processor message.Processor) error AddService(tag string, processor message.Processor) error
......
...@@ -39,7 +39,7 @@ const e2eRekeyParamsKey = "e2eRekeyParams" ...@@ -39,7 +39,7 @@ const e2eRekeyParamsKey = "e2eRekeyParams"
const e2eRekeyParamsVer = 0 const e2eRekeyParamsVer = 0
// Init Creates stores. After calling, use load // 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 // 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, func Init(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
grp *cyclic.Group, rekeyParams rekey.Params) error { grp *cyclic.Group, rekeyParams rekey.Params) error {
......
...@@ -101,7 +101,7 @@ func TestLoadLegacy(t *testing.T) { ...@@ -101,7 +101,7 @@ func TestLoadLegacy(t *testing.T) {
// t.Fatalf( // t.Fatalf(
// "Failed to create storage session: %+v", err) // "Failed to create storage session: %+v", err)
//} //}
kv := versioned.NewKV(ekv.Memstore{}) kv := versioned.NewKV(&ekv.Memstore{})
err := ratchet.New(kv, myId, myPrivKey, grp) err := ratchet.New(kv, myId, myPrivKey, grp)
if err != nil { if err != nil {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment