diff --git a/README.md b/README.md index 497f2c99231e3e0aa8908f4680aa1b76af8f802e..ebf490f59a5ab4ac6c8a154785443cff0ed28310 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,8 @@ Available Commands: Flags: --accept-channel Accept the channel request for the corresponding recipient ID + --delete-channel Delete the channel information for the + corresponding recipient ID --destfile string Read this contact file for the destination id -d, --destid string ID to send message to (if below 40, will be precanned. Use '0x' or 'b64:' for hex and diff --git a/api/client.go b/api/client.go index 5bbad8f8c76dbcafc87b9f50955339a5decaa5d2..20ccffacd0b7cec3d3b5542c68378dfff0a9e488 100644 --- a/api/client.go +++ b/api/client.go @@ -30,6 +30,7 @@ import ( "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" + "math" "sync" "time" ) @@ -235,6 +236,8 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie if def.Notification.Address != "" { hp := connect.GetDefaultHostParams() + // Client will not send KeepAlive packets + hp.KaClientOpts.Time = time.Duration(math.MaxInt64) hp.AuthEnabled = false hp.MaxRetries = 5 _, err = c.comms.AddHost(&id.NotificationBot, def.Notification.Address, []byte(def.Notification.TlsCertificate), hp) @@ -392,11 +395,10 @@ func (c *Client) StartNetworkFollower(timeout time.Duration) (<-chan interfaces. jww.INFO.Printf("StartNetworkFollower() \n\tTransmisstionID: %s "+ "\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID) - if status := c.status.get(); status != Stopped{ + if status := c.status.get(); status != Stopped { return nil, errors.Errorf("Cannot Stop the Network Follower when it is not running, status: %s", status) } - c.clientErrorChannel = make(chan interfaces.ClientError, 1000) cer := func(source, message, trace string) { @@ -456,7 +458,7 @@ func (c *Client) StopNetworkFollower() error { c.followerLock.Lock() defer c.followerLock.Unlock() - if status := c.status.get(); status != Running{ + if status := c.status.get(); status != Running { return errors.Errorf("Cannot Stop the Network Follower when it is not running, status: %s", status) } @@ -570,6 +572,19 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) { return numRegistered, len(nodes), nil } +// 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) + if err := c.storage.E2e().DeletePartner(partnerId); err != nil { + return err + } + if err := c.storage.Auth().Delete(partnerId); err != nil { + return err + } + c.storage.Conversations().Delete(partnerId) + return nil +} + // ----- Utility Functions ----- // parseNDF parses the initial ndf string for the client. do not check the // signature, it is deprecated. diff --git a/api/notifications.go b/api/notifications.go index 6be89c87670c88002f921d872c603104892c5a36..2a7d1b7c107128360f89930c8bf0bcb16dfc54de 100644 --- a/api/notifications.go +++ b/api/notifications.go @@ -8,7 +8,6 @@ package api import ( - "fmt" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/comms/mixmessages" @@ -26,7 +25,6 @@ import ( // risk to the user. func (c *Client) RegisterForNotifications(token string) error { jww.INFO.Printf("RegisterForNotifications(%s)", token) - fmt.Println("RegisterforNotifications") // Pull the host from the manage notificationBotHost, ok := c.comms.GetHost(&id.NotificationBot) if !ok { @@ -36,16 +34,15 @@ func (c *Client) RegisterForNotifications(token string) error { if err != nil { return err } - fmt.Println("Sending message") // Send the register message _, err = c.comms.RegisterForNotifications(notificationBotHost, &mixmessages.NotificationRegisterRequest{ Token: token, IntermediaryId: intermediaryReceptionID, - TransmissionRsa: rsa.CreatePublicKeyPem(c.GetUser().TransmissionRSA.GetPublic()), - TransmissionRsaSig: sig, + TransmissionRsa: rsa.CreatePublicKeyPem(c.GetStorage().User().GetCryptographicIdentity().GetTransmissionRSA().GetPublic()), TransmissionSalt: c.GetUser().TransmissionSalt, - IIDTransmissionRsaSig: []byte("temp"), + TransmissionRsaSig: c.GetStorage().User().GetTransmissionRegistrationValidationSignature(), + IIDTransmissionRsaSig: sig, RegistrationTimestamp: c.GetUser().RegistrationTimestamp.UnixNano(), }) if err != nil { @@ -97,9 +94,12 @@ func (c *Client) getIidAndSig() ([]byte, []byte, error) { return nil, nil, errors.WithMessage(err, "RegisterForNotifications: Failed to write intermediary ID to hash") } - sig, err := rsa.Sign(c.rng.GetStream(), c.GetUser().TransmissionRSA, hash.CMixHash, h.Sum(nil), nil) + stream := c.rng.GetStream() + c.GetUser() + sig, err := rsa.Sign(stream, c.storage.User().GetCryptographicIdentity().GetTransmissionRSA(), hash.CMixHash, h.Sum(nil), nil) if err != nil { return nil, nil, errors.WithMessage(err, "RegisterForNotifications: Failed to sign intermediary ID") } + stream.Close() return intermediaryReceptionID, sig, nil } diff --git a/api/version_vars.go b/api/version_vars.go index ab6b7356d36db61e2e5d548fa1893167ddcd05d5..494f2d6a7cee377c706e92d3268951f85a464490 100644 --- a/api/version_vars.go +++ b/api/version_vars.go @@ -1,9 +1,9 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2021-05-24 13:15:09.546928 -0500 CDT m=+0.071553794 +// 2021-06-22 11:16:35.397077 -0500 CDT m=+0.025546669 package api -const GITVERSION = `c85adeb9 Merge branch 'Anne/CI2' into 'release'` +const GITVERSION = `b7692cd7 added Keepalive opts` const SEMVER = "2.7.0" const DEPENDENCIES = `module gitlab.com/elixxir/client @@ -11,7 +11,7 @@ go 1.13 require ( github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 - github.com/golang/protobuf v1.4.3 + github.com/golang/protobuf v1.5.2 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect github.com/magiconair/properties v1.8.4 // indirect github.com/mitchellh/mapstructure v1.4.0 // indirect @@ -24,21 +24,18 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 - gitlab.com/elixxir/comms v0.0.4-0.20210524170509-89dd425cb228 - gitlab.com/elixxir/crypto v0.0.7-0.20210524170447-264b215ce90b + gitlab.com/elixxir/comms v0.0.4-0.20210622161439-b694033c9507 + gitlab.com/elixxir/crypto v0.0.7-0.20210614155844-c1e9c23a6ba7 gitlab.com/elixxir/ekv v0.1.5 - gitlab.com/elixxir/primitives v0.0.3-0.20210524170524-9780695d2b55 - gitlab.com/xx_network/comms v0.0.4-0.20210524170426-175f698a7b07 - gitlab.com/xx_network/crypto v0.0.5-0.20210524170434-dc9a398a2581 - gitlab.com/xx_network/primitives v0.0.4-0.20210524170438-ab712af183db + gitlab.com/elixxir/primitives v0.0.3-0.20210614155726-ebcf2d47a527 + gitlab.com/xx_network/comms v0.0.4-0.20210622161535-4f3d927d4c8c + gitlab.com/xx_network/crypto v0.0.5-0.20210614155554-8c333814205b + gitlab.com/xx_network/primitives v0.0.4-0.20210617180018-6472489fd418 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 - golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect + golang.org/x/net v0.0.0-20210525063256-abc453219eb5 google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect - google.golang.org/grpc v1.34.0 // indirect - google.golang.org/protobuf v1.26.0-rc.1 + google.golang.org/protobuf v1.26.0 gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) - -replace google.golang.org/grpc => github.com/grpc/grpc-go v1.27.1 ` diff --git a/auth/request.go b/auth/request.go index 76af994787f8e1658e13345bf14883e091e7790d..a6b9ab7dcc765509017e4b0c5d8efe988e1d1c9b 100644 --- a/auth/request.go +++ b/auth/request.go @@ -61,13 +61,13 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, "receiving a request") } else if rqType == auth.Sent { resend = true - }else{ - return 0, errors.Errorf("Cannot send a request after " + + } else { + return 0, errors.Errorf("Cannot send a request after "+ " a stored request with unknown rqType: %d", rqType) } - }else if !strings.Contains(err.Error(), auth.NoRequest){ + } else if !strings.Contains(err.Error(), auth.NoRequest) { return 0, errors.WithMessage(err, - "Cannot send a request after receiving unknown error " + + "Cannot send a request after receiving unknown error "+ "on requesting contact status") } @@ -105,11 +105,11 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, // in this case we have an ongoing request so we can resend the extant // request - if resend{ + if resend { newPrivKey = sr.GetMyPrivKey() newPubKey = sr.GetMyPubKey() - //in this case it is a new request and we must generate new keys - }else{ + //in this case it is a new request and we must generate new keys + } else { //generate new keypair newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng) newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp) @@ -143,7 +143,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, /*store state*/ //fixme: channel is bricked if the first store succedes but the second fails //store the in progress auth - if !resend{ + if !resend { err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey, newPrivKey, confirmFp) if err != nil { @@ -160,7 +160,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, if err != nil { // if the send fails just set it to failed, it will // but automatically retried - return 0, errors.WithMessagef(err, "Auth Request with %s " + + return 0, errors.WithMessagef(err, "Auth Request with %s "+ "(msgDigest: %s) failed to transmit: %+v", partner.ID, cmixMsg.Digest(), err) } diff --git a/bindings/client.go b/bindings/client.go index 432ba95160cf5373b8664e044b5d61e3098a60d5..6c430b96327fc732ff09e0cd90cccc08fd799c12 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -424,6 +424,15 @@ func (c *Client) GetNodeRegistrationStatus() (*NodeRegistrationsStatus, error) { return &NodeRegistrationsStatus{registered, total}, err } +// DeleteContact is a function which removes a contact from Client's storage +func (c *Client) DeleteContact(b []byte) error { + contactObj, err := UnmarshalContact(b) + if err != nil { + return err + } + return c.api.DeleteContact(contactObj.c.ID) +} + /* // SearchWithHandler is a non-blocking search that also registers // a callback interface for user disovery events. diff --git a/bindings/timeNow.go b/bindings/timeNow.go index 82cc2d798d8da4c16936b53b2ed3621b175e0e02..fc457b459ae43452a1920c26a8b9e24c53725d74 100644 --- a/bindings/timeNow.go +++ b/bindings/timeNow.go @@ -19,6 +19,6 @@ type TimeSource interface { // SetTimeSource sets the network time to a custom source. func SetTimeSource(timeNow TimeSource) { netTime.Now = func() time.Time { - return time.Unix(0,timeNow.NowMs()*int64(time.Millisecond)) + return time.Unix(0, timeNow.NowMs()*int64(time.Millisecond)) } } diff --git a/cmd/getndf.go b/cmd/getndf.go index 7ac150020c911d695f646993e3a409c18d6cb8da..7562acd153adc1257667faacb4d4a0ccbfbc2e74 100644 --- a/cmd/getndf.go +++ b/cmd/getndf.go @@ -70,8 +70,8 @@ var getNDFCmd = &cobra.Command{ Partial: &pb.NDFHash{ Hash: nil, }, - LastUpdate: uint64(0), - ReceptionID: dummyID[:], + LastUpdate: uint64(0), + ReceptionID: dummyID[:], ClientVersion: []byte(api.SEMVER), } resp, err := comms.SendPoll(host, pollMsg) diff --git a/cmd/root.go b/cmd/root.go index 1c495bae029e9a6b3251b3c6a893158280f69d5d..3dacf0e7b93ad1e30b3f0a93699fb624e599144a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -103,7 +103,7 @@ var rootCmd = &cobra.Command{ client.GetHealth().AddChannel(connected) waitUntilConnected(connected) - //err = client.RegisterForNotifications([]byte("dJwuGGX3KUyKldWK5PgQH8:APA91bFjuvimRc4LqOyMDiy124aLedifA8DhldtaB_b76ggphnFYQWJc_fq0hzQ-Jk4iYp2wPpkwlpE1fsOjs7XWBexWcNZoU-zgMiM0Mso9vTN53RhbXUferCbAiEylucEOacy9pniN")) + //err = client.RegisterForNotifications("dJwuGGX3KUyKldWK5PgQH8:APA91bFjuvimRc4LqOyMDiy124aLedifA8DhldtaB_b76ggphnFYQWJc_fq0hzQ-Jk4iYp2wPpkwlpE1fsOjs7XWBexWcNZoU-zgMiM0Mso9vTN53RhbXUferCbAiEylucEOacy9pniN") //if err != nil { // jww.FATAL.Panicf("Failed to register for notifications: %+v", err) //} @@ -174,6 +174,11 @@ var rootCmd = &cobra.Command{ " took %d seconds", scnt) } + // Delete this recipient + if viper.GetBool("delete-channel") { + deleteChannel(client, recipientID) + } + msg := message.Send{ Recipient: recipientID, Payload: []byte(msgBody), @@ -456,6 +461,13 @@ func acceptChannel(client *api.Client, recipientID *id.ID) { } } +func deleteChannel(client *api.Client, partnerId *id.ID) { + err := client.DeleteContact(partnerId) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } +} + func printChanRequest(requestor contact.Contact, message string) { msg := fmt.Sprintf("Authentication channel request from: %s\n", requestor.ID) @@ -769,6 +781,11 @@ func init() { viper.BindPFlag("accept-channel", rootCmd.Flags().Lookup("accept-channel")) + rootCmd.Flags().Bool("delete-channel", false, + "Delete the channel information for the corresponding recipient ID") + viper.BindPFlag("delete-channel", + rootCmd.Flags().Lookup("delete-channel")) + rootCmd.Flags().BoolP("send-auth-request", "", false, "Send an auth request to the specified destination and wait"+ "for confirmation") diff --git a/go.mod b/go.mod index 6cf6093ebada131e619b6feba03d207332111ca6..a877a15edaf7e17febd527d37da19fb807b9955a 100644 --- a/go.mod +++ b/go.mod @@ -17,12 +17,12 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 - gitlab.com/elixxir/comms v0.0.4-0.20210618021545-66a50a0519fe - gitlab.com/elixxir/crypto v0.0.7-0.20210614155844-c1e9c23a6ba7 + gitlab.com/elixxir/comms v0.0.4-0.20210623165525-33c8222c2ce3 + gitlab.com/elixxir/crypto v0.0.7-0.20210623165245-2bd12c6f4e39 gitlab.com/elixxir/ekv v0.1.5 - gitlab.com/elixxir/primitives v0.0.3-0.20210614155726-ebcf2d47a527 - gitlab.com/xx_network/comms v0.0.4-0.20210614155654-191473de2702 - gitlab.com/xx_network/crypto v0.0.5-0.20210614155554-8c333814205b + gitlab.com/elixxir/primitives v0.0.3-0.20210623165125-c395ff3484cc + gitlab.com/xx_network/comms v0.0.4-0.20210623165053-57910d8f01ee + gitlab.com/xx_network/crypto v0.0.5-0.20210623164949-495cf892172d gitlab.com/xx_network/primitives v0.0.4-0.20210617180018-6472489fd418 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/net v0.0.0-20210525063256-abc453219eb5 diff --git a/go.sum b/go.sum index cd5748235b881f7a77471ffcaea6f05225a64a9c..fb2ae995b8ac9b86edabceb4416b6dca25c5415c 100644 --- a/go.sum +++ b/go.sum @@ -235,6 +235,10 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= +github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= +github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= +github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivllc1yU3BvpjYI5BUW+zglcz6QWqeVRL5t0= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= @@ -247,33 +251,30 @@ github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0= github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0BJIk1HIzBVMjWNjIUfstrsXC2VqLYPcA= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= -gitlab.com/elixxir/comms v0.0.4-0.20210614195921-6b4a37974c50 h1:ehoUUbGelvWn2UwL9UAL4ZHKvSG3CCOe9zZ9vRD1ZyI= -gitlab.com/elixxir/comms v0.0.4-0.20210614195921-6b4a37974c50/go.mod h1:JeCKUXRS9xP3YYGPl4+OMFdvtt7ySJIxEsL9AzgeCu0= -gitlab.com/elixxir/comms v0.0.4-0.20210618021545-66a50a0519fe h1:ohY8eArU2yBrT2d/2cmRhRjmPBfQlA6+VJgIcxxF284= -gitlab.com/elixxir/comms v0.0.4-0.20210618021545-66a50a0519fe/go.mod h1:JeCKUXRS9xP3YYGPl4+OMFdvtt7ySJIxEsL9AzgeCu0= +gitlab.com/elixxir/comms v0.0.4-0.20210623165525-33c8222c2ce3 h1:oHKHY6M87Ua4O1XsD/QNXGZdkYk5yXfv029vWgXTuQE= +gitlab.com/elixxir/comms v0.0.4-0.20210623165525-33c8222c2ce3/go.mod h1:PraQe/afDikUhDE49AvREKrVE3KrBOlcuZhBh4vMfBs= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= -gitlab.com/elixxir/crypto v0.0.7-0.20210614155844-c1e9c23a6ba7 h1:UBq4/xMUWkYmEzUN2F7nLw5qQeiNKoLaoX3vZ/flz1c= -gitlab.com/elixxir/crypto v0.0.7-0.20210614155844-c1e9c23a6ba7/go.mod h1:FP848WCzyf81/Csz1lJpi3NXgIdpzJ4hoJam53xwCuo= +gitlab.com/elixxir/crypto v0.0.7-0.20210623165245-2bd12c6f4e39 h1:Htv/pPNGy7KePcwghA2WmG2SKZwbpnZ69CnOgvBU84k= +gitlab.com/elixxir/crypto v0.0.7-0.20210623165245-2bd12c6f4e39/go.mod h1:Sj8tbd/cp4T1dVPZM7G6ZQDAYuaxrRIsWs3UqOhWG5k= gitlab.com/elixxir/ekv v0.1.5 h1:R8M1PA5zRU1HVnTyrtwybdABh7gUJSCvt1JZwUSeTzk= gitlab.com/elixxir/ekv v0.1.5/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8= gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc= gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= -gitlab.com/elixxir/primitives v0.0.3-0.20210614155726-ebcf2d47a527 h1:kBNAGFy5Ylz7F0K3DmyzuHLf1npBg7a3t4qKvfqPL3Y= -gitlab.com/elixxir/primitives v0.0.3-0.20210614155726-ebcf2d47a527/go.mod h1:nSmBXcw4hkBLFdhu+araAPvf9szCDQF1fpRZ9/BgBec= +gitlab.com/elixxir/primitives v0.0.3-0.20210623165125-c395ff3484cc h1:LTxjZ4Ra69sQHgusXqpaBcb8FZZA+MHq8xGRsh4N0k8= +gitlab.com/elixxir/primitives v0.0.3-0.20210623165125-c395ff3484cc/go.mod h1:ZlS7xZMG1T/TvnwfUuVOGHbPILtCNUuT5xOPORSQxRY= gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= -gitlab.com/xx_network/comms v0.0.4-0.20210614155654-191473de2702 h1:ydi8FaAjFGfxMcvmIGlvnng491K2uEl3ymALC2Hh8Vw= -gitlab.com/xx_network/comms v0.0.4-0.20210614155654-191473de2702/go.mod h1:ehwxZxcAQHkJjP5BNkwPNK8/o6avUn0j0iDDiu+nMFc= +gitlab.com/xx_network/comms v0.0.4-0.20210623165053-57910d8f01ee h1:rsVLrqZ+us1Y/69kmP5I0pwmLpvqHxJBx8/AaFsvzsQ= +gitlab.com/xx_network/comms v0.0.4-0.20210623165053-57910d8f01ee/go.mod h1:sKfOAJkn8bLK7IPpd0Xc1UEL6hRB4p6m25ikh/QF8Yk= gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= -gitlab.com/xx_network/crypto v0.0.5-0.20210614155554-8c333814205b h1:X2Hhg9/IYowxMdI6TTnWj6WW3pnO2vMB/7f4mnu6Muw= -gitlab.com/xx_network/crypto v0.0.5-0.20210614155554-8c333814205b/go.mod h1:wiaQXyI9C9UGxxgLd+2lDmKyovO+PjFxaesCBgG0YDA= +gitlab.com/xx_network/crypto v0.0.5-0.20210623164949-495cf892172d h1:dqVruaOqcWhz1oflJZGsOAMR5JDDepPjA87aImeOiLg= +gitlab.com/xx_network/crypto v0.0.5-0.20210623164949-495cf892172d/go.mod h1:BLwPMs31pn0MNXGfhZJpRqzLWGhHS3ddDfdjZo59QSI= gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug= gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= -gitlab.com/xx_network/primitives v0.0.4-0.20210608160426-670aab2d82cf/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= gitlab.com/xx_network/primitives v0.0.4-0.20210617180018-6472489fd418 h1:F52R0wvFobjkmB8YaPNHZIu0VYqwjesMBCb9T14ygW8= gitlab.com/xx_network/primitives v0.0.4-0.20210617180018-6472489fd418/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= gitlab.com/xx_network/ring v0.0.3-0.20210527191221-ce3f170aabd5 h1:FY+4Rh1Q2rgLyv10aKJjhWApuKRCR/054XhreudfAvw= diff --git a/interfaces/params/rounds.go b/interfaces/params/rounds.go index 4a6ffab984f3ba309d7fdb77cf7cfb1710f8cef4..3e39ad47827e5f5f6f9dc526fcfffa200f5cf5a8 100644 --- a/interfaces/params/rounds.go +++ b/interfaces/params/rounds.go @@ -51,7 +51,7 @@ func GetDefaultRounds() Rounds { LookupRoundsBufferLen: 2000, ForceHistoricalRounds: false, MaxHistoricalRoundsRetries: 3, - UncheckRoundPeriod: 20 * time.Second, - ForceMessagePickupRetry: false, + UncheckRoundPeriod: 20 * time.Second, + ForceMessagePickupRetry: false, } } diff --git a/keyExchange/confirm.go b/keyExchange/confirm.go index ce1bec2baf28d92502c494ec94e659ba1e7c48c1..45224193f80a302ae24e4e4f01ec0f7afe647638 100644 --- a/keyExchange/confirm.go +++ b/keyExchange/confirm.go @@ -83,11 +83,11 @@ func unmarshalConfirm(payload []byte) (e2e.SessionID, error) { "unmarshal payload: %s", err) } - confimedSessionID := e2e.SessionID{} - if err := confimedSessionID.Unmarshal(msg.SessionID); err != nil { + confirmedSessionID := e2e.SessionID{} + if err := confirmedSessionID.Unmarshal(msg.SessionID); err != nil { return e2e.SessionID{}, errors.Errorf("Failed to unmarshal"+ " sessionID: %s", err) } - return confimedSessionID, nil + return confirmedSessionID, nil } diff --git a/network/manager.go b/network/manager.go index fcb20f2d77f94a57c4c2f01e581b03fca06b6178..d480f4afe6c2b23da229c4c20b0b752c3e4d936f 100644 --- a/network/manager.go +++ b/network/manager.go @@ -28,6 +28,8 @@ import ( "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/primitives/ndf" + "math" + "time" ) // Manager implements the NetworkManager interface inside context. It @@ -95,6 +97,8 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard, // Set up gateway.Sender poolParams := gateway.DefaultPoolParams() + // Client will not send KeepAlive packets + poolParams.HostParams.KaClientOpts.Time = time.Duration(math.MaxInt64) m.sender, err = gateway.NewSender(poolParams, rng, ndf, comms, session, m.NodeRegistration) if err != nil { diff --git a/network/message/parse/partition.go b/network/message/parse/partition.go index e7fbbfd313379570d3ec522d23053fbd025456cf..ad66ba2f30e09434dc090f07e0917137973d9b00 100644 --- a/network/message/parse/partition.go +++ b/network/message/parse/partition.go @@ -12,6 +12,7 @@ import ( "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/storage" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" "time" ) @@ -80,9 +81,9 @@ func (p Partitioner) HandlePartition(sender *id.ID, _ message.EncryptionType, // Handle the message ID messageID := p.session.Conversations().Get(sender). ProcessReceivedMessageID(fm.GetID()) - + storeageTimestamp := netTime.Now() return p.session.Partition().AddFirst(sender, fm.GetType(), - messageID, fm.GetPart(), fm.GetNumParts(), fm.GetTimestamp(), + messageID, fm.GetPart(), fm.GetNumParts(), fm.GetTimestamp(), storeageTimestamp, fm.GetSizedContents(), relationshipFingerprint) } else { // If it is a subsequent message part, handle it as so diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index d70cd6221a32fd84d40e9b4afba0d60f22691456..1c1e7c1f3d3b0af1e55d549c156d93d82a5a6b40 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -74,14 +74,13 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, remainingTime := cmixParams.Timeout - elapsed //find the best round to send to, excluding attempted rounds bestRound, err := instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted, sendTimeBuffer) - if err!=nil{ + if err != nil { jww.WARN.Printf("Failed to GetUpcomingRealtime (msgDigest: %s): %+v", msg.Digest(), err) } if bestRound == nil { continue } - //add the round on to the list of attempted so it is not tried again attempted.Insert(bestRound) diff --git a/permissioning/permissioning.go b/permissioning/permissioning.go index ebe00b3c3d41c3c9fcaf844e65d87fc6033dd829..87c3b6fff40c147c59a4534f7e52f588a9ad45fd 100644 --- a/permissioning/permissioning.go +++ b/permissioning/permissioning.go @@ -13,6 +13,8 @@ import ( "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" + "math" + "time" ) type Permissioning struct { @@ -31,7 +33,8 @@ func Init(comms *client.Comms, def *ndf.NetworkDefinition) (*Permissioning, erro //add the permissioning host to comms hParam := connect.GetDefaultHostParams() hParam.AuthEnabled = false - + // Client will not send KeepAlive packets + hParam.KaClientOpts.Time = time.Duration(math.MaxInt64) perm.host, err = comms.AddHost(&id.Permissioning, def.Registration.Address, []byte(def.Registration.TlsCertificate), hParam) diff --git a/permissioning/register.go b/permissioning/register.go index e332152573c112c5e7cf5f32608f6aa3f2a8c60b..ead58a5fcdd3856619294bab3708f1c75049487b 100644 --- a/permissioning/register.go +++ b/permissioning/register.go @@ -44,6 +44,6 @@ func register(comms registrationMessageSender, host *connect.Host, return nil, nil, 0, errors.Errorf("sendRegistrationMessage: error handling message: %s", response.Error) } - return response.ClientSignedByServer.Signature, - response.ClientReceptionSignedByServer.Signature, response.Timestamp, nil + return response.ClientSignedByServer.Signature, + response.ClientReceptionSignedByServer.Signature, response.Timestamp, nil } diff --git a/storage/auth/store.go b/storage/auth/store.go index 9ce2e6154e3b5bce28f4df6c36cbffca43255fc8..341bc74c01639163b9c22666263ab23b7812b1a8 100644 --- a/storage/auth/store.go +++ b/storage/auth/store.go @@ -92,7 +92,7 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St return nil, errors.WithMessagef(err, "Failed to "+ "unmarshal SentRequestMap") } - + jww.TRACE.Printf("%d found when loading AuthStore", len(requestList)) for _, rDisk := range requestList { r := &request{ rt: RequestType(rDisk.T), @@ -117,7 +117,6 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St PrivKey: nil, Request: r, } - rid = sr.partner r.sent = sr @@ -143,7 +142,6 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St func (s *Store) save() error { requestIDList := make([]requestDisk, len(s.requests)) - index := 0 for pid, r := range s.requests { rDisk := requestDisk{ @@ -158,7 +156,6 @@ func (s *Store) save() error { if err != nil { return err } - obj := versioned.Object{ Version: requestMapVersion, Timestamp: netTime.Now(), @@ -206,6 +203,7 @@ func (s *Store) AddSent(partner *id.ID, partnerHistoricalPubKey, myPrivKey, jww.INFO.Printf("AddSent PUBKEY FINGERPRINT: %v", sr.fingerprint) jww.INFO.Printf("AddSent PUBKEY: %v", sr.myPubKey.Bytes()) + jww.INFO.Printf("AddSent Partner: %s", partner) s.fingerprints[sr.fingerprint] = fingerprint{ Type: Specific, @@ -219,7 +217,7 @@ func (s *Store) AddSent(partner *id.ID, partnerHistoricalPubKey, myPrivKey, func (s *Store) AddReceived(c contact.Contact) error { s.mux.Lock() defer s.mux.Unlock() - + jww.DEBUG.Printf("AddReceived new contact: %s", c.ID) if _, ok := s.requests[*c.ID]; ok { return errors.Errorf("Cannot add contact for partner "+ "%s, one already exists", c.ID) diff --git a/storage/e2e/manager.go b/storage/e2e/manager.go index 6d7691b2b8f402c92ea6d4615a175b0b14b4b61e..a978beeae77c2fffa723c15f495ebf1fa4925c5c 100644 --- a/storage/e2e/manager.go +++ b/storage/e2e/manager.go @@ -112,6 +112,25 @@ func loadManager(ctx *context, kv *versioned.KV, partnerID *id.ID) (*Manager, er return m, nil } +// clearManager removes the relationship between the partner +// and deletes the Send and Receive sessions. This includes the +// sessions and the key vectors +func clearManager(m *Manager, kv *versioned.KV) error { + kv = kv.Prefix(fmt.Sprintf(managerPrefix, m.partner)) + + if err := DeleteRelationship(m); err != nil { + return errors.WithMessage(err, + "Failed to delete relationship") + } + + if err := utility.DeleteCyclicKey(m.kv, originPartnerPubKey); err != nil { + jww.FATAL.Panicf("Failed to delete %s: %+v", originPartnerPubKey, + err) + } + + return nil +} + // NewReceiveSession creates a new Receive session using the latest private key // this user has sent and the new public key received from the partner. If the // session already exists, then it will not be overwritten and the extant diff --git a/storage/e2e/manager_test.go b/storage/e2e/manager_test.go index 195b0752a603002dcb395507fc0b7d361a0b235a..114afac841407a4c4f8a0116ac452b7bd01c68cc 100644 --- a/storage/e2e/manager_test.go +++ b/storage/e2e/manager_test.go @@ -70,6 +70,30 @@ func TestLoadManager(t *testing.T) { } } +// Unit test for clearManager +func TestManager_ClearManager(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("clearManager error: " + + "Did not panic when loading deleted manager") + } + }() + + // Set up expected and test values + expectedM, kv := newTestManager(t) + + err := clearManager(expectedM, kv) + if err != nil { + t.Fatalf("clearManager returned an error: %v", err) + } + + // Attempt to load relationship + _, err = loadManager(expectedM.ctx, kv, expectedM.partner) + if err != nil { + t.Errorf("loadManager() returned an error: %v", err) + } +} + // Tests happy path of Manager.NewReceiveSession. func TestManager_NewReceiveSession(t *testing.T) { // Set up test values diff --git a/storage/e2e/relationship.go b/storage/e2e/relationship.go index f92e12b6901b206dcdf2cae00200555eb762894b..e0e7723d6c332c36a1ac9ceae0753e3174da4ba6 100644 --- a/storage/e2e/relationship.go +++ b/storage/e2e/relationship.go @@ -84,6 +84,33 @@ func NewRelationship(manager *Manager, t RelationshipType, return r } +// DeleteRelationship removes all relationship and +// relationship adjacent information from storage +func DeleteRelationship(manager *Manager) error { + + // Delete the send information + sendKv := manager.kv.Prefix(Send.prefix()) + manager.send.Delete() + if err := deleteRelationshipFingerprint(sendKv); err != nil { + return err + } + if err := sendKv.Delete(relationshipKey, currentRelationshipVersion); err != nil { + return errors.Errorf("Could not delete send relationship: %v", err) + } + + // Delete the receive information + receiveKv := manager.kv.Prefix(Receive.prefix()) + manager.receive.Delete() + if err := deleteRelationshipFingerprint(receiveKv); err != nil { + return err + } + if err := receiveKv.Delete(relationshipKey, currentRelationshipVersion); err != nil { + return errors.Errorf("Could not delete receive relationship: %v", err) + } + + return nil +} + func LoadRelationship(manager *Manager, t RelationshipType) (*relationship, error) { kv := manager.kv.Prefix(t.prefix()) @@ -166,6 +193,16 @@ func (r *relationship) unmarshal(b []byte) error { return nil } +func (r *relationship) Delete() { + r.mux.Lock() + defer r.mux.Unlock() + for _, s := range r.sessions { + delete(r.sessionByID, s.GetID()) + s.Delete() + } + +} + func (r *relationship) AddSession(myPrivKey, partnerPubKey, baseKey *cyclic.Int, trigger SessionID, negotiationStatus Negotiation, e2eParams params.E2ESessionParams) *Session { diff --git a/storage/e2e/relationshipFingerprint.go b/storage/e2e/relationshipFingerprint.go index a3702655319ccf0f14323d31f5b32b3fe59cb825..29b80896dfc078b8ab1a7cefa348a7860498aec2 100644 --- a/storage/e2e/relationshipFingerprint.go +++ b/storage/e2e/relationshipFingerprint.go @@ -57,3 +57,9 @@ func loadRelationshipFingerprint(kv *versioned.KV) []byte { } return obj.Data } + +// deleteRelationshipFingerprint is a helper function which deletes a fingerprint from store +func deleteRelationshipFingerprint(kv *versioned.KV) error { + return kv.Delete(relationshipFingerprintKey, + currentRelationshipVersion) +} diff --git a/storage/e2e/relationship_test.go b/storage/e2e/relationship_test.go index 457e4f6dcd508abd2014248db7738f46badf947a..1ad211fcd55a389e758711a22ac8bcff24fdd76e 100644 --- a/storage/e2e/relationship_test.go +++ b/storage/e2e/relationship_test.go @@ -68,6 +68,64 @@ func TestLoadRelationship(t *testing.T) { } } +// Shows that a deleted Relationship can no longer be pulled from store +func TestDeleteRelationship(t *testing.T) { + mgr := makeTestRelationshipManager(t) + + // Generate send relationship + mgr.send = NewRelationship(mgr, Send, params.GetDefaultE2ESessionParams()) + if err := mgr.send.save(); err != nil { + t.Fatal(err) + } + + // Generate receive relationship + mgr.receive = NewRelationship(mgr, Receive, params.GetDefaultE2ESessionParams()) + if err := mgr.receive.save(); err != nil { + t.Fatal(err) + } + + err := DeleteRelationship(mgr) + if err != nil { + t.Fatalf("DeleteRelationship error: Could not delete manager: %v", err) + } + + _, err = LoadRelationship(mgr, Send) + if err == nil { + t.Fatalf("DeleteRelationship error: Should not have loaded deleted relationship: %v", err) + } + + _, err = LoadRelationship(mgr, Receive) + if err == nil { + t.Fatalf("DeleteRelationship error: Should not have loaded deleted relationship: %v", err) + } +} + +// Shows that a deleted relationship fingerprint can no longer be pulled from store +func TestRelationship_deleteRelationshipFingerprint(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("deleteRelationshipFingerprint error: " + + "Did not panic when loading deleted fingerprint") + } + }() + + mgr := makeTestRelationshipManager(t) + sb := NewRelationship(mgr, Send, params.GetDefaultE2ESessionParams()) + + err := sb.save() + if err != nil { + t.Fatal(err) + } + + err = deleteRelationshipFingerprint(mgr.kv) + if err != nil { + t.Fatalf("deleteRelationshipFingerprint error: "+ + "Could not delete fingerprint: %v", err) + } + + loadRelationshipFingerprint(mgr.kv) +} + // Shows that Relationship returns a valid session buff func TestNewRelationshipBuff(t *testing.T) { mgr := makeTestRelationshipManager(t) diff --git a/storage/e2e/session.go b/storage/e2e/session.go index 6e85d873e36768d2372b5f713c45527625233c3c..9f74ebf35efe310214237e6da36f9f4029c872be 100644 --- a/storage/e2e/session.go +++ b/storage/e2e/session.go @@ -201,7 +201,8 @@ func (s *Session) save() error { /*METHODS*/ // Done all unused key fingerprints -// delete this session and its key states from the storage + +// Delete removes this session and its key states from the storage func (s *Session) Delete() { s.mux.Lock() defer s.mux.Unlock() @@ -221,7 +222,7 @@ func (s *Session) Delete() { } } -//Gets the base key. +// GetBaseKey retrieves the base key. func (s *Session) GetBaseKey() *cyclic.Int { // no lock is needed because this cannot be edited return s.baseKey.DeepCopy() diff --git a/storage/e2e/store.go b/storage/e2e/store.go index b6dc289c9b83edfa42e1468a015203d67dd7c1cd..2a8006902a9adf5a94704175f55f548f61eb0d7a 100644 --- a/storage/e2e/store.go +++ b/storage/e2e/store.go @@ -188,6 +188,21 @@ func (s *Store) AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.In return nil } +// DeletePartner removes the associated contact from the E2E store +func (s *Store) DeletePartner(partnerId *id.ID) error { + m, ok := s.managers[*partnerId] + if !ok { + return errors.New(NoPartnerErrorStr) + } + + if err := clearManager(m, s.kv); err != nil { + return errors.WithMessagef(err, "Could not remove partner %s from store", partnerId) + } + + delete(s.managers, *partnerId) + return s.save() +} + func (s *Store) GetPartner(partnerID *id.ID) (*Manager, error) { s.mux.RLock() defer s.mux.RUnlock() diff --git a/storage/e2e/store_test.go b/storage/e2e/store_test.go index ef23f381f0370afec21f22c75d65dee892c93163..016184b58e803a9b92d763be3c880b8a1b4dc05e 100644 --- a/storage/e2e/store_test.go +++ b/storage/e2e/store_test.go @@ -98,7 +98,10 @@ func TestStore_AddPartner(t *testing.T) { expectedManager := newManager(s.context, s.kv, partnerID, s.dhPrivateKey, pubKey, p, p) - s.AddPartner(partnerID, pubKey, s.dhPrivateKey, p, p) + err := s.AddPartner(partnerID, pubKey, s.dhPrivateKey, p, p) + if err != nil { + t.Fatalf("AddPartner returned an error: %v", err) + } m, exists := s.managers[*partnerID] if !exists { @@ -111,6 +114,30 @@ func TestStore_AddPartner(t *testing.T) { } } +// Unit test for DeletePartner +func TestStore_DeletePartner(t *testing.T) { + s, _, _ := makeTestStore() + partnerID := id.NewIdFromUInt(rand.Uint64(), id.User, t) + pubKey := diffieHellman.GeneratePublicKey(s.dhPrivateKey, s.grp) + p := params.GetDefaultE2ESessionParams() + + err := s.AddPartner(partnerID, pubKey, s.dhPrivateKey, p, p) + if err != nil { + t.Fatalf("DeletePartner error: Could not add partner in set up: %v", err) + } + + err = s.DeletePartner(partnerID) + if err != nil { + t.Fatalf("DeletePartner received an error: %v", err) + } + + _, err = s.GetPartner(partnerID) + if err == nil { + t.Errorf("DeletePartner error: Should not be able to pull deleted partner from store") + } + +} + // Tests happy path of Store.GetPartner. func TestStore_GetPartner(t *testing.T) { s, _, _ := makeTestStore() diff --git a/storage/partition/multiPartMessage.go b/storage/partition/multiPartMessage.go index 754c524702498c2c6586d54a42adedf3351a7cc5..3aa8cffb556c3bd23f8afb6f8730830919b3c07f 100644 --- a/storage/partition/multiPartMessage.go +++ b/storage/partition/multiPartMessage.go @@ -30,8 +30,11 @@ type multiPartMessage struct { MessageID uint64 NumParts uint8 PresentParts uint8 - Timestamp time.Time - MessageType message.Type + // Timestamp of message from sender + SenderTimestamp time.Time + // Timestamp in which message was stored in RAM + StorageTimestamp time.Time + MessageType message.Type parts [][]byte kv *versioned.KV @@ -48,13 +51,13 @@ func loadOrCreateMultiPartMessage(sender *id.ID, messageID uint64, if err != nil { if !ekv.Exists(err) { mpm := &multiPartMessage{ - Sender: sender, - MessageID: messageID, - NumParts: 0, - PresentParts: 0, - Timestamp: time.Time{}, - MessageType: 0, - kv: kv, + Sender: sender, + MessageID: messageID, + NumParts: 0, + PresentParts: 0, + SenderTimestamp: time.Time{}, + MessageType: 0, + kv: kv, } if err = mpm.save(); err != nil { jww.FATAL.Panicf("Failed to save new multi part "+ @@ -119,7 +122,7 @@ func (mpm *multiPartMessage) Add(partNumber uint8, part []byte) { } func (mpm *multiPartMessage) AddFirst(mt message.Type, partNumber uint8, - numParts uint8, timestamp time.Time, part []byte) { + numParts uint8, senderTimestamp, storageTimestamp time.Time, part []byte) { mpm.mux.Lock() defer mpm.mux.Unlock() @@ -129,10 +132,11 @@ func (mpm *multiPartMessage) AddFirst(mt message.Type, partNumber uint8, } mpm.NumParts = numParts - mpm.Timestamp = timestamp + mpm.SenderTimestamp = senderTimestamp mpm.MessageType = mt mpm.parts[partNumber] = part mpm.PresentParts++ + mpm.StorageTimestamp = storageTimestamp if err := savePart(mpm.kv, partNumber, part); err != nil { jww.FATAL.Panicf("Failed to save multi part "+ @@ -159,27 +163,8 @@ func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message mpm.parts = append(mpm.parts, make([][]byte, int(mpm.NumParts)-len(mpm.parts))...) } - var err error - lenMsg := 0 - // Load all parts from disk, deleting files from disk as we go along - for i := uint8(0); i < mpm.NumParts; i++ { - if mpm.parts[i] == nil { - if mpm.parts[i], err = loadPart(mpm.kv, i); err != nil { - jww.FATAL.Panicf("Failed to load multi part "+ - "message part %v from %s messageID %v: %s", i, mpm.Sender, - mpm.MessageID, err) - } - if err = deletePart(mpm.kv, i); err != nil { - jww.FATAL.Panicf("Failed to delete multi part "+ - "message part %v from %s messageID %v: %s", i, mpm.Sender, - mpm.MessageID, err) - } - } - lenMsg += len(mpm.parts[i]) - } - // delete the multipart message - mpm.delete() + lenMsg := mpm.delete() mpm.mux.Unlock() // Reconstruct the message @@ -200,7 +185,7 @@ func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message Payload: reconstructed, MessageType: mpm.MessageType, Sender: mpm.Sender, - Timestamp: mpm.Timestamp, + Timestamp: mpm.SenderTimestamp, // Encryption will be set externally Encryption: 0, ID: mid, @@ -209,7 +194,27 @@ func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message return m, true } -func (mpm *multiPartMessage) delete() { +// deletes all parts from disk and RAM. Returns the message length for reconstruction +func (mpm *multiPartMessage) delete() int { + // Load all parts from disk, deleting files from disk as we go along + var err error + lenMsg := 0 + for i := uint8(0); i < mpm.NumParts; i++ { + if mpm.parts[i] == nil { + if mpm.parts[i], err = loadPart(mpm.kv, i); err != nil { + jww.FATAL.Panicf("Failed to load multi part "+ + "message part %v from %s messageID %v: %s", i, mpm.Sender, + mpm.MessageID, err) + } + if err = deletePart(mpm.kv, i); err != nil { + jww.FATAL.Panicf("Failed to delete multi part "+ + "message part %v from %s messageID %v: %s", i, mpm.Sender, + mpm.MessageID, err) + } + } + lenMsg += len(mpm.parts[i]) + } + //key := makeMultiPartMessageKey(mpm.MessageID) if err := mpm.kv.Delete(messageKey, currentMultiPartMessageVersion); err != nil { @@ -217,4 +222,6 @@ func (mpm *multiPartMessage) delete() { "message from %s messageID %v: %s", mpm.Sender, mpm.MessageID, err) } + + return lenMsg } diff --git a/storage/partition/multiPartMessage_test.go b/storage/partition/multiPartMessage_test.go index dff3c0fabb41cffd20f714497b487ea8bcbd4644..752d53272bb121f566e2917d746087020f68d14b 100644 --- a/storage/partition/multiPartMessage_test.go +++ b/storage/partition/multiPartMessage_test.go @@ -27,13 +27,13 @@ func Test_loadOrCreateMultiPartMessage_Create(t *testing.T) { // Set up expected test value prng := rand.New(rand.NewSource(netTime.Now().UnixNano())) expectedMpm := &multiPartMessage{ - Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), - MessageID: prng.Uint64(), - NumParts: 0, - PresentParts: 0, - Timestamp: time.Time{}, - MessageType: 0, - kv: versioned.NewKV(make(ekv.Memstore)), + Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), + MessageID: prng.Uint64(), + NumParts: 0, + PresentParts: 0, + SenderTimestamp: time.Time{}, + MessageType: 0, + kv: versioned.NewKV(make(ekv.Memstore)), } expectedData, err := json.Marshal(expectedMpm) if err != nil { @@ -63,13 +63,13 @@ func Test_loadOrCreateMultiPartMessage_Load(t *testing.T) { // Set up expected test value prng := rand.New(rand.NewSource(netTime.Now().UnixNano())) expectedMpm := &multiPartMessage{ - Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), - MessageID: prng.Uint64(), - NumParts: 0, - PresentParts: 0, - Timestamp: time.Time{}, - MessageType: 0, - kv: versioned.NewKV(make(ekv.Memstore)), + Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), + MessageID: prng.Uint64(), + NumParts: 0, + PresentParts: 0, + SenderTimestamp: time.Time{}, + MessageType: 0, + kv: versioned.NewKV(make(ekv.Memstore)), } err := expectedMpm.save() if err != nil { @@ -85,8 +85,8 @@ func Test_loadOrCreateMultiPartMessage_Load(t *testing.T) { func CheckMultiPartMessages(expectedMpm *multiPartMessage, mpm *multiPartMessage, t *testing.T) { // The kv differs because it has prefix called, so we compare fields individually - if expectedMpm.Timestamp != mpm.Timestamp { - t.Errorf("timestamps mismatch: expected %v, got %v", expectedMpm.Timestamp, mpm.Timestamp) + if expectedMpm.SenderTimestamp != mpm.SenderTimestamp { + t.Errorf("timestamps mismatch: expected %v, got %v", expectedMpm.SenderTimestamp, mpm.SenderTimestamp) } if expectedMpm.MessageType != mpm.MessageType { t.Errorf("messagetype mismatch: expected %v, got %v", expectedMpm.MessageID, mpm.MessageID) @@ -159,21 +159,21 @@ func TestMultiPartMessage_AddFirst(t *testing.T) { // Generate test values prng := rand.New(rand.NewSource(netTime.Now().UnixNano())) expectedMpm := &multiPartMessage{ - Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), - MessageID: prng.Uint64(), - NumParts: uint8(prng.Uint32()), - PresentParts: 1, - Timestamp: netTime.Now(), - MessageType: message.NoType, - parts: make([][]byte, 3), - kv: versioned.NewKV(make(ekv.Memstore)), + Sender: id.NewIdFromUInt(prng.Uint64(), id.User, t), + MessageID: prng.Uint64(), + NumParts: uint8(prng.Uint32()), + PresentParts: 1, + SenderTimestamp: netTime.Now(), + MessageType: message.NoType, + parts: make([][]byte, 3), + kv: versioned.NewKV(make(ekv.Memstore)), } expectedMpm.parts[2] = []byte{5, 8, 78, 9} npm := loadOrCreateMultiPartMessage(expectedMpm.Sender, expectedMpm.MessageID, expectedMpm.kv) npm.AddFirst(expectedMpm.MessageType, 2, expectedMpm.NumParts, - expectedMpm.Timestamp, expectedMpm.parts[2]) + expectedMpm.SenderTimestamp, netTime.Now(), expectedMpm.parts[2]) CheckMultiPartMessages(expectedMpm, npm, t) @@ -203,7 +203,7 @@ func TestMultiPartMessage_IsComplete(t *testing.T) { t.Error("IsComplete() returned true when NumParts == 0.") } - mpm.AddFirst(message.Text, partNums[0], 75, netTime.Now(), parts[0]) + mpm.AddFirst(message.Text, partNums[0], 75, netTime.Now(), netTime.Now(), parts[0]) for i := range partNums { if i > 0 { mpm.Add(partNums[i], parts[i]) diff --git a/storage/partition/store.go b/storage/partition/store.go index 52f7f330f06aa4887c64d991f3f384714073b3cb..f8a0e8e2c8054e6bbad61ee764c18b7664cee57f 100644 --- a/storage/partition/store.go +++ b/storage/partition/store.go @@ -9,9 +9,12 @@ package partition import ( "encoding/binary" + "encoding/json" + jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" "golang.org/x/crypto/blake2b" "sync" "time" @@ -20,29 +23,58 @@ import ( type multiPartID [16]byte const packagePrefix = "Partition" +const clearPartitionThreshold = 24 * time.Hour +const activePartitions = "activePartitions" +const activePartitionVersion = 0 type Store struct { - multiParts map[multiPartID]*multiPartMessage - kv *versioned.KV - mux sync.Mutex + multiParts map[multiPartID]*multiPartMessage + activeParts map[*multiPartMessage]bool + kv *versioned.KV + mux sync.Mutex } func New(kv *versioned.KV) *Store { return &Store{ - multiParts: make(map[multiPartID]*multiPartMessage), - kv: kv.Prefix(packagePrefix), + multiParts: make(map[multiPartID]*multiPartMessage), + activeParts: make(map[*multiPartMessage]bool), + kv: kv.Prefix(packagePrefix), } } +func Load(kv *versioned.KV) *Store { + partitionStore := &Store{ + multiParts: make(map[multiPartID]*multiPartMessage), + activeParts: make(map[*multiPartMessage]bool), + kv: kv.Prefix(packagePrefix), + } + + partitionStore.loadActivePartitions() + + partitionStore.prune() + + return partitionStore +} + func (s *Store) AddFirst(partner *id.ID, mt message.Type, messageID uint64, - partNum, numParts uint8, timestamp time.Time, + partNum, numParts uint8, senderTimestamp, storageTimestamp time.Time, part []byte, relationshipFingerprint []byte) (message.Receive, bool) { mpm := s.load(partner, messageID) - mpm.AddFirst(mt, partNum, numParts, timestamp, part) + mpm.AddFirst(mt, partNum, numParts, senderTimestamp, storageTimestamp, part) + msg, ok := mpm.IsComplete(relationshipFingerprint) + s.mux.Lock() + defer s.mux.Unlock() + if !ok { + s.activeParts[mpm] = true + s.saveActiveParts() + } else { + mpID := getMultiPartID(mpm.Sender, mpm.MessageID) + delete(s.multiParts, mpID) + } - return mpm.IsComplete(relationshipFingerprint) + return msg, ok } func (s *Store) Add(partner *id.ID, messageID uint64, partNum uint8, @@ -52,7 +84,33 @@ func (s *Store) Add(partner *id.ID, messageID uint64, partNum uint8, mpm.Add(partNum, part) - return mpm.IsComplete(relationshipFingerprint) + msg, ok := mpm.IsComplete(relationshipFingerprint) + if !ok { + s.activeParts[mpm] = true + s.saveActiveParts() + } else { + mpID := getMultiPartID(mpm.Sender, mpm.MessageID) + delete(s.multiParts, mpID) + } + + return msg, ok +} + +// Prune clear old messages on it's stored timestamp +func (s *Store) prune() { + s.mux.Lock() + defer s.mux.Unlock() + now := netTime.Now() + for mpm, _ := range s.activeParts { + if now.Sub(mpm.StorageTimestamp) >= clearPartitionThreshold { + jww.INFO.Printf("prune partition: %v", mpm) + mpm.mux.Lock() + mpm.delete() + mpID := getMultiPartID(mpm.Sender, mpm.MessageID) + mpm.mux.Unlock() + delete(s.multiParts, mpID) + } + } } func (s *Store) load(partner *id.ID, messageID uint64) *multiPartMessage { @@ -68,6 +126,56 @@ func (s *Store) load(partner *id.ID, messageID uint64) *multiPartMessage { return mpm } +func (s *Store) saveActiveParts() { + jww.INFO.Printf("Saving %d active partitions", len(s.activeParts)) + activeList := make([]*multiPartMessage, 0, len(s.activeParts)) + for mpm := range s.activeParts { + mpm.mux.Lock() + jww.INFO.Printf("saveActiveParts saving %v", mpm) + activeList = append(activeList, mpm) + mpm.mux.Unlock() + } + + data, err := json.Marshal(&activeList) + if err != nil { + jww.FATAL.Panicf("Could not save active partitions: %v", err) + } + + obj := versioned.Object{ + Version: activePartitionVersion, + Timestamp: netTime.Now(), + Data: data, + } + + err = s.kv.Set(activePartitions, activePartitionVersion, &obj) + if err != nil { + jww.FATAL.Panicf("Could not save active partitions: %v", err) + } +} + +func (s *Store) loadActivePartitions() { + s.mux.Lock() + defer s.mux.Unlock() + obj, err := s.kv.Get(activePartitions, activePartitionVersion) + if err != nil { + jww.DEBUG.Printf("Could not load active partitions: %v", err) + return + } + + activeList := make([]*multiPartMessage, 0) + if err := json.Unmarshal(obj.Data, &activeList); err != nil { + jww.FATAL.Panicf("Failed to "+ + "unmarshal active partitions: %v", err) + } + jww.INFO.Printf("loadActivePartitions found %d active", len(activeList)) + + for _, activeMpm := range activeList { + mpm := loadOrCreateMultiPartMessage(activeMpm.Sender, activeMpm.MessageID, s.kv) + s.activeParts[mpm] = true + } + +} + func getMultiPartID(partner *id.ID, messageID uint64) multiPartID { h, _ := blake2b.New256(nil) diff --git a/storage/partition/store_test.go b/storage/partition/store_test.go index 9de6327d989d032e6ed987db0aff891d6be0fa3b..4e3d221a159be0f1fd73664c1d6d6a9e7b5097aa 100644 --- a/storage/partition/store_test.go +++ b/storage/partition/store_test.go @@ -22,8 +22,9 @@ import ( func TestNew(t *testing.T) { rootKv := versioned.NewKV(make(ekv.Memstore)) expectedStore := &Store{ - multiParts: make(map[multiPartID]*multiPartMessage), - kv: rootKv.Prefix(packagePrefix), + multiParts: make(map[multiPartID]*multiPartMessage), + activeParts: make(map[*multiPartMessage]bool), + kv: rootKv.Prefix(packagePrefix), } store := New(rootKv) @@ -40,7 +41,7 @@ func TestStore_AddFirst(t *testing.T) { s := New(versioned.NewKV(ekv.Memstore{})) msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), - message.Text, 5, 0, 1, netTime.Now(), part, + message.Text, 5, 0, 1, netTime.Now(), netTime.Now(), part, []byte{0}) if !complete { @@ -60,7 +61,7 @@ func TestStore_Add(t *testing.T) { s := New(versioned.NewKV(ekv.Memstore{})) msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), - message.Text, 5, 0, 2, netTime.Now(), part1, + message.Text, 5, 0, 2, netTime.Now(), netTime.Now(), part1, []byte{0}) if complete { @@ -79,3 +80,44 @@ func TestStore_Add(t *testing.T) { "\n\texpected: %v\n\treceived: %v", part, msg.Payload) } } + +// Unit test of prune +func TestStore_ClearMessages(t *testing.T) { + // Setup: Add 2 message to store: an old message past the threshold and a new message + part1 := []byte("Test message.") + part2 := []byte("Second Sentence.") + s := New(versioned.NewKV(ekv.Memstore{})) + + partner1 := id.NewIdFromString("User", id.User, t) + messageId1 := uint64(5) + oldTimestamp := netTime.Now().Add(-2 * clearPartitionThreshold) + s.AddFirst(partner1, + message.Text, messageId1, 0, 2, netTime.Now(), + oldTimestamp, part1, + []byte{0}) + s.Add(partner1, messageId1, 1, part2, []byte{0}) + + partner2 := id.NewIdFromString("User1", id.User, t) + messageId2 := uint64(6) + newTimestamp := netTime.Now() + s.AddFirst(partner2, message.Text, messageId2, 0, 2, netTime.Now(), + newTimestamp, part1, + []byte{0}) + + // Call clear messages + s.prune() + + // Check if old message cleared + mpmId := getMultiPartID(partner1, messageId1) + if _, ok := s.multiParts[mpmId]; ok { + t.Errorf("Prune error: " + + "Expected old message to be cleared out of store") + } + + // Check if new message remains + mpmId2 := getMultiPartID(partner2, messageId2) + if _, ok := s.multiParts[mpmId2]; !ok { + t.Errorf("Prune error: " + + "Expected new message to be remain in store") + } +} diff --git a/storage/session.go b/storage/session.go index 3c4c1932baf747b080a5272b3702876abb57c652..e42cad445594e30d7b85eafa688d90b80d4d62ed 100644 --- a/storage/session.go +++ b/storage/session.go @@ -220,7 +220,7 @@ func Load(baseDir, password string, currentVersion version.Version, } s.conversations = conversation.NewStore(s.kv) - s.partition = partition.New(s.kv) + s.partition = partition.Load(s.kv) s.reception = reception.LoadStore(s.kv) diff --git a/storage/user.go b/storage/user.go index a236f22d35e618d77c75277c9ece5999712832a3..975b574a2e9678a31eff7f0598b396ab6427a6af 100644 --- a/storage/user.go +++ b/storage/user.go @@ -14,18 +14,18 @@ func (s *Session) GetUser() user.User { defer s.mux.RUnlock() ci := s.user.GetCryptographicIdentity() return user.User{ - TransmissionID: ci.GetTransmissionID().DeepCopy(), - TransmissionSalt: copySlice(ci.GetTransmissionSalt()), - TransmissionRSA: ci.GetReceptionRSA(), - ReceptionID: ci.GetReceptionID().DeepCopy(), + TransmissionID: ci.GetTransmissionID().DeepCopy(), + TransmissionSalt: copySlice(ci.GetTransmissionSalt()), + TransmissionRSA: ci.GetReceptionRSA(), + ReceptionID: ci.GetReceptionID().DeepCopy(), RegistrationTimestamp: s.user.GetRegistrationTimestamp(), - ReceptionSalt: copySlice(ci.GetReceptionSalt()), - ReceptionRSA: ci.GetReceptionRSA(), - Precanned: ci.IsPrecanned(), - CmixDhPrivateKey: s.cmix.GetDHPrivateKey().DeepCopy(), - CmixDhPublicKey: s.cmix.GetDHPublicKey().DeepCopy(), - E2eDhPrivateKey: s.e2e.GetDHPrivateKey().DeepCopy(), - E2eDhPublicKey: s.e2e.GetDHPublicKey().DeepCopy(), + ReceptionSalt: copySlice(ci.GetReceptionSalt()), + ReceptionRSA: ci.GetReceptionRSA(), + Precanned: ci.IsPrecanned(), + CmixDhPrivateKey: s.cmix.GetDHPrivateKey().DeepCopy(), + CmixDhPublicKey: s.cmix.GetDHPublicKey().DeepCopy(), + E2eDhPrivateKey: s.e2e.GetDHPrivateKey().DeepCopy(), + E2eDhPublicKey: s.e2e.GetDHPublicKey().DeepCopy(), } } diff --git a/storage/utility/dh.go b/storage/utility/dh.go index 9b0280ed1ef4bd96e71d15fcc788b5633c51fe03..6295e446d3563127c4c1262733eb3abf8ac8b91e 100644 --- a/storage/utility/dh.go +++ b/storage/utility/dh.go @@ -42,3 +42,8 @@ func LoadCyclicKey(kv *versioned.KV, key string) (*cyclic.Int, error) { return cy, cy.GobDecode(vo.Data) } + +// DeleteCyclicKey deletes a given cyclic key from storage +func DeleteCyclicKey(kv *versioned.KV, key string) error { + return kv.Delete(key, currentCyclicVersion) +} diff --git a/storage/utility/dh_test.go b/storage/utility/dh_test.go index 4d4a31941faee3467f029ffca4dbc57f8fa9dafe..36fb3c5734af6ea7bd29479279f01b10522b803d 100644 --- a/storage/utility/dh_test.go +++ b/storage/utility/dh_test.go @@ -47,3 +47,27 @@ func TestLoadCyclicKey(t *testing.T) { t.Errorf("Stored int did not match received. Stored: %v, Received: %v", x, loaded) } } + +// Unit test for DeleteCyclicKey +func TestDeleteCyclicKey(t *testing.T) { + kv := make(ekv.Memstore) + vkv := versioned.NewKV(kv) + grp := getTestGroup() + x := grp.NewInt(77) + + intKey := "testKey" + err := StoreCyclicKey(vkv, x, intKey) + if err != nil { + t.Errorf("Failed to store cyclic key: %+v", err) + } + + err = DeleteCyclicKey(vkv, intKey) + if err != nil { + t.Fatalf("DeleteCyclicKey returned an error: %v", err) + } + + _, err = LoadCyclicKey(vkv, intKey) + if err == nil { + t.Errorf("DeleteCyclicKey error: Should not load deleted key: %+v", err) + } +} diff --git a/ud/manager.go b/ud/manager.go index fecafbd904fbad0ed4e1b82c58bbbff3ef2e157e..1b80b1ad22bcb07fb94a5944a78000c2ef56f45d 100644 --- a/ud/manager.go +++ b/ud/manager.go @@ -15,6 +15,7 @@ import ( "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" + "math" "time" ) @@ -89,6 +90,8 @@ func NewManager(client *api.Client, single *single.Manager) (*Manager, error) { // Create the user discovery host object hp := connect.GetDefaultHostParams() + // Client will not send KeepAlive packets + hp.KaClientOpts.Time = time.Duration(math.MaxInt64) hp.MaxRetries = 3 hp.SendTimeout = 3 * time.Second m.host, err = m.comms.AddHost(&id.UDB, def.UDB.Address, []byte(def.UDB.Cert), hp) diff --git a/ud/register.go b/ud/register.go index c2dd6a0adc1db8f9e61495c9b989309657f6d891..b46f99a09fd6e686c2293b35a54147d7292d58cb 100644 --- a/ud/register.go +++ b/ud/register.go @@ -48,7 +48,7 @@ func (m *Manager) register(username string, comm registerUserComms) error { DhPubKey: m.storage.E2e().GetDHPublicKey().Bytes(), Salt: cryptoUser.GetReceptionSalt(), }, - UID: cryptoUser.GetReceptionID().Marshal(), + UID: cryptoUser.GetReceptionID().Marshal(), Timestamp: user.GetRegistrationTimestamp().UnixNano(), }