diff --git a/cmd/root.go b/cmd/root.go index 66ca4426aa012dbf18666b756675b85547ce6c7a..2f0c0c013d1093b942e2bf4bf3fc2597099a7f92 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,6 +15,7 @@ import ( "encoding/json" "errors" "fmt" + "gitlab.com/elixxir/client/storage/user" "io/fs" "io/ioutil" "log" @@ -545,8 +546,15 @@ func createClient() *xxdk.Cmix { if err != nil { jww.FATAL.Panicf("%v", err) } + + protoUser := &user.Proto{} + err = json.Unmarshal(protoUserJson, protoUser) + if err != nil { + jww.FATAL.Panicf("%v", err) + } + err = xxdk.NewProtoClient_Unsafe(string(ndfJSON), storeDir, - pass, protoUserJson) + pass, protoUser) } else if userIDprefix != "" { err = xxdk.NewVanityClient(string(ndfJSON), storeDir, pass, regCode, userIDprefix) diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go index 7d9b7aaae3cbae55e8a7b5d83ed06b59649807c5..961aac77627f0f5ef15ed35b839c2c5eaafa9b4b 100644 --- a/cmix/identity/tracker.go +++ b/cmix/identity/tracker.go @@ -41,7 +41,8 @@ const ( trackedIDChanSize = 1000 deleteIDChanSize = 1000 - // DefaultExtraChecks is the default value for ExtraChecks on receptionID.Identity. + // DefaultExtraChecks is the default value for ExtraChecks + // on receptionID.Identity. DefaultExtraChecks = 10 ) @@ -225,8 +226,8 @@ func (t *manager) track(stop *stoppable.Single) { } } -// processIdentities builds and adds new identities and removes old identities from the tracker -// and returns the timestamp of the next ID event +// processIdentities builds and adds new identities and removes old +// identities from the tracker and returns the timestamp of the next ID event. func (t *manager) processIdentities(addressSize uint8) time.Time { edits := false toRemove := make(map[int]struct{}) @@ -304,7 +305,8 @@ func unmarshalTimestamp(lastTimestampObj *versioned.Object) (time.Time, error) { // generateIdentitiesOverRange generates and adds all not yet existing ephemeral Ids // and returns the timestamp of the next generation for the given TrackedID -func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, addressSize uint8) time.Time { +func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, + addressSize uint8) time.Time { // Ensure that ephemeral IDs will not be generated after the // identity is invalid generateUntil := inQuestion.NextGeneration @@ -337,7 +339,8 @@ func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, addressSize } // Move up the end time if the source identity is invalid // before the natural end of the ephemeral identity - if inQuestion.ValidUntil != Forever && newIdentity.End.After(inQuestion.ValidUntil) { + if inQuestion.ValidUntil != Forever && newIdentity.End. + After(inQuestion.ValidUntil) { newIdentity.End = inQuestion.ValidUntil } @@ -348,7 +351,8 @@ func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, addressSize // Print debug information and set return value if isLastIdentity := i == len(protoIds)-1; isLastIdentity { - jww.INFO.Printf("Current Identity: %d (source: %s), Start: %s, End: %s, addrSize: %d", + jww.INFO.Printf("Current Identity: %d (source: %s), Start: %s, "+ + "End: %s, addrSize: %d", newIdentity.EphId.Int64(), newIdentity.Source, newIdentity.StartValid, diff --git a/restlike/single/receiver.go b/restlike/single/receiver.go index f82a1f327ee9b7215aa20748da044bdc63f464c9..f25268f8160d2d257121af560619c87997d87111 100644 --- a/restlike/single/receiver.go +++ b/restlike/single/receiver.go @@ -25,7 +25,8 @@ type receiver struct { // Callback is the handler for single-use message reception for a RestServer // Automatically responds to invalid endpoint requests -func (s *receiver) Callback(req *single.Request, receptionId receptionID.EphemeralIdentity, rounds []rounds.Round) { +func (s *receiver) Callback(req *single.Request, + receptionId receptionID.EphemeralIdentity, rounds []rounds.Round) { // Unmarshal the request payload newMessage := &restlike.Message{} err := proto.Unmarshal(req.GetPayload(), newMessage) @@ -35,7 +36,8 @@ func (s *receiver) Callback(req *single.Request, receptionId receptionID.Ephemer } var respondErr error - if cb, err := s.endpoints.Get(restlike.URI(newMessage.GetUri()), restlike.Method(newMessage.GetMethod())); err == nil { + if cb, err := s.endpoints.Get(restlike.URI(newMessage.GetUri()), + restlike.Method(newMessage.GetMethod())); err == nil { // Send the payload to the proper Callback if it exists and singleRespond with the result respondErr = singleRespond(cb(newMessage), req) } else { diff --git a/single/interfaces.go b/single/interfaces.go index d72ba2fa178555e827544358b03a9c2bbfdc3af8..da28ef80a682b5d6d9ed9a5149972b269892d16b 100644 --- a/single/interfaces.go +++ b/single/interfaces.go @@ -2,7 +2,10 @@ package single import ( "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/message" + cMixMsg "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" @@ -10,6 +13,46 @@ import ( "time" ) +// Receiver contains the callback interface for any handler which +// will process the reception of a single request. Used in Listen. +type Receiver interface { + Callback(*Request, receptionID.EphemeralIdentity, []rounds.Round) +} + +// Response contains the callback interface for any handler which +// will process the response of a single request. Used in TransmitRequest. +type Response interface { + Callback(payload []byte, receptionID receptionID.EphemeralIdentity, + rounds []rounds.Round, err error) +} + +type Listener interface { + // Stop unregisters the listener + Stop() +} + +// RequestCmix interface matches a subset of the cmix.Client methods used by the +// Request for easier testing. +type RequestCmix interface { + GetMaxMessageLength() int + Send(recipient *id.ID, fingerprint format.Fingerprint, + service cMixMsg.Service, payload, mac []byte, + cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) + GetInstance() *network.Instance +} + +// ListenCmix interface matches a subset of cmix.Client methods used for Listen. +type ListenCmix interface { + RequestCmix + AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, + mp cMixMsg.Processor) error + AddService( + clientID *id.ID, newService cMixMsg.Service, response cMixMsg.Processor) + DeleteService( + clientID *id.ID, toDelete cMixMsg.Service, processor cMixMsg.Processor) + CheckInProgressMessages() +} + // Cmix is a sub-interface of the cmix.Client. It contains the methods relevant // to what is used in this package. type Cmix interface { diff --git a/single/listener.go b/single/listener.go index 138eb86f02322bd269a324001e80b2822413eb2d..01604b1e03839b8ecf23a0fbaa21501122d7d9f8 100644 --- a/single/listener.go +++ b/single/listener.go @@ -16,15 +16,6 @@ import ( "strings" ) -type Receiver interface { - Callback(*Request, receptionID.EphemeralIdentity, []rounds.Round) -} - -type Listener interface { - // Stop unregisters the listener - Stop() -} - type listener struct { tag string grp *cyclic.Group @@ -62,17 +53,6 @@ func Listen(tag string, myID *id.ID, privKey *cyclic.Int, net ListenCmix, return l } -type ListenCmix interface { - RequestCmix - AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, - mp cMixMsg.Processor) error - AddService( - clientID *id.ID, newService cMixMsg.Service, response cMixMsg.Processor) - DeleteService( - clientID *id.ID, toDelete cMixMsg.Service, processor cMixMsg.Processor) - CheckInProgressMessages() -} - // Process decrypts and collates the encrypted single-use request message. func (l *listener) Process(ecrMsg format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { diff --git a/single/receivedRequest.go b/single/receivedRequest.go index 6f81f17e7c0832a4addea0ed8c8f155560b2ab7f..b571ef1db60580ecc2f25c47543ce18dff77d226 100644 --- a/single/receivedRequest.go +++ b/single/receivedRequest.go @@ -8,14 +8,11 @@ import ( "gitlab.com/elixxir/client/cmix" cmixMsg "gitlab.com/elixxir/client/cmix/message" "gitlab.com/elixxir/client/single/message" - "gitlab.com/elixxir/comms/network" ds "gitlab.com/elixxir/comms/network/dataStructures" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e/singleUse" - "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/id/ephemeral" "sync" "sync/atomic" "testing" @@ -44,16 +41,6 @@ type Request struct { net RequestCmix } -// RequestCmix interface matches a subset of the cmix.Client methods used by the -// Request for easier testing. -type RequestCmix interface { - GetMaxMessageLength() int - Send(recipient *id.ID, fingerprint format.Fingerprint, - service cmixMsg.Service, payload, mac []byte, - cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) - GetInstance() *network.Instance -} - // Respond is used to respond to the request. It sends a payload up to // Request.GetMaxResponseLength. It will chunk the message into multiple cMix // messages if it is too long for a single message. It will fail if a single diff --git a/single/request.go b/single/request.go index ec068aebc084f1d682a82e561c6a6b17ead1f2af..1a49628653915c373fb6d7b59e632a7375eebfbc 100644 --- a/single/request.go +++ b/single/request.go @@ -23,12 +23,6 @@ import ( "time" ) -// Response interface allows for callbacks to -type Response interface { - Callback(payload []byte, receptionID receptionID.EphemeralIdentity, - rounds []rounds.Round, err error) -} - // Error messages. const ( // TransmitRequest diff --git a/storage/session.go b/storage/session.go index 73589f00564c3226f02ca7bd6073b636cfb8073b..89836d53ebf70a88a006e007e76c940927f7c9b1 100644 --- a/storage/session.go +++ b/storage/session.go @@ -104,7 +104,8 @@ func initStore(baseDir, password string) (*session, error) { // Creates new UserData in the session func New(baseDir, password string, u user.Info, - currentVersion version.Version, cmixGrp, e2eGrp *cyclic.Group) (Session, error) { + currentVersion version.Version, + cmixGrp, e2eGrp *cyclic.Group) (Session, error) { s, err := initStore(baseDir, password) if err != nil { diff --git a/xxdk/cmix.go b/xxdk/cmix.go index 6b5444bef2b5d2fad83e5bbe7cdad4b835dbb3d0..8be2429682a01a7f4a3dd07fd6a69049b9a7c23e 100644 --- a/xxdk/cmix.go +++ b/xxdk/cmix.go @@ -8,7 +8,6 @@ package xxdk import ( - "encoding/json" "math" "time" @@ -167,10 +166,12 @@ func OpenCmix(storageDir string, password []byte, // NewProtoClient_Unsafe initializes a client object from a JSON containing // predefined cryptographic which defines a user. This is designed for some // specific deployment procedures and is generally unsafe. -func NewProtoClient_Unsafe(ndfJSON, storageDir string, password, - protoClientJSON []byte) error { +func NewProtoClient_Unsafe(ndfJSON, storageDir string, password []byte, + protoUser *user.Proto) error { jww.INFO.Printf("NewProtoClient_Unsafe") + usr := user.NewUserFromProto(protoUser) + def, err := ParseNDF(ndfJSON) if err != nil { return err @@ -178,14 +179,6 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password, cmixGrp, e2eGrp := DecodeGroups(def) - protoUser := &user.Proto{} - err = json.Unmarshal(protoClientJSON, protoUser) - if err != nil { - return err - } - - usr := user.NewUserFromProto(protoUser) - storageSess, err := CheckVersionAndSetupStorage(def, storageDir, password, usr, cmixGrp, e2eGrp, protoUser.RegCode) if err != nil { @@ -263,100 +256,6 @@ func LoadCmix(storageDir string, password []byte, parameters Params) (*Cmix, err return c, nil } -// LoginWithNewBaseNDF_UNSAFE initializes a client object from existing storage -// 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, params Params) (*Cmix, error) { - jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()") - - def, err := ParseNDF(newBaseNdf) - if err != nil { - return nil, err - } - - c, err := OpenCmix(storageDir, password, params) - if err != nil { - return nil, err - } - - //store the updated base NDF - c.storage.SetNDF(def) - - 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. Cmix will not be " + - "able to register or track network.") - } - - err = c.network.Connect(def) - if err != nil { - return nil, err - } - - err = c.registerFollower() - if err != nil { - return nil, err - } - - 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, - params Params) (*Cmix, error) { - jww.INFO.Printf("LoginWithProtoClient()") - - def, err := ParseNDF(newBaseNdf) - if err != nil { - return nil, err - } - - err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, - protoClientJSON) - if err != nil { - return nil, err - } - - c, err := OpenCmix(storageDir, password, params) - if err != nil { - return nil, err - } - - c.storage.SetNDF(def) - - err = c.initPermissioning(def) - if err != nil { - return nil, err - } - - err = c.network.Connect(def) - 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? - if err != nil { - return nil, err - } - err = c.registerFollower() - if err != nil { - return nil, err - } - - return c, nil -} - func (c *Cmix) initComms() error { var err error diff --git a/xxdk/e2e.go b/xxdk/e2e.go index 6693ebdb08edee82075f4e4bd2b03bdb075da4ff..055f18cfe01ea95a49a548d9530a377f52a10782 100644 --- a/xxdk/e2e.go +++ b/xxdk/e2e.go @@ -49,9 +49,9 @@ func LoginEphemeral(client *Cmix, callbacks auth.Callbacks, } // LoginLegacy creates a new E2e backed by the xxdk.Cmix persistent versioned.KV -// Uses the pre-generated transmission ID used by xxdk.Cmix -// This function is designed to maintain backwards compatibility with previous xx messenger designs -// and should not be used for other purposes +// Uses the pre-generated transmission ID used by xxdk.Cmix. +// This function is designed to maintain backwards compatibility with previous +// xx messenger designs and should not be used for other purposes. func LoginLegacy(client *Cmix, callbacks auth.Callbacks) (m *E2e, err error) { m = &E2e{ Cmix: client, @@ -82,7 +82,114 @@ func LoginLegacy(client *Cmix, callbacks auth.Callbacks) (m *E2e, err error) { return m, err } -// login creates a new e2eApi.E2e backed by the given versioned.KV +// LoginWithNewBaseNDF_UNSAFE initializes a client object from existing storage +// 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, params Params) (*E2e, error) { + jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()") + + def, err := ParseNDF(newBaseNdf) + if err != nil { + return nil, err + } + + c, err := OpenCmix(storageDir, password, params) + if err != nil { + return nil, err + } + + //store the updated base NDF + c.storage.SetNDF(def) + + 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. Cmix will not be " + + "able to register or track network.") + } + + err = c.network.Connect(def) + if err != nil { + return nil, err + } + + err = c.registerFollower() + if err != nil { + return nil, err + } + + return LoginLegacy(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, + params Params) (*E2e, error) { + jww.INFO.Printf("LoginWithProtoClient()") + + def, err := ParseNDF(newBaseNdf) + if err != nil { + return nil, err + } + + protoUser := &user.Proto{} + err = json.Unmarshal(protoClientJSON, protoUser) + if err != nil { + return nil, err + } + + err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, + protoUser) + if err != nil { + return nil, err + } + + c, err := OpenCmix(storageDir, password, params) + if err != nil { + return nil, err + } + + c.storage.SetNDF(def) + + err = c.initPermissioning(def) + if err != nil { + return nil, err + } + + err = c.network.Connect(def) + if err != nil { + return nil, err + } + + c.network.AddIdentity(c.GetUser().ReceptionID, time.Time{}, true) + + // 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? + if err != nil { + return nil, err + } + err = c.registerFollower() + if err != nil { + return nil, err + } + + return Login(c, nil, ReceptionIdentity{ + ID: protoUser.ReceptionID, + RSAPrivatePem: protoUser.ReceptionRSA, + Salt: protoUser.ReceptionSalt, + DHKeyPrivate: protoUser.E2eDhPrivateKey, + }) +} + +// login creates a new xxdk.E2e backed by the given versioned.KV func login(client *Cmix, callbacks auth.Callbacks, identity ReceptionIdentity, kv *versioned.KV) (m *E2e, err error) { @@ -146,7 +253,6 @@ func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) { e2eHandler, err = e2e.Load(kv, client.GetCmix(), usr.ReceptionID, e2eGrp, client.GetRng(), client.GetEventReporter()) - //if no new e2e handler exists, initialize an e2e user if err != nil { jww.WARN.Printf("Failed to load e2e instance for %s, "+ "creating a new one", usr.ReceptionID) @@ -224,19 +330,21 @@ func (m *E2e) ConstructProtoUserFile() ([]byte, error) { } Usr := user.Proto{ - TransmissionID: m.GetUser().TransmissionID, - TransmissionSalt: m.GetUser().TransmissionSalt, - TransmissionRSA: m.GetUser().TransmissionRSA, - ReceptionID: m.GetUser().ReceptionID, - ReceptionSalt: m.GetUser().ReceptionSalt, - ReceptionRSA: m.GetUser().ReceptionRSA, - Precanned: m.GetUser().Precanned, - RegistrationTimestamp: m.GetUser().RegistrationTimestamp, - RegCode: regCode, - TransmissionRegValidationSig: m.GetStorage().GetTransmissionRegistrationValidationSignature(), - ReceptionRegValidationSig: m.GetStorage().GetReceptionRegistrationValidationSignature(), - E2eDhPrivateKey: m.e2e.GetHistoricalDHPrivkey(), - E2eDhPublicKey: m.e2e.GetHistoricalDHPubkey(), + TransmissionID: m.GetUser().TransmissionID, + TransmissionSalt: m.GetUser().TransmissionSalt, + TransmissionRSA: m.GetUser().TransmissionRSA, + ReceptionID: m.GetUser().ReceptionID, + ReceptionSalt: m.GetUser().ReceptionSalt, + ReceptionRSA: m.GetUser().ReceptionRSA, + Precanned: m.GetUser().Precanned, + RegistrationTimestamp: m.GetUser().RegistrationTimestamp, + RegCode: regCode, + TransmissionRegValidationSig: m.GetStorage(). + GetTransmissionRegistrationValidationSignature(), + ReceptionRegValidationSig: m.GetStorage(). + GetReceptionRegistrationValidationSignature(), + E2eDhPrivateKey: m.e2e.GetHistoricalDHPrivkey(), + E2eDhPublicKey: m.e2e.GetHistoricalDHPubkey(), } jsonBytes, err := json.Marshal(Usr) diff --git a/xxdk/identity.go b/xxdk/identity.go index da708d6c2a33d28b3df580642cc79aa16a5c2bee..923bf3d5c6704284360d319c2d7e2483df77acd2 100644 --- a/xxdk/identity.go +++ b/xxdk/identity.go @@ -23,8 +23,10 @@ type ReceptionIdentity struct { DHKeyPrivate *cyclic.Int } -// MakeReceptionIdentity generates a new cryptographic identity for receiving messages -func MakeReceptionIdentity(rng csprng.Source, grp *cyclic.Group) (ReceptionIdentity, error) { +// MakeReceptionIdentity generates a new cryptographic identity +// for receiving messages. +func MakeReceptionIdentity(rng csprng.Source, + grp *cyclic.Group) (ReceptionIdentity, error) { //make RSA Key rsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)