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

Add LoadOrNewAlternateUserDiscovery

parent 1708cd1a
No related branches found
No related tags found
2 merge requests!510Release,!323Xx 4019/new or load alt ud
......@@ -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.")
......
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 //
////////////////////////////////////////////////////////////////////////////////
......
......@@ -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)
}
}
......@@ -34,6 +34,7 @@ type mockE2e struct {
rng *fastRNG.StreamGenerator
kv *versioned.KV
network cmix.Client
mockStore mockStorage
t testing.TB
key *rsa.PrivateKey
}
......@@ -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
}
///////////////////////////////////////////////////////////////////////////////
......
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")
}
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
}
......@@ -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)
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment