diff --git a/api/client.go b/api/client.go index 038c5946962a35f48a1b379bdd29b06c77f3303f..bfcd8b7d948c2bbbb3e6983951a02b778ec127ab 100644 --- a/api/client.go +++ b/api/client.go @@ -47,10 +47,12 @@ type Client struct { session user.Session sessionV2 *storage.Session receptionManager *io.ReceptionManager + switchboard *switchboard.Switchboard ndf *ndf.NetworkDefinition topology *connect.Circuit opStatus OperationProgressCallback rekeyChan chan struct{} + quitChan chan struct{} registrationVersion string // Pointer to a send function, which allows testing to override the default @@ -145,7 +147,10 @@ func newClient(s globals.Storage, locA, locB string, ndfJSON *ndf.NetworkDefinit return } + cl.switchboard = switchboard.NewSwitchboard() + cl.rekeyChan = make(chan struct{}, 1) + cl.quitChan = make(chan struct{}) // Blocking is intentional return cl, nil } @@ -206,11 +211,11 @@ func (cl *Client) Login(password string) (*id.ID, error) { "completed registration ") } - newRm, err := io.NewReceptionManager(cl.rekeyChan, + newRm, err := io.NewReceptionManager(cl.rekeyChan, cl.quitChan, userData.ThisUser.User, rsa.CreatePrivateKeyPem(userData.RSAPrivateKey), rsa.CreatePublicKeyPem(userData.RSAPublicKey), - userData.Salt) + userData.Salt, cl.switchboard) if err != nil { return nil, errors.Wrap(err, "Failed to create new reception manager") } @@ -232,11 +237,13 @@ func (cl *Client) Logout(timeoutDuration time.Duration) error { return err } - // Here using a select statement and the fact that making cl.sess.GetQuitChan is blocking, we can detect when - // killing the reception manager is taking too long and we use the time out to stop the attempt and return an error. + // Here using a select statement and the fact that making + // cl.ReceptionQuitChan is blocking, we can detect when + // killing the reception manager is taking too long and we use + // the time out to stop the attempt and return an error. timer := time.NewTimer(timeoutDuration) select { - case cl.session.GetQuitChan() <- struct{}{}: + case cl.quitChan <- struct{}{}: cl.receptionManager.Comms.DisconnectAll() case <-timer.C: return errors.Errorf("Message receiver shut down timed out after %s ms", timeoutDuration) @@ -443,7 +450,7 @@ func (cl *Client) SetRateLimiting(limit uint32) { } func (cl *Client) Listen(user *id.ID, messageType int32, newListener switchboard.Listener) string { - listenerId := cl.session.GetSwitchboard(). + listenerId := cl.GetSwitchboard(). Register(user, messageType, newListener) globals.Log.INFO.Printf("Listening now: user %v, message type %v, id %v", user, messageType, listenerId) @@ -451,11 +458,11 @@ func (cl *Client) Listen(user *id.ID, messageType int32, newListener switchboard } func (cl *Client) StopListening(listenerHandle string) { - cl.session.GetSwitchboard().Unregister(listenerHandle) + cl.GetSwitchboard().Unregister(listenerHandle) } func (cl *Client) GetSwitchboard() *switchboard.Switchboard { - return cl.session.GetSwitchboard() + return cl.switchboard } func (cl *Client) GetUsername() string { @@ -560,13 +567,16 @@ type NickLookupCallback interface { func (cl *Client) DeleteUser(u *id.ID) (string, error) { //delete from session - v, err1 := cl.session.DeleteContact(u) + // FIXME: I believe this used to return the user name of the deleted + // user and the way we are calling this won't work since it is based on + // user name and not User ID. + err1 := cl.sessionV2.DeleteContact(u.String()) //delete from keystore err2 := cl.session.GetKeyStore().DeleteContactKeys(u) if err1 == nil && err2 == nil { - return v, nil + return "", nil } if err1 != nil && err2 == nil { @@ -574,7 +584,7 @@ func (cl *Client) DeleteUser(u *id.ID) (string, error) { } if err1 == nil && err2 != nil { - return v, errors.Wrap(err2, "Failed to remove from key store") + return "", errors.Wrap(err2, "Failed to remove from key store") } if err1 != nil && err2 != nil { @@ -582,7 +592,8 @@ func (cl *Client) DeleteUser(u *id.ID) (string, error) { "Failed to remove from key store and value store") } - return v, nil + // FIXME: Return user name deleted + return "", nil } diff --git a/api/client_test.go b/api/client_test.go index 5c5d56311e698a524eb767e1c8863096c83e088d..77e2b0979fe74d35c3376d3f6acb0d4f4544b798 100644 --- a/api/client_test.go +++ b/api/client_test.go @@ -615,7 +615,9 @@ func TestClient_LogoutHappyPath(t *testing.T) { tc, _ := NewClient(&d, ".ekv-logouthappypath/a", "", def) uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, uid, nil, nil, nil) + tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, + tc.quitChan, + uid, nil, nil, nil, tc.switchboard) err := tc.InitNetwork() if err != nil { @@ -691,7 +693,8 @@ func TestClient_LogoutTimeout(t *testing.T) { tc, _ := NewClient(&d, ".ekv-logouttimeout/a", "", def) uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, uid, nil, nil, nil) + tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, + tc.quitChan, uid, nil, nil, nil, tc.switchboard) err := tc.InitNetwork() if err != nil { @@ -758,7 +761,8 @@ func TestClient_LogoutAndLoginAgain(t *testing.T) { } uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, uid, nil, nil, nil) + tc.receptionManager, _ = io.NewReceptionManager(tc.rekeyChan, + tc.quitChan, uid, nil, nil, nil, tc.switchboard) err = tc.InitNetwork() if err != nil { diff --git a/api/connect.go b/api/connect.go index 212df62a74048e8f40279a75b64653f37a7a7207..992bba9893a71ed2a1ec130b818df1413464ef9c 100644 --- a/api/connect.go +++ b/api/connect.go @@ -25,10 +25,14 @@ var ErrNoPermissioning = errors.New("No Permissioning In NDF") func (cl *Client) InitNetwork() error { var err error if cl.receptionManager == nil { - // Start reception manager with a dummy user, so we can connect to things - cl.receptionManager, err = io.NewReceptionManager(cl.rekeyChan, &id.DummyUser, nil, nil, nil) + // Start reception manager with a dummy user, + // so we can connect to things + cl.receptionManager, err = io.NewReceptionManager(cl.rekeyChan, + cl.quitChan, &id.DummyUser, nil, nil, nil, + cl.switchboard) if err != nil { - return errors.Wrap(err, "Failed to create reception manager") + return errors.Wrap(err, + "Failed to create reception manager") } } diff --git a/api/private.go b/api/private.go index 1f724f0e9be62f96e928e4baaf4a490a914622f3..31af2569bf0b6ff4fb8b68118c03a126bfb0eca9 100644 --- a/api/private.go +++ b/api/private.go @@ -330,13 +330,20 @@ func (cl *Client) GenerateKeys(rsaPrivKey *rsa.PrivateKey, E2EGrp: e2eGrp, Salt: salt, } - cl.sessionV2.CommitUserData(userData) + err = cl.sessionV2.CommitUserData(userData) + if err != nil { + return err + } + err = cl.sessionV2.SetRegState(user.KeyGenComplete) + if err != nil { + return err + } - newRm, err := io.NewReceptionManager(cl.rekeyChan, + newRm, err := io.NewReceptionManager(cl.rekeyChan, cl.quitChan, usr.User, rsa.CreatePrivateKeyPem(privKey), rsa.CreatePublicKeyPem(pubKey), - salt) + salt, cl.switchboard) if err != nil { return errors.Wrap(err, "Couldn't create reception manager") } diff --git a/bindings/client.go b/bindings/client.go index ae5494dc6dd5878716f4369b3e4bfa914d1aea43..8a20c261a2c9e0487df9973542cbdb58da04fd78 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -273,7 +273,11 @@ func (cl *Client) ChangeUsername(un string) error { // 2 - UDBComplete func (cl *Client) GetRegState() int64 { globals.Log.INFO.Printf("Binding call: GetRegState()") - return int64(cl.client.GetSession().GetRegState()) + regState, err := cl.client.GetSessionV2().GetRegState() + if err != nil { + globals.Log.ERROR.Printf("GetRegState(): %+v", err) + } + return int64(regState) } // Registers user with all nodes it has not been registered with. diff --git a/bots/bots.go b/bots/bots.go index baee89c86d454579bebcd440b6acaba181a65f9a..8c49607787b9644cb884a35c98039d27e0a2046a 100644 --- a/bots/bots.go +++ b/bots/bots.go @@ -51,7 +51,8 @@ func (l *nickReqListener) Hear(msg switchboard.Item, isHeardElsewhere bool, i .. var nicknameRequestListener nickReqListener // InitBots is called internally by the Login API -func InitBots(s user.Session, s2 storage.Session, m io.Communications, top *connect.Circuit, host *connect.Host) { +func InitBots(s user.Session, s2 storage.Session, m io.Communications, + top *connect.Circuit, host *connect.Host) { userData, err := s2.GetUserData() if err != nil { @@ -78,7 +79,7 @@ func InitBots(s user.Session, s2 storage.Session, m io.Communications, top *conn comms = m transmissionHost = host - l := session.GetSwitchboard() + l := m.GetSwitchboard() l.Register(&id.UDB, int32(cmixproto.Type_UDB_PUSH_KEY_RESPONSE), &pushKeyResponseListener) diff --git a/bots/bots_test.go b/bots/bots_test.go index 042b65b71d29bb4b50c1806f6c951d879bbe23c3..7318d309c6f8c555594cf0ecb4bbe296521a9373 100644 --- a/bots/bots_test.go +++ b/bots/bots_test.go @@ -21,6 +21,7 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "os" @@ -32,7 +33,8 @@ import ( var ListenCh chan *format.Message type dummyMessaging struct { - listener chan *format.Message + listener chan *format.Message + switchboard *switchboard.Switchboard } // SendMessage to the server @@ -60,6 +62,11 @@ func (d *dummyMessaging) MessageReceiver(session user.Session, delay time.Duration, transmissionHost *connect.Host, callback func(error)) { } +// MessageReceiver thread to get new messages +func (d *dummyMessaging) GetSwitchboard() *switchboard.Switchboard { + return d.switchboard +} + var pubKeyBits string var keyFingerprint string var pubKey []byte @@ -85,7 +92,8 @@ func TestMain(m *testing.M) { E2EGrp: e2eGrp, }) fakeComm := &dummyMessaging{ - listener: ListenCh, + listener: ListenCh, + switchboard: switchboard.NewSwitchboard(), } h := connect.Host{} nodeID := new(id.ID) @@ -177,7 +185,7 @@ func TestNicknameFunctions(t *testing.T) { InferredType: parse.Unencrypted, Receiver: curUser, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) // Test nickname lookup @@ -191,7 +199,7 @@ func TestNicknameFunctions(t *testing.T) { InferredType: parse.Unencrypted, Receiver: curUser, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) // AFter sending the message, perform the lookup to read it nick, err := LookupNick(curUser) if err != nil { @@ -228,6 +236,10 @@ func (e *errorMessaging) MessageReceiver(session user.Session, delay time.Duration, transmissionHost *connect.Host, callback func(error)) { } +func (e *errorMessaging) GetSwitchboard() *switchboard.Switchboard { + return nil +} + // Test LookupNick returns error on sending problem func TestLookupNick_error(t *testing.T) { userData, _ := sessionV2.GetUserData() diff --git a/io/interface.go b/io/interface.go index 57e9cc9897c084a3413e11cd88875377632c4c4d..b2e6a6c8c2e4c3c5c2d4e9879ef075a664bd569a 100644 --- a/io/interface.go +++ b/io/interface.go @@ -9,6 +9,7 @@ package io import ( "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" + "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "time" @@ -30,4 +31,8 @@ type Communications interface { // MessageReceiver thread to get new messages MessageReceiver(session user.Session, delay time.Duration, receptionHost *connect.Host, callback func(error)) + + // GetSwitchboard returns the active switchboard for local message + // listening. + GetSwitchboard() *switchboard.Switchboard } diff --git a/io/receive.go b/io/receive.go index 102ca0954ed00514c5cfe1ae442a2982644aa2d8..fcfa34d229f8573cf97061927670fce7e58b3ade 100644 --- a/io/receive.go +++ b/io/receive.go @@ -48,7 +48,7 @@ func (rm *ReceptionManager) MessageReceiver(session user.Session, delay time.Dur pollingMessage := pb.ClientRequest{ UserID: userData.ThisUser.User.Bytes(), } - quit := session.GetQuitChan() + quit := rm.quitChan NumChecks := 0 NumMessages := 0 @@ -95,7 +95,7 @@ func (rm *ReceptionManager) MessageReceiver(session user.Session, delay time.Dur } NumMessages += len(encryptedMessages) case <-rm.rekeyChan: - encryptedMessages = session.PopGarbledMessages() + encryptedMessages = rm.PopGarbledMessages() } if len(encryptedMessages) != 0 { @@ -103,7 +103,7 @@ func (rm *ReceptionManager) MessageReceiver(session user.Session, delay time.Dur decryptedMessages, senders, garbledMessages := rm.decryptMessages(session, encryptedMessages) if len(garbledMessages) != 0 { - session.AppendGarbledMessage(garbledMessages...) + rm.AppendGarbledMessage(garbledMessages...) } if decryptedMessages != nil { @@ -116,7 +116,9 @@ func (rm *ReceptionManager) MessageReceiver(session user.Session, delay time.Dur } if assembledMessage != nil { // we got a fully assembled message. let's broadcast it - broadcastMessageReception(assembledMessage, session.GetSwitchboard()) + broadcastMessageReception( + assembledMessage, + rm.switchboard) } } } @@ -124,7 +126,8 @@ func (rm *ReceptionManager) MessageReceiver(session user.Session, delay time.Dur } } -func handleE2EReceiving(session user.Session, +// FIXME: put all key and external object into context var or other solution. +func handleE2EReceiving(session user.Session, switchb *switchboard.Switchboard, message *format.Message) (*id.ID, bool, error) { userData, err := SessionV2.GetUserData() @@ -179,7 +182,7 @@ func handleE2EReceiving(session user.Session, InferredType: parse.Rekey, Receiver: userData.ThisUser.User, } - go session.GetSwitchboard().Speak(rekeyMsg) + go switchb.Speak(rekeyMsg) } return sender, rekey, err } @@ -316,7 +319,8 @@ func (rm *ReceptionManager) decryptMessages(session user.Session, keyFP := msg.AssociatedData.GetKeyFP() sender, err = makeUserID(keyFP[:]) } else { - sender, rekey, err = handleE2EReceiving(session, msg) + sender, rekey, err = handleE2EReceiving(session, + rm.switchboard, msg) if err == errE2ENotFound { garbled = true diff --git a/io/receptionManager.go b/io/receptionManager.go index 4386a28cc10613d6d4050175b5a1dd1b07ff4845..0f28b8fe1d0e5e25e8c6b4479ae75bad185578ac 100644 --- a/io/receptionManager.go +++ b/io/receptionManager.go @@ -13,6 +13,8 @@ import ( "github.com/pkg/errors" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/comms/client" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/primitives/id" "sync" "time" @@ -46,14 +48,24 @@ type ReceptionManager struct { sendLock sync.Mutex + // Buffer of messages that cannot be decrypted + garbledMessages []*format.Message + garbleLck sync.Mutex + + switchboard *switchboard.Switchboard + rekeyChan chan struct{} + quitChan chan struct{} } // Build a new reception manager object using inputted key fields -func NewReceptionManager(rekeyChan chan struct{}, uid *id.ID, privKey, pubKey, salt []byte) (*ReceptionManager, error) { +func NewReceptionManager(rekeyChan, quitChan chan struct{}, uid *id.ID, + privKey, pubKey, salt []byte, switchb *switchboard.Switchboard) ( + *ReceptionManager, error) { comms, err := client.NewClientComms(uid, pubKey, privKey, salt) if err != nil { - return nil, errors.Wrap(err, "Failed to get client comms using constructor: %+v") + return nil, errors.Wrap(err, + "Failed to get client comms using constructor: %+v") } cm := &ReceptionManager{ @@ -64,6 +76,9 @@ func NewReceptionManager(rekeyChan chan struct{}, uid *id.ID, privKey, pubKey, s receivedMessages: make(map[string]struct{}), Comms: comms, rekeyChan: rekeyChan, + quitChan: quitChan, + garbledMessages: make([]*format.Message, 0), + switchboard: switchb, Tls: true, } @@ -92,3 +107,26 @@ func (rm *ReceptionManager) DisableBlockingTransmission() { // flag passed into func (rm *ReceptionManager) SetRateLimit(delay time.Duration) { // pass into received rm.transmitDelay = delay } + +// AppendGarbledMessage appends a message or messages to the garbled message +// buffer. +func (rm *ReceptionManager) AppendGarbledMessage(messages ...*format.Message) { + rm.garbleLck.Lock() + rm.garbledMessages = append(rm.garbledMessages, messages...) + rm.garbleLck.Unlock() +} + +// PopGarbledMessages returns the content of the garbled message buffer and +// deletes its contents. +func (rm *ReceptionManager) PopGarbledMessages() []*format.Message { + rm.garbleLck.Lock() + defer rm.garbleLck.Unlock() + tempBuffer := rm.garbledMessages + rm.garbledMessages = []*format.Message{} + return tempBuffer +} + +// GetSwitchboard returns the active switchboard for this reception manager +func (rm *ReceptionManager) GetSwitchboard() *switchboard.Switchboard { + return rm.switchboard +} diff --git a/io/receptionManager_test.go b/io/receptionManager_test.go new file mode 100644 index 0000000000000000000000000000000000000000..28f444a4516cf8f891c4894fb7ce8d5d707dfb9c --- /dev/null +++ b/io/receptionManager_test.go @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2019 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package io + +import ( + "gitlab.com/elixxir/primitives/format" + "reflect" + "testing" +) + +// Tests that AppendGarbledMessage properly appends an array of messages by +// testing that the final buffer matches the values appended. +func TestSessionObj_AppendGarbledMessage(t *testing.T) { + session := &ReceptionManager{ + garbledMessages: make([]*format.Message, 0), + } + msgs := GenerateTestMessages(10) + + session.AppendGarbledMessage(msgs...) + + if !reflect.DeepEqual(msgs, session.garbledMessages) { + t.Errorf("AppendGarbledMessage() did not append the correct values"+ + "\n\texpected: %v\n\trecieved: %v", + msgs, session.garbledMessages) + } +} + +// Tests that PopGarbledMessages returns the correct data and that the buffer +// is cleared. +func TestSessionObj_PopGarbledMessages(t *testing.T) { + session := &ReceptionManager{ + garbledMessages: make([]*format.Message, 0), + } + msgs := GenerateTestMessages(10) + + session.garbledMessages = msgs + + poppedMsgs := session.PopGarbledMessages() + + if !reflect.DeepEqual(msgs, poppedMsgs) { + t.Errorf("PopGarbledMessages() did not pop the correct values"+ + "\n\texpected: %v\n\trecieved: %v", + msgs, poppedMsgs) + } + + if !reflect.DeepEqual([]*format.Message{}, session.garbledMessages) { + t.Errorf("PopGarbledMessages() did not remove the values from the buffer"+ + "\n\texpected: %#v\n\trecieved: %#v", + []*format.Message{}, session.garbledMessages) + } + +} + +func GenerateTestMessages(size int) []*format.Message { + msgs := make([]*format.Message, size) + + for i := 0; i < size; i++ { + msgs[i] = format.NewMessage() + payloadBytes := make([]byte, format.PayloadLen) + payloadBytes[0] = byte(i) + msgs[i].SetPayloadA(payloadBytes) + msgs[i].SetPayloadB(payloadBytes) + } + + return msgs +} diff --git a/io/send.go b/io/send.go index 53fadf2f9e1252d16370064fa5e0ab632bdef867..2a43bd387a091de5b0630cef7cdb2ef63ac4a278 100644 --- a/io/send.go +++ b/io/send.go @@ -22,6 +22,7 @@ import ( "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "time" @@ -134,7 +135,7 @@ func (rm *ReceptionManager) send(session user.Session, topology *connect.Circuit // Check message type if cryptoType == parse.E2E { - handleE2ESending(session, message, rekey) + handleE2ESending(session, rm.switchboard, message, rekey) } else { padded, err := e2e.Pad(message.Contents.GetRightAligned(), format.ContentsLen) if err != nil { @@ -200,7 +201,8 @@ func (rm *ReceptionManager) send(session user.Session, topology *connect.Circuit return err } -func handleE2ESending(session user.Session, +// FIXME: hand off all keys via a context variable or other solution. +func handleE2ESending(session user.Session, switchb *switchboard.Switchboard, message *format.Message, rekey bool) { recipientID, err := message.GetRecipient() @@ -268,7 +270,7 @@ func handleE2ESending(session user.Session, InferredType: parse.None, Receiver: recipientID, } - go session.GetSwitchboard().Speak(rekeyMsg) + go switchb.Speak(rekeyMsg) } globals.Log.DEBUG.Printf("E2E encrypting message") diff --git a/rekey/rekey.go b/rekey/rekey.go index c20b1a7f41cb060457ce5db93fce2fcb20c1b39b..fe5997a6db20a46ff737128ed5d542e606725e94 100644 --- a/rekey/rekey.go +++ b/rekey/rekey.go @@ -104,7 +104,7 @@ func InitRekey(s user.Session, s2 storage.Session, m io.Communications, transmissionHost = host rekeyChan = rekeyChan2 - l := session.GetSwitchboard() + l := m.GetSwitchboard() userData, err := s2.GetUserData() if err != nil { diff --git a/rekey/rekey_test.go b/rekey/rekey_test.go index dc007afaa088a33bd5706f86d4a3ba182ff1e413..83c6d1c49f03ceea5f3dbdcaecdc085c364a9dcc 100644 --- a/rekey/rekey_test.go +++ b/rekey/rekey_test.go @@ -18,6 +18,7 @@ import ( "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/signature/rsa" + "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "os" @@ -28,7 +29,8 @@ import ( var ListenCh chan []byte type dummyMessaging struct { - listener chan []byte + listener chan []byte + switchboard *switchboard.Switchboard } // SendMessage to the server @@ -56,6 +58,11 @@ func (d *dummyMessaging) MessageReceiver(session user.Session, delay time.Duration, transmissionHost *connect.Host, callback func(error)) { } +// GetSwitchboard to access switchboard +func (d *dummyMessaging) GetSwitchboard() *switchboard.Switchboard { + return d.switchboard +} + func TestMain(m *testing.M) { grp, e2eGrp := getGroups() @@ -83,7 +90,8 @@ func TestMain(m *testing.M) { session := user.NewSession(&globals.RamStorage{}, "password") ListenCh = make(chan []byte, 100) fakeComm := &dummyMessaging{ - listener: ListenCh, + listener: ListenCh, + switchboard: switchboard.NewSwitchboard(), } sessionV2 := storage.InitTestingSession(m) @@ -167,7 +175,7 @@ func TestRekeyTrigger(t *testing.T) { InferredType: parse.None, Receiver: partnerID, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) // Check no error occurred in rekeytrigger processing if rekeyTriggerList.err != nil { @@ -200,7 +208,7 @@ func TestRekeyTrigger(t *testing.T) { InferredType: parse.None, Receiver: partnerID, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) time.Sleep(time.Second) // Check that error occurred in rekeytrigger for repeated message if rekeyTriggerList.err == nil { @@ -226,7 +234,7 @@ func TestRekeyConfirm(t *testing.T) { InferredType: parse.None, Receiver: userData.ThisUser.User, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) time.Sleep(time.Second) // Check that error occurred in RekeyConfirm when hash is wrong if rekeyConfirmList.err == nil { @@ -245,7 +253,7 @@ func TestRekeyConfirm(t *testing.T) { InferredType: parse.None, Receiver: userData.ThisUser.User, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) time.Sleep(time.Second) // Check no error occurred in rekeyConfirm processing if rekeyConfirmList.err != nil { @@ -271,7 +279,7 @@ func TestRekeyConfirm(t *testing.T) { InferredType: parse.None, Receiver: userData.ThisUser.User, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) time.Sleep(time.Second) // Check that error occurred in RekeyConfirm for repeated message if rekeyConfirmList.err == nil { @@ -300,7 +308,7 @@ func TestRekey(t *testing.T) { InferredType: parse.Rekey, Receiver: userData.ThisUser.User, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) // Check no error occurred in rekey processing if rekeyList.err != nil { @@ -361,7 +369,7 @@ func TestRekey_Errors(t *testing.T) { InferredType: parse.None, Receiver: partnerID, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) // Check error occurred on RekeyTrigger if rekeyTriggerList.err == nil { @@ -378,7 +386,7 @@ func TestRekey_Errors(t *testing.T) { InferredType: parse.Rekey, Receiver: userData.ThisUser.User, } - session.GetSwitchboard().Speak(msg) + comms.GetSwitchboard().Speak(msg) time.Sleep(time.Second) // Check error occurred on Rekey if rekeyList.err == nil { diff --git a/storage/contact.go b/storage/contact.go index e494c250abb37057807895c9543b0dee0d183d8f..91a54f07d6969d19f038ccee03ce3be0ab34223e 100644 --- a/storage/contact.go +++ b/storage/contact.go @@ -56,3 +56,9 @@ func (s *Session) SetContact(name string, record *Contact) error { } return s.Set(key, &obj) } + +// DeleteContact removes the contact from disk +func (s *Session) DeleteContact(name string) error { + key := MakeKeyWithPrefix("Contact", name) + return s.Delete(key) +} diff --git a/storage/session.go b/storage/session.go index 0025f998e4228a81f8640c4a1d330cfddf66ed01..0c559d76d343a0041f65396e266cb05d37735296 100644 --- a/storage/session.go +++ b/storage/session.go @@ -51,6 +51,11 @@ func (s *Session) Set(key string, object *VersionedObject) error { return s.kv.Set(key, object) } +// Delete a value in the session +func (s *Session) Delete(key string) error { + return s.kv.Delete(key) +} + // Obtain the LastMessageID from the Session func (s *Session) GetLastMessageId() (string, error) { v, err := s.Get("LastMessageID") diff --git a/user/session.go b/user/session.go index 18cc13aff3485c504c4ae376d2c36b9c81951bd3..6e598c99642ef33413d12ca6821e561cce4ce511 100644 --- a/user/session.go +++ b/user/session.go @@ -18,12 +18,9 @@ import ( "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/keyStore" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/elixxir/primitives/switchboard" "gitlab.com/xx_network/primitives/id" "io" "sync" - "sync/atomic" "time" ) @@ -34,28 +31,14 @@ var ErrQuery = errors.New("element not in map") type Session interface { StoreSession() error Immolate() error - UpsertMap(key string, element interface{}) error - QueryMap(key string) (interface{}, error) - DeleteMap(key string) error GetKeyStore() *keyStore.KeyStore GetRekeyManager() *keyStore.RekeyManager - GetSwitchboard() *switchboard.Switchboard - GetQuitChan() chan struct{} LockStorage() UnlockStorage() GetSessionData() ([]byte, error) - GetRegistrationValidationSignature() []byte - AppendGarbledMessage(messages ...*format.Message) - PopGarbledMessages() []*format.Message - SetRegState(rs uint32) error - GetRegState() uint32 StorageIsEmpty() bool - GetContactByValue(string) (*id.ID, []byte) - StoreContactByValue(string, *id.ID, []byte) - DeleteContact(*id.ID) (string, error) GetSessionLocation() uint8 LoadEncryptedSession(store globals.Storage) ([]byte, error) - RegisterPermissioningSignature(sig []byte) error SetE2EGrp(g *cyclic.Group) SetUser(u *id.ID) } @@ -68,19 +51,13 @@ type NodeKeys struct { // Creates a new Session interface for registration func NewSession(store globals.Storage, password string) Session { - regState := uint32(KeyGenComplete) // With an underlying Session data structure return Session(&SessionObj{ - InterfaceMap: make(map[string]interface{}), - KeyMaps: keyStore.NewStore(), - RekeyManager: keyStore.NewRekeyManager(), - store: store, - listeners: switchboard.NewSwitchboard(), - quitReceptionRunner: make(chan struct{}), - password: password, - RegState: ®State, - storageLocation: globals.LocationA, - ContactsByValue: make(map[string]SearchedUserRecord), + KeyMaps: keyStore.NewStore(), + RekeyManager: keyStore.NewRekeyManager(), + store: store, + password: password, + storageLocation: globals.LocationA, }) } @@ -128,11 +105,6 @@ func LoadSession(store globals.Storage, password string) (Session, error) { session.KeyMaps.ReconstructKeys(session.E2EGrp, session.CurrentUser) - // Create switchboard - session.listeners = switchboard.NewSwitchboard() - // Create quit channel for reception runner - session.quitReceptionRunner = make(chan struct{}) - // Set storage pointer session.store = store session.password = password @@ -204,12 +176,6 @@ func processSessionWrapper(sessionGob []byte, password string) (*SessionStorageW // When adding to this structure, ALWAYS ALWAYS // consider if you want the data to be in the session file type SessionObj struct { - // Last received message ID. Check messages after this on the gateway. - LastMessageID string - - //Interface map for random data storage - InterfaceMap map[string]interface{} - // E2E KeyStore KeyMaps *keyStore.KeyStore @@ -224,28 +190,12 @@ type SessionObj struct { // Local pointer to storage of this session store globals.Storage - // Switchboard - listeners *switchboard.Switchboard - - // Quit channel for message reception runner - quitReceptionRunner chan struct{} - lock sync.Mutex // The password used to encrypt this session when saved password string - //The validation signature provided by permissioning - RegValidationSignature []byte - - // Buffer of messages that cannot be decrypted - garbledMessages []*format.Message - - RegState *uint32 - storageLocation uint8 - - ContactsByValue map[string]SearchedUserRecord } //WriteToSession: Writes to the location where session is being stored the arbitrary replacement string @@ -294,52 +244,6 @@ func (s *SessionObj) StorageIsEmpty() bool { return s.store.IsEmpty() } -func (s *SessionObj) SetLastMessageID(id string) { - s.LockStorage() - s.LastMessageID = id - s.UnlockStorage() -} - -//RegisterPermissioningSignature sets sessions registration signature and -// sets the regState to reflect that registering with permissioning is complete -// Returns an error if unable to set the regState -func (s *SessionObj) RegisterPermissioningSignature(sig []byte) error { - s.LockStorage() - defer s.UnlockStorage() - - // fixme remove the below - //err := s.SetRegState(PermissioningComplete) - //if err != nil { - // return errors.Wrap(err, "Could not store permissioning signature") - //} - // - //s.RegValidationSignature = sig - - //storing to ensure we never loose the signature - err := s.storeSession() - - return err -} - -func (s *SessionObj) GetRegistrationValidationSignature() []byte { - s.LockStorage() - defer s.UnlockStorage() - return s.RegValidationSignature -} - -func (s *SessionObj) GetRegState() uint32 { - return atomic.LoadUint32(s.RegState) -} - -func (s *SessionObj) SetRegState(rs uint32) error { - prevRs := rs - 1000 - b := atomic.CompareAndSwapUint32(s.RegState, prevRs, rs) - if !b { - return errors.New("Could not increment registration state") - } - return nil -} - type SessionStorageWrapper struct { Version uint32 Timestamp time.Time @@ -404,36 +308,6 @@ func (s *SessionObj) Immolate() error { return nil } -//Upserts an element into the interface map and saves the session object -func (s *SessionObj) UpsertMap(key string, element interface{}) error { - s.LockStorage() - s.InterfaceMap[key] = element - err := s.storeSession() - s.UnlockStorage() - return err -} - -//Pulls an element from the interface in the map -func (s *SessionObj) QueryMap(key string) (interface{}, error) { - var err error - s.LockStorage() - element, ok := s.InterfaceMap[key] - if !ok { - err = ErrQuery - element = nil - } - s.UnlockStorage() - return element, err -} - -func (s *SessionObj) DeleteMap(key string) error { - s.LockStorage() - delete(s.InterfaceMap, key) - err := s.storeSession() - s.UnlockStorage() - return err -} - func (s *SessionObj) GetSessionData() ([]byte, error) { s.LockStorage() defer s.UnlockStorage() @@ -448,14 +322,6 @@ func (s *SessionObj) GetRekeyManager() *keyStore.RekeyManager { return s.RekeyManager } -func (s *SessionObj) GetSwitchboard() *switchboard.Switchboard { - return s.listeners -} - -func (s *SessionObj) GetQuitChan() chan struct{} { - return s.quitReceptionRunner -} - func (s *SessionObj) getSessionData() ([]byte, error) { var sessionBuffer bytes.Buffer @@ -556,67 +422,6 @@ func decrypt(data []byte, password string) ([]byte, error) { return plaintext, nil } -// AppendGarbledMessage appends a message or messages to the garbled message -// buffer. -// FIXME: improve performance of adding items to the buffer -func (s *SessionObj) AppendGarbledMessage(messages ...*format.Message) { - s.garbledMessages = append(s.garbledMessages, messages...) -} - -// PopGarbledMessages returns the content of the garbled message buffer and -// deletes its contents. -func (s *SessionObj) PopGarbledMessages() []*format.Message { - tempBuffer := s.garbledMessages - s.garbledMessages = []*format.Message{} - return tempBuffer -} - -func (s *SessionObj) GetContactByValue(v string) (*id.ID, []byte) { - s.LockStorage() - defer s.UnlockStorage() - u, ok := s.ContactsByValue[v] - if !ok { - return nil, nil - } - return &(u.Id), u.Pk -} - -func (s *SessionObj) StoreContactByValue(v string, uid *id.ID, pk []byte) { - s.LockStorage() - defer s.UnlockStorage() - u, ok := s.ContactsByValue[v] - if ok { - globals.Log.WARN.Printf("Attempted to store over extant "+ - "user value: %s; before: %v, new: %v", v, u.Id, *uid) - } else { - s.ContactsByValue[v] = SearchedUserRecord{ - Id: *uid, - Pk: pk, - } - } -} - -func (s *SessionObj) DeleteContact(uid *id.ID) (string, error) { - s.LockStorage() - defer s.UnlockStorage() - - for v, u := range s.ContactsByValue { - if u.Id.Cmp(uid) { - delete(s.ContactsByValue, v) - _, ok := s.ContactsByValue[v] - if ok { - return "", errors.Errorf("Failed to delete user: %+v", u) - } else { - return v, nil - } - } - } - - return "", errors.Errorf("No user found in usermap with userid: %s", - uid) - -} - func (s *SessionObj) GetSessionLocation() uint8 { if s.storageLocation == globals.LocationA { return globals.LocationA diff --git a/user/session_test.go b/user/session_test.go index 564faa9871d2cda280bc1c3f57f9e46ed41e77a1..b45c59fc895ff58a0d947b201bf076bc06db2143 100644 --- a/user/session_test.go +++ b/user/session_test.go @@ -11,9 +11,7 @@ import ( "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" "math/rand" - "reflect" "testing" ) @@ -33,13 +31,7 @@ func TestUserSession(t *testing.T) { regSignature := make([]byte, 768) rng.Read(regSignature) - err := ses.RegisterPermissioningSignature(regSignature) - if err != nil { - t.Errorf("failure in setting register up for permissioning: %s", - err.Error()) - } - - err = ses.StoreSession() + err := ses.StoreSession() if err != nil { t.Errorf("Session not stored correctly: %s", err.Error()) @@ -58,34 +50,6 @@ func TestUserSession(t *testing.T) { pass++ } - err = ses.UpsertMap("test", 5) - - if err != nil { - t.Errorf("Could not store in session map interface: %s", - err.Error()) - } - - element, err := ses.QueryMap("test") - - if err != nil { - t.Errorf("Could not read element in session map "+ - "interface: %s", err.Error()) - } - - if element.(int) != 5 { - t.Errorf("Could not read element in session map "+ - "interface: Expected: 5, Recieved: %v", element) - } - - ses.DeleteMap("test") - - _, err = ses.QueryMap("test") - - if err == nil { - t.Errorf("Could not delete element in session map " + - "interface") - } - //Logout ses.Immolate() @@ -180,95 +144,3 @@ func getGroups() (*cyclic.Group, *cyclic.Group) { return cmixGrp, e2eGrp } - -// Tests that AppendGarbledMessage properly appends an array of messages by -// testing that the final buffer matches the values appended. -func TestSessionObj_AppendGarbledMessage(t *testing.T) { - session := NewSession(nil, "") - msgs := GenerateTestMessages(10) - - session.AppendGarbledMessage(msgs...) - - if !reflect.DeepEqual(msgs, session.(*SessionObj).garbledMessages) { - t.Errorf("AppendGarbledMessage() did not append the correct values"+ - "\n\texpected: %v\n\trecieved: %v", - msgs, session.(*SessionObj).garbledMessages) - } -} - -// Tests that PopGarbledMessages returns the correct data and that the buffer -// is cleared. -func TestSessionObj_PopGarbledMessages(t *testing.T) { - session := NewSession(nil, "") - msgs := GenerateTestMessages(10) - - session.(*SessionObj).garbledMessages = msgs - - poppedMsgs := session.PopGarbledMessages() - - if !reflect.DeepEqual(msgs, poppedMsgs) { - t.Errorf("PopGarbledMessages() did not pop the correct values"+ - "\n\texpected: %v\n\trecieved: %v", - msgs, poppedMsgs) - } - - if !reflect.DeepEqual([]*format.Message{}, session.(*SessionObj).garbledMessages) { - t.Errorf("PopGarbledMessages() did not remove the values from the buffer"+ - "\n\texpected: %#v\n\trecieved: %#v", - []*format.Message{}, session.(*SessionObj).garbledMessages) - } - -} - -/*// Tests ConvertSessionV1toV2() by creating an empty session object and setting -// the RegState to the version 1, running it through the function, and testing -// that RegState has values that match version 2. -func TestSessionObj_ConvertSessionV1toV2(t *testing.T) { - ses := SessionObj{} - number := uint32(0) - ses.RegState = &number - - ConvertSessionV1toV2(&ses) - - if *ses.RegState != 0 { - t.Errorf("ConvertSessionV1toV2() did not properly convert the "+ - "session object's RegState\n\texpected: %v\n\treceived: %v", - 0, *ses.RegState) - } - - number = uint32(1) - ses.RegState = &number - - ConvertSessionV1toV2(&ses) - - if *ses.RegState != 2000 { - t.Errorf("ConvertSessionV1toV2() did not properly convert the "+ - "session object's RegState\n\texpected: %v\n\treceived: %v", - 2000, *ses.RegState) - } - - number = uint32(2) - ses.RegState = &number - - ConvertSessionV1toV2(&ses) - - if *ses.RegState != 3000 { - t.Errorf("ConvertSessionV1toV2() did not properly convert the "+ - "session object's RegState\n\texpected: %v\n\treceived: %v", - 3000, *ses.RegState) - } -}*/ - -func GenerateTestMessages(size int) []*format.Message { - msgs := make([]*format.Message, size) - - for i := 0; i < size; i++ { - msgs[i] = format.NewMessage() - payloadBytes := make([]byte, format.PayloadLen) - payloadBytes[0] = byte(i) - msgs[i].SetPayloadA(payloadBytes) - msgs[i].SetPayloadB(payloadBytes) - } - - return msgs -} diff --git a/user/sessionv1.go b/user/sessionv1.go index d1571a8b2ed3e72f535a63048ea3c788f58e2d89..14fe49944dbf764f6ab250600490a5d27a3f644e 100644 --- a/user/sessionv1.go +++ b/user/sessionv1.go @@ -106,12 +106,8 @@ func ConvertSessionV1toV2(inputWrappedSession *SessionStorageWrapper) (*SessionS *sessionV1.RegState = 3000 } - sessionV2.InterfaceMap = sessionV1.InterfaceMap sessionV2.KeyMaps = sessionV1.KeyMaps sessionV2.RekeyManager = sessionV1.RekeyManager - sessionV2.RegValidationSignature = sessionV1.regValidationSignature - sessionV2.RegState = sessionV1.RegState - sessionV2.ContactsByValue = sessionV1.ContactsByValue //re encode the session var sessionBuffer bytes.Buffer