Skip to content
Snippets Groups Projects
Select Git revision
  • 9961c1fc2f6079d88df869881693b333f26d4c69
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

utils_test.go

Blame
  • ud.go 10.09 KiB
    ///////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                          //
    //                                                                           //
    // Use of this source code is governed by a license that can be found in the //
    // LICENSE file                                                              //
    ///////////////////////////////////////////////////////////////////////////////
    
    // Package cmd initializes the CLI and config parsers as well as the logger.
    package cmd
    
    import (
    	"fmt"
    	"gitlab.com/elixxir/client/single"
    	"gitlab.com/elixxir/client/ud"
    	"gitlab.com/elixxir/client/xxmutils"
    	"gitlab.com/elixxir/primitives/fact"
    	"gitlab.com/xx_network/primitives/utils"
    	"strings"
    	"time"
    
    	"github.com/spf13/cobra"
    	jww "github.com/spf13/jwalterweatherman"
    	"github.com/spf13/viper"
    	"gitlab.com/elixxir/crypto/contact"
    )
    
    // udCmd is the user discovery subcommand, which allows for user lookup,
    // registration, and search. This basically runs a client for these functions
    // with the UD module enabled. Normally, clients do not need it so it is not
    // loaded for the rest of the commands.
    var udCmd = &cobra.Command{
    	Use:   "ud",
    	Short: "Register for and search users using the xx network user discovery service.",
    	Args:  cobra.NoArgs,
    	Run: func(cmd *cobra.Command, args []string) {
    		client := initClient()
    
    		// get user and save contact to file
    		user := client.GetUser()
    		jww.INFO.Printf("User: %s", user.ReceptionID)
    		writeContact(user.GetContact())
    
    		// // Set up reception handler
    		// swBoard := client.GetSwitchboard()
    		// recvCh := make(chan message.Receive, 10000)
    		// listenerID := swBoard.RegisterChannel("DefaultCLIReceiver",
    		// 	switchboard.AnyUser(), message.XxMessage, recvCh)
    		// jww.INFO.Printf("Message ListenerID: %v", listenerID)
    
    		// // Set up auth request handler, which simply prints the user ID of the
    		// // requester
    		// authMgr := client.GetAuthRegistrar()
    		// authMgr.AddGeneralRequestCallback(printChanRequest)
    
    		// // If unsafe channels, add auto-acceptor
    		// if viper.GetBool("unsafe-channel-creation") {
    		// 	authMgr.AddGeneralRequestCallback(func(
    		// 		requester contact.Contact) {
    		// 		jww.INFO.Printf("Got Request: %s", requester.ID)
    		// 		_, err := client.ConfirmAuthenticatedChannel(requester)
    		// 		if err != nil {
    		// 			jww.FATAL.Panicf("%+v", err)
    		// 		}
    		// 	})
    		// }
    
    		err := client.StartNetworkFollower(50 * time.Millisecond)
    		if err != nil {
    			jww.FATAL.Panicf("%+v", err)
    		}
    
    		// Wait until connected or crash on timeout
    		connected := make(chan bool, 10)
    		client.GetNetworkInterface().AddHealthCallback(
    			func(isconnected bool) {
    				connected <- isconnected
    			})
    		waitUntilConnected(connected)
    
    		// Make user discovery manager
    		stream := client.GetRng().GetStream()
    		defer stream.Close()
    		userToRegister := viper.GetString("register")
    		userDiscoveryMgr, err := ud.NewManager(client.GetNetworkInterface(),
    			client.GetE2EHandler(), client.NetworkFollowerStatus,
    			client.GetEventReporter(),
    			client.GetComms(), client.GetStorage(),
    			stream,
    			userToRegister, client.GetStorage().GetKV())
    		if err != nil {
    			if strings.Contains(err.Error(), ud.IsRegisteredErr) {
    				userDiscoveryMgr, err = ud.LoadManager(client.GetNetworkInterface(),
    					client.GetE2EHandler(), client.GetEventReporter(),
    					client.GetComms(),
    					client.GetStorage(), client.GetStorage().GetKV())
    				if err != nil {
    					jww.FATAL.Panicf("Failed to load UD manager: %+v", err)
    				}
    			} else {
    				jww.FATAL.Panicf("Failed to create new UD manager: %+v", err)
    
    			}
    		}
    
    		var newFacts fact.FactList
    		phone := viper.GetString("addphone")
    		if phone != "" {
    			f, err := fact.NewFact(fact.Phone, phone)
    			if err != nil {
    				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
    			}
    			newFacts = append(newFacts, f)
    		}
    
    		email := viper.GetString("addemail")
    		if email != "" {
    			f, err := fact.NewFact(fact.Email, email)
    			if err != nil {
    				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
    			}
    			newFacts = append(newFacts, f)
    		}
    
    		for i := 0; i < len(newFacts); i++ {
    			r, err := userDiscoveryMgr.SendRegisterFact(newFacts[i])
    			if err != nil {
    				fmt.Printf("Failed to register fact: %s\n",
    					newFacts[i])
    				jww.FATAL.Panicf("Failed to send register fact: %+v", err)
    			}
    			// TODO Store the code?
    			jww.INFO.Printf("Fact Add Response: %+v", r)
    		}
    
    		confirmID := viper.GetString("confirm")
    		if confirmID != "" {
    			err = userDiscoveryMgr.ConfirmFact(confirmID, confirmID)
    			if err != nil {
    				fmt.Printf("Couldn't confirm fact: %s\n",
    					err.Error())
    				jww.FATAL.Panicf("%+v", err)
    			}
    		}
    
    		udContact, err := userDiscoveryMgr.GetContact()
    		if err != nil {
    			fmt.Printf("Failed to get user discovery contact object: %+v", err)
    			jww.FATAL.Printf("Failed to get user discovery contact object: %+v", err)
    		}
    
    		// Handle lookup (verification) process
    		// Note: Cryptographic verification occurs above the bindings layer
    		lookupIDStr := viper.GetString("lookup")
    		if lookupIDStr != "" {
    			lookupID, _ := parseRecipient(lookupIDStr)
    			//if !ok {
    			//	jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr)
    			//}
    
    			cb := func(newContact contact.Contact, err error) {
    				if err != nil {
    					jww.FATAL.Panicf("UserDiscovery Lookup error: %+v", err)
    				}
    				printContact(newContact)
    			}
    			_, _, err = ud.Lookup(client.GetNetworkInterface(),
    				stream, client.GetE2EHandler().GetGroup(),
    				udContact, cb, lookupID, single.GetDefaultRequestParams())
    			if err != nil {
    				jww.WARN.Printf("Failed UD lookup: %+v", err)
    			}
    
    			time.Sleep(31 * time.Second)
    		}
    
    		if viper.GetString("batchadd") != "" {
    			idListFile, err := utils.ReadFile(viper.GetString("batchadd"))
    			if err != nil {
    				fmt.Printf("BATCHADD: Couldn't read file: %s\n",
    					err.Error())
    				jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
    			}
    			restored, _, _, err := xxmutils.RestoreContactsFromBackup(
    				idListFile, client, userDiscoveryMgr, nil)
    			if err != nil {
    				jww.FATAL.Panicf("%+v", err)
    			}
    			for i := 0; i < len(restored); i++ {
    				uid := restored[i]
    				for !client.HasAuthenticatedChannel(uid) {
    					time.Sleep(time.Second)
    				}
    				jww.INFO.Printf("Authenticated channel established for %s", uid)
    			}
    		}
    		usernameSearchStr := viper.GetString("searchusername")
    		emailSearchStr := viper.GetString("searchemail")
    		phoneSearchStr := viper.GetString("searchphone")
    
    		var facts fact.FactList
    		if usernameSearchStr != "" {
    			f, err := fact.NewFact(fact.Username, usernameSearchStr)
    			if err != nil {
    				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
    			}
    			facts = append(facts, f)
    		}
    		if emailSearchStr != "" {
    			f, err := fact.NewFact(fact.Email, emailSearchStr)
    			if err != nil {
    				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
    			}
    			facts = append(facts, f)
    		}
    		if phoneSearchStr != "" {
    			f, err := fact.NewFact(fact.Phone, phoneSearchStr)
    			if err != nil {
    				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
    			}
    			facts = append(facts, f)
    		}
    
    		userToRemove := viper.GetString("remove")
    		if userToRemove != "" {
    			f, err := fact.NewFact(fact.Username, userToRemove)
    			if err != nil {
    				jww.FATAL.Panicf(
    					"Failed to create new fact: %+v", err)
    			}
    			err = userDiscoveryMgr.PermanentDeleteAccount(f)
    			if err != nil {
    				fmt.Printf("Couldn't remove user %s\n",
    					userToRemove)
    				jww.FATAL.Panicf(
    					"Failed to remove user %s: %+v",
    					userToRemove, err)
    			}
    			fmt.Printf("Removed user from discovery: %s\n",
    				userToRemove)
    		}
    
    		if len(facts) == 0 {
    			err = client.StopNetworkFollower()
    			if err != nil {
    				jww.WARN.Print(err)
    			}
    			return
    		}
    
    		cb := func(contacts []contact.Contact, err error) {
    			if err != nil {
    				jww.FATAL.Panicf("%+v", err)
    			}
    			for _, c := range contacts {
    				printContact(c)
    			}
    		}
    
    		_, _, err = ud.Search(client.GetNetworkInterface(),
    			client.GetEventReporter(),
    			stream, client.GetE2EHandler().GetGroup(),
    			udContact, cb, facts, single.GetDefaultRequestParams())
    		if err != nil {
    			jww.FATAL.Panicf("%+v", err)
    		}
    
    		time.Sleep(91 * time.Second)
    		err = client.StopNetworkFollower()
    		if err != nil {
    			jww.WARN.Print(err)
    		}
    	},
    }
    
    func init() {
    	// User Discovery subcommand Options
    	udCmd.Flags().StringP("register", "r", "",
    		"Register this user with user discovery.")
    	_ = viper.BindPFlag("register", udCmd.Flags().Lookup("register"))
    
    	udCmd.Flags().StringP("remove", "", "",
    		"Remove this user with user discovery.")
    	_ = viper.BindPFlag("remove", udCmd.Flags().Lookup("remove"))
    
    	udCmd.Flags().String("addphone", "",
    		"Add phone number to existing user registration.")
    	_ = viper.BindPFlag("addphone", udCmd.Flags().Lookup("addphone"))
    
    	udCmd.Flags().StringP("addemail", "e", "",
    		"Add email to existing user registration.")
    	_ = viper.BindPFlag("addemail", udCmd.Flags().Lookup("addemail"))
    
    	udCmd.Flags().String("confirm", "", "Confirm fact with confirmation ID.")
    	_ = viper.BindPFlag("confirm", udCmd.Flags().Lookup("confirm"))
    
    	udCmd.Flags().StringP("lookup", "u", "",
    		"Look up user ID. Use '0x' or 'b64:' for hex and base64 representations.")
    	_ = viper.BindPFlag("lookup", udCmd.Flags().Lookup("lookup"))
    
    	udCmd.Flags().String("searchusername", "",
    		"Search for users with this username.")
    	_ = viper.BindPFlag("searchusername", udCmd.Flags().Lookup("searchusername"))
    
    	udCmd.Flags().String("searchemail", "",
    		"Search for users with this email address.")
    	_ = viper.BindPFlag("searchemail", udCmd.Flags().Lookup("searchemail"))
    
    	udCmd.Flags().String("searchphone", "",
    		"Search for users with this email address.")
    	_ = viper.BindPFlag("searchphone", udCmd.Flags().Lookup("searchphone"))
    
    	udCmd.Flags().String("batchadd", "",
    		"Path to JSON marshalled slice of partner IDs that will be looked up on UD.")
    	_ = viper.BindPFlag("batchadd", udCmd.Flags().Lookup("batchadd"))
    
    	rootCmd.AddCommand(udCmd)
    }
    
    func printContact(c contact.Contact) {
    	jww.DEBUG.Printf("Printing contact: %+v", c)
    	cBytes := c.Marshal()
    	if len(cBytes) == 0 {
    		jww.ERROR.Print("Marshaled contact has a size of 0.")
    	} else {
    		jww.DEBUG.Printf("Printing marshaled contact of size %d.", len(cBytes))
    	}
    
    	fmt.Print(string(cBytes))
    }