Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
client
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Automate
Agent sessions
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Terraform modules
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
elixxir
client
Commits
3d2544f9
Commit
3d2544f9
authored
Apr 13, 2022
by
Josh Brooks
Browse files
Options
Downloads
Patches
Plain Diff
Manually pull UD changes from release
parent
b19e510f
No related branches found
No related tags found
4 merge requests
!510
Release
,
!207
WIP: Client Restructure
,
!203
Symmetric broadcast
,
!199
Xx 3866/user discovery
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
bindings/ud.go
+58
-31
58 additions, 31 deletions
bindings/ud.go
ud/manager.go
+66
-12
66 additions, 12 deletions
ud/manager.go
ud/store/facts.go
+21
-4
21 additions, 4 deletions
ud/store/facts.go
ud/store/facts_test.go
+60
-0
60 additions, 0 deletions
ud/store/facts_test.go
with
205 additions
and
47 deletions
bindings/ud.go
+
58
−
31
View file @
3d2544f9
...
...
@@ -9,6 +9,7 @@ package bindings
import
(
"fmt"
jww
"github.com/spf13/jwalterweatherman"
"time"
"github.com/pkg/errors"
...
...
@@ -46,6 +47,63 @@ func NewUserDiscovery(client *Client) (*UserDiscovery, error) {
}
}
// NewUserDiscoveryFromBackup returns a new user discovery object. It
// wil set up the manager with the backup data. Pass into it the backed up
// facts, one email and phone number each. This will add the registered facts
// to the backed Store. Any one of these fields may be empty,
// however both fields being empty will cause an error. Any other fact that is not
// an email or phone number will return an error. You may only add a fact for the
// accepted types once each. If you attempt to back up a fact type that has already
// been backed up, an error will be returned. Anytime an error is returned, it means
// the backup was not successful.
// NOTE: Do not use this as a direct store operation. This feature is intended to add facts
// to a backend store that have ALREADY BEEN REGISTERED on the account.
// THIS IS NOT FOR ADDING NEWLY REGISTERED FACTS. That is handled on the backend.
// Only call this once. It must be called after StartNetworkFollower
// is called and will fail if the network has never been contacted.
// This function technically has a memory leak because it causes both sides of
// the bindings to think the other is in charge of the client object.
// In general this is not an issue because the client object should exist
// for the life of the program.
// This must be called while start network follower is running.
func
NewUserDiscoveryFromBackup
(
client
*
Client
,
email
,
phone
string
)
(
*
UserDiscovery
,
error
)
{
single
,
err
:=
client
.
getSingle
()
if
err
!=
nil
{
return
nil
,
errors
.
WithMessage
(
err
,
"Failed to create User Discovery Manager"
)
}
var
emailFact
,
phoneFact
fact
.
Fact
// Parse email as a fact, if it exists
if
len
(
email
)
>
2
{
emailFact
,
err
=
fact
.
UnstringifyFact
(
email
)
if
err
!=
nil
{
return
nil
,
errors
.
WithMessagef
(
err
,
"Failed to parse malformed email fact: %s"
,
email
)
}
}
else
{
jww
.
WARN
.
Printf
(
"Loading manager without a registered email"
)
}
// Parse phone number as a fact, if it exists
if
len
(
phone
)
>
2
{
phoneFact
,
err
=
fact
.
UnstringifyFact
(
phone
)
if
err
!=
nil
{
return
nil
,
errors
.
WithMessagef
(
err
,
"Failed to parse "
+
"stringified phone fact %q"
,
phone
)
}
}
else
{
jww
.
WARN
.
Printf
(
"Loading manager without a registered phone number"
)
}
m
,
err
:=
ud
.
NewManagerFromBackup
(
&
client
.
api
,
single
,
emailFact
,
phoneFact
)
if
err
!=
nil
{
return
nil
,
errors
.
WithMessage
(
err
,
"Failed to create User Discovery Manager"
)
}
else
{
return
&
UserDiscovery
{
ud
:
m
},
nil
}
}
// Register registers a user with user discovery. Will return an error if the
// network signatures are malformed or if the username is taken. Usernames
// cannot be changed after registration at this time. Will fail if the user is
...
...
@@ -103,37 +161,6 @@ func (ud *UserDiscovery) RemoveUser(fStr string) error {
return
ud
.
ud
.
RemoveUser
(
f
)
}
//BackUpMissingFacts adds a registered fact to the Store object and saves
// it to storage. It can take in both an email or a phone number, passed into
// the function in that order. Any one of these fields may be empty,
// however both fields being empty will cause an error. Any other fact that is not
// an email or phone number will return an error. You may only add a fact for the
// accepted types once each. If you attempt to back up a fact type that has already
// been backed up, an error will be returned. Anytime an error is returned, it means
// the backup was not successful.
// NOTE: Do not use this as a direct store operation. This feature is intended to add facts
// to a backend store that have ALREADY BEEN REGISTERED on the account.
// THIS IS NOT FOR ADDING NEWLY REGISTERED FACTS. That is handled on the backend.
func
(
ud
*
UserDiscovery
)
BackUpMissingFacts
(
email
,
phone
string
)
error
{
var
emailFact
,
phoneFact
fact
.
Fact
var
err
error
if
len
(
email
)
>
2
{
emailFact
,
err
=
fact
.
UnstringifyFact
(
email
)
if
err
!=
nil
{
return
errors
.
WithMessagef
(
err
,
"Failed to parse malformed email fact: %s"
,
email
)
}
}
if
len
(
phone
)
>
2
{
phoneFact
,
err
=
fact
.
UnstringifyFact
(
phone
)
if
err
!=
nil
{
return
errors
.
WithMessagef
(
err
,
"Failed to parse malformed phone fact: %s"
,
phone
)
}
}
return
ud
.
ud
.
BackUpMissingFacts
(
emailFact
,
phoneFact
)
}
// SearchCallback returns the result of a search
type
SearchCallback
interface
{
Callback
(
contacts
*
ContactList
,
error
string
)
...
...
This diff is collapsed.
Click to expand it.
ud/manager.go
+
66
−
12
View file @
3d2544f9
...
...
@@ -22,6 +22,7 @@ import (
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id"
"math"
"time"
)
...
...
@@ -158,6 +159,71 @@ func NewManager(services cmix.Client, e2e e2e.Handler, events event.Manager,
return
m
,
nil
}
// NewManagerFromBackup builds a new user discover manager from a backup.
// It will construct a manager that is already registered and restore
// already registered facts into store.
func
NewManagerFromBackup
(
client
*
api
.
Client
,
single
*
single
.
Manager
,
email
,
phone
fact
.
Fact
)
(
*
Manager
,
error
)
{
jww
.
INFO
.
Println
(
"ud.NewManagerFromBackup()"
)
if
client
.
NetworkFollowerStatus
()
!=
api
.
Running
{
return
nil
,
errors
.
New
(
"cannot start UD Manager when network follower is not running."
)
}
registered
:=
uint32
(
0
)
m
:=
&
Manager
{
client
:
client
,
comms
:
client
.
GetComms
(),
rng
:
client
.
GetRng
(),
sw
:
client
.
GetSwitchboard
(),
storage
:
client
.
GetStorage
(),
net
:
client
.
GetNetworkInterface
(),
single
:
single
,
registered
:
&
registered
,
}
err
:=
m
.
client
.
GetStorage
()
.
GetUd
()
.
BackUpMissingFacts
(
email
,
phone
)
if
err
!=
nil
{
return
nil
,
errors
.
WithMessage
(
err
,
"Failed to restore UD store "
+
"from backup"
)
}
// check that user discovery is available in the NDF
def
:=
m
.
net
.
GetInstance
()
.
GetPartialNdf
()
.
Get
()
if
def
.
UDB
.
Cert
==
""
{
return
nil
,
errors
.
New
(
"NDF does not have User Discovery information, "
+
"is there network access?: Cert not present."
)
}
// 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
hp
.
AuthEnabled
=
false
m
.
myID
=
m
.
storage
.
User
()
.
GetCryptographicIdentity
()
.
GetReceptionID
()
// Get the commonly used data from storage
m
.
privKey
=
m
.
storage
.
GetUser
()
.
ReceptionRSA
// Set as registered. Since it's from a backup,
// the client is already registered
if
err
=
m
.
setRegistered
();
err
!=
nil
{
return
nil
,
errors
.
WithMessage
(
err
,
"failed to set client as "
+
"registered with user discovery."
)
}
// Store the pointer to the group locally for easy access
m
.
grp
=
m
.
storage
.
E2e
()
.
GetGroup
()
return
m
,
nil
}
func
LoadManager
(
services
cmix
.
Client
,
e2e
e2e
.
Handler
,
events
event
.
Manager
,
comms
Comms
,
userStore
Userinfo
,
rng
*
fastRNG
.
StreamGenerator
,
privKey
*
rsa
.
PrivateKey
,
kv
*
versioned
.
KV
)
(
*
Manager
,
error
)
{
...
...
@@ -234,18 +300,6 @@ func (m *Manager) UnsetAlternativeUserDiscovery() error {
return
nil
}
// BackUpMissingFacts adds a registered fact to the Store object.
// It can take in both an email and a phone number. One or the other may be nil,
// however both is considered an error. It checks for the proper fact type for
// the associated fact. Any other fact.FactType is not accepted and returns an
// error and nothing is backed up. If you attempt to back up a fact type that h
// as already been backed up, an error will be returned and nothing will be
// backed up. Otherwise, it adds the fact and returns whether the Store saved
// successfully.
func
(
m
*
Manager
)
BackUpMissingFacts
(
email
,
phone
fact
.
Fact
)
error
{
return
m
.
store
.
BackUpMissingFacts
(
email
,
phone
)
}
// GetFacts returns a list of fact.Fact objects that exist within the
// Store's registeredFacts map.
func
(
m
*
Manager
)
GetFacts
()
[]
fact
.
Fact
{
...
...
This diff is collapsed.
Click to expand it.
ud/store/facts.go
+
21
−
4
View file @
3d2544f9
...
...
@@ -21,6 +21,7 @@ const (
"%s (%s) is non-empty but not an email. Cancelling backup operation"
backupMissingAllZeroesFactErr
=
"Cannot backup missing facts: Both email and phone facts are empty!"
factNotInStoreErr
=
"Fact %v does not exist in store"
statefulStoreErr
=
"cannot overwrite ud store with existing data"
)
// Store is the storage object for the higher level ud.Manager object.
...
...
@@ -48,6 +49,26 @@ func NewStore(kv *versioned.KV) (*Store, error) {
return
s
,
s
.
save
()
}
// RestoreFromBackUp initializes the confirmedFacts map
// with the backed up fact data. This will error if
// the store is already stateful.
func
(
s
*
Store
)
RestoreFromBackUp
(
backupData
fact
.
FactList
)
error
{
s
.
mux
.
Lock
()
defer
s
.
mux
.
Unlock
()
if
len
(
s
.
confirmedFacts
)
!=
0
||
len
(
s
.
unconfirmedFacts
)
!=
0
{
return
errors
.
New
(
statefulStoreErr
)
}
for
_
,
f
:=
range
backupData
{
if
!
isFactZero
(
f
)
{
s
.
confirmedFacts
[
f
]
=
struct
{}{}
}
}
return
s
.
save
()
}
// StoreUnconfirmedFact stores a fact that has been added to UD but has not been
// confirmed by the user. It is keyed on the confirmation ID given by UD.
func
(
s
*
Store
)
StoreUnconfirmedFact
(
confirmationId
string
,
f
fact
.
Fact
)
error
{
...
...
@@ -94,10 +115,6 @@ func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error {
s
.
mux
.
Lock
()
defer
s
.
mux
.
Unlock
()
if
isFactZero
(
email
)
&&
isFactZero
(
phone
)
{
return
errors
.
New
(
backupMissingAllZeroesFactErr
)
}
modifiedEmail
,
modifiedPhone
:=
false
,
false
// Handle email if it is not zero (empty string)
...
...
This diff is collapsed.
Click to expand it.
ud/store/facts_test.go
+
60
−
0
View file @
3d2544f9
...
...
@@ -27,6 +27,66 @@ func TestNewStore(t *testing.T) {
}
// Unit test
func
TestStore_RestoreFromBackUp
(
t
*
testing
.
T
)
{
kv
:=
versioned
.
NewKV
(
make
(
ekv
.
Memstore
))
s
,
err
:=
NewStore
(
kv
)
if
err
!=
nil
{
t
.
Errorf
(
"NewStore() produced an error: %v"
,
err
)
}
expected
:=
fact
.
Fact
{
Fact
:
"josh"
,
T
:
fact
.
Username
,
}
fl
:=
fact
.
FactList
{
expected
}
err
=
s
.
RestoreFromBackUp
(
fl
)
if
err
!=
nil
{
t
.
Fatalf
(
"RestoreFromBackup err: %v"
,
err
)
}
_
,
exists
:=
s
.
confirmedFacts
[
expected
]
if
!
exists
{
t
.
Fatalf
(
"Fact %s does not exist in map"
,
expected
)
}
}
// Error case.
func
TestStore_RestoreFromBackUp_StatefulStore
(
t
*
testing
.
T
)
{
kv
:=
versioned
.
NewKV
(
make
(
ekv
.
Memstore
))
s
,
err
:=
NewStore
(
kv
)
if
err
!=
nil
{
t
.
Errorf
(
"NewStore() produced an error: %v"
,
err
)
}
confirmId
:=
"confirm"
expected
:=
fact
.
Fact
{
Fact
:
"josh"
,
T
:
fact
.
Username
,
}
err
=
s
.
StoreUnconfirmedFact
(
confirmId
,
expected
)
if
err
!=
nil
{
t
.
Fatalf
(
"StoreUnconfirmedFact error: %v"
,
err
)
}
// Expected error: should error when restoring on
// a stateful store.
fl
:=
fact
.
FactList
{
expected
}
err
=
s
.
RestoreFromBackUp
(
fl
)
if
err
==
nil
{
t
.
Fatalf
(
"RestoreFromBackup err: %v"
,
err
)
}
}
func
TestStore_ConfirmFact
(
t
*
testing
.
T
)
{
kv
:=
versioned
.
NewKV
(
make
(
ekv
.
Memstore
))
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
sign in
to comment