Skip to content
Snippets Groups Projects
Commit d0f46a84 authored by Josh Brooks's avatar Josh Brooks
Browse files

Flatten the connect/ package

parent 5c1addd7
No related branches found
No related tags found
3 merge requests!510Release,!216Xx 3895/authenticated connection,!207WIP: Client Restructure
...@@ -45,6 +45,6 @@ const ( ...@@ -45,6 +45,6 @@ const (
// IdentityAuthenticationRequest is sent by the recipient // IdentityAuthenticationRequest is sent by the recipient
// of an authenticated connection request // of an authenticated connection request
// (see the connections/ package) // (see the connect/ package)
ConnectionAuthenticationRequest = 60 ConnectionAuthenticationRequest = 60
) )
...@@ -5,14 +5,13 @@ ...@@ -5,14 +5,13 @@
// LICENSE file // // LICENSE file //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
package authenticated package connect
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/connections/connect"
clientE2e "gitlab.com/elixxir/client/e2e" clientE2e "gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
...@@ -21,25 +20,32 @@ import ( ...@@ -21,25 +20,32 @@ import (
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/netTime" "gitlab.com/xx_network/primitives/netTime"
"sync" "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 // has the receiver authenticating their identity back to the
// initiator. // initiator.
type Connection interface { type AuthenticatedConnection interface {
// Connection is the base connections API. This allows // Connection is the base Connect API. This allows
// sending and listening to the partner // sending and listening to the partner
connect.Connection Connection
// IsAuthenticated is a function which returns whether the // IsAuthenticated is a function which returns whether the
// authenticated connection has been completely established. // authenticated connection has been completely established.
IsAuthenticated() bool IsAuthenticated() bool
} }
// Callback is the callback format required to retrieve // AuthenticatedCallback is the callback format required to retrieve
// new authenticated.Connection objects as they are established. // new AuthenticatedConnection objects as they are established.
type Callback func(connection Connection) type AuthenticatedCallback func(connection AuthenticatedConnection)
// ConnectWithAuthentication is called by the client, ie the one establishing // ConnectWithAuthentication is called by the client, ie the one establishing
// connection with the server. Once a connect.Connection has been established // connection with the server. Once a connect.Connection has been established
...@@ -47,62 +53,70 @@ type Callback func(connection Connection) ...@@ -47,62 +53,70 @@ type Callback func(connection Connection)
func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID,
salt []byte, myRsaPrivKey *rsa.PrivateKey, myDhPrivKey *cyclic.Int, salt []byte, myRsaPrivKey *rsa.PrivateKey, myDhPrivKey *cyclic.Int,
rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, 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 { if err != nil {
return nil, errors.WithMessagef(err, "Failed to establish connection "+ return nil, errors.Errorf("failed to establish connection "+
"with recipient %s", recipient.ID) "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) payload, err := makeClientAuthRequest(conn.GetPartner(), rng, myRsaPrivKey, salt)
if err != nil { if err != nil {
// Close connection on an error
errClose := conn.Close() errClose := conn.Close()
if errClose != nil { if errClose != nil {
return nil, errors.Errorf( return nil, errors.Errorf(
"failed to close connection with %s after error %v: %+v", failedToCloseConnectionErr,
recipient.ID, err, errClose) recipient.ID, err, errClose)
} }
return nil, errors.WithMessagef(err, "failed to construct client "+ return nil, errors.WithMessagef(err, "failed to construct client "+
"authentication message") "authentication message")
} }
// Send message to user // Send message to server
e2eParams := clientE2e.GetDefaultParams()
rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest,
payload, e2eParams) payload, clientE2e.GetDefaultParams())
if err != nil { if err != nil {
// Close connection on an error
errClose := conn.Close() errClose := conn.Close()
if errClose != nil { if errClose != nil {
return nil, errors.Errorf( return nil, errors.Errorf(
"failed to close connection with %s after error %v: %+v", failedToCloseConnectionErr,
recipient.ID, err, errClose) recipient.ID, err, errClose)
} }
return nil, errors.WithMessagef(err, "failed to construct client "+ return nil, errors.WithMessagef(err, "failed to send client "+
"authentication message") "authentication message")
} }
// Record since we first successfully sen the message
timeStart := netTime.Now()
// Determine that the message is properly sent by tracking the success // Determine that the message is properly sent by tracking the success
// of the round(s) // of the round(s)
authConnChan := make(chan Connection, 1) roundErr := make(chan error, 1)
roundCb := cmix.RoundEventCallback(func(allRoundsSucceeded, roundCb := cmix.RoundEventCallback(func(allRoundsSucceeded,
timedOut bool, rounds map[id.Round]cmix.RoundResult) { timedOut bool, rounds map[id.Round]cmix.RoundResult) {
if allRoundsSucceeded { // Check for failures while tracking rounds
// If rounds succeeded, assume recipient has successfully if timedOut || !allRoundsSucceeded {
// confirmed the authentication. Pass the connection if timedOut {
// along via the callback roundErr <- errors.New(roundTrackingTimeoutErr)
authConn := buildAuthenticatedConnection(conn) } else {
authConn.setAuthenticated() // If we did not time out, then not all rounds succeeded
authConnChan <- authConn 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 // 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 // Track the result of the round(s) we sent the
// identity authentication message on // identity authentication message on
...@@ -113,37 +127,42 @@ func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, ...@@ -113,37 +127,42 @@ func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID,
"identity confirmation message delivery") "identity confirmation message delivery")
} }
// Block waiting for confirmation of the round(s) success (or timeout // 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()) "connection with %s to be established...", recipient.ID.String())
timeout := time.NewTimer(p.Timeout) // Wait for the round callback to send a round error
defer timeout.Stop() err = <-roundErr
select { if err != nil {
case authConn := <-authConnChan: // Close connection on an error
if authConn == nil { errClose := conn.Close()
if errClose != nil {
return nil, errors.Errorf( return nil, errors.Errorf(
"Unable to complete authenticated connection with partner %s", failedToCloseConnectionErr,
recipient.ID.String()) recipient.ID, err, errClose)
} }
return authConn, nil
case <-timeout.C: return nil, errors.Errorf("failed to confirm if identity "+
return nil, errors.Errorf("Authenticated connection with "+ "authentication message was sent to %s: %v", recipient.ID, err)
"partner %s timed out", recipient.ID.String())
} }
// 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 // authenticated connection request. Calling this will indicate that they
// will handle authenticated requests and verify the client's attempt to // 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. // be passed via the callback.
func StartServer(cb Callback, func StartAuthenticatedServer(cb AuthenticatedCallback,
myId *id.ID, privKey *cyclic.Int, myId *id.ID, privKey *cyclic.Int,
rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client,
p connect.Params) error { p Params) error {
// Register the waiter for a connection establishment // 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 // Upon establishing a connection, register a listener for the
// client's identity proof. If a identity authentication // client's identity proof. If a identity authentication
// message is received and validated, an authenticated connection will // message is received and validated, an authenticated connection will
...@@ -151,34 +170,35 @@ func StartServer(cb Callback, ...@@ -151,34 +170,35 @@ func StartServer(cb Callback,
connection.RegisterListener(catalog.ConnectionAuthenticationRequest, connection.RegisterListener(catalog.ConnectionAuthenticationRequest,
buildAuthConfirmationHandler(cb, connection)) buildAuthConfirmationHandler(cb, connection))
}) })
return connect.StartServer(connCb, myId, privKey, rng, grp, return StartServer(connCb, myId, privKey, rng, grp,
net, p) net, p)
} }
// handler provides an implementation for the authenticated.Connection // authenticatedHandler provides an implementation for the AuthenticatedConnection
// interface. // interface.
type handler struct { type authenticatedHandler struct {
connect.Connection Connection
isAuthenticated bool isAuthenticated bool
authMux sync.Mutex authMux sync.Mutex
} }
// buildAuthenticatedConnection assembles an authenticated.Connection object. // buildAuthenticatedConnection assembles an AuthenticatedConnection object.
func buildAuthenticatedConnection(conn connect.Connection) *handler { func buildAuthenticatedConnection(conn Connection) *authenticatedHandler {
return &handler{ return &authenticatedHandler{
Connection: conn, Connection: conn,
isAuthenticated: false, isAuthenticated: false,
} }
} }
// IsAuthenticated returns whether the Connection has completed the authentication // IsAuthenticated returns whether the AuthenticatedConnection has completed the
// process. // authentication process.
func (h *handler) IsAuthenticated() bool { func (h *authenticatedHandler) IsAuthenticated() bool {
return h.isAuthenticated return h.isAuthenticated
} }
// setAuthenticated is a helper function which sets the Connection as authenticated. // setAuthenticated is a helper function which sets the
func (h *handler) setAuthenticated() { // AuthenticatedConnection as authenticated.
func (h *authenticatedHandler) setAuthenticated() {
h.authMux.Lock() h.authMux.Lock()
defer h.authMux.Unlock() defer h.authMux.Unlock()
h.isAuthenticated = true h.isAuthenticated = true
......
// Code generated by protoc-gen-go. DO NOT EDIT. // 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 proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
...@@ -80,7 +80,7 @@ func init() { ...@@ -80,7 +80,7 @@ func init() {
} }
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{ var fileDescriptor_authenticated_9ed9358e4abe7a3a = []byte{
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
syntax = "proto3"; syntax = "proto3";
package authenticatedConnectionMessages; 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. // Sent by the receiver of the authenticated connection request.
message IdentityAuthentication { message IdentityAuthentication {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// LICENSE file // // LICENSE file //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
package authenticated package connect
import ( import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
...@@ -21,8 +21,7 @@ func makeClientAuthRequest(newPartner partner.Manager, ...@@ -21,8 +21,7 @@ func makeClientAuthRequest(newPartner partner.Manager,
rng *fastRNG.StreamGenerator, rsaPrivKey *rsa.PrivateKey, rng *fastRNG.StreamGenerator, rsaPrivKey *rsa.PrivateKey,
salt []byte) ([]byte, error) { salt []byte) ([]byte, error) {
// The connection fingerprint (hashed) represents a shared nonce // The connection fingerprint (hashed) will be used as a nonce
// between these two partners
connectionFp := newPartner.ConnectionFingerprint().Bytes() connectionFp := newPartner.ConnectionFingerprint().Bytes()
opts := rsa.NewDefaultOptions() opts := rsa.NewDefaultOptions()
h := opts.Hash.New() h := opts.Hash.New()
......
File moved
...@@ -5,20 +5,20 @@ ...@@ -5,20 +5,20 @@
// LICENSE file // // LICENSE file //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
package authenticated package connect
import ( import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/connections/connect"
"gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/crypto/xx"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
) )
// serverListenerName is the name of the client's listener interface. // authenticatedServerListenerName is the name of the client's
const serverListenerName = "AuthenticatedServerListener" //listener interface.
const authenticatedServerListenerName = "AuthenticatedServerListener"
// server is an interface that wraps receive.Listener. This handles // server is an interface that wraps receive.Listener. This handles
// the server listening for the client's proof of identity message. // the server listening for the client's proof of identity message.
...@@ -29,20 +29,20 @@ type server interface { ...@@ -29,20 +29,20 @@ type server interface {
// serverListener provides an implementation of the server interface. // serverListener provides an implementation of the server interface.
// This will handle the identity message sent by the client. // This will handle the identity message sent by the client.
type serverListener struct { type serverListener struct {
// connectionCallback allows an authenticated.Connection // connectionCallback allows an AuthenticatedConnection
// to be passed back upon establishment. // to be passed back upon establishment.
connectionCallback Callback connectionCallback AuthenticatedCallback
// conn used to retrieve the connection context with the partner. // conn used to retrieve the connection context with the partner.
conn connect.Connection conn Connection
} }
// buildAuthConfirmationHandler returns a serverListener object. // buildAuthConfirmationHandler returns a serverListener object.
// This will handle incoming identity authentication confirmations // 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 // will be passed along via the serverListener.connectionCallback
func buildAuthConfirmationHandler(cb Callback, func buildAuthConfirmationHandler(cb AuthenticatedCallback,
connection connect.Connection) server { connection Connection) server {
return &serverListener{ return &serverListener{
connectionCallback: cb, connectionCallback: cb,
conn: connection, conn: connection,
...@@ -84,8 +84,7 @@ func (a serverListener) Hear(item receive.Message) { ...@@ -84,8 +84,7 @@ func (a serverListener) Hear(item receive.Message) {
return return
} }
// The connection fingerprint (hashed) represents a shared nonce // The connection fingerprint (hashed) will be used as a nonce
// between these two partners
connectionFp := newPartner.ConnectionFingerprint().Bytes() connectionFp := newPartner.ConnectionFingerprint().Bytes()
// Hash the connection fingerprint // Hash the connection fingerprint
...@@ -103,11 +102,11 @@ func (a serverListener) Hear(item receive.Message) { ...@@ -103,11 +102,11 @@ func (a serverListener) Hear(item receive.Message) {
// If successful, pass along the established authenticated connection // If successful, pass along the established authenticated connection
// via the callback // via the callback
jww.DEBUG.Printf("Connection auth request for %s confirmed", jww.DEBUG.Printf("AuthenticatedConnection auth request for %s confirmed",
item.Sender.String()) item.Sender.String())
authConn := buildAuthenticatedConnection(a.conn) authConn := buildAuthenticatedConnection(a.conn)
authConn.setAuthenticated() authConn.setAuthenticated()
a.connectionCallback(authConn) go a.connectionCallback(authConn)
} }
// handleAuthConfirmationErr is a helper function which will close the connection // handleAuthConfirmationErr is a helper function which will close the connection
...@@ -127,5 +126,5 @@ func (a serverListener) handleAuthConfirmationErr(err error, sender *id.ID) { ...@@ -127,5 +126,5 @@ func (a serverListener) handleAuthConfirmationErr(err error, sender *id.ID) {
// Name returns the name of this listener. This is typically for // Name returns the name of this listener. This is typically for
// printing/debugging purposes. // printing/debugging purposes.
func (a serverListener) Name() string { func (a serverListener) Name() string {
return serverListenerName return authenticatedServerListenerName
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment