diff --git a/bindings/ud.go b/bindings/ud.go index 5fdb2cd0e0bf9a92f67c32fc74d82a780783f701..15b0e012a7ffaad5b290da54b832bcffdf39fa57 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -80,6 +80,7 @@ func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error { // Removes a previously confirmed fact. Will fail if the passed fact string is // not well formed or if the fact is not associated with this client. +// Users cannot remove username facts and must instead remove the user. func (ud *UserDiscovery) RemoveFact(fStr string) error { f, err := fact.UnstringifyFact(fStr) if err != nil { @@ -89,6 +90,18 @@ func (ud *UserDiscovery) RemoveFact(fStr string) error { return ud.ud.RemoveFact(f) } +// RemoveUser deletes a user. The fact sent must be the username. +// This function preserves the username forever and makes it +// unusable. +func (ud *UserDiscovery) RemoveUser(fStr string) error { + f, err := fact.UnstringifyFact(fStr) + if err != nil { + return errors.WithMessage(err, "Failed to remove due to "+ + "malformed fact") + } + return ud.ud.RemoveUser(f) +} + // SearchCallback returns the result of a search type SearchCallback interface { Callback(contacts *ContactList, error string) diff --git a/cmd/ud.go b/cmd/ud.go index 4fa083d32cdd3641f2c333fd63a2e47cf36e1af2..880a503f32ec6783591e238165a4ea11bb24eb16 100644 --- a/cmd/ud.go +++ b/cmd/ud.go @@ -198,6 +198,22 @@ var udCmd = &cobra.Command{ if err != nil { jww.FATAL.Panicf("%+v", err) } + + userToRemove := viper.GetString("remove") + if userToRemove != "" { + f, err := fact.NewFact(fact.Username, usernameSearchStr) + if err != nil { + jww.FATAL.Panicf( + "Failed to create new fact: %+v", err) + } + err = userDiscoveryMgr.RemoveUser(f) + if err != nil { + jww.FATAL.Panicf( + "Failed to remove user %s: %+v", + userToRemove, err) + } + } + time.Sleep(91 * time.Second) err = client.StopNetworkFollower() if err != nil { @@ -212,6 +228,10 @@ func init() { "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")) diff --git a/go.mod b/go.mod index 4374a2dd5a339fa386637cf5b8a10d5fcc367968..2e5f10caf977093d5bba142c8ee0060f88222ed6 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ 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.20210823164208-0e219b367d23 + gitlab.com/elixxir/comms v0.0.4-0.20210903140456-430cebcae4ec gitlab.com/elixxir/crypto v0.0.7-0.20210803232056-ba3ff44cc618 gitlab.com/elixxir/ekv v0.1.5 gitlab.com/elixxir/primitives v0.0.3-0.20210803231939-7b924f78eaac diff --git a/go.sum b/go.sum index c8eb24d11ebf4db213445d279faf780c546faa42..4281cb4a024da594ef0e693b34a14d0cc8f846a1 100644 --- a/go.sum +++ b/go.sum @@ -253,6 +253,8 @@ gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0 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.20210823164208-0e219b367d23 h1:ZculIcPFJjVN+Z9mCe2fdZ5JG2LW/tu0yWnceOcJ/TU= gitlab.com/elixxir/comms v0.0.4-0.20210823164208-0e219b367d23/go.mod h1:1fHnPjj5Sv2qfnQplu8+BKlehQy54vtgM7khp5axXMU= +gitlab.com/elixxir/comms v0.0.4-0.20210903140456-430cebcae4ec h1:n6lL2/cNYLXExdB5fVnLJY2C+gFfqwjovjwdEsWKAQo= +gitlab.com/elixxir/comms v0.0.4-0.20210903140456-430cebcae4ec/go.mod h1:1fHnPjj5Sv2qfnQplu8+BKlehQy54vtgM7khp5axXMU= 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.20210803232056-ba3ff44cc618 h1:Z1SI2a8mXP4Zf2xfhURT1Hbmtq3tufTdebNLgCdlufg= diff --git a/ud/remove.go b/ud/remove.go index 69514a579f4169128c455a181c34116ad7b63a61..99d9447f330cf0a5c133975abea3a29de1a71b0e 100644 --- a/ud/remove.go +++ b/ud/remove.go @@ -59,3 +59,50 @@ func (m *Manager) removeFact(fact fact.Fact, rFC removeFactComms) error { // Return the error return err } + +type removeUserComms interface { + SendRemoveUser(host *connect.Host, message *mixmessages.FactRemovalRequest) (*messages.Ack, error) +} + +// Removes a previously confirmed fact. Will fail if the fact is not +// associated with this client. +func (m *Manager) RemoveUser(fact fact.Fact) error { + jww.INFO.Printf("ud.RemoveUser(%s)", fact.Stringify()) + return m.removeUser(fact, m.comms) +} + +func (m *Manager) removeUser(fact fact.Fact, rFC removeUserComms) error { + if !m.IsRegistered() { + return errors.New("Failed to remove fact: " + + "client is not registered") + } + + // Construct the message to send + // Convert our Fact to a mixmessages Fact for sending + mmFact := mixmessages.Fact{ + Fact: fact.Fact, + FactType: uint32(fact.T), + } + + // Create a hash of our fact + fhash := factID.Fingerprint(fact) + + // Sign our inFact for putting into the request + fsig, err := rsa.Sign(rand.Reader, m.privKey, hash.CMixHash, fhash, nil) + if err != nil { + return err + } + + // Create our Fact Removal Request message data + remFactMsg := mixmessages.FactRemovalRequest{ + UID: m.myID.Marshal(), + RemovalData: &mmFact, + FactSig: fsig, + } + + // Send the message + _, err = rFC.SendRemoveUser(m.host, &remFactMsg) + + // Return the error + return err +} diff --git a/ud/remove_test.go b/ud/remove_test.go index 2adf4c976a0a895c30a2afc6fda98281fd8cb5c2..d65cb0e8ccd888e374e42c2585fe41dfe2305c66 100644 --- a/ud/remove_test.go +++ b/ud/remove_test.go @@ -51,3 +51,42 @@ func TestRemoveFact(t *testing.T) { t.Fatal(err) } } + +func (rFC *testRFC) SendRemoveUser(host *connect.Host, message *pb.FactRemovalRequest) (*messages.Ack, error) { + return &messages.Ack{}, nil +} + +func TestRemoveUser(t *testing.T) { + h, err := connect.NewHost(&id.DummyUser, "address", nil, connect.GetDefaultHostParams()) + if err != nil { + t.Fatal(err) + } + + rng := csprng.NewSystemRNG() + cpk, err := rsa.GenerateKey(rng, 2048) + if err != nil { + t.Fatal(err) + } + + isReg := uint32(1) + + m := Manager{ + comms: nil, + host: h, + privKey: cpk, + registered: &isReg, + myID: &id.ID{}, + } + + f := fact.Fact{ + Fact: "testing", + T: 2, + } + + trfc := testRFC{} + + err = m.removeUser(f, &trfc) + if err != nil { + t.Fatal(err) + } +}