diff --git a/ud/alternate.go b/ud/alternate.go index f53281c43470d44ed24b40f65a02c143c8d785e3..4f0013bfc77b53278de23012abe7e8d4fe7c876a 100644 --- a/ud/alternate.go +++ b/ud/alternate.go @@ -16,12 +16,12 @@ type alternateUd struct { dhPubKey []byte } -// SetAlternativeUserDiscovery sets the alternativeUd object within manager. +// setAlternateUserDiscovery sets the alternativeUd object within manager. // Once set, any user discovery operation will go through the alternative // user discovery service. // // To undo this operation, use UnsetAlternativeUserDiscovery. -func (m *Manager) SetAlternativeUserDiscovery(altCert, altAddress, +func (m *Manager) setAlternateUserDiscovery(altCert, altAddress, contactFile []byte) error { params := connect.GetDefaultHostParams() params.AuthEnabled = false @@ -54,6 +54,9 @@ func (m *Manager) SetAlternativeUserDiscovery(altCert, altAddress, // UnsetAlternativeUserDiscovery clears out the information from // the Manager object. +// fixme: I think this should be removed to avoid creating a Manager object +// which has never been registered to production, and can't be w/o exporting +// the Manger.register method. func (m *Manager) UnsetAlternativeUserDiscovery() error { if m.alternativeUd == nil { return errors.New("Alternative User Discovery is already unset.") diff --git a/ud/manager.go b/ud/manager.go index 845d2b800d86170b19a1954a1530bff639617d52..c1d51d00202bef9847220bcfd19376724e898378 100644 --- a/ud/manager.go +++ b/ud/manager.go @@ -1,7 +1,6 @@ package ud import ( - "fmt" "gitlab.com/elixxir/crypto/fastRNG" "sync" "time" @@ -59,54 +58,18 @@ func LoadOrNewManager(user udE2e, comms Comms, follower udNetworkStatus, username string, networkValidationSig []byte) (*Manager, error) { jww.INFO.Println("ud.LoadOrNewManager()") - if follower() != xxdk.Running { - return nil, errors.New( - "cannot start UD Manager when network follower is not running.") - } - - // Initialize manager - m := &Manager{ - user: user, - comms: comms, - } - - if m.isRegistered() { - // Load manager if already registered - var err error - m.store, err = store.NewOrLoadStore(m.getKv()) - if err != nil { - return nil, errors.Errorf("Failed to initialize store: %v", err) - } - return m, nil - } - - // Initialize store - var err error - m.store, err = store.NewOrLoadStore(m.getKv()) - if err != nil { - return nil, errors.Errorf("Failed to initialize store: %v", err) - } - - // Initialize/Get host - udHost, err := m.getOrAddUdHost() + // Construct manager + m, err := loadOrNewManager(user, comms, follower) if err != nil { - return nil, errors.WithMessage(err, "User Discovery host object could "+ - "not be constructed.") + return nil, err } - // Register with user discovery - stream := m.getRng().GetStream() - defer stream.Close() - err = m.register(username, networkValidationSig, stream, m.comms, udHost) + // Register manager + rng := m.getRng().GetStream() + defer rng.Close() + err = m.register(username, networkValidationSig, rng, comms) if err != nil { - return nil, errors.Errorf("Failed to register: %v", err) - } - - // Set storage to registered - if err = setRegistered(m.getKv()); err != nil && m.getEventReporter() != nil { - m.getEventReporter().Report(1, "UserDiscovery", "Registration", - fmt.Sprintf("User Registered with UD: %+v", - username)) + return nil, err } return m, nil @@ -161,6 +124,55 @@ func NewManagerFromBackup(user udE2e, comms Comms, follower udNetworkStatus, return m, nil } +// LoadOrNewAlternateUserDiscovery loads an existing Manager from storage or creates a +// new one if there is no extant storage information. This is different from LoadOrNewManager +// in that it allows the user to provide alternate User Discovery contact information. +// These parameters may be used to contact a separate UD server than the one run by the +// xx network team, one the user or a third-party may operate. +// +// Params +// - user is an interface that adheres to the xxdk.E2e object. +// - comms is an interface that adheres to client.Comms object. +// - follower is a method off of xxdk.Cmix which returns the network follower's status. +// - username is the name of the user as it is registered with UD. This will be what the end user +// provides if through the bindings. +// - networkValidationSig is a signature provided by the network (i.e. the client registrar). This may +// be nil, however UD may return an error in some cases (e.g. in a production level environment). +// - altCert is the TLS certificate for the alternate UD server. +// - altAddress is the IP address of the alternate UD server. +// - marshalledContact is the data within a marshalled contact.Contact. +// +// Returns +// - A Manager object which is registered to the specified alternate UD service. +func LoadOrNewAlternateUserDiscovery(user udE2e, comms Comms, follower udNetworkStatus, + username string, networkValidationSig []byte, altCert, altAddress, + marshalledContact []byte) (*Manager, error) { + + jww.INFO.Println("ud.LoadOrNewAlternateUserDiscovery()") + + // Construct manager + m, err := loadOrNewManager(user, comms, follower) + if err != nil { + return nil, err + } + + // Set alternative user discovery + err = m.setAlternateUserDiscovery(altCert, altAddress, marshalledContact) + if err != nil { + return nil, err + } + + // Register manager + rng := m.getRng().GetStream() + defer rng.Close() + err = m.register(username, networkValidationSig, rng, comms) + if err != nil { + return nil, err + } + + return m, nil +} + // InitStoreFromBackup initializes the UD storage from the backup subsystem. func InitStoreFromBackup(kv *versioned.KV, username, email, phone fact.Fact) error { @@ -291,6 +303,41 @@ func (m *Manager) getOrAddUdHost() (*connect.Host, error) { return host, nil } +// loadOrNewManager is a helper function which loads from storage or +// creates a new Manager object. +func loadOrNewManager(user udE2e, comms Comms, + follower udNetworkStatus) (*Manager, error) { + if follower() != xxdk.Running { + return nil, errors.New( + "cannot start UD Manager when network follower is not running.") + } + + // Initialize manager + m := &Manager{ + user: user, + comms: comms, + } + + if m.isRegistered() { + // Load manager if already registered + var err error + m.store, err = store.NewOrLoadStore(m.getKv()) + if err != nil { + return nil, errors.Errorf("Failed to initialize store: %v", err) + } + return m, nil + } + + // Initialize store + var err error + m.store, err = store.NewOrLoadStore(m.getKv()) + if err != nil { + return nil, errors.Errorf("Failed to initialize store: %v", err) + } + + return m, nil +} + //////////////////////////////////////////////////////////////////////////////// // Internal Getters // //////////////////////////////////////////////////////////////////////////////// diff --git a/ud/manager_test.go b/ud/manager_test.go index 1bf18a58b4f3aa41915eddecc789c2c1f240fb4f..33a124c0d32f0e7d9a6b92b217a993712415e5d5 100644 --- a/ud/manager_test.go +++ b/ud/manager_test.go @@ -53,8 +53,8 @@ func TestManager_SetAlternativeUserDiscovery(t *testing.T) { m, _ := newTestManager(t) altAddr := "0.0.0.0:11420" - err := m.SetAlternativeUserDiscovery([]byte(testCert), []byte(altAddr), []byte(testContact)) + err := m.setAlternateUserDiscovery([]byte(testCert), []byte(altAddr), []byte(testContact)) if err != nil { - t.Fatalf("Unexpected error in SetAlternativeUserDiscovery: %v", err) + t.Fatalf("Unexpected error in setAlternateUserDiscovery: %v", err) } } diff --git a/ud/mockE2e_test.go b/ud/mockE2e_test.go index 28ddaeb0badeab3fd2eb0d18e0cacaba137927e0..c57e148fe6a63845a480bebb1aa939789b600bfc 100644 --- a/ud/mockE2e_test.go +++ b/ud/mockE2e_test.go @@ -29,13 +29,14 @@ import ( /////////////////////////////////////////////////////////////////////////////// type mockE2e struct { - grp *cyclic.Group - events event.Reporter - rng *fastRNG.StreamGenerator - kv *versioned.KV - network cmix.Client - t testing.TB - key *rsa.PrivateKey + grp *cyclic.Group + events event.Reporter + rng *fastRNG.StreamGenerator + kv *versioned.KV + network cmix.Client + mockStore mockStorage + t testing.TB + key *rsa.PrivateKey } func (m mockE2e) GetE2E() e2e.Handler { @@ -89,8 +90,7 @@ func (m mockE2e) GetCmix() cmix.Client { } func (m mockE2e) GetStorage() storage.Session { - //TODO implement me - panic("implement me") + return m.mockStore } /////////////////////////////////////////////////////////////////////////////// diff --git a/ud/mockStore_test.go b/ud/mockStore_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5031f491bbfa8b8f24ca35c9f57d3b5dd6df0575 --- /dev/null +++ b/ud/mockStore_test.go @@ -0,0 +1,160 @@ +package ud + +import ( + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/user" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/ekv" + "gitlab.com/elixxir/primitives/version" + "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/ndf" + "time" +) + +type mockStorage struct{} + +func (m mockStorage) GetKV() *versioned.KV { + return versioned.NewKV(ekv.MakeMemstore()) +} + +func (m mockStorage) GetClientVersion() version.Version { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) Get(key string) (*versioned.Object, error) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) Set(key string, object *versioned.Object) error { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) Delete(key string) error { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetCmixGroup() *cyclic.Group { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetE2EGroup() *cyclic.Group { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) ForwardRegistrationStatus(regStatus storage.RegistrationStatus) error { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetRegistrationStatus() storage.RegistrationStatus { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetRegCode(regCode string) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetRegCode() (string, error) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetNDF(def *ndf.NetworkDefinition) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetNDF() *ndf.NetworkDefinition { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetTransmissionID() *id.ID { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetTransmissionSalt() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetReceptionID() *id.ID { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetReceptionSalt() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetReceptionRSA() *rsa.PrivateKey { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetTransmissionRSA() *rsa.PrivateKey { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) IsPrecanned() bool { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetUsername(username string) error { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetUsername() (string, error) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) PortableUserInfo() user.Info { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetTransmissionRegistrationValidationSignature() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetReceptionRegistrationValidationSignature() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) GetRegistrationTimestamp() time.Time { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetTransmissionRegistrationValidationSignature(b []byte) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetReceptionRegistrationValidationSignature(b []byte) { + //TODO implement me + panic("implement me") +} + +func (m mockStorage) SetRegistrationTimestamp(tsNano int64) { + //TODO implement me + panic("implement me") +} diff --git a/ud/register.go b/ud/register.go index f41532bd5605ae7d45ddf90baea152293c489d3e..e59e378c13e4c23cea768eefdc58e0b9136e61bb 100644 --- a/ud/register.go +++ b/ud/register.go @@ -1,13 +1,13 @@ package ud import ( + "fmt" "github.com/pkg/errors" pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/crypto/diffieHellman" "gitlab.com/elixxir/crypto/factID" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/primitives/fact" - "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/signature/rsa" ) @@ -15,9 +15,17 @@ import ( // register initiates registration with user discovery given a specified // username. Provided a comms sub-interface to facilitate testing. func (m *Manager) register(username string, networkSignature []byte, - rng csprng.Source, comm registerUserComms, udHost *connect.Host) error { + rng csprng.Source, comm registerUserComms) error { - var err error + // Initialize/Get host + udHost, err := m.getOrAddUdHost() + if err != nil { + return errors.WithMessage(err, + "User Discovery host object could "+ + "not be constructed.") + } + + // Retrieve data used for registration identity := m.user.GetReceptionIdentity() privKey, err := identity.GetRSAPrivatePem() if err != nil { @@ -63,6 +71,9 @@ func (m *Manager) register(username string, networkSignature []byte, // Hash and sign fact hashedFact := factID.Fingerprint(usernameFact) signedFact, err := rsa.Sign(rng, privKey, hash.CMixHash, hashedFact, nil) + if err != nil { + return errors.Errorf("Failed to sign fact: %v", err) + } // Add username fact register request to the user registration message msg.Frs = &pb.FactRegisterRequest{ @@ -76,5 +87,16 @@ func (m *Manager) register(username string, networkSignature []byte, // Register user with user discovery _, err = comm.SendRegisterUser(udHost, msg) + if err != nil { + return err + } + + // Set storage to registered + if err = setRegistered(m.getKv()); err != nil && m.getEventReporter() != nil { + m.getEventReporter().Report(1, "UserDiscovery", "Registration", + fmt.Sprintf("User Registered with UD: %+v", + username)) + } + return err } diff --git a/ud/register_test.go b/ud/register_test.go index 3a521042c31d8703e752efd439a1456ce8b789af..f5c4f57828f27826ebd025354bc91a13cb81ec49 100644 --- a/ud/register_test.go +++ b/ud/register_test.go @@ -26,17 +26,12 @@ func (t *testRegisterComm) SendRegisterUser(_ *connect.Host, msg *pb.UDBUserRegi func TestManager_register(t *testing.T) { m, _ := newTestManager(t) - udHost, err := m.getOrAddUdHost() - if err != nil { - t.Fatalf("Failed to get/add ud host: %+v", err) - } - c := &testRegisterComm{} prng := NewPrng(42) mockSig := []byte("mock") - err = m.register("testUser", mockSig, prng, c, udHost) + err := m.register("testUser", mockSig, prng, c) if err != nil { t.Errorf("register() returned an error: %+v", err) }