diff --git a/cmd/group.go b/cmd/group.go index 9a718542250f5cc89977c02e45f87677e535c766..1520d97c648ed47d952636c9f8aba703c04295cd 100644 --- a/cmd/group.go +++ b/cmd/group.go @@ -155,7 +155,7 @@ func createGroup(name, msg []byte, filePath string, gm groupChat.GroupChat) { userIdStrings := ReadLines(filePath) userIDs := make([]*id.ID, 0, len(userIdStrings)) for _, userIdStr := range userIdStrings { - userID, _ := parseRecipient(userIdStr) + userID := parseRecipient(userIdStr) userIDs = append(userIDs, userID) } @@ -174,7 +174,7 @@ func createGroup(name, msg []byte, filePath string, gm groupChat.GroupChat) { // resendRequests resends group requests for the group ID. func resendRequests(groupIdString string, gm groupChat.GroupChat) { - groupID, _ := parseRecipient(groupIdString) + groupID := parseRecipient(groupIdString) rids, status, err := gm.ResendRequest(groupID) if err != nil { jww.FATAL.Panicf("[GC] Failed to resend requests to group %s: %+v", @@ -212,7 +212,7 @@ func joinGroup(reqChan chan groupStore.Group, timeout time.Duration, // leaveGroup leaves the group. func leaveGroup(groupIdString string, gm groupChat.GroupChat) { - groupID, _ := parseRecipient(groupIdString) + groupID := parseRecipient(groupIdString) jww.INFO.Printf("[GC] Leaving group %s.", groupID) err := gm.LeaveGroup(groupID) @@ -226,7 +226,7 @@ func leaveGroup(groupIdString string, gm groupChat.GroupChat) { // sendGroup send the message to the group. func sendGroup(groupIdString string, msg []byte, gm groupChat.GroupChat) { - groupID, _ := parseRecipient(groupIdString) + groupID := parseRecipient(groupIdString) jww.INFO.Printf("[GC] Sending to group %s message %q", groupID, msg) @@ -272,7 +272,7 @@ func listGroups(gm groupChat.GroupChat) { // showGroup prints all the information of the group. func showGroup(groupIdString string, gm groupChat.GroupChat) { - groupID, _ := parseRecipient(groupIdString) + groupID := parseRecipient(groupIdString) grp, ok := gm.GetGroup(groupID) if !ok { diff --git a/cmd/root.go b/cmd/root.go index e4b8d0155bac546096b637e76eb4ef65f51998c5..fa78f7dacb34f9a5f5789634fdb88a665fbcb8fb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -201,29 +201,29 @@ var rootCmd = &cobra.Command{ jww.INFO.Printf("Client Initialized...") - user := client.GetReceptionIdentity() - jww.INFO.Printf("User: %s", user.ID) - writeContact(user.GetContact()) - - // get Recipient and/or set it to myself - 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 || recipientID.Cmp(user.ID) { - jww.INFO.Printf("sending message to self") - recipientID = user.ID - recipientContact = user.GetContact() + receptionIdentity := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", receptionIdentity.ID) + writeContact(receptionIdentity.GetContact()) + + var recipientContact contact.Contact + var recipientID *id.ID + + destFile := viper.GetString("destfile") + destId := viper.GetString("destid") + sendId := viper.GetString("sendid") + if destFile != "" { + recipientContact = readContact(destFile) + recipientID = recipientContact.ID + } else if destId == "0" || sendId == destId { + jww.INFO.Printf("Sending message to self") + recipientID = receptionIdentity.ID + recipientContact = receptionIdentity.GetContact() + } else { + recipientID = parseRecipient(destId) } + isPrecanPartner := isPrecanID(recipientID) - jww.INFO.Printf("Client: %s, Partner: %s", user.ID, + jww.INFO.Printf("Client: %s, Partner: %s", receptionIdentity.ID, recipientID) client.GetE2E().EnableUnsafeReception() @@ -293,6 +293,7 @@ var rootCmd = &cobra.Command{ authConfirmed = true } + jww.INFO.Printf("Preexisting E2e partners: %+v", client.GetE2E().GetAllPartnerIDs()) if client.GetE2E().HasAuthenticatedChannel(recipientID) { jww.INFO.Printf("Authenticated channel already in "+ "place for %s", recipientID) @@ -318,19 +319,22 @@ var rootCmd = &cobra.Command{ authConfirmed = false } - go func() { - for { - authID := <-authCbs.confCh - if authID.Cmp(recipientID) { - authConfirmed = true + if !unsafe && !authConfirmed { + // Signal for authConfirm callback in a separate thread + go func() { + for { + authID := <-authCbs.confCh + if authID.Cmp(recipientID) { + authConfirmed = true + } } - } - }() + }() - if !unsafe && !authConfirmed { jww.INFO.Printf("Waiting for authentication channel"+ " confirmation with partner %s", recipientID) scnt := uint(0) + + // Wait until authConfirmed waitSecs := viper.GetUint("auth-timeout") for !authConfirmed && scnt < waitSecs { time.Sleep(1 * time.Second) @@ -344,6 +348,8 @@ var rootCmd = &cobra.Command{ } jww.INFO.Printf("Authentication channel confirmation"+ " took %d seconds", scnt) + jww.INFO.Printf("Authenticated partners saved: %v\n PartnersList: %+v", + !client.GetStorage().GetKV().IsMemStore(), client.GetE2E().GetAllPartnerIDs()) } // DeleteFingerprint this recipient @@ -549,6 +555,9 @@ func initCmix() (*xxdk.Cmix, xxdk.ReceptionIdentity) { backupPath := viper.GetString("backupIn") backupPass := []byte(viper.GetString("backupPass")) + // FIXME: All branches of the upcoming path + var knownReception xxdk.ReceptionIdentity + // create a new client if none exist if _, err := os.Stat(storeDir); errors.Is(err, fs.ErrNotExist) { // Load NDF @@ -558,7 +567,7 @@ func initCmix() (*xxdk.Cmix, xxdk.ReceptionIdentity) { } if precannedID != 0 { - err = xxdk.NewPrecannedClient(precannedID, + knownReception, err = xxdk.NewPrecannedClient(precannedID, string(ndfJSON), storeDir, pass) } else if protoUserPath != "" { protoUserJson, err := utils.ReadFile(protoUserPath) @@ -627,12 +636,19 @@ func initCmix() (*xxdk.Cmix, xxdk.ReceptionIdentity) { } params := initParams() - client, err := xxdk.OpenCmix(storeDir, pass, params) if err != nil { jww.FATAL.Panicf("%+v", err) } + // If there is a known xxdk.ReceptionIdentity, store it now + if knownReception.ID != nil { + err = xxdk.StoreReceptionIdentity(identityStorageKey, knownReception, client) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + } + // Attempt to load extant xxdk.ReceptionIdentity identity, err := xxdk.LoadReceptionIdentity(identityStorageKey, client) if err != nil { @@ -691,7 +707,7 @@ func initE2e() *xxdk.E2e { // Force LoginLegacy for precanned senderID var client *xxdk.E2e - if isPrecanned := viper.GetUint("sendid") != 0; isPrecanned { + if isPrecanID(receptionIdentity.ID) { jww.INFO.Printf("Using LoginLegacy for precan sender") client, err = xxdk.LoginLegacy(baseClient, authCbs) if err != nil { @@ -1036,20 +1052,18 @@ func parsePassword(pwStr string) []byte { } } -func parseRecipient(idStr string) (*id.ID, bool) { +func parseRecipient(idStr string) *id.ID { if idStr == "0" { - return nil, false + jww.FATAL.Panicf("No recipient specified") } - var recipientID *id.ID if strings.HasPrefix(idStr, "0x") { - recipientID = getUIDFromHexString(idStr[2:]) + return getUIDFromHexString(idStr[2:]) } else if strings.HasPrefix(idStr, "b64:") { - recipientID = getUIDFromb64String(idStr[4:]) + return getUIDFromb64String(idStr[4:]) } else { - recipientID = getUIDFromString(idStr) + return getUIDFromString(idStr) } - return recipientID, isPrecanID(recipientID) } func getUIDFromHexString(idStr string) *id.ID { @@ -1316,7 +1330,7 @@ func init() { "for confirmation") viper.BindPFlag("send-auth-request", rootCmd.Flags().Lookup("send-auth-request")) - rootCmd.Flags().UintP("auth-timeout", "", 120, + rootCmd.Flags().UintP("auth-timeout", "", 60, "The number of seconds to wait for an authentication channel"+ "to confirm") viper.BindPFlag("auth-timeout", diff --git a/cmd/ud.go b/cmd/ud.go index 94de6775c2a031dc37410fdc186dc4b090f1186c..9f8d84835d37b16dd14c8d09c09e17ba54f97b3d 100644 --- a/cmd/ud.go +++ b/cmd/ud.go @@ -152,7 +152,7 @@ var udCmd = &cobra.Command{ // Note: Cryptographic verification occurs above the bindings layer lookupIDStr := viper.GetString("lookup") if lookupIDStr != "" { - lookupID, _ := parseRecipient(lookupIDStr) + lookupID := parseRecipient(lookupIDStr) //if !ok { // jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr) //} diff --git a/cmd/utils.go b/cmd/utils.go index aca4fc016ca31eae6efee3087791510ddef0ea42..12c01738e45ecae13c9a4fef3fdb4140f3284a42 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -87,8 +87,7 @@ func writeContact(c contact.Contact) { } } -func readContact() contact.Contact { - inputFilePath := viper.GetString("destfile") +func readContact(inputFilePath string) contact.Contact { if inputFilePath == "" { return contact.Contact{} } diff --git a/xxdk/e2e.go b/xxdk/e2e.go index 650428be9707f07cb0ce6a440f5004ac72785659..8811994fd3e1b5032d6b5821c4d34e798cb41fdd 100644 --- a/xxdk/e2e.go +++ b/xxdk/e2e.go @@ -72,7 +72,7 @@ func LoginLegacy(client *Cmix, callbacks AuthCallbacks) (m *E2e, err error) { backup: &Container{}, } - m.e2e, err = LoadOrInitE2e(client) + m.e2e, err = loadOrInitE2eLegacy(client) if err != nil { return nil, err } @@ -201,33 +201,38 @@ func login(client *Cmix, callbacks AuthCallbacks, identity.ID.String()) } - e2eGrp := client.GetStorage().GetE2EGroup() m = &E2e{ Cmix: client, backup: &Container{}, e2eIdentity: identity, } - - client.network.AddIdentity(identity.ID, time.Time{}, true) - - //initialize the e2e storage dhPrivKey, err := identity.GetDHKeyPrivate() if err != nil { return nil, err } - err = e2e.Init(kv, identity.ID, dhPrivKey, e2eGrp, - rekey.GetDefaultEphemeralParams()) - if err != nil { - return nil, err - } - //load the new e2e storage + // load or init the new e2e storage + e2eGrp := client.GetStorage().GetE2EGroup() m.e2e, err = e2e.Load(kv, client.GetCmix(), identity.ID, e2eGrp, client.GetRng(), client.GetEventReporter()) if err != nil { - return nil, errors.WithMessage(err, "Failed to load a "+ - "newly created e2e store") + //initialize the e2e storage + jww.INFO.Printf("Initializing new e2e.Handler for %s", identity.ID.String()) + err = e2e.Init(kv, identity.ID, dhPrivKey, e2eGrp, + rekey.GetDefaultParams()) + if err != nil { + return nil, err + } + + //load the new e2e storage + m.e2e, err = e2e.Load(kv, + client.GetCmix(), identity.ID, e2eGrp, client.GetRng(), + client.GetEventReporter()) + if err != nil { + return nil, errors.WithMessage(err, "Failed to load a "+ + "newly created e2e store") + } } err = client.AddService(m.e2e.StartProcesses) @@ -243,13 +248,14 @@ func login(client *Cmix, callbacks AuthCallbacks, return nil, err } + client.network.AddIdentity(identity.ID, time.Time{}, true) return m, err } -// LoadOrInitE2e loads the e2e handler or makes a new one, generating a new +// loadOrInitE2eLegacy loads the e2e handler or makes a new one, generating a new // e2e private key. It attempts to load via a legacy construction, then tries // to load the modern one, creating a new modern ID if neither can be found -func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) { +func loadOrInitE2eLegacy(client *Cmix) (e2e.Handler, error) { usr := client.GetStorage().PortableUserInfo() e2eGrp := client.GetStorage().GetE2EGroup() kv := client.GetStorage().GetKV() diff --git a/xxdk/precan.go b/xxdk/precan.go index b710954cc27f6901d5f4b0226a3b5aa920bb8f4a..51ae566f33d7983bf2009c3b5e3107551653f1ab 100644 --- a/xxdk/precan.go +++ b/xxdk/precan.go @@ -62,7 +62,7 @@ func CreatePrecannedUser(precannedID uint, rng csprng.Source) user.Info { // username/identity, but merely creates a new cryptographic identity // for adding such information at a later date. func NewPrecannedClient(precannedID uint, defJSON, storageDir string, - password []byte) error { + password []byte) (ReceptionIdentity, error) { jww.INFO.Printf("NewPrecannedClient()") rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) @@ -70,26 +70,32 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, def, err := ParseNDF(defJSON) if err != nil { - return err + return ReceptionIdentity{}, err } cmixGrp, e2eGrp := DecodeGroups(def) + dhPrivKey := generatePrecanDHKeypair(precannedID, e2eGrp) + protoUser := CreatePrecannedUser(precannedID, rngStream) + identity, err := buildReceptionIdentity(protoUser, e2eGrp, dhPrivKey) + if err != nil { + return ReceptionIdentity{}, err + } store, err := CheckVersionAndSetupStorage(def, storageDir, password, protoUser, cmixGrp, e2eGrp, "") if err != nil { - return err + return ReceptionIdentity{}, err } // Mark the precanned user as finished with permissioning and registered // with the network. err = store.ForwardRegistrationStatus(storage.PermissioningComplete) if err != nil { - return err + return ReceptionIdentity{}, err } - return nil + return identity, err } func generatePrecanDHKeypair(precannedID uint, e2eGrp *cyclic.Group) *cyclic.Int {