diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go index 01d486c577d8c50752f19e706511fd71455eaba7..a9125a0306b5f4bcbb0229320dd495c25bffb103 100644 --- a/api/authenticatedChannel.go +++ b/api/authenticatedChannel.go @@ -7,6 +7,7 @@ import ( "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/contact" "gitlab.com/elixxir/client/storage/e2e" + "gitlab.com/elixxir/primitives/fact" "gitlab.com/xx_network/primitives/id" ) @@ -110,6 +111,6 @@ func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact { ID: precanned.ID, DhPubKey: partnerPubKey, OwnershipProof: nil, - Facts: make([]contact.Fact, 0), + Facts: make([]fact.Fact, 0), } } \ No newline at end of file diff --git a/api/version.go b/api/version.go index d8a8e2a056308b8a6f02f3b20f37bf68fa37d339..30ddb01b686346e1f3d28442ded20f2ad3ab6294 100644 --- a/api/version.go +++ b/api/version.go @@ -32,7 +32,7 @@ func (c *Client) checkVersion() error { "\tClient: %s", netVersion.String(), clientVersion.String()) } } else { - jww.WARN.Printf("Network requires no minnimim version") + jww.INFO.Printf("Network requires no minimum version") } return nil diff --git a/auth/callback.go b/auth/callback.go index f7c522e3d22911a835f9ef2694cfea717a182743..060d74030f73fdf7e91e23827635b3ec3e8dfcd0 100644 --- a/auth/callback.go +++ b/auth/callback.go @@ -9,7 +9,9 @@ import ( "gitlab.com/elixxir/client/storage/auth" "gitlab.com/elixxir/client/storage/e2e" "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/diffieHellman" cAuth "gitlab.com/elixxir/crypto/e2e/auth" + "gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/format" "strings" ) @@ -28,11 +30,13 @@ func (m *Manager) StartProcessies() stoppable.Stoppable { //lookup the message, check if it is an auth request cmixMsg := format.Unmarshal(msg.Payload) fp := cmixMsg.GetKeyFP() + jww.INFO.Printf("RAW AUTH FP: %v", fp) // this takes the request lock if it is a specific fp, // all exits after this need to call fail or Delete if it is // specific fpType, sr, myHistoricalPrivKey, err := authStore.GetFingerprint(fp) if err != nil { + jww.INFO.Printf("FINGERPRINT FAILURE: %s", err.Error()) // if the lookup fails, ignore the message. It is likely // garbled or for a different protocol break @@ -64,6 +68,11 @@ func (m *Manager) handleRequest(cmixMsg format.Message, return } + myPubKey := diffieHellman.GeneratePublicKey(myHistoricalPrivKey, grp) + + jww.INFO.Printf("handleRequest MYPUBKEY: %v", myPubKey.Bytes()) + jww.INFO.Printf("handleRequest PARTNERPUBKEY: %v", partnerPubKey.Bytes()) + //decrypt the message success, payload := cAuth.Decrypt(myHistoricalPrivKey, partnerPubKey, baseFmt.GetSalt(), baseFmt.GetEcrPayload(), @@ -112,7 +121,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, //check if the relationship already exists, rType, sr2, _, err := m.storage.Auth().GetRequest(partnerID) if err != nil && !strings.Contains(err.Error(), auth.NoRequest) { - // if another error is recieved, print it and exist + // if another error is recieved, print it and exit jww.WARN.Printf("Recieved new Auth request for %s, "+ "internal lookup produced bad result: %+v", partnerID, err) @@ -140,7 +149,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, } //process the inner payload - facts, msg, err := contact.UnstringifyFactList( + facts, msg, err := fact.UnstringifyFactList( string(requestFmt.msgPayload)) if err != nil { jww.WARN.Printf("failed to parse facts and message "+ @@ -193,6 +202,9 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, return } + jww.INFO.Printf("handleConfirm PARTNERPUBKEY: %v", partnerPubKey.Bytes()) + jww.INFO.Printf("handleConfirm SRMYPUBKEY: %v", sr.GetMyPubKey().Bytes()) + // decrypt the payload success, payload := cAuth.Decrypt(sr.GetMyPrivKey(), partnerPubKey, baseFmt.GetSalt(), baseFmt.GetEcrPayload(), @@ -253,7 +265,7 @@ func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group, ID: sr.GetPartner().DeepCopy(), DhPubKey: partnerPubKey.DeepCopy(), OwnershipProof: copySlice(ownershipProof), - Facts: make([]contact.Fact, 0), + Facts: make([]fact.Fact, 0), } // fixme: if a crash occurs before or during the calls, the notification @@ -291,4 +303,4 @@ func handleBaseFormat(cmixMsg format.Message, grp *cyclic.Group) (baseFormat, } partnerPubKey := grp.NewIntFromBytes(baseFmt.pubkey) return baseFmt, partnerPubKey, nil -} \ No newline at end of file +} diff --git a/auth/callbacks.go b/auth/callbacks.go index ab6a2ead168f2ba363373371e6d9c43a61707cb0..6eb758af2a1aad2030387e238ca6ca8f98d1958d 100644 --- a/auth/callbacks.go +++ b/auth/callbacks.go @@ -63,7 +63,7 @@ func (cm *callbackMap) Get(id *id.ID) []interface{} { if specific, ok := cm.specificCallback[*id]; ok { cbList = append(cbList, specific) } else { - cbList = append(cbList, cm.generalCallback) + cbList = append(cbList, cm.generalCallback...) } return cbList diff --git a/auth/confirm.go b/auth/confirm.go index 57b230e171fe1356aa048a23b3ada37bdff0944e..2ffa7a979f3c547c16928c08ca692eab85fda8bd 100644 --- a/auth/confirm.go +++ b/auth/confirm.go @@ -79,7 +79,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, //encrypt the payload ecrPayload, mac := cAuth.Encrypt(newPrivKey, partner.DhPubKey, - salt, ecrFmt.payload, grp) + salt, ecrFmt.data, grp) //get the fingerprint from the old ownership proof fp := cAuth.MakeOwnershipProofFP(storedContact.OwnershipProof) @@ -92,6 +92,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, cmixMsg.SetKeyFP(fp) cmixMsg.SetMac(mac) cmixMsg.SetContents(baseFmt.Marshal()) + cmixMsg.SetRecipientID(partner.ID) // fixme: channel can get into a bricked state if the first save occurs and // the second does not or the two occur and the storage into critical @@ -123,7 +124,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, if err != nil { // if the send fails just set it to failed, it will but automatically // retried - jww.ERROR.Printf("request failed to transmit, will be "+ + jww.ERROR.Printf("auth confirm failed to transmit, will be "+ "handled on reconnect: %+v", err) storage.GetCriticalRawMessages().Failed(cmixMsg) } @@ -137,7 +138,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, success, _, _ := utility.TrackResults(sendResults, 1) if !success { - jww.ERROR.Printf("request failed to transmit, will be " + + jww.ERROR.Printf("auth confirm failed to transmit, will be " + "handled on reconnect") storage.GetCriticalRawMessages().Failed(cmixMsg) } else { diff --git a/auth/fmt.go b/auth/fmt.go index 5ee0c4874a28a63edbd0b66f74fed704ec3d5797..04605c95772077de79b2392763330991424e7335 100644 --- a/auth/fmt.go +++ b/auth/fmt.go @@ -177,7 +177,7 @@ func newRequestFormat(ecrFmt ecrFormat) (requestFormat, error) { } rf.id = rf.payload[:id.ArrIDLen] - rf.id = rf.payload[id.ArrIDLen:] + rf.msgPayload = rf.payload[id.ArrIDLen:] return rf, nil } diff --git a/auth/manager.go b/auth/manager.go index 4fbfd6bed3ae20db24badf4ff76fb3f8533a61d2..16222cbbb65aa2ee38106a18d0e3635330189eec 100644 --- a/auth/manager.go +++ b/auth/manager.go @@ -4,6 +4,7 @@ import ( "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/switchboard" "gitlab.com/xx_network/primitives/id" ) @@ -27,7 +28,7 @@ func NewManager(sw interfaces.Switchboard, storage *storage.Session, net: net, } - sw.RegisterChannel("Auth", &id.ID{}, message.Raw, m.rawMessages) + sw.RegisterChannel("Auth", switchboard.AnyUser(), message.Raw, m.rawMessages) return m } diff --git a/auth/request.go b/auth/request.go index ba231d297821e97f3e06c819bb109867cd585078..ff2811c493a4be0df86c72df69e21241a1dab1e7 100644 --- a/auth/request.go +++ b/auth/request.go @@ -1,8 +1,8 @@ package auth import ( - ds "gitlab.com/elixxir/comms/network/dataStructures" "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/contact" "gitlab.com/elixxir/client/interfaces/params" @@ -10,6 +10,7 @@ import ( "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage/auth" "gitlab.com/elixxir/client/storage/e2e" + ds "gitlab.com/elixxir/comms/network/dataStructures" "gitlab.com/elixxir/crypto/diffieHellman" cAuth "gitlab.com/elixxir/crypto/e2e/auth" "gitlab.com/elixxir/primitives/format" @@ -17,10 +18,9 @@ import ( "io" "strings" "time" - jww "github.com/spf13/jwalterweatherman" ) -const eol = string(0x0a) +const terminator = ";" func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, storage *storage.Session, net interfaces.NetworkManager) error { @@ -46,21 +46,25 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, } // check that the message is properly formed - if strings.Contains(message, eol) { - return errors.Errorf("Message cannot contain 'EOL'") + if strings.Contains(message, terminator) { + return errors.Errorf("Message cannot contain '%s'", terminator) } //lookup if an ongoing request is occurring rqType, _, _, err := storage.Auth().GetRequest(partner.ID) - if err != nil && !strings.Contains(err.Error(), auth.NoRequest) { - return errors.WithMessage(err, "Error on lookup of potential "+ - "existing request") - } else if rqType == auth.Receive { - return errors.WithMessage(err, "Cannot send a request after"+ - "receiving a request") - } else if rqType == auth.Sent { - return errors.WithMessage(err, "Cannot send a request after"+ - "already sending one") + if err != nil && strings.Contains(err.Error(), auth.NoRequest) { + err = nil + } + if err != nil { + if rqType == auth.Receive { + return errors.WithMessage(err, + "Cannot send a request after "+ + "receiving a request") + } else if rqType == auth.Sent { + return errors.WithMessage(err, + "Cannot send a request after "+ + "already sending one") + } } grp := storage.E2e().GetGroup() @@ -76,7 +80,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, //check the payload fits facts := me.Facts.Stringify() - msgPayload := facts + message + eol + msgPayload := facts + message + terminator msgPayloadBytes := []byte(msgPayload) if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() { @@ -101,28 +105,34 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, newPrivKey := diffieHellman.GeneratePrivateKey(256, grp, rng) newPubKey := diffieHellman.GeneratePublicKey(newPrivKey, grp) + jww.INFO.Printf("RequestAuth MYPUBKEY: %v", newPubKey.Bytes()) + jww.INFO.Printf("RequestAuth THEIRPUBKEY: %v", partner.DhPubKey.Bytes()) + /*encrypt payload*/ requestFmt.SetID(storage.GetUser().ID) requestFmt.SetMsgPayload(msgPayloadBytes) ecrFmt.SetOwnership(ownership) ecrPayload, mac := cAuth.Encrypt(newPrivKey, partner.DhPubKey, - salt, ecrFmt.payload, grp) - fp := cAuth.MakeOwnershipProofFP(ownership) + salt, ecrFmt.data, grp) + confirmFp := cAuth.MakeOwnershipProofFP(ownership) + requestfp := cAuth.MakeRequestFingerprint(partner.DhPubKey) /*construct message*/ baseFmt.SetEcrPayload(ecrPayload) baseFmt.SetSalt(salt) baseFmt.SetPubKey(newPubKey) - cmixMsg.SetKeyFP(fp) + cmixMsg.SetKeyFP(requestfp) cmixMsg.SetMac(mac) cmixMsg.SetContents(baseFmt.Marshal()) + cmixMsg.SetRecipientID(partner.ID) + jww.INFO.Printf("PARTNER ID: %s", partner.ID) /*store state*/ //fixme: channel is bricked if the first store succedes but the second fails //store the in progress auth err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey, - newPrivKey, fp) + newPrivKey, confirmFp) if err != nil { return errors.Errorf("Failed to store auth request: %s", err) } @@ -130,12 +140,17 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, //store the message as a critical message so it will always be sent storage.GetCriticalRawMessages().AddProcessing(cmixMsg) + //jww.INFO.Printf("CMIX MESSAGE 1: %s, %v, %v, %v", cmixMsg.GetRecipientID(), + // cmixMsg.GetKeyFP(), cmixMsg.GetMac(), cmixMsg.GetContents()) + jww.INFO.Printf("CMIX MESSAGE FP: %s, %v", cmixMsg.GetRecipientID(), + cmixMsg.GetKeyFP()) + /*send message*/ round, err := net.SendCMIX(cmixMsg, params.GetDefaultCMIX()) if err != nil { // if the send fails just set it to failed, it will but automatically // retried - jww.ERROR.Printf("request failed to transmit, will be "+ + jww.ERROR.Printf("auth request failed to transmit, will be "+ "handled on reconnect: %+v", err) storage.GetCriticalRawMessages().Failed(cmixMsg) } @@ -149,7 +164,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, success, _, _ := utility.TrackResults(sendResults, 1) if !success { - jww.ERROR.Printf("request failed to transmit, will be " + + jww.ERROR.Printf("auth request failed to transmit, will be " + "handled on reconnect") storage.GetCriticalRawMessages().Failed(cmixMsg) } else { diff --git a/bindings/contact.go b/bindings/contact.go index 012eada71c84fc1a196cfc95acb24268b6a2f8f9..2bcc1d2b9c627a27ef0f091709fb4d458efe669e 100644 --- a/bindings/contact.go +++ b/bindings/contact.go @@ -3,11 +3,12 @@ package bindings import ( "errors" "gitlab.com/elixxir/client/interfaces/contact" + "gitlab.com/elixxir/primitives/fact" ) /* fact object*/ type Fact struct { - f *contact.Fact + f *fact.Fact } func (f *Fact) Get() string { @@ -61,13 +62,13 @@ func (fl *FactList) Get(i int) Fact { return Fact{f: &(fl.c.Facts)[i]} } -func (fl *FactList) Add(fact string, factType int) error { - ft := contact.FactType(factType) +func (fl *FactList) Add(factData string, factType int) error { + ft := fact.FactType(factType) if !ft.IsValid() { return errors.New("Invalid fact type") } - fl.c.Facts = append(fl.c.Facts, contact.Fact{ - Fact: fact, + fl.c.Facts = append(fl.c.Facts, fact.Fact{ + Fact: factData, T: ft, }) return nil diff --git a/cmd/root.go b/cmd/root.go index d20a4845d2e4f8e875f7b74a87e7d3b4dbeab5f6..eef8d776d18f773bf9e97b78c38aabe99437edd6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,6 +16,7 @@ import ( jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" "gitlab.com/elixxir/client/api" + "gitlab.com/elixxir/client/interfaces/contact" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/interfaces/params" "gitlab.com/elixxir/client/switchboard" @@ -37,62 +38,6 @@ func Execute() { } } -// func setKeyParams(client *api.Client) { -// jww.DEBUG.Printf("Trying to parse key parameters...") -// minKeys, err := strconv.Atoi(keyParams[0]) -// if err != nil { -// return -// } - -// maxKeys, err := strconv.Atoi(keyParams[1]) -// if err != nil { -// return -// } - -// numRekeys, err := strconv.Atoi(keyParams[2]) -// if err != nil { -// return -// } - -// ttlScalar, err := strconv.ParseFloat(keyParams[3], 64) -// if err != nil { -// return -// } - -// minNumKeys, err := strconv.Atoi(keyParams[4]) -// if err != nil { -// return -// } - -// jww.DEBUG.Printf("Setting key generation parameters: %d, %d, %d, %f, %d", -// minKeys, maxKeys, numRekeys, ttlScalar, minNumKeys) - -// params := client.GetKeyParams() -// params.MinKeys = uint16(minKeys) -// params.MaxKeys = uint16(maxKeys) -// params.NumRekeys = uint16(numRekeys) -// params.TTLScalar = ttlScalar -// params.MinNumKeys = uint16(minNumKeys) -// } - -// type userSearcher struct { -// foundUserChan chan []byte -// } - -// func newUserSearcher() api.SearchCallback { -// us := userSearcher{} -// us.foundUserChan = make(chan []byte) -// return &us -// } - -// func (us *userSearcher) Callback(userID, pubKey []byte, err error) { -// if err != nil { -// jww.ERROR.Printf("Could not find searched user: %+v", err) -// } else { -// us.foundUserChan <- userID -// } -// } - // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "client", @@ -137,6 +82,7 @@ var rootCmd = &cobra.Command{ user := client.GetUser() jww.INFO.Printf("User: %s", user.ID) + writeContact(user.GetContact()) // Set up reception handler swboard := client.GetSwitchboard() @@ -145,6 +91,24 @@ var rootCmd = &cobra.Command{ switchboard.AnyUser(), message.Text, recvCh) jww.INFO.Printf("Message ListenerID: %v", listenerID) + // Set up auth request handler, which simply prints the + // user id of the requestor. + authMgr := client.GetAuthRegistrar() + authMgr.AddGeneralRequestCallback(printChanRequest) + + // If unsafe channels, add auto-acceptor + if viper.GetBool("unsafe-channel-creation") { + authMgr.AddGeneralRequestCallback(func( + requestor contact.Contact, message string) { + jww.INFO.Printf("Got Request: %s", requestor.ID) + err := client.ConfirmAuthenticatedChannel( + requestor) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + }) + } + err = client.StartNetworkFollower() if err != nil { jww.FATAL.Panicf("%+v", err) @@ -157,19 +121,36 @@ var rootCmd = &cobra.Command{ // Send Messages msgBody := viper.GetString("message") - recipientID, isPrecanPartner := parseRecipient( - viper.GetString("destid")) - // Send unsafe messages or not? - unsafe := viper.GetBool("unsafe") - if !unsafe { - addAuthenticatedChannel(client, recipientID, - isPrecanPartner) + isPrecanPartner := false + recipientContact := readContact() + recipientID := recipientContact.ID + + // Try to get recipientID from destid + if recipientID == nil { + recipientID, isPrecanPartner = parseRecipient( + viper.GetString("destid")) } + // Set it to myself if recipientID == nil { jww.INFO.Printf("sending message to self") recipientID = user.ID + recipientContact = user.GetContact() + } + + time.Sleep(10 * time.Second) + + // Accept auth request for this recipient + if viper.GetBool("accept-channel") { + acceptChannel(client, recipientID) + } + + // Send unsafe messages or not? + unsafe := viper.GetBool("unsafe") + if !unsafe { + addAuthenticatedChannel(client, recipientID, + recipientContact, isPrecanPartner) } msg := message.Send{ @@ -215,6 +196,7 @@ var rootCmd = &cobra.Command{ case m := <-recvCh: fmt.Printf("Message received: %s\n", string( m.Payload)) + //fmt.Printf("%s", m.Timestamp) receiveCnt++ if receiveCnt == expectedCnt { done = true @@ -226,8 +208,62 @@ var rootCmd = &cobra.Command{ }, } +func writeContact(c contact.Contact) { + outfilePath := viper.GetString("writeContact") + if outfilePath == "" { + return + } + cBytes, err := c.Marshal() + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + err = ioutil.WriteFile(outfilePath, cBytes, 0644) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } +} + +func readContact() contact.Contact { + inputFilePath := viper.GetString("destfile") + if inputFilePath == "" { + return contact.Contact{} + } + data, err := ioutil.ReadFile(inputFilePath) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + c, err := contact.Unmarshal(data) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + return c +} + +func acceptChannel(client *api.Client, recipientID *id.ID) { + recipientContact, err := client.GetAuthenticatedChannelRequest( + recipientID) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + err = client.ConfirmAuthenticatedChannel( + recipientContact) + 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) + jww.INFO.Printf(msg) + fmt.Printf(msg) + msg = fmt.Sprintf("Authentication channel request message: %s", message) + jww.INFO.Printf(msg) + fmt.Printf(msg) +} + func addAuthenticatedChannel(client *api.Client, recipientID *id.ID, - isPrecanPartner bool) { + recipient contact.Contact, isPrecanPartner bool) { if client.HasAuthenticatedChannel(recipientID) { jww.INFO.Printf("Authenticated channel already in place for %s", recipientID) @@ -247,7 +283,22 @@ func addAuthenticatedChannel(client *api.Client, recipientID *id.ID, jww.FATAL.Panicf("User did not allow channel creation!") } - msg := fmt.Sprintf("Adding authenticated channel for: %s\n", + // Check if a channel exists for this recipientID + recipientContact, err := client.GetAuthenticatedChannelRequest( + recipientID) + if err == nil { + jww.INFO.Printf("Accepting existing channel request for %s", + recipientID) + err := client.ConfirmAuthenticatedChannel(recipientContact) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + return + } else { + recipientContact = recipient + } + + msg := fmt.Sprintf("Adding authenticated channel for: %s", recipientID) jww.INFO.Printf(msg) fmt.Printf(msg) @@ -269,8 +320,18 @@ func addAuthenticatedChannel(client *api.Client, recipientID *id.ID, preBytes, idBytes) } } + } else if recipientContact.ID != nil && recipientContact.DhPubKey != nil { + me := client.GetUser().GetContact() + jww.INFO.Printf("Requesting auth channel from: %s", + recipientID) + err := client.RequestAuthenticatedChannel(recipientContact, + me, msg) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } } else { - jww.FATAL.Panicf("e2e unimplemented") + jww.ERROR.Printf("Could not add auth channel for %s", + recipientID) } } @@ -282,7 +343,7 @@ func waitUntilConnected(connected chan bool) { for !isConnected { select { case isConnected = <-connected: - jww.INFO.Printf("health status: %v\n", + jww.INFO.Printf("Network Status: %v\n", isConnected) break case <-timeoutTimer.C: @@ -300,7 +361,7 @@ func waitUntilConnected(connected chan bool) { if isConnected != prev { prev = isConnected jww.INFO.Printf( - "health status changed: %v\n", + "Network Status Changed: %v\n", isConnected) } break @@ -461,6 +522,10 @@ func init() { "client storage") viper.BindPFlag("session", rootCmd.Flags().Lookup("session")) + rootCmd.Flags().StringP("writeContact", "w", + "", "Write the contact file for this user to this file") + viper.BindPFlag("writeContact", rootCmd.Flags().Lookup("writeContact")) + rootCmd.Flags().StringP("password", "p", "", "Password to the session file") viper.BindPFlag("password", rootCmd.Flags().Lookup("password")) @@ -489,6 +554,10 @@ func init() { "'0x' or 'b64:' for hex and base64 representations)") viper.BindPFlag("destid", rootCmd.Flags().Lookup("destid")) + rootCmd.Flags().StringP("destfile", "", + "", "Read this contact file for the destination id") + viper.BindPFlag("destfile", rootCmd.Flags().Lookup("destfile")) + rootCmd.Flags().UintP("sendCount", "", 1, "The number of times to send the message") viper.BindPFlag("sendCount", rootCmd.Flags().Lookup("sendCount")) @@ -510,11 +579,15 @@ func init() { rootCmd.Flags().BoolP("unsafe-channel-creation", "", false, "Turns off the user identity authenticated channel check, "+ - "which prompts the user to answer yes or no "+ - "to approve authenticated channels") + "automatically approving authenticated channels") viper.BindPFlag("unsafe-channel-creation", rootCmd.Flags().Lookup("unsafe-channel-creation")) + rootCmd.Flags().BoolP("accept-channel", "", false, + "Accept the channel request for the corresponding recipient ID") + viper.BindPFlag("accept-channel", + rootCmd.Flags().Lookup("accept-channel")) + // Cobra also supports local flags, which will only run // when this action is called directly. // rootCmd.Flags().StringVarP(¬ificationToken, "nbRegistration", "x", "", diff --git a/go.mod b/go.mod index 80036c5f95502d32484917358f32ef83f915f415..84ed766a410405b2465dc08a5aac8068b2034814 100644 --- a/go.mod +++ b/go.mod @@ -17,13 +17,14 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 - gitlab.com/elixxir/comms v0.0.4-0.20201116233755-b476dea10095 - gitlab.com/elixxir/crypto v0.0.5-0.20201110193609-6b5e881867b4 + gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 + gitlab.com/elixxir/comms v0.0.3 + gitlab.com/elixxir/crypto v0.0.5-0.20201109234712-7e64de16970d gitlab.com/elixxir/ekv v0.1.3 gitlab.com/elixxir/primitives v0.0.3-0.20201116174806-97f190989704 - gitlab.com/xx_network/comms v0.0.4-0.20201110022115-4a6171cad07d + gitlab.com/xx_network/comms v0.0.3 gitlab.com/xx_network/crypto v0.0.4 - gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c + gitlab.com/xx_network/primitives v0.0.2 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 google.golang.org/protobuf v1.25.0 gopkg.in/ini.v1 v1.61.0 // indirect diff --git a/go.sum b/go.sum index cee607cb4a69b94fd55e8494a2d575e567810cbd..5e5de048d2a894d2bb57d6dcccd3d2cbc5501294 100644 --- a/go.sum +++ b/go.sum @@ -250,24 +250,18 @@ github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05 h1:4pW5fMvVkrgkMXdvIsVRR github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05/go.mod h1:Gr+78ptB0MwXxm//LBaEvBiaXY7hXJ6KGe2V32X2F6E= 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/comms v0.0.4-0.20201103220934-c476c9282f30 h1:9q+xVbu5m7XDvT1CVz8s1S/SOVpasWJOx7V/3rAY/pE= -gitlab.com/elixxir/comms v0.0.4-0.20201103220934-c476c9282f30/go.mod h1:5p7oz4yFrK037rPap6ooaWrloJrzuVZ4jnzOdvgyqnU= -gitlab.com/elixxir/comms v0.0.4-0.20201111205457-b073b28c367a h1:GnZLdgn5ZSDtPFsiCUPgqQk2D+e7LmzVOZ9Rq/B8hCY= -gitlab.com/elixxir/comms v0.0.4-0.20201111205457-b073b28c367a/go.mod h1:5p7oz4yFrK037rPap6ooaWrloJrzuVZ4jnzOdvgyqnU= -gitlab.com/elixxir/comms v0.0.4-0.20201112000135-4147e270e129 h1:d4s9JGimUVmqdKlK4NhICayzWBUSM2XmKta821ZJTF0= -gitlab.com/elixxir/comms v0.0.4-0.20201112000135-4147e270e129/go.mod h1:5p7oz4yFrK037rPap6ooaWrloJrzuVZ4jnzOdvgyqnU= -gitlab.com/elixxir/comms v0.0.4-0.20201116233755-b476dea10095 h1:YptJAYLxqy5CAJIcM9kOwfxmJ2D2A8uXWTT8rgXYG+E= -gitlab.com/elixxir/comms v0.0.4-0.20201116233755-b476dea10095/go.mod h1:spFKl7jsMy8M6NDvhJ27IJ+CnZ/07JHJCYpYsG8JQ4o= +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.3 h1:7cFvBZddX/8JSY5MvfPpg21niV88IpeqQkoKs15erZM= +gitlab.com/elixxir/comms v0.0.3/go.mod h1:5p7oz4yFrK037rPap6ooaWrloJrzuVZ4jnzOdvgyqnU= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3 h1:znCt/x2bL4y8czTPaaFkwzdgSgW3BJc/1+dxyf1jqVw= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/crypto v0.0.4 h1:8eWjvUepCU2PiqZM2NFYo6rFg1w8KWO1hMDwMNFEqoI= gitlab.com/elixxir/crypto v0.0.4/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= -gitlab.com/elixxir/crypto v0.0.5-0.20201109203841-ba162a25be6e h1:rkT8Pzjgo9oF3uS8ExHGNUQoJX/22qK3lU+vU8QsOCY= -gitlab.com/elixxir/crypto v0.0.5-0.20201109203841-ba162a25be6e/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= -gitlab.com/elixxir/crypto v0.0.5-0.20201110193609-6b5e881867b4 h1:1a1zZDuqZ56qU1EPgpc+Sqny1YFl0kAKJgQbsVc0WJQ= -gitlab.com/elixxir/crypto v0.0.5-0.20201110193609-6b5e881867b4/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= +gitlab.com/elixxir/crypto v0.0.5-0.20201109234712-7e64de16970d h1:9Peb/peftTVeO5gYqi37sZycMEiu05+2VZ/j8d5lldI= +gitlab.com/elixxir/crypto v0.0.5-0.20201109234712-7e64de16970d/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/ekv v0.1.3 h1:OE+LBMIhjGUMwc6hHJzYvEPNJQV7t1vMnJyIgxUMUo8= gitlab.com/elixxir/ekv v0.1.3/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= @@ -282,8 +276,6 @@ gitlab.com/elixxir/primitives v0.0.3-0.20201116174806-97f190989704/go.mod h1:3fx gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= gitlab.com/xx_network/comms v0.0.3 h1:ch1eJI4WXUE/Kz0Kp9uDWX16B+hfVFmdHY+EOai4Wzc= gitlab.com/xx_network/comms v0.0.3/go.mod h1:YViGbRj7FjJYoaO4NpALGEd9dK/l8uUT000FEBbUTL8= -gitlab.com/xx_network/comms v0.0.4-0.20201110022115-4a6171cad07d h1:wPsoqWNusbFJxvPB1Rvzu+TLZxth3G+ay8qkNrpAuzM= -gitlab.com/xx_network/comms v0.0.4-0.20201110022115-4a6171cad07d/go.mod h1:YViGbRj7FjJYoaO4NpALGEd9dK/l8uUT000FEBbUTL8= gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE= gitlab.com/xx_network/crypto v0.0.4 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= @@ -292,8 +284,6 @@ gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da h1:CCVslUwNC gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug= gitlab.com/xx_network/primitives v0.0.2 h1:r45yKenJ9e7PylI1ZXJ1Es09oYNaYXjxVy9+uYlwo7Y= gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= -gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c h1:mYId667WIN97E6KhPw4HDYyCjWzsG7gCM/HLTNTCXZQ= -gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0= gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/interfaces/contact/contact.go b/interfaces/contact/contact.go index 2579f7a0501c1e6633c81fe2a8f147b6ab73b024..6c6e070d055a093c71f796cf284ffc5558c71e17 100644 --- a/interfaces/contact/contact.go +++ b/interfaces/contact/contact.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/pkg/errors" "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/primitives/fact" "gitlab.com/xx_network/primitives/id" ) @@ -18,7 +19,7 @@ type Contact struct { ID *id.ID DhPubKey *cyclic.Int OwnershipProof []byte - Facts FactList + Facts fact.FactList } func (c Contact) Marshal() ([]byte, error) { diff --git a/interfaces/contact/fact.go b/interfaces/contact/fact.go deleted file mode 100644 index bc838160dc33f6952d9b21ab6de8af2fb5c03cad..0000000000000000000000000000000000000000 --- a/interfaces/contact/fact.go +++ /dev/null @@ -1,28 +0,0 @@ -package contact - -type Fact struct { - Fact string - T FactType -} - -func NewFact(ft FactType, fact string) (Fact, error) { - //todo: filter the fact string - return Fact{ - Fact: fact, - T: ft, - }, nil -} - -// marshal is for transmission for UDB, not a part of the fact interface -func (f Fact) Stringify() string { - return f.T.Stringify() + f.Fact -} - -func UnstringifyFact(s string) (Fact, error) { - ft, err := UnstringifyFactType(s) - if err != nil { - return Fact{}, err - } - - return NewFact(ft, s) -} diff --git a/interfaces/contact/factList.go b/interfaces/contact/factList.go deleted file mode 100644 index ad2b7c09627d530a9de0cb29f9b217bdf319d062..0000000000000000000000000000000000000000 --- a/interfaces/contact/factList.go +++ /dev/null @@ -1,43 +0,0 @@ -package contact - -import ( - "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" - "strings" -) - -type FactList []Fact - -func (fl FactList) Stringify() string { - stringList := make([]string, len(fl)) - for index, f := range fl { - stringList[index] = f.Stringify() - } - - return strings.Join(stringList, factDelimiter) + factBreak -} - -// unstrignifys facts followed by a facts break and with arbatrary data -// atttached at the end -func UnstringifyFactList(s string) ([]Fact, string, error) { - parts := strings.SplitN(s, factBreak, 1) - if len(parts) == 1{ - return nil, parts[0], nil - }else if len(parts) != 2 { - return nil, "", errors.New("Invalid fact string passed") - } - factStrings := strings.Split(parts[0], factDelimiter) - - var factList []Fact - for _, fString := range factStrings { - fact, err := UnstringifyFact(fString) - if err != nil { - jww.WARN.Printf("Fact failed to unstringify, dropped: %s", - err) - } else { - factList = append(factList, fact) - } - - } - return factList, parts[1], nil -} \ No newline at end of file diff --git a/interfaces/contact/type.go b/interfaces/contact/type.go deleted file mode 100644 index cc7263d5ffd0b4cc7714c3b18ecce674c8b31996..0000000000000000000000000000000000000000 --- a/interfaces/contact/type.go +++ /dev/null @@ -1,57 +0,0 @@ -package contact - -import ( - "fmt" - "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" -) - -type FactType uint8 - -const ( - Username FactType = 0 - Email FactType = 1 - Phone FactType = 2 -) - -func (t FactType) String() string { - switch t { - case Username: - return "Username" - case Email: - return "Email" - case Phone: - return "Phone" - default: - return fmt.Sprintf("Unknown Fact FactType: %d", t) - } -} - -func (t FactType) Stringify() string { - switch t { - case Username: - return "U" - case Email: - return "E" - case Phone: - return "P" - } - jww.FATAL.Panicf("Unknown Fact FactType: %d", t) - return "error" -} - -func UnstringifyFactType(s string) (FactType, error) { - switch s { - case "U": - return Username, nil - case "E": - return Email, nil - case "P": - return Phone, nil - } - return 3, errors.Errorf("Unknown Fact FactType: %s", s) -} - -func (t FactType) IsValid() bool { - return t == Username || t == Email || t == Phone -} diff --git a/interfaces/params/CMIX.go b/interfaces/params/CMIX.go index 0413b418ddd545319dc4ceb6f10d740a6c15b8ac..dc8658ea7a0d4b01c224ba071ffb96198ae17395 100644 --- a/interfaces/params/CMIX.go +++ b/interfaces/params/CMIX.go @@ -11,8 +11,8 @@ type CMIX struct { func GetDefaultCMIX() CMIX { return CMIX{ - RoundTries: 3, + RoundTries: 10, Timeout: 25 * time.Second, - RetryDelay: 2 * time.Second, + RetryDelay: 1 * time.Second, } } diff --git a/interfaces/params/CMIX_test.go b/interfaces/params/CMIX_test.go index 9b0a3bdffd9465a3181975632c9b4e939df443ae..5af967495b140e43fa102d2f1dd074192e1c8b96 100644 --- a/interfaces/params/CMIX_test.go +++ b/interfaces/params/CMIX_test.go @@ -7,7 +7,7 @@ import ( func TestGetDefaultCMIX(t *testing.T) { c := GetDefaultCMIX() - if c.RoundTries != 3 || c.Timeout != 25*time.Second { + if c.RoundTries != 10 || c.Timeout != 25*time.Second { t.Errorf("GetDefaultCMIX did not return expected values") } } diff --git a/interfaces/user/user.go b/interfaces/user/user.go index a4fdb7d86e6e6f82ed4b5572bf70d7f379554836..094f9386abcd5298ce9cb09da1ea8f378783d3f9 100644 --- a/interfaces/user/user.go +++ b/interfaces/user/user.go @@ -3,6 +3,7 @@ package user import ( "gitlab.com/elixxir/client/interfaces/contact" "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/primitives/fact" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" ) @@ -23,10 +24,10 @@ type User struct { E2eDhPublicKey *cyclic.Int } -func (u *User) GetContact() contact.Contact { +func (u User) GetContact() contact.Contact { return contact.Contact{ ID: u.ID.DeepCopy(), DhPubKey: u.E2eDhPublicKey, - Facts: make([]contact.Fact, 0), + Facts: make([]fact.Fact, 0), } -} \ No newline at end of file +} diff --git a/network/follow.go b/network/follow.go index ddb7cd96a1a4bea4b387f8981cf07ab5d469cb75..a52eff6923bb4d03ef09034608cdacbe783da807 100644 --- a/network/follow.go +++ b/network/follow.go @@ -24,16 +24,19 @@ package network import ( "gitlab.com/elixxir/client/network/gateway" //"gitlab.com/elixxir/client/storage" + jww "github.com/spf13/jwalterweatherman" + bloom "gitlab.com/elixxir/bloomfilter" + pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/primitives/knownRounds" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/csprng" - - jww "github.com/spf13/jwalterweatherman" - pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/xx_network/primitives/id" "time" ) +const bloomFilterSize = 71888 // In Bits +const bloomFilterHashes = 8 + //comms interface makes testing easier type followNetworkComms interface { GetHost(hostId *id.ID) (*connect.Host, bool) @@ -96,6 +99,20 @@ func (m *manager) follow(rng csprng.Source, comms followNetworkComms) { jww.ERROR.Printf("Failed to unmartial: %+v", err) return } + var filterList []*bloom.Ring + for _, f := range pollResp.BloomFilters { + jww.INFO.Printf("Bloom Filter received: %v", f) + filter, err := bloom.InitByParameters(bloomFilterSize, bloomFilterHashes) + if err != nil { + jww.FATAL.Panicf("Unable to create a bloom filter: %v", err) + } + if err := filter.UnmarshalBinary(f); err != nil { + jww.WARN.Printf("Failed to unmarshal filter: %+v", err) + continue + } + filterList = append(filterList, filter) + } + jww.INFO.Printf("Bloom filters found in response: %d", len(filterList)) // ---- Node Events ---- // NOTE: this updates the structure, AND sends events over the node @@ -130,7 +147,7 @@ func (m *manager) follow(rng csprng.Source, comms followNetworkComms) { // are messages waiting in rounds and then sends signals to the appropriate // handling threads roundChecker := func(rid id.Round) bool { - return m.round.Checker(rid) + return m.round.Checker(rid, filterList) } // get the bit vector of rounds that have been checked diff --git a/network/message/critical.go b/network/message/critical.go index 2720b84f41a2dd835d6a7db9bf585da4efb522e2..f4e7971de759a855af68834ab069c67e47edfc14 100644 --- a/network/message/critical.go +++ b/network/message/critical.go @@ -47,11 +47,12 @@ func (m *Manager) criticalMessages() { //if the message fail to send, notify the buffer so it can be handled //in the future and exit if err != nil { - jww.ERROR.Printf("Failed to send critical message on " + - "notification of healthy network") + jww.ERROR.Printf("Failed to send critical message on "+ + "notification of healthy network: %+v", err) critMsgs.Failed(msg) return } + jww.INFO.Printf("critical RoundIDs: %v", rounds) //wait on the results to make sure the rounds were sucesfull sendResults := make(chan ds.EventReturn, len(rounds)) roundEvents := m.Instance.GetRoundEvents() @@ -81,11 +82,13 @@ func (m *Manager) criticalMessages() { //if the message fail to send, notify the buffer so it can be handled //in the future and exit if err != nil { - jww.ERROR.Printf("Failed to send critical message on " + - "notification of healthy network") + jww.ERROR.Printf("Failed to send critical message on "+ + "notification of healthy network: %+v", err) critRawMsgs.Failed(msg) return } + jww.INFO.Printf("critical healthy RoundIDs: %v", round) + //wait on the results to make sure the rounds were sucesfull sendResults := make(chan ds.EventReturn, 1) roundEvents := m.Instance.GetRoundEvents() @@ -105,6 +108,4 @@ func (m *Manager) criticalMessages() { }(msg) } - - } diff --git a/network/message/handler.go b/network/message/handler.go index 8e3b34f30de7502844daebc01b057b62810802ac..9018e36f847d1fb5364f12d51e45f0a7c1e06353 100644 --- a/network/message/handler.go +++ b/network/message/handler.go @@ -72,6 +72,7 @@ func (m *Manager) handleMessage(ecrMsg format.Message) { Timestamp: time.Time{}, Encryption: message.None, } + jww.INFO.Printf("Garbled/RAW Message: %v", msg.GetKeyFP()) m.Session.GetGarbledMessages().Add(msg) m.Switchboard.Speak(raw) return diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index 25e93f33dda8d3e7b9060e68471baf9451c8dd86..162ff37ce868c5670dc727f9b3c0faad97a09894 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -8,12 +8,15 @@ import ( "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "strings" "time" ) +const sendTimeBuffer = uint64(100*time.Millisecond) + // WARNING: Potentially Unsafe // Payloads send are not End to End encrypted, MetaData is NOT protected with // this call, see SendE2E for End to End encryption and full privacy protection @@ -39,6 +42,13 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err //find the best round to send to, excluding attempted rounds bestRound, _ := m.Instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted) + if (bestRound.Timestamps[states.REALTIME]+sendTimeBuffer)> + uint64(time.Now().UnixNano()){ + jww.WARN.Println("Round received which has already started" + + " realtime") + continue + } + //build the topology idList, err := id.NewIDListFromBytes(bestRound.Topology) if err != nil { @@ -77,6 +87,7 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err return 0, errors.WithMessage(err, "Failed to generate "+ "salt, this should never happen") } + jww.INFO.Printf("RECIPIENTIDPRE_ENCRYPT: %s", msg.GetRecipientID()) encMsg, kmacs := roundKeys.Encrypt(msg, salt) //build the message payload diff --git a/network/rounds/check.go b/network/rounds/check.go index bfdf1579b6f7fe23b8efd17616ba1047ea30e735..d6ddf537e3f43b651d3615d78dce24cc0acfdeb0 100644 --- a/network/rounds/check.go +++ b/network/rounds/check.go @@ -1,7 +1,9 @@ package rounds import ( + "encoding/binary" jww "github.com/spf13/jwalterweatherman" + bloom "gitlab.com/elixxir/bloomfilter" "gitlab.com/xx_network/primitives/id" ) @@ -16,8 +18,8 @@ import ( // if the information about that round is already present, if it is the data is // sent to Message Retrieval Workers, otherwise it is sent to Historical Round // Retrieval -func (m *Manager) Checker(roundID id.Round) bool { - jww.INFO.Printf("Checking round ID: %d", roundID) +func (m *Manager) Checker(roundID id.Round, filters []*bloom.Ring) bool { + jww.DEBUG.Printf("Checker(roundID: %d)", roundID) // Set round to processing, if we can processing, count := m.p.Process(roundID) if !processing { @@ -34,19 +36,41 @@ func (m *Manager) Checker(roundID id.Round) bool { return true } - // TODO: Bloom filter lookup -- return true when we don't have + //check if the round is in the bloom filters + hasRound := false + serialRid := serializeRound(roundID) + + for _, filter := range filters { + hasRound = filter.Test(serialRid) + if hasRound { + break + } + } + + //if it is not present, set the round as checked + //that means no messages are available for the user in the round + if !hasRound { + m.p.Done(roundID) + return true + } // Go get the round from the round infos, if it exists ri, err := m.Instance.GetRound(roundID) if err != nil { - jww.INFO.Printf("Historical Round: %d", roundID) + jww.DEBUG.Printf("HistoricalRound <- %d", roundID) // If we didn't find it, send to Historical Rounds Retrieval m.historicalRounds <- roundID } else { - jww.INFO.Printf("Looking up Round: %d", roundID) + jww.DEBUG.Printf("lookupRoundMessages <- %d", roundID) // IF found, send to Message Retrieval Workers m.lookupRoundMessages <- ri } return false } + +func serializeRound(roundId id.Round) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(roundId)) + return b +} diff --git a/storage/auth/request.go b/storage/auth/request.go index 421fbc714bc6598877aaeb984bca6275d7b0fff5..e54632c2b806d3b68a6662a86844be2410003911 100644 --- a/storage/auth/request.go +++ b/storage/auth/request.go @@ -8,8 +8,8 @@ import ( type RequestType uint const ( - Sent RequestType = 0 - Receive RequestType = 1 + Sent RequestType = 1 + Receive RequestType = 2 ) type request struct { diff --git a/storage/auth/sentRequest.go b/storage/auth/sentRequest.go index aefd76dc6f9413fdb456d1eb268ecbe05904ef69..94a7a6ed36c976c9223eff6d17aae26789d0cd40 100644 --- a/storage/auth/sentRequest.go +++ b/storage/auth/sentRequest.go @@ -7,7 +7,6 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" - "sync" "time" ) @@ -21,7 +20,6 @@ type SentRequest struct { myPrivKey *cyclic.Int myPubKey *cyclic.Int fingerprint format.Fingerprint - sentMux sync.Mutex } type sentRequestDisk struct { diff --git a/storage/auth/store.go b/storage/auth/store.go index bf0e8830a325509d660c96c089f059243cff9baa..11eac13f3471887d629f626ae0c6669166765f10 100644 --- a/storage/auth/store.go +++ b/storage/auth/store.go @@ -42,7 +42,8 @@ func NewStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*Sto } for _, key := range privKeys { - fp := auth.MakeRequestFingerprint(key) + pubkey := grp.ExpG(key, grp.NewInt(1)) + fp := auth.MakeRequestFingerprint(pubkey) s.fingerprints[fp] = fingerprint{ Type: General, PrivKey: key, @@ -70,7 +71,8 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St } for _, key := range privKeys { - fp := auth.MakeRequestFingerprint(key) + pubkey := grp.ExpG(key, grp.NewInt(1)) + fp := auth.MakeRequestFingerprint(pubkey) s.fingerprints[fp] = fingerprint{ Type: General, PrivKey: key, @@ -89,6 +91,8 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St rt: RequestType(rDisk.T), } + var rid *id.ID + partner, err := id.Unmarshal(rDisk.ID) if err != nil { jww.FATAL.Panicf("Failed to load stored id: %+v", err) @@ -107,17 +111,24 @@ func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*St Request: r, } + rid = sr.partner + r.sent = sr + case Receive: c, err := utility.LoadContact(kv, partner) if err != nil { jww.FATAL.Panicf("Failed to load stored contact for: %+v", err) } + rid = c.ID r.receive = &c default: jww.FATAL.Panicf("Unknown request type: %d", r.rt) } + + //store in the request map + s.requests[*rid] = r } return s, nil @@ -186,6 +197,9 @@ func (s *Store) AddSent(partner *id.ID, partnerHistoricalPubKey, myPrivKey, "partern %s", partner) } + jww.INFO.Printf("AddSent PUBKEY FINGERPRINT: %v", sr.fingerprint) + jww.INFO.Printf("AddSent PUBKEY: %v", sr.myPubKey.Bytes()) + s.fingerprints[sr.fingerprint] = fingerprint{ Type: Specific, PrivKey: nil, @@ -252,8 +266,8 @@ func (s *Store) GetFingerprint(fp format.Fingerprint) (FingerprintType, _, ok := s.requests[*r.Request.sent.partner] s.mux.RUnlock() if !ok { - return 0, nil, nil, errors.Errorf("Fingerprint cannot be "+ - "found: %s", fp) + return 0, nil, nil, errors.Errorf("request associated with " + + "fingerprint cannot be found: %s", fp) } // Return the request return Specific, r.Request.sent, nil, nil diff --git a/storage/auth/store_test.go b/storage/auth/store_test.go index fb85f92b625def200f0604b2bb8dfa427113992f..dc938688e091f524bc46c6fac3a70659e8a82cc5 100644 --- a/storage/auth/store_test.go +++ b/storage/auth/store_test.go @@ -18,10 +18,12 @@ import ( // Happy path. func TestNewStore(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) - grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(0)) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) privKeys := make([]*cyclic.Int, 10) + pubKeys := make([]*cyclic.Int, 10) for i := range privKeys { privKeys[i] = grp.NewInt(rand.Int63n(172)) + pubKeys[i] = grp.ExpG(privKeys[i],grp.NewInt(1)) } store, err := NewStore(kv, grp, privKeys) @@ -30,8 +32,12 @@ func TestNewStore(t *testing.T) { } for i, key := range privKeys { - if store.fingerprints[auth.MakeRequestFingerprint(key)].PrivKey != key { - t.Errorf("Key not found in map (%d): %s", i, key.Text(10)) + rq, ok := store.fingerprints[auth.MakeRequestFingerprint(pubKeys[i])] + if !ok { + t.Errorf("Key not found in map (%d): %s", i, pubKeys[i].Text(16)) + }else if rq.PrivKey.Cmp(key)!=0{ + t.Errorf("Key found in map (%d) does not match private: " + + "%s vs %s", i, key.Text(10), rq.PrivKey.Text(10)) } } } @@ -64,15 +70,6 @@ func TestLoadStore(t *testing.T) { t.Errorf("LoadStore() returned an error: %+v", err) } - s.requests = map[id.ID]*request{} - s.fingerprints[sr.fingerprint] = fingerprint{ - Type: Specific, - Request: &request{ - rt: Sent, - sent: sr, - }, - } - if !reflect.DeepEqual(s, store) { t.Errorf("LoadStore() returned incorrect Store."+ "\n\texpected: %+v\n\treceived: %+v", s, store) @@ -181,7 +178,8 @@ func TestStore_AddReceived_PartnerAlreadyExistsError(t *testing.T) { func TestStore_GetFingerprint_GeneralFingerprintType(t *testing.T) { s, _, privKeys := makeTestStore(t) - fp := auth.MakeRequestFingerprint(privKeys[0]) + pubkey := s.grp.ExpG(privKeys[0],s.grp.NewInt(1)) + fp := auth.MakeRequestFingerprint(pubkey) fpType, request, key, err := s.GetFingerprint(fp) if err != nil { t.Errorf("GetFingerprint() returned an error: %+v", err) @@ -194,6 +192,7 @@ func TestStore_GetFingerprint_GeneralFingerprintType(t *testing.T) { t.Errorf("GetFingerprint() returned incorrect request."+ "\n\texpected: %+v\n\treceived: %+v", nil, request) } + if key.Cmp(privKeys[0]) == -2 { t.Errorf("GetFingerprint() returned incorrect key."+ "\n\texpected: %s\n\treceived: %s", privKeys[0].Text(10), key.Text(10)) diff --git a/storage/e2e/key.go b/storage/e2e/key.go index 6e046afd24eb8192ca21bfbd05014e1da0ddc39a..ead73ff230cabde2efb177bda5714552de9e0855 100644 --- a/storage/e2e/key.go +++ b/storage/e2e/key.go @@ -36,7 +36,8 @@ func (k *Key) Fingerprint() format.Fingerprint { if k.fp != nil { return *k.fp } - return e2eCrypto.DeriveKeyFingerprint(k.session.baseKey, k.keyNum) + return e2eCrypto.DeriveKeyFingerprint(k.session.baseKey, k.keyNum, + k.session.relationshipFingerprint) } // the E2E key to encrypt msg to its intended recipient diff --git a/storage/e2e/session.go b/storage/e2e/session.go index 09e33c17b7c33d9e9530c50e01eef0816a882541..7cad5b163fbf8e2046e57c109ad9abc9d77131e4 100644 --- a/storage/e2e/session.go +++ b/storage/e2e/session.go @@ -115,6 +115,17 @@ func newSession(ship *relationship, t RelationshipType, myPrivKey, partnerPubKey session.kv = session.generate(ship.kv) + jww.INFO.Printf("New Session with Partner %s:\n\tType: %s" + + "\n\tBaseKey: %s\n\tRelationship Fingerprint: %v\n\tNumKeys: %d" + + "\n\tMy Private Key: %s\n\tPartner Public Key: %s", + ship.manager.partner, + t, + session.baseKey.TextVerbose(16, 0), + session.relationshipFingerprint, + session.ttl, + session.myPrivKey.TextVerbose(16,0), + session.partnerPubKey.TextVerbose(16,0)) + err := session.save() if err != nil { jww.FATAL.Printf("Failed to make new session for Partner %s: %s", diff --git a/storage/e2e/store.go b/storage/e2e/store.go index ee6cacbf3193aeb83f89d4301406f45eaed3fa15..6b38d2e0641605ed57ee214afac52f743b1f2981 100644 --- a/storage/e2e/store.go +++ b/storage/e2e/store.go @@ -158,11 +158,17 @@ func (s *Store) AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.In s.mux.Lock() defer s.mux.Unlock() + jww.INFO.Printf("Adding Partner %s:\n\tMy Private Key: %s" + + "\n\tPartner Public Key: %s", + partnerID, + myPrivKey.TextVerbose(16, 0), + partnerPubKey.TextVerbose(16, 0)) + if _, ok := s.managers[*partnerID]; ok { return errors.New("Cannot overwrite existing partner") } - m := newManager(s.context, s.kv, partnerID, s.dhPrivateKey, partnerPubKey, + m := newManager(s.context, s.kv, partnerID, myPrivKey, partnerPubKey, sendParams, receiveParams) s.managers[*partnerID] = m diff --git a/storage/partition/multiPartMessage.go b/storage/partition/multiPartMessage.go index f6cdb54937e01b853425b1252a22e4e4bffc1eeb..b43f0d39978454aa0227403d6a87d61d27e56dad 100644 --- a/storage/partition/multiPartMessage.go +++ b/storage/partition/multiPartMessage.go @@ -193,7 +193,7 @@ func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message Payload: reconstructed, MessageType: mpm.MessageType, Sender: mpm.Sender, - Timestamp: time.Time{}, + Timestamp: mpm.Timestamp, // Encryption will be set externally Encryption: 0, ID: mid, diff --git a/storage/partition/multiPartMessage_test.go b/storage/partition/multiPartMessage_test.go index 5c546e9e90c30f2a4b3c9d496f432be95161edc1..35e5b02772477ca7f91b47124565a0d5a0c805ba 100644 --- a/storage/partition/multiPartMessage_test.go +++ b/storage/partition/multiPartMessage_test.go @@ -216,7 +216,7 @@ func TestMultiPartMessage_IsComplete(t *testing.T) { Payload: payload, MessageType: mpm.MessageType, Sender: mpm.Sender, - Timestamp: time.Time{}, + Timestamp: msg.Timestamp, Encryption: 0, ID: e2e.NewMessageID([]byte{0}, mid), } diff --git a/storage/session.go b/storage/session.go index 9db8fc9cbe54761434255fa667a15a9422cbf260..25145a2a59a53247c400584200eda7aeae4767c6 100644 --- a/storage/session.go +++ b/storage/session.go @@ -167,7 +167,7 @@ func Load(baseDir, password string, rng *fastRNG.StreamGenerator) (*Session, err return nil, errors.WithMessage(err, "Failed to load Session") } - s.auth, err = auth.NewStore(s.kv, s.e2e.GetGroup(), + s.auth, err = auth.LoadStore(s.kv, s.e2e.GetGroup(), []*cyclic.Int{s.e2e.GetDHPrivateKey()}) if err != nil { return nil, errors.WithMessage(err, "Failed to load auth store") diff --git a/storage/utility/messageBuffer.go b/storage/utility/messageBuffer.go index 197e669c4af6436544f3d90c25c0c903fafa809f..b6bcde652dffa2dbb4938bf066a355e1e791ea0e 100644 --- a/storage/utility/messageBuffer.go +++ b/storage/utility/messageBuffer.go @@ -270,6 +270,7 @@ func (mb *MessageBuffer) Succeeded(m interface{}) { // Done message from buffer delete(mb.processingMessages, h) + delete(mb.messages, h) // Done message from key value store err := mb.handler.DeleteMessage(mb.kv, makeStoredMessageKey(mb.key, h))