diff --git a/api/authenticatedChannel.go b/api/auth.go similarity index 99% rename from api/authenticatedChannel.go rename to api/auth.go index 4b9ef33192279c0d5a6d36c520e17ddddf77c35d..3114bee8cf73da4e610615524fb7a87d2d9e8512 100644 --- a/api/authenticatedChannel.go +++ b/api/auth.go @@ -9,9 +9,10 @@ package api import ( "encoding/binary" - "gitlab.com/elixxir/client/catalog" "math/rand" + "gitlab.com/elixxir/client/catalog" + "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -36,7 +37,7 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact, message string) (id.Round, error) { jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID) - if !c.network.GetHealthTracker().IsHealthy() { + if !c.network.HealthTracker().IsHealthy() { return 0, errors.New("Cannot request authenticated channel " + "creation when the network is not healthy") } diff --git a/api/client.go b/api/client.go index 85894ca42f590f64843d820d50339a6d22d3ec32..048cc24a6b84e1813ab44131fe0a698c63ff873b 100644 --- a/api/client.go +++ b/api/client.go @@ -9,18 +9,20 @@ package api import ( "encoding/json" + "math" + "time" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/auth" - "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix" - keyExchange2 "gitlab.com/elixxir/client/e2e/rekey" + "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/event" "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/interfaces/user" "gitlab.com/elixxir/client/registration" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/user" "gitlab.com/elixxir/comms/client" "gitlab.com/elixxir/crypto/backup" "gitlab.com/elixxir/crypto/cyclic" @@ -33,8 +35,6 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/region" - "math" - "time" ) const followerStoppableName = "client" @@ -44,20 +44,23 @@ type Client struct { rng *fastRNG.StreamGenerator // the storage session securely stores data to disk and memoizes as is // appropriate - storage *storage.Session + storage storage.Session + + // user state object + userState *user.User + //object used for communications comms *client.Comms // Network parameters parameters cmix.Params - // note that the manager has a pointer to the context in many cases, but - // this interface allows it to be mocked for easy testing without the - // loop - network interfaces.NetworkManager + network cmix.Client //object used to register and communicate with permissioning permissioning *registration.Registration //object containing auth interactions - auth *auth.State + auth auth.State + + e2e e2e.Handler //services system to track running threads followerServices *services @@ -65,7 +68,7 @@ type Client struct { clientErrorChannel chan interfaces.ClientError // Event reporting in event.go - events *event.Manager + events event.Manager // Handles the triggering and delivery of backups backup *interfaces.BackupContainer @@ -78,10 +81,9 @@ type Client struct { func NewClient(ndfJSON, storageDir string, password []byte, registrationCode string) error { jww.INFO.Printf("NewClient(dir: %s)", storageDir) - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) - rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) + rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, + csprng.NewSystemRNG) - // Parse the NDF def, err := parseNDF(ndfJSON) if err != nil { return err @@ -90,10 +92,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, cmixGrp, e2eGrp := decodeGroups(def) start := time.Now() protoUser := createNewUser(rngStreamGen, cmixGrp, e2eGrp) - jww.DEBUG.Printf("PortableUserInfo generation took: %s", time.Now().Sub(start)) + jww.DEBUG.Printf("PortableUserInfo generation took: %s", + time.Now().Sub(start)) - _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, - cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) + _, err = checkVersionAndSetupStorage(def, storageDir, password, + protoUser, cmixGrp, e2eGrp, rngStreamGen, false, + registrationCode) if err != nil { return err } @@ -102,29 +106,29 @@ func NewClient(ndfJSON, storageDir string, password []byte, return nil } -// NewPrecannedClient creates an insecure user with predetermined keys with nodes -// It creates client storage, generates keys, connects, and registers -// with the network. Note that this does not register a username/identity, but -// merely creates a new cryptographic identity for adding such information -// at a later date. +// NewPrecannedClient creates an insecure user with predetermined keys +// with nodes It creates client storage, generates keys, connects, and +// registers with the network. Note that this does not register a +// username/identity, but merely creates a new cryptographic identity +// for adding such information at a later date. func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) error { jww.INFO.Printf("NewPrecannedClient()") - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) - rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) + rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, + csprng.NewSystemRNG) rngStream := rngStreamGen.GetStream() - // Parse the NDF def, err := parseNDF(defJSON) if err != nil { return err } cmixGrp, e2eGrp := decodeGroups(def) - protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp) + protoUser := createPrecannedUser(precannedID, rngStream, + cmixGrp, e2eGrp) - _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, - cmixGrp, e2eGrp, rngStreamGen, true, "") + _, err = checkVersionAndSetupStorage(def, storageDir, password, + protoUser, cmixGrp, e2eGrp, rngStreamGen, true, "") if err != nil { return err } @@ -132,29 +136,31 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, return nil } -// NewVanityClient creates a user with a receptionID that starts with the supplied prefix -// It creates client storage, generates keys, connects, and registers -// with the network. Note that this does not register a username/identity, but -// merely creates a new cryptographic identity for adding such information -// at a later date. +// NewVanityClient creates a user with a receptionID that starts with +// the supplied prefix It creates client storage, generates keys, +// connects, and registers with the network. Note that this does not +// register a username/identity, but merely creates a new +// cryptographic identity for adding such information at a later date. func NewVanityClient(ndfJSON, storageDir string, password []byte, registrationCode string, userIdPrefix string) error { jww.INFO.Printf("NewVanityClient()") - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) - rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) + + rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, + csprng.NewSystemRNG) rngStream := rngStreamGen.GetStream() - // Parse the NDF def, err := parseNDF(ndfJSON) if err != nil { return err } cmixGrp, e2eGrp := decodeGroups(def) - protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix) + protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, + userIdPrefix) - _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, - cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) + _, err = checkVersionAndSetupStorage(def, storageDir, password, + protoUser, cmixGrp, e2eGrp, rngStreamGen, false, + registrationCode) if err != nil { return err } @@ -163,22 +169,24 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte, return nil } -// NewClientFromBackup constructs a new Client from an encrypted backup. The backup -// is decrypted using the backupPassphrase. On success a successful client creation, -// the function will return a JSON encoded list of the E2E partners -// contained in the backup and a json-encoded string containing parameters stored in the backup +// NewClientFromBackup constructs a new Client from an encrypted +// backup. The backup is decrypted using the backupPassphrase. On +// success a successful client creation, the function will return a +// JSON encoded list of the E2E partners contained in the backup and a +// json-encoded string containing parameters stored in the backup func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword, - backupPassphrase []byte, backupFileContents []byte) ([]*id.ID, string, error) { + backupPassphrase []byte, backupFileContents []byte) ([]*id.ID, + string, error) { backUp := &backup.Backup{} err := backUp.Decrypt(string(backupPassphrase), backupFileContents) if err != nil { - return nil, "", errors.WithMessage(err, "Failed to unmarshal decrypted client contents.") + return nil, "", errors.WithMessage(err, + "Failed to unmarshal decrypted client contents.") } usr := user.NewUserFromBackup(backUp) - // Parse the NDF def, err := parseNDF(ndfJSON) if err != nil { return nil, "", err @@ -186,21 +194,23 @@ func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword, cmixGrp, e2eGrp := decodeGroups(def) - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) - // Create storage object. - // Note we do not need registration - storageSess, err := checkVersionAndSetupStorage(def, storageDir, []byte(sessionPassword), usr, - cmixGrp, e2eGrp, rngStreamGen, false, backUp.RegistrationCode) + // Note we do not need registration here + storageSess, err := checkVersionAndSetupStorage(def, storageDir, + []byte(sessionPassword), usr, cmixGrp, e2eGrp, rngStreamGen, + false, backUp.RegistrationCode) - // Set registration values in storage - storageSess.User().SetReceptionRegistrationValidationSignature(backUp.ReceptionIdentity.RegistrarSignature) - storageSess.User().SetTransmissionRegistrationValidationSignature(backUp.TransmissionIdentity.RegistrarSignature) - storageSess.User().SetRegistrationTimestamp(backUp.RegistrationTimestamp) + storageSess.SetReceptionRegistrationValidationSignature( + backUp.ReceptionIdentity.RegistrarSignature) + storageSess.SetTransmissionRegistrationValidationSignature( + backUp.TransmissionIdentity.RegistrarSignature) + storageSess.SetRegistrationTimestamp(backUp.RegistrationTimestamp) - //move the registration state to indicate registered with registration on proto client - err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete) + //move the registration state to indicate registered with + // registration on proto client + err = storageSess.ForwardRegistrationStatus( + storage.PermissioningComplete) if err != nil { return nil, "", err } @@ -209,36 +219,35 @@ func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword, } // OpenClient session, but don't connect to the network or log in -func OpenClient(storageDir string, password []byte, parameters params.Network) (*Client, error) { +func OpenClient(storageDir string, password []byte, + parameters cmix.Params) (*Client, error) { jww.INFO.Printf("OpenClient()") - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) - rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) - // get current client version + rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, + csprng.NewSystemRNG) + currentVersion, err := version.ParseVersion(SEMVER) if err != nil { - return nil, errors.WithMessage(err, "Could not parse version string.") + return nil, errors.WithMessage(err, + "Could not parse version string.") } - // Load Storage passwordStr := string(password) - storageSess, err := storage.Load(storageDir, passwordStr, currentVersion, - rngStreamGen) + storageSess, err := storage.Load(storageDir, passwordStr, + currentVersion) if err != nil { return nil, err } - // Set up a new context c := &Client{ storage: storageSess, - switchboard: switchboard.New(), rng: rngStreamGen, comms: nil, network: nil, followerServices: newServices(), parameters: parameters, clientErrorChannel: make(chan interfaces.ClientError, 1000), - events: event.newEventManager(), + events: event.NewEventManager(), backup: &interfaces.BackupContainer{}, } @@ -252,10 +261,8 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password, protoClientJSON []byte) error { jww.INFO.Printf("NewProtoClient_Unsafe") - // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) - // Parse the NDF def, err := parseNDF(ndfJSON) if err != nil { return err @@ -263,30 +270,31 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password, cmixGrp, e2eGrp := decodeGroups(def) - // Pull the proto user from the JSON protoUser := &user.Proto{} err = json.Unmarshal(protoClientJSON, protoUser) if err != nil { return err } - // Initialize a user object for storage set up usr := user.NewUserFromProto(protoUser) - // Set up storage - storageSess, err := checkVersionAndSetupStorage(def, storageDir, password, usr, - cmixGrp, e2eGrp, rngStreamGen, false, protoUser.RegCode) + storageSess, err := checkVersionAndSetupStorage(def, storageDir, + password, usr, cmixGrp, e2eGrp, rngStreamGen, false, + protoUser.RegCode) if err != nil { return err } - // Set registration values in storage - storageSess.User().SetReceptionRegistrationValidationSignature(protoUser.ReceptionRegValidationSig) - storageSess.User().SetTransmissionRegistrationValidationSignature(protoUser.TransmissionRegValidationSig) - storageSess.User().SetRegistrationTimestamp(protoUser.RegistrationTimestamp) + storageSess.SetReceptionRegistrationValidationSignature( + protoUser.ReceptionRegValidationSig) + storageSess.SetTransmissionRegistrationValidationSignature( + protoUser.TransmissionRegValidationSig) + storageSess.SetRegistrationTimestamp(protoUser.RegistrationTimestamp) - //move the registration state to indicate registered with registration on proto client - err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete) + // move the registration state to indicate registered with + // registration on proto client + err = storageSess.ForwardRegistrationStatus( + storage.PermissioningComplete) if err != nil { return err } @@ -295,26 +303,24 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password, } // Login initializes a client object from existing storage. -func Login(storageDir string, password []byte, parameters params.Network) (*Client, error) { +func Login(storageDir string, password []byte, + parameters cmix.Params) (*Client, error) { jww.INFO.Printf("Login()") - //Open the client c, err := OpenClient(storageDir, password, parameters) if err != nil { return nil, err } - u := c.storage.GetUser() + u := c.GetUser() jww.INFO.Printf("Client Logged in: \n\tTransmisstionID: %s "+ "\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID) - // initialize comms err = c.initComms() if err != nil { return nil, err } - //get the NDF to pass into registration and the network manager def := c.storage.GetNDF() //initialize registration @@ -324,9 +330,9 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie return nil, err } } else { - jww.WARN.Printf("Registration with permissioning skipped due to " + - "blank permissioning address. Client will not be able to register " + - "or track network.") + jww.WARN.Printf("Registration with permissioning skipped due " + + "to blank permissioning address. Client will not be " + + "able to register or track network.") } if def.Notification.Address != "" { @@ -335,25 +341,38 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie hp.KaClientOpts.Time = time.Duration(math.MaxInt64) hp.AuthEnabled = false hp.MaxRetries = 5 - _, err = c.comms.AddHost(&id.NotificationBot, def.Notification.Address, + _, err = c.comms.AddHost(&id.NotificationBot, + def.Notification.Address, []byte(def.Notification.TlsCertificate), hp) if err != nil { - jww.WARN.Printf("Failed adding host for notifications: %+v", err) + jww.WARN.Printf("Failed adding host for "+ + "notifications: %+v", err) } } - // Initialize network and link it to context - c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng, - c.events, c.comms, parameters, def) + c.network, err = cmix.NewClient(parameters, c.comms, c.storage, + c.storage.GetNDF(), c.rng, c.events) + if err != nil { + return nil, err + } + + c.e2e, err = e2e.Load(c.storage.GetKV(), c.network, + c.GetUser().ReceptionID, c.storage.GetE2EGroup(), + c.rng, c.events) if err != nil { return nil, err } - // initialize the auth tracker - c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng, - c.backup.TriggerBackup, parameters.ReplayRequests) + // FIXME: The callbacks need to be set, so I suppose we would need to + // either set them via a special type or add them + // to the login call? + authParams := auth.GetDefaultParams() + c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng, + c.events, authParams, nil) + if err != nil { + return nil, err + } - // Add all processes to the followerServices err = c.registerFollower() if err != nil { return nil, err @@ -366,22 +385,19 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie // while replacing the base NDF. This is designed for some specific deployment // procedures and is generally unsafe. func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte, - newBaseNdf string, parameters params.Network) (*Client, error) { + newBaseNdf string, parameters cmix.Params) (*Client, error) { jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()") - // Parse the NDF def, err := parseNDF(newBaseNdf) if err != nil { return nil, err } - //Open the client c, err := OpenClient(storageDir, password, parameters) if err != nil { return nil, err } - //initialize comms err = c.initComms() if err != nil { return nil, err @@ -390,28 +406,39 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte, //store the updated base NDF c.storage.SetNDF(def) - //initialize registration if def.Registration.Address != "" { err = c.initPermissioning(def) if err != nil { return nil, err } } else { - jww.WARN.Printf("Registration with permissioning skipped due to " + - "blank permissionign address. Client will not be able to register " + - "or track network.") + jww.WARN.Printf("Registration with permissioning skipped due " + + "to blank permissionign address. Client will not be " + + "able to register or track network.") } - // Initialize network and link it to context - c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng, - c.events, c.comms, parameters, def) + c.network, err = cmix.NewClient(parameters, c.comms, c.storage, + c.storage.GetNDF(), c.rng, c.events) if err != nil { return nil, err } - // initialize the auth tracker - c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng, - c.backup.TriggerBackup, parameters.ReplayRequests) + c.e2e, err = e2e.Load(c.storage.GetKV(), c.network, + c.GetUser().ReceptionID, c.storage.GetE2EGroup(), + c.rng, c.events) + if err != nil { + return nil, err + } + + // FIXME: The callbacks need to be set, so I suppose we would need to + // either set them via a special type or add them + // to the login call? + authParams := auth.GetDefaultParams() + c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng, + c.events, authParams, nil) + if err != nil { + return nil, err + } err = c.registerFollower() if err != nil { @@ -421,38 +448,35 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte, return c, nil } -// LoginWithProtoClient creates a client object with a protoclient JSON containing the -// cryptographic primitives. This is designed for some specific deployment -//// procedures and is generally unsafe. -func LoginWithProtoClient(storageDir string, password []byte, protoClientJSON []byte, - newBaseNdf string, parameters params.Network) (*Client, error) { +// LoginWithProtoClient creates a client object with a protoclient +// JSON containing the cryptographic primitives. This is designed for +// some specific deployment procedures and is generally unsafe. +func LoginWithProtoClient(storageDir string, password []byte, + protoClientJSON []byte, newBaseNdf string, + parameters cmix.Params) (*Client, error) { jww.INFO.Printf("LoginWithProtoClient()") - // Parse the NDF def, err := parseNDF(newBaseNdf) if err != nil { return nil, err } - //Open the client - err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, protoClientJSON) + err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, + protoClientJSON) if err != nil { return nil, err } - //Open the client c, err := OpenClient(storageDir, password, parameters) if err != nil { return nil, err } - //initialize comms err = c.initComms() if err != nil { return nil, err } - //store the updated base NDF c.storage.SetNDF(def) err = c.initPermissioning(def) @@ -460,17 +484,28 @@ func LoginWithProtoClient(storageDir string, password []byte, protoClientJSON [] return nil, err } - // Initialize network and link it to context - c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng, - c.events, c.comms, parameters, def) + c.network, err = cmix.NewClient(parameters, c.comms, c.storage, + c.storage.GetNDF(), c.rng, c.events) if err != nil { return nil, err } - // initialize the auth tracker - c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng, - c.backup.TriggerBackup, parameters.ReplayRequests) + c.e2e, err = e2e.Load(c.storage.GetKV(), c.network, + c.GetUser().ReceptionID, c.storage.GetE2EGroup(), + c.rng, c.events) + if err != nil { + return nil, err + } + // FIXME: The callbacks need to be set, so I suppose we would need to + // either set them via a special type or add them + // to the login call? + authParams := auth.GetDefaultParams() + c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng, + c.events, authParams, nil) + if err != nil { + return nil, err + } err = c.registerFollower() if err != nil { return nil, err @@ -483,14 +518,16 @@ func (c *Client) initComms() error { var err error //get the user from session - u := c.storage.User() - cryptoUser := u.GetCryptographicIdentity() + u := c.userState + cryptoUser := u.CryptographicIdentity + + privKey := cryptoUser.GetTransmissionRSA() + pubPEM := rsa.CreatePublicKeyPem(privKey.GetPublic()) + privPEM := rsa.CreatePrivateKeyPem(privKey) //start comms c.comms, err = client.NewClientComms(cryptoUser.GetTransmissionID(), - rsa.CreatePublicKeyPem(cryptoUser.GetTransmissionRSA().GetPublic()), - rsa.CreatePrivateKeyPem(cryptoUser.GetTransmissionRSA()), - cryptoUser.GetTransmissionSalt()) + pubPEM, privPEM, cryptoUser.GetTransmissionSalt()) if err != nil { return errors.WithMessage(err, "failed to load client") } @@ -508,18 +545,22 @@ func (c *Client) initPermissioning(def *ndf.NetworkDefinition) error { //register with registration if necessary if c.storage.GetRegistrationStatus() == storage.KeyGenComplete { - jww.INFO.Printf("Client has not registered yet, attempting registration") + jww.INFO.Printf("Client has not registered yet, " + + "attempting registration") err = c.registerWithPermissioning() if err != nil { - jww.ERROR.Printf("Client has failed registration: %s", err) + jww.ERROR.Printf("Client has failed registration: %s", + err) return errors.WithMessage(err, "failed to load client") } - jww.INFO.Printf("Client successfully registered with the network") + jww.INFO.Printf("Client successfully registered " + + "with the network") } return nil } -// registerFollower adds the follower processes to the client's follower service list. +// registerFollower adds the follower processes to the client's +// follower service list. // This should only ever be called once func (c *Client) registerFollower() error { //build the error callback @@ -531,11 +572,12 @@ func (c *Client) registerFollower() error { Trace: trace, }: default: - jww.WARN.Printf("Failed to notify about ClientError from %s: %s", source, message) + jww.WARN.Printf("Failed to notify about ClientError "+ + "from %s: %s", source, message) } } - err := c.followerServices.add(c.events.eventService) + err := c.followerServices.add(c.events.EventService) if err != nil { return errors.WithMessage(err, "Couldn't start event reporting") } @@ -549,26 +591,14 @@ func (c *Client) registerFollower() error { "the network") } - //register the incremental key upgrade service - err = c.followerServices.add(c.auth.StartProcesses) - if err != nil { - return errors.WithMessage(err, "Failed to start following "+ - "the network") - } - - //register the key exchange service - keyXchange := func() (stoppable.Stoppable, error) { - return keyExchange2.Start(c.switchboard, c.storage, c.network, c.parameters.Rekey) - } - err = c.followerServices.add(keyXchange) - return nil } // ----- Client Functions ----- // GetErrorsChannel returns a channel which passess errors from the -// long running threads controlled by StartNetworkFollower and StopNetworkFollower +// long running threads controlled by StartNetworkFollower and +// StopNetworkFollower func (c *Client) GetErrorsChannel() <-chan interfaces.ClientError { return c.clientErrorChannel } @@ -584,16 +614,20 @@ func (c *Client) GetErrorsChannel() <-chan interfaces.ClientError { // - Network Follower (/network/follow.go) // tracks the network events and hands them off to workers for handling // - Historical Round Retrieval (/network/rounds/historical.go) -// Retrieves data about rounds which are too old to be stored by the client +// Retrieves data about rounds which are too old to be +// stored by the client // - Message Retrieval Worker Group (/network/rounds/retrieve.go) -// Requests all messages in a given round from the gateway of the last nodes +// Requests all messages in a given round from the +// gateway of the last nodes // - Message Handling Worker Group (/network/message/handle.go) -// Decrypts and partitions messages when signals via the Switchboard +// Decrypts and partitions messages when signals via the +// Switchboard // - health Tracker (/network/health) // Via the network instance tracks the state of the network // - Garbled Messages (/network/message/garbled.go) -// Can be signaled to check all recent messages which could be be decoded -// Uses a message store on disk for persistence +// Can be signaled to check all recent messages which +// could be be decoded Uses a message store on disk for +// persistence // - Critical Messages (/network/message/critical.go) // Ensures all protocol layer mandatory messages are sent // Uses a message store on disk for persistence @@ -640,20 +674,15 @@ func (c *Client) HasRunningProcessies() bool { // Returns the health tracker for registration and polling func (c *Client) GetHealth() interfaces.HealthTracker { jww.INFO.Printf("GetHealth()") - return c.network.GetHealthTracker() -} - -// Returns the switchboard for Registration -func (c *Client) GetSwitchboard() interfaces.Switchboard { - jww.INFO.Printf("GetSwitchboard()") - return c.switchboard + return c.GetHealth() } // RegisterRoundEventsCb registers a callback for round // events. func (c *Client) GetRoundEvents() interfaces.RoundEvents { jww.INFO.Printf("GetRoundEvents()") - jww.WARN.Printf("GetRoundEvents does not handle Client Errors edge case!") + jww.WARN.Printf("GetRoundEvents does not handle Client Errors " + + "edge case!") return c.network.GetInstance().GetRoundEvents() } @@ -667,7 +696,7 @@ func (c *Client) AddService(sp Service) error { // can be serialized into a byte stream for out-of-band sharing. func (c *Client) GetUser() user.Info { jww.INFO.Printf("GetUser()") - return c.storage.GetUser() + return c.GetUser() } // GetComms returns the client comms object @@ -681,12 +710,12 @@ func (c *Client) GetRng() *fastRNG.StreamGenerator { } // GetStorage returns the client storage object -func (c *Client) GetStorage() *storage.Session { +func (c *Client) GetStorage() storage.Session { return c.storage } // GetNetworkInterface returns the client Network Interface -func (c *Client) GetNetworkInterface() interfaces.NetworkManager { +func (c *Client) GetNetworkInterface() cmix.Client { return c.network } @@ -696,13 +725,6 @@ func (c *Client) GetBackup() *interfaces.BackupContainer { return c.backup } -// GetRateLimitParams retrieves the rate limiting parameters. -func (c *Client) GetRateLimitParams() (uint32, uint32, int64) { - rateLimitParams := c.storage.GetBucketParams().Get() - return rateLimitParams.Capacity, rateLimitParams.LeakedTokens, - rateLimitParams.LeakDuration.Nanoseconds() -} - // GetNodeRegistrationStatus gets the current state of nodes registration. It // returns the total number of nodes in the NDF and the number of those which // are currently registers with. An error is returned if the network is not @@ -714,9 +736,7 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) { "network is not healthy") } - nodes := c.GetNetworkInterface().GetInstance().GetPartialNdf().Get().Nodes - - cmixStore := c.storage.Cmix() + nodes := c.network.GetInstance().GetFullNdf().Get().Nodes var numRegistered int var numStale = 0 @@ -730,7 +750,7 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) { numStale += 1 continue } - if cmixStore.Has(nid) { + if c.network.HasNode(nid) { numRegistered++ } } @@ -744,124 +764,50 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) { // partner ID an error will be returned. func (c *Client) DeleteRequest(partnerId *id.ID) error { jww.DEBUG.Printf("Deleting request for partner ID: %s", partnerId) - return c.GetStorage().Auth().DeleteRequest(partnerId) + return c.auth.DeleteRequest(partnerId) } // DeleteAllRequests clears all requests from client's auth storage. func (c *Client) DeleteAllRequests() error { jww.DEBUG.Printf("Deleting all requests") - return c.GetStorage().Auth().DeleteAllRequests() + return c.auth.DeleteAllRequests() } // DeleteSentRequests clears sent requests from client's auth storage. func (c *Client) DeleteSentRequests() error { jww.DEBUG.Printf("Deleting all sent requests") - return c.GetStorage().Auth().DeleteSentRequests() + return c.auth.DeleteSentRequests() } // DeleteReceiveRequests clears receive requests from client's auth storage. func (c *Client) DeleteReceiveRequests() error { jww.DEBUG.Printf("Deleting all received requests") - return c.GetStorage().Auth().DeleteReceiveRequests() + return c.auth.DeleteReceiveRequests() } // DeleteContact is a function which removes a partner from Client's storage func (c *Client) DeleteContact(partnerId *id.ID) error { jww.DEBUG.Printf("Deleting contact with ID %s", partnerId) - // get the partner so that they can be removed from preimage store - partner, err := c.storage.E2e().GetPartner(partnerId) + + _, err := c.e2e.GetPartner(partnerId) if err != nil { return errors.WithMessagef(err, "Could not delete %s because "+ "they could not be found", partnerId) } - e2ePreimage := partner.GetE2EPreimage() - rekeyPreimage := partner.GetSilentPreimage() - fileTransferPreimage := partner.GetFileTransferPreimage() - groupRequestPreimage := partner.GetGroupRequestPreimage() - //delete the partner - if err = c.storage.E2e().DeletePartner(partnerId); err != nil { + if err = c.e2e.DeletePartner(partnerId); err != nil { return err } - // Trigger backup c.backup.TriggerBackup("contact deleted") - //delete the preimages - if err = c.storage.GetEdge().Remove(edge.Preimage{ - Data: e2ePreimage, - Type: catalog.E2e, - Source: partnerId[:], - }, c.storage.GetUser().ReceptionID); err != nil { - jww.WARN.Printf("Failed delete the preimage for e2e "+ - "from %s on contact deletion: %+v", partnerId, err) - } - - if err = c.storage.GetEdge().Remove(edge.Preimage{ - Data: rekeyPreimage, - Type: catalog.Silent, - Source: partnerId[:], - }, c.storage.GetUser().ReceptionID); err != nil { - jww.WARN.Printf("Failed delete the preimage for rekey "+ - "from %s on contact deletion: %+v", partnerId, err) - } - - if err = c.storage.GetEdge().Remove(edge.Preimage{ - Data: fileTransferPreimage, - Type: catalog.EndFT, - Source: partnerId[:], - }, c.storage.GetUser().ReceptionID); err != nil { - jww.WARN.Printf("Failed delete the preimage for file transfer "+ - "from %s on contact deletion: %+v", partnerId, err) - } - - if err = c.storage.GetEdge().Remove(edge.Preimage{ - Data: groupRequestPreimage, - Type: catalog.GroupRq, - Source: partnerId[:], - }, c.storage.GetUser().ReceptionID); err != nil { - jww.WARN.Printf("Failed delete the preimage for group request "+ - "from %s on contact deletion: %+v", partnerId, err) - } - - //delete conversations - c.storage.Conversations().Delete(partnerId) + // FIXME: Do we need this? + // c.e2e.Conversations().Delete(partnerId) // call delete requests to make sure nothing is lingering. // this is for saftey to ensure the contact can be readded // in the future - _ = c.storage.Auth().Delete(partnerId) - - return nil -} - -// SetProxiedBins updates the host pool filter that filters out gateways that -// are not in one of the specified bins. -func (c *Client) SetProxiedBins(binStrings []string) error { - // Convert each region string into a region.GeoBin and place in a map for - // easy lookup - bins := make(map[region.GeoBin]bool, len(binStrings)) - for i, binStr := range binStrings { - bin, err := region.GetRegion(binStr) - if err != nil { - return errors.Errorf("failed to parse geographic bin #%d: %+v", i, err) - } - - bins[bin] = true - } - - // Create filter func - f := func(m map[id.ID]int, netDef *ndf.NetworkDefinition) map[id.ID]int { - prunedList := make(map[id.ID]int, len(m)) - for gwID, i := range m { - if bins[netDef.Gateways[i].Bin] { - prunedList[gwID] = i - } - } - return prunedList - } - - c.network.SetPoolFilter(f) + _ = c.auth.DeleteRequest(partnerId) return nil } @@ -872,8 +818,8 @@ func (c *Client) GetPreferredBins(countryCode string) ([]string, error) { // get the bin that the country is in bin, exists := region.GetCountryBin(countryCode) if !exists { - return nil, errors.Errorf("failed to find geographic bin for country %q", - countryCode) + return nil, errors.Errorf("failed to find geographic bin "+ + "for country %q", countryCode) } // Add bin to list of geographic bins @@ -884,17 +830,24 @@ func (c *Client) GetPreferredBins(countryCode string) ([]string, error) { case region.SouthAndCentralAmerica: bins = append(bins, region.NorthAmerica.String()) case region.MiddleEast: - bins = append(bins, region.EasternEurope.String(), region.CentralEurope.String(), region.WesternAsia.String()) + bins = append(bins, region.EasternEurope.String(), + region.CentralEurope.String(), + region.WesternAsia.String()) case region.NorthernAfrica: - bins = append(bins, region.WesternEurope.String(), region.CentralEurope.String()) + bins = append(bins, region.WesternEurope.String(), + region.CentralEurope.String()) case region.SouthernAfrica: - bins = append(bins, region.WesternEurope.String(), region.CentralEurope.String()) + bins = append(bins, region.WesternEurope.String(), + region.CentralEurope.String()) case region.EasternAsia: - bins = append(bins, region.WesternAsia.String(), region.Oceania.String(), region.NorthAmerica.String()) + bins = append(bins, region.WesternAsia.String(), + region.Oceania.String(), region.NorthAmerica.String()) case region.WesternAsia: - bins = append(bins, region.EasternAsia.String(), region.Russia.String(), region.MiddleEast.String()) + bins = append(bins, region.EasternAsia.String(), + region.Russia.String(), region.MiddleEast.String()) case region.Oceania: - bins = append(bins, region.EasternAsia.String(), region.NorthAmerica.String()) + bins = append(bins, region.EasternAsia.String(), + region.NorthAmerica.String()) } return bins, nil @@ -932,23 +885,25 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) { return cmixGrp, e2eGrp } -// checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient -// it checks client version and creates a new storage for user data +// checkVersionAndSetupStorage is common code shared by NewClient, +// NewPrecannedClient and NewVanityClient it checks client version and +// creates a new storage for user data func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, password []byte, protoUser user.Info, cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator, - isPrecanned bool, registrationCode string) (*storage.Session, error) { + isPrecanned bool, registrationCode string) (storage.Session, error) { // get current client version currentVersion, err := version.ParseVersion(SEMVER) if err != nil { - return nil, errors.WithMessage(err, "Could not parse version string.") + return nil, errors.WithMessage(err, + "Could not parse version string.") } // Create Storage passwordStr := string(password) storageSess, err := storage.New(storageDir, passwordStr, protoUser, - currentVersion, cmixGrp, e2eGrp, rngStreamGen, def.RateLimits) + currentVersion, cmixGrp, e2eGrp) if err != nil { return nil, err } @@ -960,19 +915,15 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, //store the registration code for later use storageSess.SetRegCode(registrationCode) //move the registration state to keys generated - err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) + err = storageSess.ForwardRegistrationStatus( + storage.KeyGenComplete) } else { - //move the registration state to indicate registered with registration - err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete) + //move the registration state to indicate registered + // with registration + err = storageSess.ForwardRegistrationStatus( + storage.PermissioningComplete) } - //add the request preiamge - storageSess.GetEdge().Add(edge.Preimage{ - Data: preimage.GenerateRequest(protoUser.ReceptionID), - Type: catalog.Request, - Source: protoUser.ReceptionID[:], - }, protoUser.ReceptionID) - if err != nil { return nil, errors.WithMessage(err, "Failed to denote state "+ "change in session") diff --git a/api/send.go b/api/send.go index 5af5704d82b3696693997a7c6911fd08955440dc..9f14e2b7a7092dea74e491da62eb2689371214a5 100644 --- a/api/send.go +++ b/api/send.go @@ -8,15 +8,19 @@ package api import ( + "time" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/crypto/e2e" + e2eCrypto "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" - "time" ) //This holds all functions to send messages over the network @@ -24,11 +28,12 @@ import ( // SendE2E sends an end-to-end payload to the provided recipient with // the provided msgType. Returns the list of rounds in which parts of // the message were sent or an error if it fails. -func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, - e2e.MessageID, time.Time, error) { - jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient, - m.MessageType, m.Payload) - return c.network.SendE2E(m, param, nil) +func (c *Client) SendE2E(mt catalog.MessageType, recipient *id.ID, + payload []byte, param e2e.Params) ([]id.Round, + e2eCrypto.MessageID, time.Time, error) { + jww.INFO.Printf("SendE2E(%s, %d. %v)", recipient, + mt, payload) + return c.e2e.SendE2E(mt, recipient, payload, param) } // SendUnsafe sends an unencrypted payload to the provided recipient @@ -36,11 +41,12 @@ func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, // of the message were sent or an error if it fails. // NOTE: Do not use this function unless you know what you are doing. // This function always produces an error message in client logging. -func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round, +func (c *Client) SendUnsafe(mt catalog.MessageType, recipient *id.ID, + payload []byte, param e2e.Params) ([]id.Round, time.Time, error) { - jww.INFO.Printf("SendUnsafe(%s, %d. %v)", m.Recipient, - m.MessageType, m.Payload) - return c.network.SendUnsafe(m, param) + jww.INFO.Printf("SendUnsafe(%s, %d. %v)", recipient, + mt, payload) + return c.e2e.SendUnsafe(mt, recipient, payload, param) } // SendCMIX sends a "raw" CMIX message payload to the provided @@ -48,9 +54,11 @@ func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round, // Returns the round ID of the round the payload was sent or an error // if it fails. func (c *Client) SendCMIX(msg format.Message, recipientID *id.ID, - param params.CMIX) (id.Round, ephemeral.Id, error) { + param cmix.CMIXParams) (id.Round, ephemeral.Id, error) { jww.INFO.Printf("Send(%s)", string(msg.GetContents())) - return c.network.SendCMIX(msg, recipientID, param) + return c.network.Send(recipientID, msg.GetKeyFP(), + message.GetDefaultService(recipientID), + msg.GetContents(), msg.GetMac(), param) } // SendManyCMIX sends many "raw" CMIX message payloads to each of the diff --git a/api/user.go b/api/user.go index 5b64f0b0a2df63408cf0b6f3baa0c2a391132caf..ab8ccebd5284161a872e3c82cc9eab6e1fb1d8fe 100644 --- a/api/user.go +++ b/api/user.go @@ -9,19 +9,20 @@ package api import ( "encoding/binary" + "math/rand" + "regexp" + "runtime" + "strings" + "sync" + jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/interfaces/user" + "gitlab.com/elixxir/client/storage/user" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/primitives/id" - "math/rand" - "regexp" - "runtime" - "strings" - "sync" ) const ( @@ -30,7 +31,8 @@ const ( ) // createNewUser generates an identity for cMix -func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.Info { +func createNewUser(rng *fastRNG.StreamGenerator, cmix, + e2e *cyclic.Group) user.Info { // CMIX Keygen var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey @@ -65,12 +67,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.I stream.Close() - transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User) + transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), + transmissionSalt, id.User) if err != nil { jww.FATAL.Panicf(err.Error()) } - receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User) + receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), + receptionSalt, id.User) if err != nil { jww.FATAL.Panicf(err.Error()) } @@ -98,13 +102,17 @@ func createDhKeys(rng *fastRNG.StreamGenerator, go func() { defer wg.Done() var err error - // DH Keygen - // FIXME: Why 256 bits? -- this is spec but not explained, it has - // to do with optimizing operations on one side and still preserves - // decent security -- cite this. Why valid for BOTH e2e and cmix? - stream := rng.GetStream() - e2eKeyBytes, err = csprng.GenerateInGroup(e2e.GetPBytes(), 256, stream) - stream.Close() + rngStream := rng.GetStream() + prime := e2e.GetPBytes() + // FIXME: Why 256 bits? -- this is spec but not + // explained, it has to do with optimizing operations + // on one side and still preserves decent security -- + // cite this. Why valid for BOTH e2e and cmix? + //keyLen := len(prime) + keyLen := 256 + e2eKeyBytes, err = csprng.GenerateInGroup(prime, keyLen, + rngStream) + rngStream.Close() if err != nil { jww.FATAL.Panicf(err.Error()) } @@ -115,7 +123,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, defer wg.Done() var err error stream := rng.GetStream() - transmissionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen) + transmissionRsaKey, err = rsa.GenerateKey(stream, + rsa.DefaultRSABitLen) stream.Close() if err != nil { jww.FATAL.Panicf(err.Error()) @@ -126,7 +135,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, defer wg.Done() var err error stream := rng.GetStream() - receptionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen) + receptionRsaKey, err = rsa.GenerateKey(stream, + rsa.DefaultRSABitLen) stream.Close() if err != nil { jww.FATAL.Panicf(err.Error()) @@ -140,7 +150,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator, // TODO: Add precanned user code structures here. // creates a precanned user -func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.Group) user.Info { +func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, + e2e *cyclic.Group) user.Info { // DH Keygen // FIXME: Why 256 bits? -- this is spec but not explained, it has // to do with optimizing operations on one side and still preserves @@ -178,7 +189,8 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic. // createNewVanityUser generates an identity for cMix // The identity's ReceptionID is not random but starts with the supplied prefix -func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.Info { +func createNewVanityUser(rng csprng.Source, cmix, + e2e *cyclic.Group, prefix string) user.Info { // DH Keygen // FIXME: Why 256 bits? -- this is spec but not explained, it has // to do with optimizing operations on one side and still preserves @@ -203,7 +215,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri if n != SaltSize { jww.FATAL.Panicf("transmissionSalt size too small: %d", n) } - transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User) + transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), + transmissionSalt, id.User) if err != nil { jww.FATAL.Panicf(err.Error()) } @@ -213,7 +226,9 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri jww.FATAL.Panicf(err.Error()) } - var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID + // just in case more than one go routine tries to access + // receptionSalt and receptionID + var mu sync.Mutex done := make(chan struct{}) found := make(chan bool) wg := &sync.WaitGroup{} @@ -234,7 +249,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri if match == false { jww.FATAL.Panicf("Prefix contains non-Base64 characters") } - jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores) + jww.INFO.Printf("Vanity userID generation started. Prefix: %s "+ + "Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores) for w := 0; w < cores; w++ { wg.Add(1) go func() { @@ -245,14 +261,20 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri defer wg.Done() return default: - n, err = csprng.NewSystemRNG().Read(rSalt) + n, err = csprng.NewSystemRNG().Read( + rSalt) if err != nil { jww.FATAL.Panicf(err.Error()) } if n != SaltSize { - jww.FATAL.Panicf("receptionSalt size too small: %d", n) + jww.FATAL.Panicf( + "receptionSalt size "+ + "too small: %d", + n) } - rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User) + rID, err := xx.NewID( + receptionRsaKey.GetPublic(), + rSalt, id.User) if err != nil { jww.FATAL.Panicf(err.Error()) } @@ -273,7 +295,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri } }() } - // wait for a solution then close the done channel to signal the workers to exit + // wait for a solution then close the done channel to signal + // the workers to exit <-found close(done) wg.Wait() diff --git a/auth/interface.go b/auth/interface.go index f44e221acf77e303b0e19559d5a3410335fa7a56..8ccd87c92b0072b6bdda2d777eb69a8dad219e3d 100644 --- a/auth/interface.go +++ b/auth/interface.go @@ -60,4 +60,19 @@ type State interface { // CallAllReceivedRequests will iterate through all pending contact requests // and replay them on the callbacks. CallAllReceivedRequests() + + // DeleteRequest deletes sent or received requests for a + // specific partner ID. + DeleteRequest(partnerID *id.ID) error + + // DeleteAllRequests clears all requests from client's auth storage. + DeleteAllRequests() error + + // DeleteSentRequests clears all sent requests from client's auth + // storage. + DeleteSentRequests() error + + // DeleteReceiveRequests clears all received requests from client's auth + // storage. + DeleteReceiveRequests() error } diff --git a/auth/request.go b/auth/request.go index 3e6b8c874b8243c313182d39437aca0d1d412153..756a70197e032d7cce32f11422a92a5418dcefd5 100644 --- a/auth/request.go +++ b/auth/request.go @@ -9,6 +9,9 @@ package auth import ( "fmt" + "io" + "strings" + "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -23,8 +26,6 @@ import ( "gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" - "io" - "strings" ) const terminator = ";" @@ -199,3 +200,19 @@ func createRequestAuth(sender *id.ID, payload, ownership []byte, myDHPriv, return &baseFmt, mac, nil } + +func (s *state) DeleteRequest(partnerID *id.ID) error { + return s.store.DeleteRequest(partnerID) +} + +func (s *state) DeleteAllRequests() error { + return s.store.DeleteAllRequests() +} + +func (s *state) DeleteSentRequests() error { + return s.store.DeleteSentRequests() +} + +func (s *state) DeleteReceiveRequests() error { + return s.store.DeleteReceiveRequests() +} diff --git a/cmix/client.go b/cmix/client.go index 76fd6377fdee71f9cbe2ffc6fcdb6fdcd8197640..af5f7dc13df08b65f6b0433e77ed4df862ac8297 100644 --- a/cmix/client.go +++ b/cmix/client.go @@ -11,6 +11,11 @@ package cmix // and intra-client state are accessible through the context object. import ( + "math" + "strconv" + "sync/atomic" + "time" + "github.com/pkg/errors" "gitlab.com/elixxir/client/cmix/address" "gitlab.com/elixxir/client/cmix/gateway" @@ -30,10 +35,6 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/ndf" - "math" - "strconv" - "sync/atomic" - "time" ) // fakeIdentityRange indicates the range generated between 0 (most current) and @@ -94,7 +95,8 @@ func NewClient(params Params, comms *commClient.Comms, session storage.Session, // Start network instance instance, err := commNetwork.NewInstance( - comms.ProtoComms, ndf, nil, nil, commNetwork.None, params.FastPolling) + comms.ProtoComms, ndf, nil, nil, commNetwork.None, + params.FastPolling) if err != nil { return nil, errors.WithMessage( err, "failed to create network client") diff --git a/event/event.go b/event/event.go index 4a15a56fb8aea3968f2d39ff1592d749f8427ee5..84831d997c79eb44a2d5c11df7ffc55279d84b2f 100644 --- a/event/event.go +++ b/event/event.go @@ -9,10 +9,11 @@ package event import ( "fmt" + "sync" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/stoppable" - "sync" ) // ReportableEvent is used to surface events to client users. @@ -35,7 +36,7 @@ type eventManager struct { eventCbs sync.Map } -func newEventManager() *eventManager { +func NewEventManager() Manager { return &eventManager{ eventCh: make(chan reportableEvent, 1000), } @@ -77,7 +78,7 @@ func (e *eventManager) UnregisterEventCallback(name string) { e.eventCbs.Delete(name) } -func (e *eventManager) eventService() (stoppable.Stoppable, error) { +func (e *eventManager) EventService() (stoppable.Stoppable, error) { stop := stoppable.NewSingle("EventReporting") go e.reportEventsHandler(stop) return stop, nil diff --git a/event/event_test.go b/event/event_test.go index c960f1374b134f5635984a3571e154fb4e901291..302c0422453aece8e57b8484444ee65593b27939 100644 --- a/event/event_test.go +++ b/event/event_test.go @@ -25,7 +25,7 @@ func TestEventReporting(t *testing.T) { evts = append(evts, evt) } - evtMgr := newEventManager() + evtMgr := NewEventManager() stop, _ := evtMgr.eventService() // Register a callback err := evtMgr.RegisterEventCallback("test", myCb) diff --git a/event/interface.go b/event/interface.go index 47e8d9795d7cc63d30b04715b92f0ec842479cf5..9de7af0741b16ca1bbd484a3504df6b351ae9e49 100644 --- a/event/interface.go +++ b/event/interface.go @@ -7,10 +7,13 @@ package event +import "gitlab.com/elixxir/client/stoppable" + // Callback defines the callback functions for client event reports type Callback func(priority int, category, evtType, details string) // Manager reporting api (used internally) type Manager interface { Report(priority int, category, evtType, details string) + EventService() (stoppable.Stoppable, error) } diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index b5104d1018151632d4d1ae41767378333990d1bd..1315c7d710571d694f6ca77d7b0222e2e50aa0f9 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -8,13 +8,14 @@ package interfaces import ( + "time" + "gitlab.com/elixxir/comms/network" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/ndf" - "time" - "gitlab.com/elixxir/client/interfaces/message" - "gitlab.com/elixxir/client/interfaces/params" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/message" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/primitives/format" @@ -29,24 +30,26 @@ type NetworkManager interface { // Only one follower may run at a time. Follow(report ClientErrorReport) (stoppable.Stoppable, error) - /*===Sending==============================================================*/ + /*===Sending==========================================================*/ - // SendCMIX sends a "raw" CMIX message payload to the provided recipient. - // Returns the round ID of the round the payload was sent or an error - // if it fails. - SendCMIX(message format.Message, recipient *id.ID, p params.CMIX) ( + // SendCMIX sends a "raw" CMIX message payload to the provided + // recipient. Returns the round ID of the round the payload + // was sent or an error if it fails. + SendCMIX(message format.Message, recipient *id.ID, p cmix.Params) ( id.Round, ephemeral.Id, error) - // SendManyCMIX sends many "raw" cMix message payloads to each of the provided - // recipients. Used to send messages in group chats. Metadata is NOT as well - // protected with this call and can leak data about yourself. Should be - // replaced with multiple uses of SendCmix in most cases. Returns the round - // ID of the round the payload was sent or an error if it fails. + // SendManyCMIX sends many "raw" cMix message payloads to each + // of the provided recipients. Used to send messages in group + // chats. Metadata is NOT as well protected with this call and + // can leak data about yourself. Should be replaced with + // multiple uses of SendCmix in most cases. Returns the round + // ID of the round the payload was sent or an error if it + // fails. // WARNING: Potentially Unsafe - SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) ( + SendManyCMIX(messages []cmix.TargetedCmixMessage, p cmix.Params) ( id.Round, []ephemeral.Id, error) - /*===Message Reception====================================================*/ + /*===Message Reception================================================*/ /* Identities are all network identites which the client is currently trying to pick up message on. An identity must be added to receive messages, fake ones will be used to poll the network @@ -60,23 +63,24 @@ type NetworkManager interface { // RemoveIdentity removes a currently tracked identity. RemoveIdentity(id *id.ID) - /* Fingerprints are the primary mechanism of identifying a picked up - message over cMix. They are a unique one time use 255 bit vector generally - associated with a specific encryption key, but can be used for an - alternative protocol.When registering a fingerprint, a MessageProcessor - is registered to handle the message.*/ + /* Fingerprints are the primary mechanism of identifying a + picked up message over cMix. They are a unique one time use + 255 bit vector generally associated with a specific encryption + key, but can be used for an alternative protocol.When + registering a fingerprint, a MessageProcessor is registered to + handle the message.*/ // AddFingerprint - Adds a fingerprint which will be handled by a // specific processor for messages received by the given identity AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, - mp MessageProcessor) error + mp message.Processor) error - // DeleteFingerprint deletes a single fingerprint associated with the given - // identity if it exists + // DeleteFingerprint deletes a single fingerprint associated + // with the given identity if it exists DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) - // DeleteClientFingerprints deletes al fingerprint associated with the given - // identity if it exists + // DeleteClientFingerprints deletes al fingerprint associated + // with the given identity if it exists DeleteClientFingerprints(identity *id.ID) /* trigger - predefined hash based tags appended to all cMix messages @@ -87,60 +91,72 @@ type NetworkManager interface { notifications system, or can be used to implement custom non fingerprint processing of payloads. I.E. key negotiation, broadcast negotiation - A tag is appended to the message of the format tag = H(H(messageContents), - preimage) and trial hashing is used to determine if a message adheres to a - tag. - WARNING: If a preimage is known by an adversary, they can determine which - messages are for the client on reception (which is normally hidden due to - collision between ephemeral IDs. + A tag is appended to the message of the format tag = + H(H(messageContents), preimage) and trial hashing is used to + determine if a message adheres to a tag. - Due to the extra overhead of trial hashing, triggers are processed after fingerprints. - If a fingerprint match occurs on the message, triggers will not be handled. + WARNING: If a preimage is known by an adversary, they can + determine which messages are for the client on reception + (which is normally hidden due to collision between ephemeral + IDs. - Triggers are address to the session. When starting a new client, all triggers must be - re-added before StartNetworkFollower is called. + Due to the extra overhead of trial hashing, triggers are + processed after fingerprints. If a fingerprint match occurs + on the message, triggers will not be handled. + + Triggers are address to the session. When starting a new + client, all triggers must be re-added before + StartNetworkFollower is called. */ - // AddTrigger - Adds a trigger which can call a message handing function or - // be used for notifications. Multiple triggers can be registered for the - // same preimage. + // AddTrigger - Adds a trigger which can call a message + // handing function or be used for notifications. Multiple + // triggers can be registered for the same preimage. // preimage - the preimage which is triggered on - // type - a descriptive string of the trigger. Generally used in notifications - // source - a byte buffer of related data. Generally used in notifications. + // type - a descriptive string of the trigger. Generally + // used in notifications + // source - a byte buffer of related data. Generally used in + // notifications. // Example: Sender ID - AddTrigger(identity *id.ID, newTrigger Trigger, response MessageProcessor) + AddTrigger(identity *id.ID, newTrigger message.Service, + response message.Processor) // DeleteTrigger - If only a single response is associated with the // preimage, the entire preimage is removed. If there is more than one // response, only the given response is removed if nil is passed in for // response, all triggers for the preimage will be removed - DeleteTrigger(identity *id.ID, preimage Preimage, response MessageProcessor) error + DeleteTrigger(identity *id.ID, preimage Preimage, + response message.Processor) error - // DeleteClientTriggers - deletes all triggers assoseated with the given identity + // DeleteClientTriggers - deletes all triggers assoseated with + // the given identity DeleteClientTriggers(identity *id.ID) - // TrackTriggers - Registers a callback which will get called every time triggers change. + // TrackTriggers - Registers a callback which will get called + // every time triggers change. // It will receive the triggers list every time it is modified. // Will only get callbacks while the Network Follower is running. // Multiple trackTriggers can be registered - TrackTriggers(TriggerTracker) + TrackServices(message.ServicesTracker) /* In inProcess */ - // it is possible to receive a message over cMix before the fingerprints or - // triggers are registered. As a result, when handling fails, messages are - // put in the inProcess que for a set number of retries. + // it is possible to receive a message over cMix before the + // fingerprints or triggers are registered. As a result, when + // handling fails, messages are put in the inProcess que for a + // set number of retries. // CheckInProgressMessages - retry processing all messages in check in // progress messages. Call this after adding fingerprints or triggers //while the follower is running. CheckInProgressMessages() - /*===Nodes================================================================*/ - /* Keys must be registed with nodes in order to send messages throug them. - this process is in general automatically handled by the Network Manager*/ + /*===Nodes============================================================*/ + /* Keys must be registed with nodes in order to send messages + throug them. this process is in general automatically handled + by the Network Manager*/ - // HasNode can be used to determine if a keying relationship exists with a - // node. + // HasNode can be used to determine if a keying relationship + // exists with a node. HasNode(nid *id.ID) bool // NumRegisteredNodes Returns the total number of nodes we have a keying @@ -150,7 +166,7 @@ type NetworkManager interface { // Triggers the generation of a keying relationship with a given node TriggerNodeRegistration(nid *id.ID) - /*===Historical Rounds====================================================*/ + /*===Historical Rounds================================================*/ /* A complete set of round info is not kept on the client, and sometimes the network will need to be queried to get round info. Historical rounds is the system internal to the Network Manager to do this. @@ -158,52 +174,59 @@ type NetworkManager interface { // LookupHistoricalRound - looks up the passed historical round on the // network - LookupHistoricalRound(rid id.Round, callback func(info *mixmessages.RoundInfo, - success bool)) error + LookupHistoricalRound(rid id.Round, + callback func(info *mixmessages.RoundInfo, + success bool)) error - /*===Sender===============================================================*/ - /* The sender handles sending comms to the network. It tracks connections to - gateways and handles proxying to gateways for targeted comms. It can be - used externally to contact gateway directly, bypassing the majority of - the network package*/ + /*===Sender===========================================================*/ + /* The sender handles sending comms to the network. It tracks + connections to gateways and handles proxying to gateways for + targeted comms. It can be used externally to contact gateway + directly, bypassing the majority of the network package*/ // SendToAny can be used to send the comm to any gateway in the network. - SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error) + SendToAny(sendFunc func(host *connect.Host) (interface{}, error), + stop *stoppable.Single) (interface{}, error) // SendToPreferred sends to a specific gateway, doing so through another // gateway as a proxy if not directly connected. SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host, target *id.ID, timeout time.Duration) (interface{}, error), - stop *stoppable.Single, timeout time.Duration) (interface{}, error) + stop *stoppable.Single, timeout time.Duration) (interface{}, + error) - // SetGatewayFilter sets a function which will be used to filter gateways - // before connecting. + // SetGatewayFilter sets a function which will be used to + // filter gateways before connecting. SetGatewayFilter(f func(map[id.ID]int, *ndf.NetworkDefinition) map[id.ID]int) - // GetHostParams - returns the host params used when connectign to gateways + // GetHostParams - returns the host params used when + // connectign to gateways GetHostParams() connect.HostParams - /*===Address Space========================================================*/ - // The network compasses identities into a smaller address space to cause - // collisions and hide the actual recipient of messages. These functions - // allow for the tracking of this addresses space. In general, address space - // issues are completely handled by the network package + /*===Address Space====================================================*/ + // The network compasses identities into a smaller address + // space to cause collisions and hide the actual recipient of + // messages. These functions allow for the tracking of this + // addresses space. In general, address space issues are + // completely handled by the network package - // GetAddressSpace GetAddressSize returns the current address size of IDs. Blocks until an - // address size is known. + // GetAddressSpace GetAddressSize returns the current address + // size of IDs. Blocks until an address size is known. GetAddressSpace() uint8 - // RegisterAddressSpaceNotification returns a channel that will trigger for - // every address space size update. The provided tag is the unique ID for - // the channel. Returns an error if the tag is already used. + // RegisterAddressSpaceNotification returns a channel that + // will trigger for every address space size update. The + // provided tag is the unique ID for the channel. Returns an + // error if the tag is already used. RegisterAddressSpaceNotification(tag string) (chan uint8, error) - // UnregisterAddressSpaceNotification stops broadcasting address space size - // updates on the channel with the specified tag. + // UnregisterAddressSpaceNotification stops broadcasting + // address space size updates on the channel with the + // specified tag. UnregisterAddressSpaceNotification(tag string) - /*===Accessors============================================================*/ + /*===Accessors========================================================*/ // GetInstance returns the network instance object, which tracks the // state of the network @@ -218,8 +241,3 @@ type NetworkManager interface { } type Preimage [32]byte - -type ClientErrorReport func(source, message, trace string) - -//for use in key exchange which needs to be callable inside of network -///type SendE2E func(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) diff --git a/interfaces/switchboard.go b/interfaces/switchboard.go deleted file mode 100644 index 2566bfb51de98fe6f5ce6abf0b1038b752f78a74..0000000000000000000000000000000000000000 --- a/interfaces/switchboard.go +++ /dev/null @@ -1,75 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the // -// LICENSE file // -/////////////////////////////////////////////////////////////////////////////// - -package interfaces - -import ( - "gitlab.com/elixxir/client/interfaces/message" - "gitlab.com/elixxir/client/switchboard" - "gitlab.com/xx_network/primitives/id" -) - -// public switchboard interface which only allows registration and does not -// allow speaking messages -type Switchboard interface { - // Registers a new listener. Returns the ID of the new listener. - // Keep this around if you want to be able to delete the listener later. - // - // name is used for debug printing and not checked for uniqueness - // - // user: 0 for all, or any user ID to listen for messages from a particular - // user. 0 can be id.ZeroUser or id.ZeroID - // messageType: 0 for all, or any message type to listen for messages of - // that type. 0 can be Receive.AnyType - // newListener: something implementing the Listener interface. Do not - // pass nil to this. - // - // If a message matches multiple listeners, all of them will hear the - // message. - RegisterListener(user *id.ID, messageType message.Type, - newListener switchboard.Listener) switchboard.ListenerID - - // Registers a new listener built around the passed function. - // Returns the ID of the new listener. - // Keep this around if you want to be able to delete the listener later. - // - // name is used for debug printing and not checked for uniqueness - // - // user: 0 for all, or any user ID to listen for messages from a particular - // user. 0 can be id.ZeroUser or id.ZeroID - // messageType: 0 for all, or any message type to listen for messages of - // that type. 0 can be Receive.AnyType - // newListener: a function implementing the ListenerFunc function type. - // Do not pass nil to this. - // - // If a message matches multiple listeners, all of them will hear the - // message. - RegisterFunc(name string, user *id.ID, messageType message.Type, - newListener switchboard.ListenerFunc) switchboard.ListenerID - - // Registers a new listener built around the passed channel. - // Returns the ID of the new listener. - // Keep this around if you want to be able to delete the listener later. - // - // name is used for debug printing and not checked for uniqueness - // - // user: 0 for all, or any user ID to listen for messages from a particular - // user. 0 can be id.ZeroUser or id.ZeroID - // messageType: 0 for all, or any message type to listen for messages of - // that type. 0 can be Receive.AnyType - // newListener: an item channel. - // Do not pass nil to this. - // - // If a message matches multiple listeners, all of them will hear the - // message. - RegisterChannel(name string, user *id.ID, messageType message.Type, - newListener chan message.Receive) switchboard.ListenerID - - // Unregister removes the listener with the specified ID so it will no - // longer get called - Unregister(listenerID switchboard.ListenerID) -} diff --git a/storage/ndf_test.go b/storage/ndf_test.go index ece36461e5368cd110b0004d95fc09bf3f28837f..4d48ab2d28d7330511f8474a9a335ef023505eb6 100644 --- a/storage/ndf_test.go +++ b/storage/ndf_test.go @@ -17,10 +17,10 @@ func TestSession_SetGetNDF(t *testing.T) { testNdf := getNDF() sess.SetNDF(testNdf) - if !reflect.DeepEqual(testNdf, sess.ndf) { + if !reflect.DeepEqual(testNdf, sess.GetNDF()) { t.Errorf("SetNDF error: "+ "Unexpected value after setting ndf:"+ - "Expected: %v\n\tReceived: %v", testNdf, sess.ndf) + "Expected: %v\n\tReceived: %v", testNdf, sess.GetNDF()) } receivedNdf := sess.GetNDF() diff --git a/storage/session.go b/storage/session.go index 2f2c543e8f3096c3875b4f553fc8df964213a003..e9bee8ae363597a4e43e6b4b4fb2a30cfc938ecf 100644 --- a/storage/session.go +++ b/storage/session.go @@ -10,15 +10,15 @@ package storage import ( - "gitlab.com/elixxir/client/storage/utility" - "gitlab.com/xx_network/crypto/large" "sync" "testing" "time" + "gitlab.com/elixxir/client/storage/utility" + "gitlab.com/xx_network/crypto/large" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - userInterface "gitlab.com/elixxir/client/interfaces/user" "gitlab.com/elixxir/client/storage/clientVersion" "gitlab.com/elixxir/client/storage/user" "gitlab.com/elixxir/client/storage/versioned" @@ -60,7 +60,7 @@ type Session interface { IsPrecanned() bool SetUsername(username string) error GetUsername() (string, error) - PortableUserInfo() userInterface.Info + PortableUserInfo() user.Info GetTransmissionRegistrationValidationSignature() []byte GetReceptionRegistrationValidationSignature() []byte GetRegistrationTimestamp() time.Time @@ -103,7 +103,7 @@ func initStore(baseDir, password string) (*session, error) { } // Creates new UserData in the session -func New(baseDir, password string, u userInterface.Info, +func New(baseDir, password string, u user.Info, currentVersion version.Version, cmixGrp, e2eGrp *cyclic.Group) (Session, error) { s, err := initStore(baseDir, password) diff --git a/storage/user/Info.go b/storage/user/Info.go deleted file mode 100644 index 8091bffe0c38791c93a944621639a1679b3d8895..0000000000000000000000000000000000000000 --- a/storage/user/Info.go +++ /dev/null @@ -1,28 +0,0 @@ -package user - -import "gitlab.com/elixxir/client/interfaces/user" - -func (u *User) PortableUserInfo() user.Info { - ci := u.CryptographicIdentity - return user.Info{ - TransmissionID: ci.GetTransmissionID().DeepCopy(), - TransmissionSalt: copySlice(ci.GetTransmissionSalt()), - TransmissionRSA: ci.GetTransmissionRSA(), - ReceptionID: ci.GetReceptionID().DeepCopy(), - RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(), - ReceptionSalt: copySlice(ci.GetReceptionSalt()), - ReceptionRSA: ci.GetReceptionRSA(), - Precanned: ci.IsPrecanned(), - //fixme: set these in the e2e layer, the command line layer - //needs more logical seperation so this can be removed - E2eDhPrivateKey: nil, - E2eDhPublicKey: nil, - } - -} - -func copySlice(s []byte) []byte { - n := make([]byte, len(s)) - copy(n, s) - return n -} diff --git a/storage/user/info.go b/storage/user/info.go new file mode 100644 index 0000000000000000000000000000000000000000..11d9381ef07cbad22a91dc49db8cff48d551fed8 --- /dev/null +++ b/storage/user/info.go @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package user + +import ( + "gitlab.com/elixxir/crypto/backup" + "gitlab.com/elixxir/crypto/contact" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/primitives/id" +) + +type Proto struct { + //General Identity + TransmissionID *id.ID + TransmissionSalt []byte + TransmissionRSA *rsa.PrivateKey + ReceptionID *id.ID + ReceptionSalt []byte + ReceptionRSA *rsa.PrivateKey + Precanned bool + // Timestamp in which user has registered with the network + RegistrationTimestamp int64 + + RegCode string + + TransmissionRegValidationSig []byte + ReceptionRegValidationSig []byte + + //e2e Identity + E2eDhPrivateKey *cyclic.Int + E2eDhPublicKey *cyclic.Int +} + +type Info struct { + //General Identity + TransmissionID *id.ID + TransmissionSalt []byte + TransmissionRSA *rsa.PrivateKey + ReceptionID *id.ID + ReceptionSalt []byte + ReceptionRSA *rsa.PrivateKey + Precanned bool + // Timestamp in which user has registered with the network + RegistrationTimestamp int64 + + //e2e Identity + E2eDhPrivateKey *cyclic.Int + E2eDhPublicKey *cyclic.Int +} + +func (u Info) GetContact() contact.Contact { + return contact.Contact{ + ID: u.ReceptionID.DeepCopy(), + DhPubKey: u.E2eDhPublicKey, + Facts: make([]fact.Fact, 0), + } +} + +func NewUserFromProto(proto *Proto) Info { + return Info{ + TransmissionID: proto.TransmissionID, + TransmissionSalt: proto.TransmissionSalt, + TransmissionRSA: proto.TransmissionRSA, + ReceptionID: proto.ReceptionID, + ReceptionSalt: proto.ReceptionSalt, + ReceptionRSA: proto.ReceptionRSA, + Precanned: proto.Precanned, + RegistrationTimestamp: proto.RegistrationTimestamp, + E2eDhPrivateKey: proto.E2eDhPrivateKey, + E2eDhPublicKey: proto.E2eDhPublicKey, + } +} + +func NewUserFromBackup(backup *backup.Backup) Info { + return Info{ + TransmissionID: backup.TransmissionIdentity.ComputedID, + TransmissionSalt: backup.TransmissionIdentity.Salt, + TransmissionRSA: backup.TransmissionIdentity.RSASigningPrivateKey, + ReceptionID: backup.ReceptionIdentity.ComputedID, + ReceptionSalt: backup.ReceptionIdentity.Salt, + ReceptionRSA: backup.ReceptionIdentity.RSASigningPrivateKey, + Precanned: false, + RegistrationTimestamp: backup.RegistrationTimestamp, + E2eDhPrivateKey: backup.ReceptionIdentity.DHPrivateKey, + E2eDhPublicKey: backup.ReceptionIdentity.DHPublicKey, + } +} + +func (u *User) PortableUserInfo() Info { + ci := u.CryptographicIdentity + return Info{ + TransmissionID: ci.GetTransmissionID().DeepCopy(), + TransmissionSalt: copySlice(ci.GetTransmissionSalt()), + TransmissionRSA: ci.GetTransmissionRSA(), + ReceptionID: ci.GetReceptionID().DeepCopy(), + RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(), + ReceptionSalt: copySlice(ci.GetReceptionSalt()), + ReceptionRSA: ci.GetReceptionRSA(), + Precanned: ci.IsPrecanned(), + //fixme: set these in the e2e layer, the command line layer + //needs more logical seperation so this can be removed + E2eDhPrivateKey: nil, + E2eDhPublicKey: nil, + } + +} + +func copySlice(s []byte) []byte { + n := make([]byte, len(s)) + copy(n, s) + return n +}