diff --git a/catalog/messageTypes.go b/catalog/messageTypes.go index c6107e05624e2d603052969db40a0c0b41a8aaf8..859a84635b4b22e01cce5d7fe816e7c397a29c54 100644 --- a/catalog/messageTypes.go +++ b/catalog/messageTypes.go @@ -45,6 +45,6 @@ const ( // IdentityAuthenticationRequest is sent by the recipient // of an authenticated connection request - // (see the connections/ package) + // (see the connect/ package) ConnectionAuthenticationRequest = 60 ) diff --git a/connections/authenticated/authenticated.go b/connect/authenticated.go similarity index 53% rename from connections/authenticated/authenticated.go rename to connect/authenticated.go index 65942fa0caca70298d1d042175413353a247b7a1..a05a3a2b60ce1db2f305ca2c9a117a265024c912 100644 --- a/connections/authenticated/authenticated.go +++ b/connect/authenticated.go @@ -5,14 +5,13 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -package authenticated +package connect import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/connections/connect" clientE2e "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/cyclic" @@ -21,25 +20,32 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" "sync" - "time" ) -// Connection is a connect.Connection interface that +// Constant error messages +const ( + roundTrackingTimeoutErr = "timed out waiting for round results" + notAllRoundsSucceededErr = "not all rounds succeeded" + failedToCloseConnectionErr = "failed to close connection with %s " + + "after error %v: %+v" +) + +// AuthenticatedConnection is a connect.Connection interface that // has the receiver authenticating their identity back to the // initiator. -type Connection interface { - // Connection is the base connections API. This allows +type AuthenticatedConnection interface { + // Connection is the base Connect API. This allows // sending and listening to the partner - connect.Connection + Connection // IsAuthenticated is a function which returns whether the // authenticated connection has been completely established. IsAuthenticated() bool } -// Callback is the callback format required to retrieve -// new authenticated.Connection objects as they are established. -type Callback func(connection Connection) +// AuthenticatedCallback is the callback format required to retrieve +// new AuthenticatedConnection objects as they are established. +type AuthenticatedCallback func(connection AuthenticatedConnection) // ConnectWithAuthentication is called by the client, ie the one establishing // connection with the server. Once a connect.Connection has been established @@ -47,62 +53,70 @@ type Callback func(connection Connection) func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, salt []byte, myRsaPrivKey *rsa.PrivateKey, myDhPrivKey *cyclic.Int, rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, - p connect.Params) (Connection, error) { + p Params) (AuthenticatedConnection, error) { + + // Track the time since we started to attempt to establish a connection + timeStart := netTime.Now() - conn, err := connect.Connect(recipient, myId, myDhPrivKey, rng, grp, net, p) + // Establish a connection with the server + conn, err := Connect(recipient, myId, myDhPrivKey, rng, grp, net, p) if err != nil { - return nil, errors.WithMessagef(err, "Failed to establish connection "+ - "with recipient %s", recipient.ID) + return nil, errors.Errorf("failed to establish connection "+ + "with recipient %s: %v", recipient.ID, err) } - // Construct message + // Construct message to prove your identity to the server payload, err := makeClientAuthRequest(conn.GetPartner(), rng, myRsaPrivKey, salt) if err != nil { + // Close connection on an error errClose := conn.Close() if errClose != nil { return nil, errors.Errorf( - "failed to close connection with %s after error %v: %+v", + failedToCloseConnectionErr, recipient.ID, err, errClose) } return nil, errors.WithMessagef(err, "failed to construct client "+ "authentication message") } - // Send message to user - e2eParams := clientE2e.GetDefaultParams() + // Send message to server rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, - payload, e2eParams) + payload, clientE2e.GetDefaultParams()) if err != nil { + // Close connection on an error errClose := conn.Close() if errClose != nil { return nil, errors.Errorf( - "failed to close connection with %s after error %v: %+v", + failedToCloseConnectionErr, recipient.ID, err, errClose) } - return nil, errors.WithMessagef(err, "failed to construct client "+ + return nil, errors.WithMessagef(err, "failed to send client "+ "authentication message") } - // Record since we first successfully sen the message - timeStart := netTime.Now() - // Determine that the message is properly sent by tracking the success // of the round(s) - authConnChan := make(chan Connection, 1) + roundErr := make(chan error, 1) roundCb := cmix.RoundEventCallback(func(allRoundsSucceeded, timedOut bool, rounds map[id.Round]cmix.RoundResult) { - if allRoundsSucceeded { - // If rounds succeeded, assume recipient has successfully - // confirmed the authentication. Pass the connection - // along via the callback - authConn := buildAuthenticatedConnection(conn) - authConn.setAuthenticated() - authConnChan <- authConn + // Check for failures while tracking rounds + if timedOut || !allRoundsSucceeded { + if timedOut { + roundErr <- errors.New(roundTrackingTimeoutErr) + } else { + // If we did not time out, then not all rounds succeeded + roundErr <- errors.New(notAllRoundsSucceededErr) + } + return } + + // If no errors occurred, signal so; an authenticated channel may + // be constructed now + roundErr <- nil }) // Find the remaining time in the timeout since we first sent the message - remainingTime := e2eParams.Timeout - netTime.Since(timeStart) + remainingTime := p.Timeout - netTime.Since(timeStart) // Track the result of the round(s) we sent the // identity authentication message on @@ -113,37 +127,42 @@ func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, "identity confirmation message delivery") } // Block waiting for confirmation of the round(s) success (or timeout - jww.DEBUG.Printf("Connection waiting for authenticated "+ + jww.DEBUG.Printf("AuthenticatedConnection waiting for authenticated "+ "connection with %s to be established...", recipient.ID.String()) - timeout := time.NewTimer(p.Timeout) - defer timeout.Stop() - select { - case authConn := <-authConnChan: - if authConn == nil { + // Wait for the round callback to send a round error + err = <-roundErr + if err != nil { + // Close connection on an error + errClose := conn.Close() + if errClose != nil { return nil, errors.Errorf( - "Unable to complete authenticated connection with partner %s", - recipient.ID.String()) + failedToCloseConnectionErr, + recipient.ID, err, errClose) } - return authConn, nil - case <-timeout.C: - return nil, errors.Errorf("Authenticated connection with "+ - "partner %s timed out", recipient.ID.String()) + + return nil, errors.Errorf("failed to confirm if identity "+ + "authentication message was sent to %s: %v", recipient.ID, err) } + // If channel received no error, construct and return the + // authenticated connection + authConn := buildAuthenticatedConnection(conn) + authConn.setAuthenticated() + return authConn, nil } -// StartServer is called by the receiver of an +// StartAuthenticatedServer is called by the receiver of an // authenticated connection request. Calling this will indicate that they // will handle authenticated requests and verify the client's attempt to -// authenticate themselves. An established authenticated.Connection will +// authenticate themselves. An established AuthenticatedConnection will // be passed via the callback. -func StartServer(cb Callback, +func StartAuthenticatedServer(cb AuthenticatedCallback, myId *id.ID, privKey *cyclic.Int, rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, - p connect.Params) error { + p Params) error { // Register the waiter for a connection establishment - connCb := connect.Callback(func(connection connect.Connection) { + connCb := Callback(func(connection Connection) { // Upon establishing a connection, register a listener for the // client's identity proof. If a identity authentication // message is received and validated, an authenticated connection will @@ -151,34 +170,35 @@ func StartServer(cb Callback, connection.RegisterListener(catalog.ConnectionAuthenticationRequest, buildAuthConfirmationHandler(cb, connection)) }) - return connect.StartServer(connCb, myId, privKey, rng, grp, + return StartServer(connCb, myId, privKey, rng, grp, net, p) } -// handler provides an implementation for the authenticated.Connection +// authenticatedHandler provides an implementation for the AuthenticatedConnection // interface. -type handler struct { - connect.Connection +type authenticatedHandler struct { + Connection isAuthenticated bool authMux sync.Mutex } -// buildAuthenticatedConnection assembles an authenticated.Connection object. -func buildAuthenticatedConnection(conn connect.Connection) *handler { - return &handler{ +// buildAuthenticatedConnection assembles an AuthenticatedConnection object. +func buildAuthenticatedConnection(conn Connection) *authenticatedHandler { + return &authenticatedHandler{ Connection: conn, isAuthenticated: false, } } -// IsAuthenticated returns whether the Connection has completed the authentication -// process. -func (h *handler) IsAuthenticated() bool { +// IsAuthenticated returns whether the AuthenticatedConnection has completed the +// authentication process. +func (h *authenticatedHandler) IsAuthenticated() bool { return h.isAuthenticated } -// setAuthenticated is a helper function which sets the Connection as authenticated. -func (h *handler) setAuthenticated() { +// setAuthenticated is a helper function which sets the +// AuthenticatedConnection as authenticated. +func (h *authenticatedHandler) setAuthenticated() { h.authMux.Lock() defer h.authMux.Unlock() h.isAuthenticated = true diff --git a/connections/authenticated/authenticated.pb.go b/connect/authenticated.pb.go similarity index 93% rename from connections/authenticated/authenticated.pb.go rename to connect/authenticated.pb.go index 1682d43c28f851e67cf300e87693a25eb860f3dd..a12961650fe8a763a5b07be50163f4b4ef496acc 100644 --- a/connections/authenticated/authenticated.pb.go +++ b/connect/authenticated.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: connections/authenticated/authenticated.proto +// source: connect/authenticated/authenticated.proto -package authenticated // import "gitlab.com/elixxir/client/connections/authenticated" +package connect // import "gitlab.com/elixxir/client/connect/authenticated" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -80,7 +80,7 @@ func init() { } func init() { - proto.RegisterFile("connections/authenticated/authenticated.proto", fileDescriptor_authenticated_9ed9358e4abe7a3a) + proto.RegisterFile("connect/authenticated/authenticated.proto", fileDescriptor_authenticated_9ed9358e4abe7a3a) } var fileDescriptor_authenticated_9ed9358e4abe7a3a = []byte{ diff --git a/connections/authenticated/authenticated.proto b/connect/authenticated.proto similarity index 92% rename from connections/authenticated/authenticated.proto rename to connect/authenticated.proto index 80e1308ae0a3e1389ba7b59680b71b9a95b8dae2..926ca845e35c6a25e91ff4b1d4f477c2eaea5c2d 100644 --- a/connections/authenticated/authenticated.proto +++ b/connect/authenticated.proto @@ -7,7 +7,7 @@ syntax = "proto3"; package authenticatedConnectionMessages; -option go_package = "gitlab.com/elixxir/client/connections/authenticated"; +option go_package = "gitlab.com/elixxir/client/connect/authenticated"; // Sent by the receiver of the authenticated connection request. message IdentityAuthentication { diff --git a/connections/authenticated/client.go b/connect/client.go similarity index 93% rename from connections/authenticated/client.go rename to connect/client.go index dbf7027dae1ac9cc593fa56996ec94307e0a1769..a26c80f02a8b195a31167735f59a245c4ab65f70 100644 --- a/connections/authenticated/client.go +++ b/connect/client.go @@ -5,7 +5,7 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -package authenticated +package connect import ( "github.com/golang/protobuf/proto" @@ -21,8 +21,7 @@ func makeClientAuthRequest(newPartner partner.Manager, rng *fastRNG.StreamGenerator, rsaPrivKey *rsa.PrivateKey, salt []byte) ([]byte, error) { - // The connection fingerprint (hashed) represents a shared nonce - // between these two partners + // The connection fingerprint (hashed) will be used as a nonce connectionFp := newPartner.ConnectionFingerprint().Bytes() opts := rsa.NewDefaultOptions() h := opts.Hash.New() diff --git a/connections/connect/connect.go b/connect/connect.go similarity index 100% rename from connections/connect/connect.go rename to connect/connect.go diff --git a/connections/authenticated/generateProto.sh b/connect/generateProto.sh similarity index 100% rename from connections/authenticated/generateProto.sh rename to connect/generateProto.sh diff --git a/connections/authenticated/server.go b/connect/server.go similarity index 84% rename from connections/authenticated/server.go rename to connect/server.go index 5435f2b0302a66e3c0d969dc75e817bdd2096403..6fa5af4c9f3ff409b0a55eb9d5d6aa25bb9dd88f 100644 --- a/connections/authenticated/server.go +++ b/connect/server.go @@ -5,20 +5,20 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -package authenticated +package connect import ( "github.com/golang/protobuf/proto" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/connections/connect" "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/primitives/id" ) -// serverListenerName is the name of the client's listener interface. -const serverListenerName = "AuthenticatedServerListener" +// authenticatedServerListenerName is the name of the client's +//listener interface. +const authenticatedServerListenerName = "AuthenticatedServerListener" // server is an interface that wraps receive.Listener. This handles // the server listening for the client's proof of identity message. @@ -29,20 +29,20 @@ type server interface { // serverListener provides an implementation of the server interface. // This will handle the identity message sent by the client. type serverListener struct { - // connectionCallback allows an authenticated.Connection + // connectionCallback allows an AuthenticatedConnection // to be passed back upon establishment. - connectionCallback Callback + connectionCallback AuthenticatedCallback // conn used to retrieve the connection context with the partner. - conn connect.Connection + conn Connection } // buildAuthConfirmationHandler returns a serverListener object. // This will handle incoming identity authentication confirmations -// via the serverListener.Hear method. A successful authenticated.Connection +// via the serverListener.Hear method. A successful AuthenticatedConnection // will be passed along via the serverListener.connectionCallback -func buildAuthConfirmationHandler(cb Callback, - connection connect.Connection) server { +func buildAuthConfirmationHandler(cb AuthenticatedCallback, + connection Connection) server { return &serverListener{ connectionCallback: cb, conn: connection, @@ -84,8 +84,7 @@ func (a serverListener) Hear(item receive.Message) { return } - // The connection fingerprint (hashed) represents a shared nonce - // between these two partners + // The connection fingerprint (hashed) will be used as a nonce connectionFp := newPartner.ConnectionFingerprint().Bytes() // Hash the connection fingerprint @@ -103,11 +102,11 @@ func (a serverListener) Hear(item receive.Message) { // If successful, pass along the established authenticated connection // via the callback - jww.DEBUG.Printf("Connection auth request for %s confirmed", + jww.DEBUG.Printf("AuthenticatedConnection auth request for %s confirmed", item.Sender.String()) authConn := buildAuthenticatedConnection(a.conn) authConn.setAuthenticated() - a.connectionCallback(authConn) + go a.connectionCallback(authConn) } // handleAuthConfirmationErr is a helper function which will close the connection @@ -127,5 +126,5 @@ func (a serverListener) handleAuthConfirmationErr(err error, sender *id.ID) { // Name returns the name of this listener. This is typically for // printing/debugging purposes. func (a serverListener) Name() string { - return serverListenerName + return authenticatedServerListenerName }