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
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
d06c890b
Commit
d06c890b
authored
Nov 22, 2019
by
Jonah Husson
Browse files
Options
Downloads
Patches
Plain Diff
move register functions to their own file
parent
64ac846b
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
api/client.go
+186
-511
186 additions, 511 deletions
api/client.go
api/register.go
+341
-0
341 additions, 0 deletions
api/register.go
with
527 additions
and
511 deletions
api/client.go
+
186
−
511
View file @
d06c890b
...
...
@@ -9,7 +9,6 @@ package api
import
(
"bufio"
"crypto"
"crypto/rand"
gorsa
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
...
...
@@ -25,11 +24,8 @@ import (
"gitlab.com/elixxir/client/rekey"
"gitlab.com/elixxir/client/user"
"gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
"gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/crypto/registration"
"gitlab.com/elixxir/crypto/signature/rsa"
"gitlab.com/elixxir/crypto/tls"
"gitlab.com/elixxir/primitives/circuit"
...
...
@@ -38,7 +34,6 @@ import (
"gitlab.com/elixxir/primitives/switchboard"
goio
"io"
"strings"
"sync"
"time"
)
...
...
@@ -58,145 +53,6 @@ var noNDFErr = errors.New("Failed to get ndf from permissioning: rpc error: code
//used to report the state of registration
type
OperationProgressCallback
func
(
int
)
// Populates a text message and returns its wire representation
// TODO support multi-type messages or telling if a message is too long?
func
FormatTextMessage
(
message
string
)
[]
byte
{
textMessage
:=
cmixproto
.
TextMessage
{
Color
:
-
1
,
Message
:
message
,
Time
:
time
.
Now
()
.
Unix
(),
}
wireRepresentation
,
_
:=
proto
.
Marshal
(
&
textMessage
)
return
wireRepresentation
}
//GetUpdatedNDF: Connects to the permissioning server to get the updated NDF from it
func
(
cl
*
Client
)
getUpdatedNDF
()
(
*
ndf
.
NetworkDefinition
,
error
)
{
// again, uses internal ndf. stay here, return results instead
//Hash the client's ndf for comparison with registration's ndf
hash
:=
sha256
.
New
()
ndfBytes
:=
cl
.
ndf
.
Serialize
()
hash
.
Write
(
ndfBytes
)
ndfHash
:=
hash
.
Sum
(
nil
)
//Put the hash in a message
msg
:=
&
mixmessages
.
NDFHash
{
Hash
:
ndfHash
}
host
,
ok
:=
cl
.
commManager
.
Comms
.
GetHost
(
PermissioningAddrID
)
if
!
ok
{
return
nil
,
errors
.
New
(
"Failed to find permissioning host"
)
}
//Send the hash to registration
response
,
err
:=
cl
.
commManager
.
Comms
.
SendGetUpdatedNDF
(
host
,
msg
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get ndf from permissioning: %v"
,
err
)
return
nil
,
errors
.
New
(
errMsg
)
}
//If there was no error and the response is nil, client's ndf is up-to-date
if
response
==
nil
{
globals
.
Log
.
DEBUG
.
Printf
(
"Client NDF up-to-date"
)
return
nil
,
nil
}
//FixMe: use verify instead? Probs need to add a signature to ndf, like in registration's getupdate?
globals
.
Log
.
INFO
.
Printf
(
"Remote NDF: %s"
,
string
(
response
.
Ndf
))
//Otherwise pull the ndf out of the response
updatedNdf
,
_
,
err
:=
ndf
.
DecodeNDF
(
string
(
response
.
Ndf
))
if
err
!=
nil
{
//If there was an error decoding ndf
errMsg
:=
fmt
.
Sprintf
(
"Failed to decode response to ndf: %v"
,
err
)
return
nil
,
errors
.
New
(
errMsg
)
}
return
updatedNdf
,
nil
}
// VerifyNDF verifies the signature of the network definition file (NDF) and
// returns the structure. Panics when the NDF string cannot be decoded and when
// the signature cannot be verified. If the NDF public key is empty, then the
// signature verification is skipped and warning is printed.
func
VerifyNDF
(
ndfString
,
ndfPub
string
)
*
ndf
.
NetworkDefinition
{
// If there is no public key, then skip verification and print warning
if
ndfPub
==
""
{
globals
.
Log
.
WARN
.
Printf
(
"Running without signed network "
+
"definition file"
)
}
else
{
ndfReader
:=
bufio
.
NewReader
(
strings
.
NewReader
(
ndfString
))
ndfData
,
err
:=
ndfReader
.
ReadBytes
(
'\n'
)
ndfData
=
ndfData
[
:
len
(
ndfData
)
-
1
]
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF: %v"
,
err
)
}
ndfSignature
,
err
:=
ndfReader
.
ReadBytes
(
'\n'
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF Sig: %v"
,
err
)
}
ndfSignature
,
err
=
base64
.
StdEncoding
.
DecodeString
(
string
(
ndfSignature
[
:
len
(
ndfSignature
)
-
1
]))
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF Sig: %v"
,
err
)
}
// Load the TLS cert given to us, and from that get the RSA public key
cert
,
err
:=
tls
.
LoadCertificate
(
ndfPub
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not load public key: %v"
,
err
)
}
pubKey
:=
&
rsa
.
PublicKey
{
PublicKey
:
*
cert
.
PublicKey
.
(
*
gorsa
.
PublicKey
)}
// Hash NDF JSON
rsaHash
:=
sha256
.
New
()
rsaHash
.
Write
(
ndfData
)
globals
.
Log
.
INFO
.
Printf
(
"%s
\n
::
\n
%s"
,
ndfSignature
,
ndfData
)
// Verify signature
err
=
rsa
.
Verify
(
pubKey
,
crypto
.
SHA256
,
rsaHash
.
Sum
(
nil
),
ndfSignature
,
nil
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not verify NDF: %v"
,
err
)
}
}
ndfJSON
,
_
,
err
:=
ndf
.
DecodeNDF
(
ndfString
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not decode NDF: %v"
,
err
)
}
return
ndfJSON
}
//request calls getUpdatedNDF for a new NDF repeatedly until it gets an NDF
func
requestNdf
(
cl
*
Client
)
error
{
// Continuously polls for a new ndf after sleeping until response if gotten
globals
.
Log
.
INFO
.
Printf
(
"Polling for a new NDF"
)
newNDf
,
err
:=
cl
.
getUpdatedNDF
()
if
err
!=
nil
{
//lets the client continue when permissioning does not provide NDFs
if
err
.
Error
()
==
noNDFErr
.
Error
()
{
globals
.
Log
.
WARN
.
Println
(
"Continuing without an updated NDF"
)
return
nil
}
errMsg
:=
fmt
.
Sprintf
(
"Failed to get updated ndf: %v"
,
err
)
globals
.
Log
.
ERROR
.
Printf
(
errMsg
)
return
errors
.
New
(
errMsg
)
}
if
newNDf
!=
nil
{
cl
.
ndf
=
newNDf
}
return
nil
}
// Creates a new Client using the storage mechanism provided.
// If none is provided, a default storage using OS file access
// is created
...
...
@@ -244,383 +100,171 @@ func NewClient(s globals.Storage, locA, locB string, ndfJSON *ndf.NetworkDefinit
return
cl
,
nil
}
func
(
cl
*
Client
)
GetRegistrationVersion
()
string
{
// on client
return
cl
.
registrationVersion
}
//GetNDF returns the clients ndf
func
(
cl
*
Client
)
GetNDF
()
*
ndf
.
NetworkDefinition
{
return
cl
.
ndf
}
func
(
cl
*
Client
)
SetOperationProgressCallback
(
rpc
OperationProgressCallback
)
{
cl
.
opStatus
=
func
(
i
int
)
{
go
rpc
(
i
)
}
}
const
SaltSize
=
256
// RegisterWithPermissioning registers user with permissioning and returns the
// User ID. Returns an error if registration fails.
func
(
cl
*
Client
)
RegisterWithPermissioning
(
preCan
bool
,
registrationCode
,
nick
,
email
,
password
string
,
privateKeyRSA
*
rsa
.
PrivateKey
)
(
*
id
.
User
,
error
)
{
// LoadSession loads the session object for the UID
func
(
cl
*
Client
)
Login
(
password
string
)
(
string
,
error
)
{
var
session
user
.
Session
var
err
error
var
u
*
user
.
User
var
UID
*
id
.
User
cl
.
opStatus
(
globals
.
REG_KEYGEN
)
largeIntBits
:=
16
cmixGrp
:=
cyclic
.
NewGroup
(
large
.
NewIntFromString
(
cl
.
ndf
.
CMIX
.
Prime
,
largeIntBits
),
large
.
NewIntFromString
(
cl
.
ndf
.
CMIX
.
Generator
,
largeIntBits
))
e2eGrp
:=
cyclic
.
NewGroup
(
large
.
NewIntFromString
(
cl
.
ndf
.
E2E
.
Prime
,
largeIntBits
),
large
.
NewIntFromString
(
cl
.
ndf
.
E2E
.
Generator
,
largeIntBits
))
// Make CMIX keys array
nk
:=
make
(
map
[
id
.
Node
]
user
.
NodeKeys
)
// GENERATE CLIENT RSA KEYS
if
privateKeyRSA
==
nil
{
privateKeyRSA
,
err
=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsa
.
DefaultRSABitLen
)
if
err
!=
nil
{
return
nil
,
err
}
}
publicKeyRSA
:=
privateKeyRSA
.
GetPublic
()
cmixPrivKeyDHByte
,
err
:=
csprng
.
GenerateInGroup
(
cmixGrp
.
GetPBytes
(),
256
,
csprng
.
NewSystemRNG
())
done
:=
make
(
chan
struct
{})
if
err
!=
nil
{
return
nil
,
errors
.
New
(
fmt
.
Sprintf
(
"Could not generate cmix DH private key: %s"
,
err
.
Error
()))
// run session loading in a separate goroutine so if it panics it can
// be caught and an error can be returned
go
func
()
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
globals
.
Log
.
ERROR
.
Println
(
"Session file loading crashed"
)
err
=
sessionFileError
done
<-
struct
{}{}
}
}()
cmixPrivateKeyDH
:=
cmixGrp
.
NewIntFromBytes
(
cmixPrivKeyDHByte
)
cmixPublicKeyDH
:=
cmixGrp
.
ExpG
(
cmixPrivateKeyDH
,
cmixGrp
.
NewMaxInt
())
session
,
err
=
user
.
LoadSession
(
cl
.
storage
,
password
)
done
<-
struct
{}{}
}()
e2ePrivKeyDHByte
,
err
:=
csprng
.
GenerateInGroup
(
cmixGrp
.
GetPBytes
(),
256
,
csprng
.
NewSystemRNG
())
//wait for session file loading to complete
<-
done
if
err
!=
nil
{
return
nil
,
errors
.
New
(
fmt
.
Sprintf
(
"Could not generate e2e DH private key: %s"
,
err
.
Error
())
)
return
""
,
errors
.
Wrap
(
err
,
"Login: Could not login"
)
}
e2ePrivateKeyDH
:=
e2eGrp
.
NewIntFromBytes
(
e2ePrivKeyDHByte
)
e2ePublicKeyDH
:=
e2eGrp
.
ExpG
(
e2ePrivateKeyDH
,
e2eGrp
.
NewMaxInt
())
// Initialized response from Registration Server
regValidationSignature
:=
make
([]
byte
,
0
)
var
salt
[]
byte
// Handle precanned registration
if
preCan
{
cl
.
opStatus
(
globals
.
REG_PRECAN
)
globals
.
Log
.
INFO
.
Printf
(
"Registering precanned user..."
)
u
,
UID
,
nk
,
err
=
cl
.
precannedRegister
(
registrationCode
,
nick
,
nk
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Unable to complete precanned registration: %+v"
,
err
)
return
id
.
ZeroID
,
err
if
session
==
nil
{
return
""
,
errors
.
New
(
"Unable to load session, no error reported"
)
}
}
else
{
cl
.
opStatus
(
globals
.
REG_UID_GEN
)
globals
.
Log
.
INFO
.
Printf
(
"Registering dynamic user..."
)
// Generate salt for UserID
salt
=
make
([]
byte
,
SaltSize
)
_
,
err
=
csprng
.
NewSystemRNG
()
.
Read
(
salt
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Register: Unable to generate salt! %s"
,
err
)
return
id
.
ZeroID
,
err
if
session
.
GetRegState
()
<
user
.
PermissioningComplete
{
return
""
,
errors
.
New
(
"Cannot log a user in which has not "
+
"completed registration "
)
}
// Generate UserID by hashing salt and public key
UID
=
registration
.
GenUserID
(
publicKeyRSA
,
salt
)
// If Registration Server is specified, contact it
// Only if registrationCode is set
globals
.
Log
.
INFO
.
Println
(
"Register: Contacting registration server"
)
if
cl
.
ndf
.
Registration
.
Address
!=
""
&&
registrationCode
!=
""
{
cl
.
opStatus
(
globals
.
REG_PERM
)
regValidationSignature
,
err
=
cl
.
sendRegistrationMessage
(
registrationCode
,
publicKeyRSA
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Register: Unable to send registration message: %+v"
,
err
)
return
id
.
ZeroID
,
err
}
cl
.
session
=
session
return
cl
.
session
.
GetCurrentUser
()
.
Nick
,
nil
}
globals
.
Log
.
INFO
.
Println
(
"Register: successfully passed Registration message"
)
var
actualNick
string
if
nick
!=
""
{
actualNick
=
nick
}
else
{
actualNick
=
base64
.
StdEncoding
.
EncodeToString
(
UID
[
:
])
}
u
=
user
.
Users
.
NewUser
(
UID
,
actualNick
)
user
.
Users
.
UpsertUser
(
u
)
// Logout closes the connection to the server at this time and does
// nothing with the user id. In the future this will release resources
// and safely release any sensitive memory.
// fixme: blocks forever is message reciever
func
(
cl
*
Client
)
Logout
()
error
{
if
cl
.
session
==
nil
{
err
:=
errors
.
New
(
"Logout: Cannot Logout when you are not logged in"
)
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
u
.
Email
=
email
// Create the user session
newSession
:=
user
.
NewSession
(
cl
.
storage
,
u
,
nk
,
publicKeyRSA
,
privateKeyRSA
,
cmixPublicKeyDH
,
cmixPrivateKeyDH
,
e2ePublicKeyDH
,
e2ePrivateKeyDH
,
salt
,
cmixGrp
,
e2eGrp
,
password
,
regValidationSignature
)
cl
.
opStatus
(
globals
.
REG_SAVE
)
// Stop reception runner goroutine
close
(
cl
.
session
.
GetQuitChan
())
//set the registration state
err
=
newSession
.
SetRegState
(
user
.
PermissioningComplete
)
if
err
!=
nil
{
return
id
.
ZeroID
,
errors
.
Wrap
(
err
,
"Permissioning Registration "
+
"Failed"
)
}
cl
.
commManager
.
Comms
.
DisconnectAll
()
// Store the user session
errStore
:=
newSession
.
StoreSession
()
errStore
:=
cl
.
session
.
StoreSession
()
if
errStore
!=
nil
{
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Permissioning Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
id
.
ZeroID
,
err
}
cl
.
session
=
newSession
return
UID
,
nil
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Logout: Store Failed: %s"
+
errStore
.
Error
()))
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
// RegisterWithUDB uses the account's email to register with the UDB for
// User discovery. Must be called after Register and InitNetwork.
// It will fail if the user has already registered with UDB
func
(
cl
*
Client
)
RegisterWithUDB
(
timeout
time
.
Duration
)
error
{
regState
:=
cl
.
GetSession
()
.
GetRegState
()
errImmolate
:=
cl
.
session
.
Immolate
()
cl
.
session
=
nil
if
regState
!=
user
.
PermissioningComplete
{
return
errors
.
New
(
"Cannot register with UDB when registration "
+
"state is not PermissioningComplete"
)
if
errImmolate
!=
nil
{
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Logout: Immolation Failed: %s"
+
errImmolate
.
Error
()))
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
email
:=
cl
.
session
.
GetCurrentUser
()
.
Email
var
err
error
if
email
!=
""
{
globals
.
Log
.
INFO
.
Printf
(
"Registering user as %s with UDB"
,
email
)
valueType
:=
"EMAIL"
publicKeyBytes
:=
cl
.
session
.
GetE2EDHPublicKey
()
.
Bytes
()
err
=
bots
.
Register
(
valueType
,
email
,
publicKeyBytes
,
cl
.
opStatus
,
timeout
)
if
err
==
nil
{
globals
.
Log
.
INFO
.
Printf
(
"Registered with UDB!"
)
}
else
{
globals
.
Log
.
WARN
.
Printf
(
"Could not register with UDB: %s"
,
err
)
return
nil
}
// VerifyNDF verifies the signature of the network definition file (NDF) and
// returns the structure. Panics when the NDF string cannot be decoded and when
// the signature cannot be verified. If the NDF public key is empty, then the
// signature verification is skipped and warning is printed.
func
VerifyNDF
(
ndfString
,
ndfPub
string
)
*
ndf
.
NetworkDefinition
{
// If there is no public key, then skip verification and print warning
if
ndfPub
==
""
{
globals
.
Log
.
WARN
.
Printf
(
"Running without signed network "
+
"definition file"
)
}
else
{
globals
.
Log
.
INFO
.
Printf
(
"Not registering with UDB because no "
+
"email found"
)
}
ndfReader
:=
bufio
.
NewReader
(
strings
.
NewReader
(
ndfString
))
ndfData
,
err
:=
ndfReader
.
ReadBytes
(
'\n'
)
ndfData
=
ndfData
[
:
len
(
ndfData
)
-
1
]
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"Could not register with UDB"
)
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF: %v"
,
err
)
}
//set the registration state
err
=
cl
.
session
.
SetRegState
(
user
.
UDBComplete
)
ndfSignature
,
err
:=
ndfReader
.
ReadBytes
(
'\n'
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"UDB Registration Failed"
)
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF Sig: %v"
,
err
)
}
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
errStore
:=
cl
.
session
.
StoreSession
()
// FIXME If we have an error here, the session that gets created
// doesn't get immolated. Immolation should happen in a deferred
// call instead.
if
errStore
!=
nil
{
err
=
errors
.
New
(
fmt
.
Sprintf
(
"UDB Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
err
ndfSignature
,
err
=
base64
.
StdEncoding
.
DecodeString
(
string
(
ndfSignature
[
:
len
(
ndfSignature
)
-
1
]))
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not read NDF Sig: %v"
,
err
)
}
return
nil
// Load the TLS cert given to us, and from that get the RSA public key
cert
,
err
:=
tls
.
LoadCertificate
(
ndfPub
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not load public key: %v"
,
err
)
}
pubKey
:=
&
rsa
.
PublicKey
{
PublicKey
:
*
cert
.
PublicKey
.
(
*
gorsa
.
PublicKey
)}
func
(
cl
*
Client
)
RegisterWithNodes
()
error
{
cl
.
opStatus
(
globals
.
REG_NODE
)
session
:=
cl
.
GetSession
()
//Load Cmix keys & group
cmixDHPrivKey
:=
session
.
GetCMIXDHPrivateKey
()
cmixDHPubKey
:=
session
.
GetCMIXDHPublicKey
()
cmixGrp
:=
session
.
GetCmixGroup
()
//Load the rsa keys
rsaPubKey
:=
session
.
GetRSAPublicKey
()
rsaPrivKey
:=
session
.
GetRSAPrivateKey
()
//Load the user ID
UID
:=
session
.
GetCurrentUser
()
.
User
//Load the registration signature
regSignature
:=
session
.
GetRegistrationValidationSignature
()
var
wg
sync
.
WaitGroup
errChan
:=
make
(
chan
error
,
len
(
cl
.
ndf
.
Gateways
))
//Get the registered node keys
registeredNodes
:=
session
.
GetNodes
()
// Hash NDF JSON
rsaHash
:=
sha256
.
New
()
rsaHash
.
Write
(
ndfData
)
salt
:=
session
.
GetSalt
()
globals
.
Log
.
INFO
.
Printf
(
"%s
\n
::
\n
%s"
,
ndfSignature
,
ndfData
)
//
This variable keeps track of whether there were new registrations
// required, thus requiring the state file to be saved again
newRegistrations
:=
false
//
Verify signature
err
=
rsa
.
Verify
(
pubKey
,
crypto
.
SHA256
,
rsaHash
.
Sum
(
nil
),
ndfSignature
,
nil
)
for
i
:=
range
cl
.
ndf
.
Gateways
{
localI
:=
i
nodeID
:=
*
id
.
NewNodeFromBytes
(
cl
.
ndf
.
Nodes
[
i
]
.
ID
)
//Register with node if the node has not been registered with already
if
_
,
ok
:=
registeredNodes
[
nodeID
];
!
ok
{
wg
.
Add
(
1
)
newRegistrations
=
true
go
func
()
{
cl
.
registerWithNode
(
localI
,
salt
,
regSignature
,
UID
,
rsaPubKey
,
rsaPrivKey
,
cmixDHPubKey
,
cmixDHPrivKey
,
cmixGrp
,
errChan
)
wg
.
Done
()
}()
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not verify NDF: %v"
,
err
)
}
}
wg
.
Wait
()
//See if the registration returned errors at all
var
errs
error
for
len
(
errChan
)
>
0
{
err
:=
<-
errChan
if
errs
!=
nil
{
errs
=
errors
.
Wrap
(
errs
,
err
.
Error
())
}
else
{
errs
=
err
}
ndfJSON
,
_
,
err
:=
ndf
.
DecodeNDF
(
ndfString
)
if
err
!=
nil
{
globals
.
Log
.
FATAL
.
Panicf
(
"Could not decode NDF: %v"
,
err
)
}
//If an error every occurred, return with error
if
errs
!=
nil
{
cl
.
opStatus
(
globals
.
REG_FAIL
)
return
errs
return
ndfJSON
}
// Store the user session if there were changes during node registration
if
newRegistrations
{
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
errStore
:=
session
.
StoreSession
()
if
errStore
!=
nil
{
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
err
}
func
(
cl
*
Client
)
GetRegistrationVersion
()
string
{
// on client
return
cl
.
registrationVersion
}
return
nil
//GetNDF returns the clients ndf
func
(
cl
*
Client
)
GetNDF
()
*
ndf
.
NetworkDefinition
{
return
cl
.
ndf
}
//registerWithNode registers a user. It serves as a helper for Register
func
(
cl
*
Client
)
registerWithNode
(
index
int
,
salt
,
registrationValidationSignature
[]
byte
,
UID
*
id
.
User
,
publicKeyRSA
*
rsa
.
PublicKey
,
privateKeyRSA
*
rsa
.
PrivateKey
,
cmixPublicKeyDH
,
cmixPrivateKeyDH
*
cyclic
.
Int
,
cmixGrp
*
cyclic
.
Group
,
errorChan
chan
error
)
{
gatewayID
:=
id
.
NewNodeFromBytes
(
cl
.
ndf
.
Nodes
[
index
]
.
ID
)
.
NewGateway
()
// Initialise blake2b hash for transmission keys and sha256 for reception
// keys
transmissionHash
,
_
:=
hash
.
NewCMixHash
()
receptionHash
:=
sha256
.
New
()
// Request nonce message from gateway
globals
.
Log
.
INFO
.
Printf
(
"Register: Requesting nonce from gateway %v/%v"
,
index
+
1
,
len
(
cl
.
ndf
.
Gateways
))
nonce
,
dhPub
,
err
:=
cl
.
requestNonce
(
salt
,
registrationValidationSignature
,
cmixPublicKeyDH
,
publicKeyRSA
,
privateKeyRSA
,
gatewayID
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Register: Failed requesting nonce from gateway: %+v"
,
err
)
errorChan
<-
errors
.
New
(
errMsg
)
func
(
cl
*
Client
)
SetOperationProgressCallback
(
rpc
OperationProgressCallback
)
{
cl
.
opStatus
=
func
(
i
int
)
{
go
rpc
(
i
)
}
}
// Load server DH pubkey
serverPubDH
:=
cmixGrp
.
NewIntFromBytes
(
dhPub
)
// Confirm received nonce
globals
.
Log
.
INFO
.
Println
(
"Register: Confirming received nonce"
)
err
=
cl
.
confirmNonce
(
UID
.
Bytes
(),
nonce
,
privateKeyRSA
,
gatewayID
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Register: Unable to confirm nonce: %v"
,
err
)
errorChan
<-
errors
.
New
(
errMsg
)
}
nodeID
:=
cl
.
topology
.
GetNodeAtIndex
(
index
)
key
:=
user
.
NodeKeys
{
TransmissionKey
:
registration
.
GenerateBaseKey
(
cmixGrp
,
serverPubDH
,
cmixPrivateKeyDH
,
transmissionHash
),
ReceptionKey
:
registration
.
GenerateBaseKey
(
cmixGrp
,
serverPubDH
,
cmixPrivateKeyDH
,
receptionHash
),
// Populates a text message and returns its wire representation
// TODO support multi-type messages or telling if a message is too long?
func
FormatTextMessage
(
message
string
)
[]
byte
{
textMessage
:=
cmixproto
.
TextMessage
{
Color
:
-
1
,
Message
:
message
,
Time
:
time
.
Now
()
.
Unix
(),
}
cl
.
session
.
PushNodeKey
(
nodeID
,
key
)
wireRepresentation
,
_
:=
proto
.
Marshal
(
&
textMessage
)
return
wireRepresentation
}
var
sessionFileError
=
errors
.
New
(
"Session file cannot be loaded and "
+
"is possibly corrupt. Please contact support@xxmessenger.io"
)
// LoadSession loads the session object for the UID
func
(
cl
*
Client
)
Login
(
password
string
)
(
string
,
error
)
{
var
session
user
.
Session
var
err
error
done
:=
make
(
chan
struct
{})
// run session loading in a separate goroutine so if it panics it can
// be caught and an error can be returned
go
func
()
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
globals
.
Log
.
ERROR
.
Println
(
"Session file loading crashed"
)
err
=
sessionFileError
done
<-
struct
{}{}
}
}()
session
,
err
=
user
.
LoadSession
(
cl
.
storage
,
password
)
done
<-
struct
{}{}
}()
//wait for session file loading to complete
<-
done
if
err
!=
nil
{
return
""
,
errors
.
Wrap
(
err
,
"Login: Could not login"
)
}
if
session
==
nil
{
return
""
,
errors
.
New
(
"Unable to load session, no error reported"
)
}
if
session
.
GetRegState
()
<
user
.
PermissioningComplete
{
return
""
,
errors
.
New
(
"Cannot log a user in which has not "
+
"completed registration "
)
}
cl
.
session
=
session
return
cl
.
session
.
GetCurrentUser
()
.
Nick
,
nil
}
// Logs in user and sets session on client object
// returns the nickname or error if login fails
func
(
cl
*
Client
)
StartMessageReceiver
(
callback
func
(
error
))
error
{
...
...
@@ -706,44 +350,6 @@ func (cl *Client) GetKeyParams() *keyStore.KeyParams {
return
cl
.
session
.
GetKeyStore
()
.
GetKeyParams
()
}
// Logout closes the connection to the server at this time and does
// nothing with the user id. In the future this will release resources
// and safely release any sensitive memory.
// fixme: blocks forever is message reciever
func
(
cl
*
Client
)
Logout
()
error
{
if
cl
.
session
==
nil
{
err
:=
errors
.
New
(
"Logout: Cannot Logout when you are not logged in"
)
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
// Stop reception runner goroutine
close
(
cl
.
session
.
GetQuitChan
())
cl
.
commManager
.
Comms
.
DisconnectAll
()
errStore
:=
cl
.
session
.
StoreSession
()
if
errStore
!=
nil
{
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Logout: Store Failed: %s"
+
errStore
.
Error
()))
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
errImmolate
:=
cl
.
session
.
Immolate
()
cl
.
session
=
nil
if
errImmolate
!=
nil
{
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Logout: Immolation Failed: %s"
+
errImmolate
.
Error
()))
globals
.
Log
.
ERROR
.
Printf
(
err
.
Error
())
return
err
}
return
nil
}
// Returns the local version of the client repo
func
GetLocalVersion
()
string
{
return
globals
.
SEMVER
...
...
@@ -920,3 +526,72 @@ func (cl *Client) GetSession() user.Session {
func
(
cl
*
Client
)
GetCommManager
()
*
io
.
ReceptionManager
{
return
cl
.
commManager
}
//GetUpdatedNDF: Connects to the permissioning server to get the updated NDF from it
func
(
cl
*
Client
)
getUpdatedNDF
()
(
*
ndf
.
NetworkDefinition
,
error
)
{
// again, uses internal ndf. stay here, return results instead
//Hash the client's ndf for comparison with registration's ndf
hash
:=
sha256
.
New
()
ndfBytes
:=
cl
.
ndf
.
Serialize
()
hash
.
Write
(
ndfBytes
)
ndfHash
:=
hash
.
Sum
(
nil
)
//Put the hash in a message
msg
:=
&
mixmessages
.
NDFHash
{
Hash
:
ndfHash
}
host
,
ok
:=
cl
.
commManager
.
Comms
.
GetHost
(
PermissioningAddrID
)
if
!
ok
{
return
nil
,
errors
.
New
(
"Failed to find permissioning host"
)
}
//Send the hash to registration
response
,
err
:=
cl
.
commManager
.
Comms
.
SendGetUpdatedNDF
(
host
,
msg
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Failed to get ndf from permissioning: %v"
,
err
)
return
nil
,
errors
.
New
(
errMsg
)
}
//If there was no error and the response is nil, client's ndf is up-to-date
if
response
==
nil
{
globals
.
Log
.
DEBUG
.
Printf
(
"Client NDF up-to-date"
)
return
nil
,
nil
}
//FixMe: use verify instead? Probs need to add a signature to ndf, like in registration's getupdate?
globals
.
Log
.
INFO
.
Printf
(
"Remote NDF: %s"
,
string
(
response
.
Ndf
))
//Otherwise pull the ndf out of the response
updatedNdf
,
_
,
err
:=
ndf
.
DecodeNDF
(
string
(
response
.
Ndf
))
if
err
!=
nil
{
//If there was an error decoding ndf
errMsg
:=
fmt
.
Sprintf
(
"Failed to decode response to ndf: %v"
,
err
)
return
nil
,
errors
.
New
(
errMsg
)
}
return
updatedNdf
,
nil
}
//request calls getUpdatedNDF for a new NDF repeatedly until it gets an NDF
func
requestNdf
(
cl
*
Client
)
error
{
// Continuously polls for a new ndf after sleeping until response if gotten
globals
.
Log
.
INFO
.
Printf
(
"Polling for a new NDF"
)
newNDf
,
err
:=
cl
.
getUpdatedNDF
()
if
err
!=
nil
{
//lets the client continue when permissioning does not provide NDFs
if
err
.
Error
()
==
noNDFErr
.
Error
()
{
globals
.
Log
.
WARN
.
Println
(
"Continuing without an updated NDF"
)
return
nil
}
errMsg
:=
fmt
.
Sprintf
(
"Failed to get updated ndf: %v"
,
err
)
globals
.
Log
.
ERROR
.
Printf
(
errMsg
)
return
errors
.
New
(
errMsg
)
}
if
newNDf
!=
nil
{
cl
.
ndf
=
newNDf
}
return
nil
}
This diff is collapsed.
Click to expand it.
api/register.go
0 → 100644
+
341
−
0
View file @
d06c890b
package
api
import
(
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"github.com/pkg/errors"
"gitlab.com/elixxir/client/bots"
"gitlab.com/elixxir/client/globals"
"gitlab.com/elixxir/client/user"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
"gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/crypto/registration"
"gitlab.com/elixxir/crypto/signature/rsa"
"gitlab.com/elixxir/primitives/id"
"sync"
"time"
)
const
SaltSize
=
256
// RegisterWithPermissioning registers user with permissioning and returns the
// User ID. Returns an error if registration fails.
func
(
cl
*
Client
)
RegisterWithPermissioning
(
preCan
bool
,
registrationCode
,
nick
,
email
,
password
string
,
privateKeyRSA
*
rsa
.
PrivateKey
)
(
*
id
.
User
,
error
)
{
var
err
error
var
u
*
user
.
User
var
UID
*
id
.
User
cl
.
opStatus
(
globals
.
REG_KEYGEN
)
largeIntBits
:=
16
cmixGrp
:=
cyclic
.
NewGroup
(
large
.
NewIntFromString
(
cl
.
ndf
.
CMIX
.
Prime
,
largeIntBits
),
large
.
NewIntFromString
(
cl
.
ndf
.
CMIX
.
Generator
,
largeIntBits
))
e2eGrp
:=
cyclic
.
NewGroup
(
large
.
NewIntFromString
(
cl
.
ndf
.
E2E
.
Prime
,
largeIntBits
),
large
.
NewIntFromString
(
cl
.
ndf
.
E2E
.
Generator
,
largeIntBits
))
// Make CMIX keys array
nk
:=
make
(
map
[
id
.
Node
]
user
.
NodeKeys
)
// GENERATE CLIENT RSA KEYS
if
privateKeyRSA
==
nil
{
privateKeyRSA
,
err
=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsa
.
DefaultRSABitLen
)
if
err
!=
nil
{
return
nil
,
err
}
}
publicKeyRSA
:=
privateKeyRSA
.
GetPublic
()
cmixPrivKeyDHByte
,
err
:=
csprng
.
GenerateInGroup
(
cmixGrp
.
GetPBytes
(),
256
,
csprng
.
NewSystemRNG
())
if
err
!=
nil
{
return
nil
,
errors
.
New
(
fmt
.
Sprintf
(
"Could not generate cmix DH private key: %s"
,
err
.
Error
()))
}
cmixPrivateKeyDH
:=
cmixGrp
.
NewIntFromBytes
(
cmixPrivKeyDHByte
)
cmixPublicKeyDH
:=
cmixGrp
.
ExpG
(
cmixPrivateKeyDH
,
cmixGrp
.
NewMaxInt
())
e2ePrivKeyDHByte
,
err
:=
csprng
.
GenerateInGroup
(
cmixGrp
.
GetPBytes
(),
256
,
csprng
.
NewSystemRNG
())
if
err
!=
nil
{
return
nil
,
errors
.
New
(
fmt
.
Sprintf
(
"Could not generate e2e DH private key: %s"
,
err
.
Error
()))
}
e2ePrivateKeyDH
:=
e2eGrp
.
NewIntFromBytes
(
e2ePrivKeyDHByte
)
e2ePublicKeyDH
:=
e2eGrp
.
ExpG
(
e2ePrivateKeyDH
,
e2eGrp
.
NewMaxInt
())
// Initialized response from Registration Server
regValidationSignature
:=
make
([]
byte
,
0
)
var
salt
[]
byte
// Handle precanned registration
if
preCan
{
cl
.
opStatus
(
globals
.
REG_PRECAN
)
globals
.
Log
.
INFO
.
Printf
(
"Registering precanned user..."
)
u
,
UID
,
nk
,
err
=
cl
.
precannedRegister
(
registrationCode
,
nick
,
nk
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Unable to complete precanned registration: %+v"
,
err
)
return
id
.
ZeroID
,
err
}
}
else
{
cl
.
opStatus
(
globals
.
REG_UID_GEN
)
globals
.
Log
.
INFO
.
Printf
(
"Registering dynamic user..."
)
// Generate salt for UserID
salt
=
make
([]
byte
,
SaltSize
)
_
,
err
=
csprng
.
NewSystemRNG
()
.
Read
(
salt
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Register: Unable to generate salt! %s"
,
err
)
return
id
.
ZeroID
,
err
}
// Generate UserID by hashing salt and public key
UID
=
registration
.
GenUserID
(
publicKeyRSA
,
salt
)
// If Registration Server is specified, contact it
// Only if registrationCode is set
globals
.
Log
.
INFO
.
Println
(
"Register: Contacting registration server"
)
if
cl
.
ndf
.
Registration
.
Address
!=
""
&&
registrationCode
!=
""
{
cl
.
opStatus
(
globals
.
REG_PERM
)
regValidationSignature
,
err
=
cl
.
sendRegistrationMessage
(
registrationCode
,
publicKeyRSA
)
if
err
!=
nil
{
globals
.
Log
.
ERROR
.
Printf
(
"Register: Unable to send registration message: %+v"
,
err
)
return
id
.
ZeroID
,
err
}
}
globals
.
Log
.
INFO
.
Println
(
"Register: successfully passed Registration message"
)
var
actualNick
string
if
nick
!=
""
{
actualNick
=
nick
}
else
{
actualNick
=
base64
.
StdEncoding
.
EncodeToString
(
UID
[
:
])
}
u
=
user
.
Users
.
NewUser
(
UID
,
actualNick
)
user
.
Users
.
UpsertUser
(
u
)
}
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
u
.
Email
=
email
// Create the user session
newSession
:=
user
.
NewSession
(
cl
.
storage
,
u
,
nk
,
publicKeyRSA
,
privateKeyRSA
,
cmixPublicKeyDH
,
cmixPrivateKeyDH
,
e2ePublicKeyDH
,
e2ePrivateKeyDH
,
salt
,
cmixGrp
,
e2eGrp
,
password
,
regValidationSignature
)
cl
.
opStatus
(
globals
.
REG_SAVE
)
//set the registration state
err
=
newSession
.
SetRegState
(
user
.
PermissioningComplete
)
if
err
!=
nil
{
return
id
.
ZeroID
,
errors
.
Wrap
(
err
,
"Permissioning Registration "
+
"Failed"
)
}
// Store the user session
errStore
:=
newSession
.
StoreSession
()
if
errStore
!=
nil
{
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Permissioning Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
id
.
ZeroID
,
err
}
cl
.
session
=
newSession
return
UID
,
nil
}
// RegisterWithUDB uses the account's email to register with the UDB for
// User discovery. Must be called after Register and InitNetwork.
// It will fail if the user has already registered with UDB
func
(
cl
*
Client
)
RegisterWithUDB
(
timeout
time
.
Duration
)
error
{
regState
:=
cl
.
GetSession
()
.
GetRegState
()
if
regState
!=
user
.
PermissioningComplete
{
return
errors
.
New
(
"Cannot register with UDB when registration "
+
"state is not PermissioningComplete"
)
}
email
:=
cl
.
session
.
GetCurrentUser
()
.
Email
var
err
error
if
email
!=
""
{
globals
.
Log
.
INFO
.
Printf
(
"Registering user as %s with UDB"
,
email
)
valueType
:=
"EMAIL"
publicKeyBytes
:=
cl
.
session
.
GetE2EDHPublicKey
()
.
Bytes
()
err
=
bots
.
Register
(
valueType
,
email
,
publicKeyBytes
,
cl
.
opStatus
,
timeout
)
if
err
==
nil
{
globals
.
Log
.
INFO
.
Printf
(
"Registered with UDB!"
)
}
else
{
globals
.
Log
.
WARN
.
Printf
(
"Could not register with UDB: %s"
,
err
)
}
}
else
{
globals
.
Log
.
INFO
.
Printf
(
"Not registering with UDB because no "
+
"email found"
)
}
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"Could not register with UDB"
)
}
//set the registration state
err
=
cl
.
session
.
SetRegState
(
user
.
UDBComplete
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"UDB Registration Failed"
)
}
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
errStore
:=
cl
.
session
.
StoreSession
()
// FIXME If we have an error here, the session that gets created
// doesn't get immolated. Immolation should happen in a deferred
// call instead.
if
errStore
!=
nil
{
err
=
errors
.
New
(
fmt
.
Sprintf
(
"UDB Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
err
}
return
nil
}
func
(
cl
*
Client
)
RegisterWithNodes
()
error
{
cl
.
opStatus
(
globals
.
REG_NODE
)
session
:=
cl
.
GetSession
()
//Load Cmix keys & group
cmixDHPrivKey
:=
session
.
GetCMIXDHPrivateKey
()
cmixDHPubKey
:=
session
.
GetCMIXDHPublicKey
()
cmixGrp
:=
session
.
GetCmixGroup
()
//Load the rsa keys
rsaPubKey
:=
session
.
GetRSAPublicKey
()
rsaPrivKey
:=
session
.
GetRSAPrivateKey
()
//Load the user ID
UID
:=
session
.
GetCurrentUser
()
.
User
//Load the registration signature
regSignature
:=
session
.
GetRegistrationValidationSignature
()
var
wg
sync
.
WaitGroup
errChan
:=
make
(
chan
error
,
len
(
cl
.
ndf
.
Gateways
))
//Get the registered node keys
registeredNodes
:=
session
.
GetNodes
()
salt
:=
session
.
GetSalt
()
// This variable keeps track of whether there were new registrations
// required, thus requiring the state file to be saved again
newRegistrations
:=
false
for
i
:=
range
cl
.
ndf
.
Gateways
{
localI
:=
i
nodeID
:=
*
id
.
NewNodeFromBytes
(
cl
.
ndf
.
Nodes
[
i
]
.
ID
)
//Register with node if the node has not been registered with already
if
_
,
ok
:=
registeredNodes
[
nodeID
];
!
ok
{
wg
.
Add
(
1
)
newRegistrations
=
true
go
func
()
{
cl
.
registerWithNode
(
localI
,
salt
,
regSignature
,
UID
,
rsaPubKey
,
rsaPrivKey
,
cmixDHPubKey
,
cmixDHPrivKey
,
cmixGrp
,
errChan
)
wg
.
Done
()
}()
}
}
wg
.
Wait
()
//See if the registration returned errors at all
var
errs
error
for
len
(
errChan
)
>
0
{
err
:=
<-
errChan
if
errs
!=
nil
{
errs
=
errors
.
Wrap
(
errs
,
err
.
Error
())
}
else
{
errs
=
err
}
}
//If an error every occurred, return with error
if
errs
!=
nil
{
cl
.
opStatus
(
globals
.
REG_FAIL
)
return
errs
}
// Store the user session if there were changes during node registration
if
newRegistrations
{
cl
.
opStatus
(
globals
.
REG_SECURE_STORE
)
errStore
:=
session
.
StoreSession
()
if
errStore
!=
nil
{
err
:=
errors
.
New
(
fmt
.
Sprintf
(
"Register: could not register due to failed session save"
+
": %s"
,
errStore
.
Error
()))
return
err
}
}
return
nil
}
//registerWithNode registers a user. It serves as a helper for Register
func
(
cl
*
Client
)
registerWithNode
(
index
int
,
salt
,
registrationValidationSignature
[]
byte
,
UID
*
id
.
User
,
publicKeyRSA
*
rsa
.
PublicKey
,
privateKeyRSA
*
rsa
.
PrivateKey
,
cmixPublicKeyDH
,
cmixPrivateKeyDH
*
cyclic
.
Int
,
cmixGrp
*
cyclic
.
Group
,
errorChan
chan
error
)
{
gatewayID
:=
id
.
NewNodeFromBytes
(
cl
.
ndf
.
Nodes
[
index
]
.
ID
)
.
NewGateway
()
// Initialise blake2b hash for transmission keys and sha256 for reception
// keys
transmissionHash
,
_
:=
hash
.
NewCMixHash
()
receptionHash
:=
sha256
.
New
()
// Request nonce message from gateway
globals
.
Log
.
INFO
.
Printf
(
"Register: Requesting nonce from gateway %v/%v"
,
index
+
1
,
len
(
cl
.
ndf
.
Gateways
))
nonce
,
dhPub
,
err
:=
cl
.
requestNonce
(
salt
,
registrationValidationSignature
,
cmixPublicKeyDH
,
publicKeyRSA
,
privateKeyRSA
,
gatewayID
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Register: Failed requesting nonce from gateway: %+v"
,
err
)
errorChan
<-
errors
.
New
(
errMsg
)
}
// Load server DH pubkey
serverPubDH
:=
cmixGrp
.
NewIntFromBytes
(
dhPub
)
// Confirm received nonce
globals
.
Log
.
INFO
.
Println
(
"Register: Confirming received nonce"
)
err
=
cl
.
confirmNonce
(
UID
.
Bytes
(),
nonce
,
privateKeyRSA
,
gatewayID
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"Register: Unable to confirm nonce: %v"
,
err
)
errorChan
<-
errors
.
New
(
errMsg
)
}
nodeID
:=
cl
.
topology
.
GetNodeAtIndex
(
index
)
key
:=
user
.
NodeKeys
{
TransmissionKey
:
registration
.
GenerateBaseKey
(
cmixGrp
,
serverPubDH
,
cmixPrivateKeyDH
,
transmissionHash
),
ReceptionKey
:
registration
.
GenerateBaseKey
(
cmixGrp
,
serverPubDH
,
cmixPrivateKeyDH
,
receptionHash
),
}
cl
.
session
.
PushNodeKey
(
nodeID
,
key
)
}
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
register
or
sign in
to comment