Skip to content
Snippets Groups Projects
Commit 4e535f4e authored by Richard T. Carback III's avatar Richard T. Carback III
Browse files

Buildable code

parent 63dfe4e0
Branches
Tags
No related merge requests found
...@@ -7,38 +7,46 @@ ...@@ -7,38 +7,46 @@
package api package api
import ( import (
"bufio"
"crypto"
"crypto/sha256"
"encoding/base64"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/context" "gitlab.com/elixxir/client/context"
"gitlab.com/elixxir/client/context/stoppable"
"gitlab.com/elixxir/client/context/switchboard" "gitlab.com/elixxir/client/context/switchboard"
"gitlab.com/elixxir/client/network"
"gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage"
pb "gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/crypto/tls"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/ndf"
"strings"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
) )
type Client struct { type Client struct {
storage *storage.Session storage *storage.Session
ctx *context.Context ctx *context.Context
switchboard *switchboard.Switchboard switchboard *switchboard.Switchboard
network *network.Network network context.NetworkManager
} }
// NewClient creates client storage, generates keys, connects, and registers // NewClient creates client storage, generates keys, connects, and registers
// with the network. Note that this does not register a username/identity, but // with the network. Note that this does not register a username/identity, but
// merely creates a new cryptographic identity for adding such information // merely creates a new cryptographic identity for adding such information
// at a later date. // at a later date.
func NewClient(network, storageDir string, password []byte) (Client, error) { func NewClient(network, storageDir string, password []byte) (*Client, error) {
if clientStorageExists(storageDir) { if clientStorageExists(storageDir) {
return errors.New("client already exists at %s", return nil, errors.Errorf("client already exists at %s",
storageDir) storageDir)
} }
// Parse the NDF // Parse the NDF
ndf, err := parseNDF(network) //ndf, err := parseNDF(network)
if err != nil { //if err != nil {
return nil, err // return nil, err
} //}
// Create Storage // Create Storage
...@@ -48,7 +56,7 @@ func NewClient(network, storageDir string, password []byte) (Client, error) { ...@@ -48,7 +56,7 @@ func NewClient(network, storageDir string, password []byte) (Client, error) {
// Register with network // Register with network
client = Client{ client := &Client{
storage: nil, storage: nil,
ctx: nil, ctx: nil,
switchboard: nil, switchboard: nil,
...@@ -58,9 +66,9 @@ func NewClient(network, storageDir string, password []byte) (Client, error) { ...@@ -58,9 +66,9 @@ func NewClient(network, storageDir string, password []byte) (Client, error) {
} }
// LoadClient initalizes a client object from existing storage. // LoadClient initalizes a client object from existing storage.
func LoadClient(storageDir string, password []byte) (Client, error) { func LoadClient(storageDir string, password []byte) (*Client, error) {
if !clientStorageExists(storageDir) { if !clientStorageExists(storageDir) {
return errors.New("client does not exist at %s", return nil, errors.Errorf("client does not exist at %s",
storageDir) storageDir)
} }
...@@ -68,7 +76,7 @@ func LoadClient(storageDir string, password []byte) (Client, error) { ...@@ -68,7 +76,7 @@ func LoadClient(storageDir string, password []byte) (Client, error) {
// Load and create network, context, switchboard // Load and create network, context, switchboard
client = Client{ client := &Client{
storage: nil, storage: nil,
ctx: nil, ctx: nil,
switchboard: nil, switchboard: nil,
...@@ -81,16 +89,16 @@ func LoadClient(storageDir string, password []byte) (Client, error) { ...@@ -81,16 +89,16 @@ func LoadClient(storageDir string, password []byte) (Client, error) {
// RegisterListener registers a listener callback function that is called // RegisterListener registers a listener callback function that is called
// every time a new message matches the specified parameters. // every time a new message matches the specified parameters.
func (c Client) RegisterListener(uid id.ID, msgType int, username string, func (c *Client) RegisterListenerCb(uid id.ID, msgType int, username string,
listenerCb func(msg Message)) { listenerCb func(msg Message)) {
jww.INFO.Printf("RegisterListener(%s, %d, %s, %v)", uid, msgType, jww.INFO.Printf("RegisterListener(%s, %d, %s, func())", uid, msgType,
username, listenerCb) username)
} }
// SendE2E sends an end-to-end payload to the provided recipient with // SendE2E sends an end-to-end payload to the provided recipient with
// the provided msgType. Returns the list of rounds in which parts of // the provided msgType. Returns the list of rounds in which parts of
// the message were sent or an error if it fails. // the message were sent or an error if it fails.
func (c Client) SendE2E(payload []byte, recipient id.ID, msgType int) ( func (c *Client) SendE2E(payload []byte, recipient id.ID, msgType int) (
[]int, error) { []int, error) {
jww.INFO.Printf("SendE2E(%s, %s, %d)", payload, recipient, jww.INFO.Printf("SendE2E(%s, %s, %d)", payload, recipient,
msgType) msgType)
...@@ -102,7 +110,7 @@ func (c Client) SendE2E(payload []byte, recipient id.ID, msgType int) ( ...@@ -102,7 +110,7 @@ func (c Client) SendE2E(payload []byte, recipient id.ID, msgType int) (
// of the message were sent or an error if it fails. // of the message were sent or an error if it fails.
// NOTE: Do not use this function unless you know what you are doing. // NOTE: Do not use this function unless you know what you are doing.
// This function always produces an error message in client logging. // This function always produces an error message in client logging.
func (c Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int, func (c *Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int,
error) { error) {
jww.INFO.Printf("SendUnsafe(%s, %s, %d)", payload, recipient, jww.INFO.Printf("SendUnsafe(%s, %s, %d)", payload, recipient,
msgType) msgType)
...@@ -113,9 +121,8 @@ func (c Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int, ...@@ -113,9 +121,8 @@ func (c Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int,
// recipient. Note that both SendE2E and SendUnsafe call SendCMIX. // recipient. Note that both SendE2E and SendUnsafe call SendCMIX.
// Returns the round ID of the round the payload was sent or an error // Returns the round ID of the round the payload was sent or an error
// if it fails. // if it fails.
func (c Client) SendCMIX(payload []byte, recipient id.ID) (int, error) { func (c *Client) SendCMIX(payload []byte, recipient id.ID) (int, error) {
jww.INFO.Printf("SendCMIX(%s, %s)", payload, recipient, jww.INFO.Printf("SendCMIX(%s, %s)", payload, recipient)
msgType)
return 0, nil return 0, nil
} }
...@@ -125,14 +132,45 @@ func (c Client) SendCMIX(payload []byte, recipient id.ID) (int, error) { ...@@ -125,14 +132,45 @@ func (c Client) SendCMIX(payload []byte, recipient id.ID) (int, error) {
// especially as these rely on third parties (i.e., Firebase *cough* // especially as these rely on third parties (i.e., Firebase *cough*
// *cough* google's palantir *cough*) that may represent a security // *cough* google's palantir *cough*) that may represent a security
// risk to the user. // risk to the user.
func (c Client) RegisterForNotifications(token []byte) error { func (c *Client) RegisterForNotifications(token []byte) error {
jww.INFO.Printf("RegisterForNotifications(%s)", token) jww.INFO.Printf("RegisterForNotifications(%s)", token)
// // Pull the host from the manage
// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
// if !ok {
// return errors.New("Failed to retrieve host for notification bot")
// }
// // Send the register message
// _, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost,
// &mixmessages.NotificationToken{
// Token: notificationToken,
// })
// if err != nil {
// err := errors.Errorf(
// "RegisterForNotifications: Unable to register for notifications! %s", err)
// return err
// }
return nil return nil
} }
// UnregisterForNotifications turns of notifications for this client // UnregisterForNotifications turns of notifications for this client
func (c Client) UnregisterForNotifications() error { func (c *Client) UnregisterForNotifications() error {
jww.INFO.Printf("UnregisterForNotifications()") jww.INFO.Printf("UnregisterForNotifications()")
// // Pull the host from the manage
// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
// if !ok {
// return errors.New("Failed to retrieve host for notification bot")
// }
// // Send the unregister message
// _, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost)
// if err != nil {
// err := errors.Errorf(
// "RegisterForNotifications: Unable to register for notifications! %s", err)
// return err
// }
return nil return nil
} }
...@@ -142,16 +180,15 @@ func (c Client) UnregisterForNotifications() error { ...@@ -142,16 +180,15 @@ func (c Client) UnregisterForNotifications() error {
// out of band methods to exchange cryptographic identities // out of band methods to exchange cryptographic identities
// (e.g., QR codes), but failing to be registered precludes usage // (e.g., QR codes), but failing to be registered precludes usage
// of the user discovery mechanism (this may be preferred by user). // of the user discovery mechanism (this may be preferred by user).
func (c Client) IsRegistered() bool { func (c *Client) IsRegistered() bool {
jww.INFO.Printf("IsRegistered(%s, %s, %d)", payload, recipient, jww.INFO.Printf("IsRegistered()")
msgType)
return false return false
} }
// RegisterIdentity registers an arbitrary username with the user // RegisterIdentity registers an arbitrary username with the user
// discovery protocol. Returns an error when it cannot connect or // discovery protocol. Returns an error when it cannot connect or
// the username is already registered. // the username is already registered.
func (c Client) RegisterIdentity(username string) error { func (c *Client) RegisterIdentity(username string) error {
jww.INFO.Printf("RegisterIdentity(%s)", username) jww.INFO.Printf("RegisterIdentity(%s)", username)
return nil return nil
} }
...@@ -159,7 +196,7 @@ func (c Client) RegisterIdentity(username string) error { ...@@ -159,7 +196,7 @@ func (c Client) RegisterIdentity(username string) error {
// RegisterEmail makes the users email searchable after confirmation. // RegisterEmail makes the users email searchable after confirmation.
// It returns a registration confirmation token to be used with // It returns a registration confirmation token to be used with
// ConfirmRegistration or an error on failure. // ConfirmRegistration or an error on failure.
func (c Client) RegisterEmail(email string) ([]byte, error) { func (c *Client) RegisterEmail(email string) ([]byte, error) {
jww.INFO.Printf("RegisterEmail(%s)", email) jww.INFO.Printf("RegisterEmail(%s)", email)
return nil, nil return nil, nil
} }
...@@ -167,7 +204,7 @@ func (c Client) RegisterEmail(email string) ([]byte, error) { ...@@ -167,7 +204,7 @@ func (c Client) RegisterEmail(email string) ([]byte, error) {
// RegisterPhone makes the users phone searchable after confirmation. // RegisterPhone makes the users phone searchable after confirmation.
// It returns a registration confirmation token to be used with // It returns a registration confirmation token to be used with
// ConfirmRegistration or an error on failure. // ConfirmRegistration or an error on failure.
func (c Client) RegisterPhone(phone string) ([]byte, error) { func (c *Client) RegisterPhone(phone string) ([]byte, error) {
jww.INFO.Printf("RegisterPhone(%s)", phone) jww.INFO.Printf("RegisterPhone(%s)", phone)
return nil, nil return nil, nil
} }
...@@ -175,28 +212,28 @@ func (c Client) RegisterPhone(phone string) ([]byte, error) { ...@@ -175,28 +212,28 @@ func (c Client) RegisterPhone(phone string) ([]byte, error) {
// ConfirmRegistration sends the user discovery agent a confirmation // ConfirmRegistration sends the user discovery agent a confirmation
// token (from Register Email/Phone) and code (string sent via Email // token (from Register Email/Phone) and code (string sent via Email
// or SMS to confirm ownership) to confirm ownership. // or SMS to confirm ownership) to confirm ownership.
func (c Client) ConfirmRegistration(token, code []byte) error { func (c *Client) ConfirmRegistration(token, code []byte) error {
jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code) jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code)
return nil return nil
} }
// GetUser returns the current user Identity for this client. This // GetUser returns the current user Identity for this client. This
// can be serialized into a byte stream for out-of-band sharing. // can be serialized into a byte stream for out-of-band sharing.
func (c Client) GetUser() (Contact, error) { func (c *Client) GetUser() (Contact, error) {
jww.INFO.Printf("GetUser()") jww.INFO.Printf("GetUser()")
return Contact{}, nil return Contact{}, nil
} }
// MakeContact creates a contact from a byte stream (i.e., unmarshal's a // MakeContact creates a contact from a byte stream (i.e., unmarshal's a
// Contact object), allowing out-of-band import of identities. // Contact object), allowing out-of-band import of identities.
func (c Client) MakeContact(contactBytes []byte) (Contact, error) { func (c *Client) MakeContact(contactBytes []byte) (Contact, error) {
jww.INFO.Printf("MakeContact(%s)", contactBytes) jww.INFO.Printf("MakeContact(%s)", contactBytes)
return Contact{}, nil return Contact{}, nil
} }
// GetContact returns a Contact object for the given user id, or // GetContact returns a Contact object for the given user id, or
// an error // an error
func (c Client) GetContact(uid []byte) (Contact, error) { func (c *Client) GetContact(uid []byte) (Contact, error) {
jww.INFO.Printf("GetContact(%s)", uid) jww.INFO.Printf("GetContact(%s)", uid)
return Contact{}, nil return Contact{}, nil
} }
...@@ -204,19 +241,19 @@ func (c Client) GetContact(uid []byte) (Contact, error) { ...@@ -204,19 +241,19 @@ func (c Client) GetContact(uid []byte) (Contact, error) {
// Search accepts a "separator" separated list of search elements with // Search accepts a "separator" separated list of search elements with
// an associated list of searchTypes. It returns a ContactList which // an associated list of searchTypes. It returns a ContactList which
// allows you to iterate over the found contact objects. // allows you to iterate over the found contact objects.
func (c Client) Search(data, separator string, searchTypes []byte) []Contact { func (c *Client) Search(data, separator string, searchTypes []byte) []Contact {
jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes) jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes)
return nil return nil
} }
// SearchWithHandler is a non-blocking search that also registers // SearchWithHandler is a non-blocking search that also registers
// a callback interface for user disovery events. // a callback interface for user disovery events.
func (c Client) SearchWithCallback(data, separator string, searchTypes []byte, func (c *Client) SearchWithCallback(data, separator string, searchTypes []byte,
cb func(results []Contact)) { cb func(results []Contact)) {
resultCh := make(chan []Contact, 1) resultCh := make(chan []Contact, 1)
go func(out chan []Contact, data, separator string, srchTypes []byte) { go func(out chan []Contact, data, separator string, srchTypes []byte) {
out <- c.Search(data, separator, srchTypes) out <- c.Search(data, separator, srchTypes)
out.Close() close(out)
}(resultCh, data, separator, searchTypes) }(resultCh, data, separator, searchTypes)
go func(in chan []Contact, cb func(results []Contact)) { go func(in chan []Contact, cb func(results []Contact)) {
...@@ -232,23 +269,23 @@ func (c Client) SearchWithCallback(data, separator string, searchTypes []byte, ...@@ -232,23 +269,23 @@ func (c Client) SearchWithCallback(data, separator string, searchTypes []byte,
// so this user can send messages to the desired recipient Contact. // so this user can send messages to the desired recipient Contact.
// To receive confirmation from the remote user, clients must // To receive confirmation from the remote user, clients must
// register a listener to do that. // register a listener to do that.
func (c Client) CreateAuthenticatedChannel(recipient Contact, func (c *Client) CreateAuthenticatedChannel(recipient Contact,
payload []byte) error { payload []byte) error {
jww.INFO.Printf("CreateAuthenticatedChannel(%s, %s)", jww.INFO.Printf("CreateAuthenticatedChannel(%v, %v)",
recipient, payload) recipient, payload)
return nil return nil
} }
// RegisterAuthConfirmationCb registers a callback for channel // RegisterAuthConfirmationCb registers a callback for channel
// authentication confirmation events. // authentication confirmation events.
func (c Client) RegisterAuthConfirmationCb(cb func(contact Contact, func (c *Client) RegisterAuthConfirmationCb(cb func(contact Contact,
payload []byte)) { payload []byte)) {
jww.INFO.Printf("RegisterAuthConfirmationCb(...)") jww.INFO.Printf("RegisterAuthConfirmationCb(...)")
} }
// RegisterAuthRequestCb registers a callback for channel // RegisterAuthRequestCb registers a callback for channel
// authentication request events. // authentication request events.
func (c Client) RegisterAuthRequestCb(cb func(contact Contact, func (c *Client) RegisterAuthRequestCb(cb func(contact Contact,
payload []byte)) { payload []byte)) {
jww.INFO.Printf("RegisterAuthRequestCb(...)") jww.INFO.Printf("RegisterAuthRequestCb(...)")
} }
...@@ -257,13 +294,15 @@ func (c Client) RegisterAuthRequestCb(cb func(contact Contact, ...@@ -257,13 +294,15 @@ func (c Client) RegisterAuthRequestCb(cb func(contact Contact,
// and returns an object for checking state and stopping those threads. // and returns an object for checking state and stopping those threads.
// Call this when returning from sleep and close when going back to // Call this when returning from sleep and close when going back to
// sleep. // sleep.
func (c Client) StartNetworkRunner() NetworkRunner { func (c *Client) StartNetworkRunner() stoppable.Stoppable {
jww.INFO.Printf("StartNetworkRunner()") jww.INFO.Printf("StartNetworkRunner()")
return nil
} }
// RegisterRoundEventsCb registers a callback for round // RegisterRoundEventsCb registers a callback for round
// events. // events.
func (c Client) RegisterRoundEventsCb(cb func(re RoundEvent)) { func (c *Client) RegisterRoundEventsCb(
cb func(re *pb.RoundInfo, timedOut bool)) {
jww.INFO.Printf("RegisterRoundEventsCb(...)") jww.INFO.Printf("RegisterRoundEventsCb(...)")
} }
...@@ -314,19 +353,19 @@ func parseNDF(ndfString string) (*ndf.NetworkDefinition, error) { ...@@ -314,19 +353,19 @@ func parseNDF(ndfString string) (*ndf.NetworkDefinition, error) {
} }
// Load the TLS cert given to us, and from that get the RSA public key // Load the TLS cert given to us, and from that get the RSA public key
cert, err := tls.LoadCertificate(ndf.NdfPub) cert, err := tls.LoadCertificate(ndf.Registration.TlsCertificate)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pubKey := &rsa.PublicKey{PublicKey: *cert.PublicKey.(*gorsa.PublicKey)} pubKey := cert.PublicKey.(*rsa.PublicKey)
// Hash NDF JSON // Hash NDF JSON
rsaHash := sha256.New() rsaHash := sha256.New()
rsaHash.Write(ndfData) rsaHash.Write(ndfData)
// Verify signature // Verify signature
err = rsa.Verify( err = rsa.Verify(pubKey, crypto.SHA256,
pubKey, crypto.SHA256, rsaHash.Sum(nil), ndfSignature, nil) rsaHash.Sum(nil), ndfSignature, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
package api package api
import (
"gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id"
)
// Contact implements the Contact interface defined in bindings/interfaces.go, // Contact implements the Contact interface defined in bindings/interfaces.go,
type Contact struct { type Contact struct {
ID id.ID ID id.ID
...@@ -22,7 +27,7 @@ func (c Contact) GetID() []byte { ...@@ -22,7 +27,7 @@ func (c Contact) GetID() []byte {
// GetPublicKey returns the publickey bytes for this user. // GetPublicKey returns the publickey bytes for this user.
func (c Contact) GetPublicKey() []byte { func (c Contact) GetPublicKey() []byte {
return c.PubKey.Bytes() return rsa.CreatePublicKeyPem(&c.PubKey)
} }
// GetSalt returns the salt used to initiate an authenticated channel // GetSalt returns the salt used to initiate an authenticated channel
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package api
import (
"gitlab.com/xx_network/primitives/id"
)
// Message is a message received from the cMix network in the clear
// or that has been decrypted using established E2E keys.
type Message interface {
// Returns the message's sender ID, if available
GetSender() id.ID
GetSenderBytes() []byte
// Returns the message payload/contents
// Parse this with protobuf/whatever according to the message type
GetPayload() []byte
// Returns the message's recipient ID
// This is usually your userID but could be an ephemeral/group ID
GetRecipient() id.ID
GetRecipientBytes() []byte
// Returns the message's type
GetMessageType() int32
// Returns the message's timestamp in seconds since unix epoc
GetTimestamp() int64
// Returns the message's timestamp in ns since unix epoc
GetTimestampNano() int64
}
// RoundEvent contains event information for a given round.
// TODO: This is a half-baked interface and will be filled out later.
type RoundEvent interface {
// GetID returns the round ID for this round.
GetID() int
// GetStatus returns the status of this round.
GetStatus() int
}
This diff is collapsed.
package api
import (
"github.com/pkg/errors"
"gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/xx_network/primitives/id"
)
// RegisterForNotifications sends a message to notification bot indicating it
// is registering for notifications
func (cl *Client) RegisterForNotifications(notificationToken []byte) error {
// Pull the host from the manage
notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
if !ok {
return errors.New("Failed to retrieve host for notification bot")
}
// Send the register message
_, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost,
&mixmessages.NotificationToken{
Token: notificationToken,
})
if err != nil {
err := errors.Errorf(
"RegisterForNotifications: Unable to register for notifications! %s", err)
return err
}
return nil
}
// UnregisterForNotifications sends a message to notification bot indicating it
// no longer wants to be registered for notifications
func (cl *Client) UnregisterForNotifications() error {
// Pull the host from the manage
notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
if !ok {
return errors.New("Failed to retrieve host for notification bot")
}
// Send the unregister message
_, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost)
if err != nil {
err := errors.Errorf(
"RegisterForNotifications: Unable to register for notifications! %s", err)
return err
}
return nil
}
package api
import (
"gitlab.com/xx_network/crypto/signature/rsa"
"testing"
)
var dummy_key = `-----BEGIN PRIVATE KEY-----
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
jR+QSAa9eEozCngV6LUagC0YYWDZ
-----END PRIVATE KEY-----`
// Happy path
func TestClient_RegisterForNotifications(t *testing.T) {
// Initialize client with dummy storage
storage := DummyStorage{LocationA: ".ekv-registernotifications/a", StoreA: []byte{'a', 'b', 'c'}}
client, err := NewClient(&storage, ".ekv-registernotifications/a", "", def)
if err != nil {
t.Errorf("Failed to initialize dummy client: %s", err.Error())
return
}
privKey, err := rsa.LoadPrivateKeyFromPem([]byte(dummy_key))
if err != nil {
t.Errorf("Failed to load private key: %+v", err)
}
// InitNetwork to gateways and reg server
err = client.InitNetwork()
if err != nil {
t.Errorf("Client failed of connect: %+v", err)
}
err = client.GenerateKeys(privKey, "test")
if err != nil {
t.Errorf("Failed to properly set up keys: %+v", err)
}
token := make([]byte, 32)
err = client.RegisterForNotifications(token)
if err != nil {
t.Errorf("Expected happy path, received error: %+v", err)
}
}
// Happy path
func TestClient_UnregisterForNotifications(t *testing.T) {
// Initialize client with dummy storage
storage := DummyStorage{LocationA: ".ekv-unregisternotifications/a", StoreA: []byte{'a', 'b', 'c'}}
client, err := NewClient(&storage, ".ekv-unregisternotifications/a", "", def)
if err != nil {
t.Errorf("Failed to initialize dummy client: %s", err.Error())
}
privKey, err := rsa.LoadPrivateKeyFromPem([]byte(dummy_key))
if err != nil {
t.Errorf("Failed to load private key: %+v", err)
return
}
err = client.GenerateKeys(privKey, "test")
if err != nil {
t.Errorf("Failed to properly set up keys: %+v", err)
return
}
// InitNetwork to gateways and reg server
err = client.InitNetwork()
if err != nil {
t.Errorf("Client failed of connect: %+v", err)
}
err = client.UnregisterForNotifications()
if err != nil {
t.Errorf("Expected happy path, received error: %+v", err)
}
}
...@@ -8,17 +8,14 @@ package api ...@@ -8,17 +8,14 @@ package api
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/elixxir/client/context"
"gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/globals"
"gitlab.com/elixxir/client/network/permissioning"
"gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/comms/client"
) )
// Returns an error if registration fails. // Returns an error if registration fails.
func (c *Client) RegisterWithPermissioning(registrationCode string) error { func (c *Client) RegisterWithPermissioning(registrationCode string) error {
instance := ctx.Manager.GetInstance() ctx := c.ctx
instance.GetPartialNdf() netman := ctx.Manager
//Check the regState is in proper state for registration //Check the regState is in proper state for registration
regState := c.storage.GetRegistrationStatus() regState := c.storage.GetRegistrationStatus()
...@@ -29,8 +26,8 @@ func (c *Client) RegisterWithPermissioning(registrationCode string) error { ...@@ -29,8 +26,8 @@ func (c *Client) RegisterWithPermissioning(registrationCode string) error {
userData := ctx.Session.User() userData := ctx.Session.User()
// Register with the permissioning server and generate user information // Register with the permissioning server and generate user information
regValidationSignature, err := permissioning.RegisterWithPermissioning(&comms, regValidationSignature, err := netman.RegisterWithPermissioning(
userData.GetCryptographicIdentity().GetRSA().GetPublic(), registrationCode) registrationCode)
if err != nil { if err != nil {
globals.Log.INFO.Printf(err.Error()) globals.Log.INFO.Printf(err.Error())
return err return err
......
...@@ -10,6 +10,12 @@ import ( ...@@ -10,6 +10,12 @@ import (
"gitlab.com/elixxir/client/api" "gitlab.com/elixxir/client/api"
) )
// BindingsClient wraps the api.Client, implementing additional functions
// to support the gomobile Client interface
type BindingsClient struct {
api.Client
}
// NewClient connects and registers to the network using a json encoded // NewClient connects and registers to the network using a json encoded
// network information string and then creates a new client at the specified // network information string and then creates a new client at the specified
// storageDir using the specified password. This function will fail // storageDir using the specified password. This function will fail
...@@ -29,7 +35,12 @@ import ( ...@@ -29,7 +35,12 @@ import (
// Users of this function should delete the storage directory on error. // Users of this function should delete the storage directory on error.
func NewClient(network, storageDir string, password []byte) (Client, error) { func NewClient(network, storageDir string, password []byte) (Client, error) {
// TODO: This should wrap the bindings ClientImpl, when available. // TODO: This should wrap the bindings ClientImpl, when available.
return api.NewClient(network, storageDir, password) client, err := api.NewClient(network, storageDir, password)
if err != nil {
return nil, err
}
bindingsClient := &BindingsClient{*client}
return bindingsClient, nil
} }
// LoadClient will load an existing client from the storageDir // LoadClient will load an existing client from the storageDir
...@@ -41,5 +52,66 @@ func NewClient(network, storageDir string, password []byte) (Client, error) { ...@@ -41,5 +52,66 @@ func NewClient(network, storageDir string, password []byte) (Client, error) {
// starts subprocesses to perform network operations. // starts subprocesses to perform network operations.
func LoadClient(storageDir string, password []byte) (Client, error) { func LoadClient(storageDir string, password []byte) (Client, error) {
// TODO: This should wrap the bindings ClientImpl, when available. // TODO: This should wrap the bindings ClientImpl, when available.
return api.LoadClient(storageDir, password) client, err := api.LoadClient(storageDir, password)
if err != nil {
return nil, err
}
bindingsClient := &BindingsClient{*client}
return bindingsClient, nil
}
// RegisterListener records and installs a listener for messages
// matching specific uid, msgType, and/or username
func (b *BindingsClient) RegisterListener(uid []byte, msgType int,
username string, listener Listener) {
}
// SearchWithHandler is a non-blocking search that also registers
// a callback interface for user disovery events.
func (b *BindingsClient) SearchWithHandler(data, separator string,
searchTypes []byte, hdlr UserDiscoveryHandler) {
}
// RegisterAuthEventsHandler registers a callback interface for channel
// authentication events.
func (b *BindingsClient) RegisterAuthEventsHandler(hdlr AuthEventHandler) {
}
// RegisterRoundEventsHandler registers a callback interface for round
// events.
func (b *BindingsClient) RegisterRoundEventsHandler(hdlr RoundEventHandler) {
}
// SendE2E sends an end-to-end payload to the provided recipient with
// the provided msgType. Returns the list of rounds in which parts of
// the message were sent or an error if it fails.
func (b *BindingsClient) SendE2E(payload, recipient []byte,
msgType int) (RoundList, error) {
return nil, nil
}
// SendUnsafe sends an unencrypted payload to the provided recipient
// with the provided msgType. Returns the list of rounds in which parts
// of the message were sent or an error if it fails.
// NOTE: Do not use this function unless you know what you are doing.
// This function always produces an error message in client logging.
func (b *BindingsClient) SendUnsafe(payload, recipient []byte,
msgType int) (RoundList, error) {
return nil, nil
}
// SendCMIX sends a "raw" CMIX message payload to the provided
// recipient. Note that both SendE2E and SendUnsafe call SendCMIX.
// Returns the round ID of the round the payload was sent or an error
// if it fails.
func (b *BindingsClient) SendCMIX(payload, recipient []byte) (int, error) {
return 0, nil
}
// Search accepts a "separator" separated list of search elements with
// an associated list of searchTypes. It returns a ContactList which
// allows you to iterate over the found contact objects.
func (b *BindingsClient) Search(data, separator string,
searchTypes []byte) ContactList {
return nil
} }
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
package bindings package bindings
import ( import (
"gitlab.com/elixxir/primitives/switchboard" "gitlab.com/elixxir/client/api"
"gitlab.com/elixxir/client/context/stoppable"
) )
// Client is defined inside the api package. At minimum, it implements all of // Client is defined inside the api package. At minimum, it implements all of
...@@ -84,13 +85,13 @@ type Client interface { ...@@ -84,13 +85,13 @@ type Client interface {
// GetUser returns the current user Identity for this client. This // GetUser returns the current user Identity for this client. This
// can be serialized into a byte stream for out-of-band sharing. // can be serialized into a byte stream for out-of-band sharing.
GetUser() (Contact, error) GetUser() (api.Contact, error)
// MakeContact creates a contact from a byte stream (i.e., unmarshal's a // MakeContact creates a contact from a byte stream (i.e., unmarshal's a
// Contact object), allowing out-of-band import of identities. // Contact object), allowing out-of-band import of identities.
MakeContact(contactBytes []byte) (Contact, error) MakeContact(contactBytes []byte) (api.Contact, error)
// GetContact returns a Contact object for the given user id, or // GetContact returns a Contact object for the given user id, or
// an error // an error
GetContact(uid []byte) (Contact, error) GetContact(uid []byte) (api.Contact, error)
// ----- User Discovery ----- // ----- User Discovery -----
...@@ -109,7 +110,7 @@ type Client interface { ...@@ -109,7 +110,7 @@ type Client interface {
// so this user can send messages to the desired recipient Contact. // so this user can send messages to the desired recipient Contact.
// To receive confirmation from the remote user, clients must // To receive confirmation from the remote user, clients must
// register a listener to do that. // register a listener to do that.
CreateAuthenticatedChannel(recipient Contact, payload []byte) error CreateAuthenticatedChannel(recipient api.Contact, payload []byte) error
// RegierAuthEventsHandler registers a callback interface for channel // RegierAuthEventsHandler registers a callback interface for channel
// authentication events. // authentication events.
RegisterAuthEventsHandler(hdlr AuthEventHandler) RegisterAuthEventsHandler(hdlr AuthEventHandler)
...@@ -120,68 +121,19 @@ type Client interface { ...@@ -120,68 +121,19 @@ type Client interface {
// and returns an object for checking state and stopping those threads. // and returns an object for checking state and stopping those threads.
// Call this when returning from sleep and close when going back to // Call this when returning from sleep and close when going back to
// sleep. // sleep.
StartNetworkRunner() NetworkRunner StartNetworkRunner() stoppable.Stoppable
// RegisterRoundEventsHandler registers a callback interface for round // RegisterRoundEventsHandler registers a callback interface for round
// events. // events.
RegisterRoundEventsHandler(hdlr RoundEventHandler) RegisterRoundEventsHandler(hdlr RoundEventHandler)
} }
// Message is a message received from the cMix network in the clear
// or that has been decrypted using established E2E keys.
type Message interface {
// Returns the message's sender ID, if available
GetSender() []byte
// Returns the message payload/contents
// Parse this with protobuf/whatever according to the message type
GetPayload() []byte
// Returns the message's recipient ID
// This is usually your userID but could be an ephemeral/group ID
GetRecipient() []byte
// Returns the message's type
GetMessageType() int32
// Returns the message's timestamp in seconds since unix epoc
GetTimestamp() int64
// Returns the message's timestamp in ns since unix epoc
GetTimestampNano() int64
}
// RoundEvent contains event information for a given round.
// TODO: This is a half-baked interface and will be filled out later.
type RoundEvent interface {
// GetID returns the round ID for this round.
GetID() int
// GetStatus returns the status of this round.
GetStatus() int
}
// ContactList contains a list of contacts // ContactList contains a list of contacts
type ContactList interface { type ContactList interface {
// GetLen returns the number of contacts in the list // GetLen returns the number of contacts in the list
GetLen() int GetLen() int
// GetContact returns the contact at index i // GetContact returns the contact at index i
GetContact(i int) Contact GetContact(i int) api.Contact
}
// Contact contains the contacts information. Note that this object
// is a copy of the contact at the time it was generated, so api users
// cannot rely on this object being updated once it has been received.
type Contact interface {
// GetID returns the user ID for this user.
GetID() []byte
// GetPublicKey returns the publickey bytes for this user.
GetPublicKey() []byte
// GetSalt returns the salt used to initiate an authenticated channel
GetSalt() []byte
// IsAuthenticated returns true if an authenticated channel exists for
// this user so we can begin to send messages.
IsAuthenticated() bool
// IsConfirmed returns true if the user has confirmed the authenticated
// channel on their end.
IsConfirmed() bool
// Marshal creates a serialized representation of a contact for
// out-of-band contact exchange.
Marshal() ([]byte, error)
} }
// ----- Callback interfaces ----- // ----- Callback interfaces -----
...@@ -192,7 +144,7 @@ type Contact interface { ...@@ -192,7 +144,7 @@ type Contact interface {
// time. // time.
type Listener interface { type Listener interface {
// Hear is called to receive a message in the UI // Hear is called to receive a message in the UI
Hear(msg Message) Hear(msg api.Message)
} }
// AuthEventHandler handles authentication requests initiated by // AuthEventHandler handles authentication requests initiated by
...@@ -202,13 +154,30 @@ type AuthEventHandler interface { ...@@ -202,13 +154,30 @@ type AuthEventHandler interface {
// the client has called CreateAuthenticatedChannel for // the client has called CreateAuthenticatedChannel for
// the provided contact. Payload is typically empty but // the provided contact. Payload is typically empty but
// may include a small introductory message. // may include a small introductory message.
HandleConfirmation(contact Contact, payload []byte) HandleConfirmation(contact api.Contact, payload []byte)
// HandleRequest handles AuthEvents received before // HandleRequest handles AuthEvents received before
// the client has called CreateAuthenticatedChannel for // the client has called CreateAuthenticatedChannel for
// the provided contact. It should prompt the user to accept // the provided contact. It should prompt the user to accept
// the channel creation "request" and, if approved, // the channel creation "request" and, if approved,
// call CreateAuthenticatedChannel for this Contact. // call CreateAuthenticatedChannel for this Contact.
HandleRequest(contact Contact, payload []byte) HandleRequest(contact api.Contact, payload []byte)
}
// RoundList contains a list of contacts
type RoundList interface {
// GetLen returns the number of contacts in the list
GetLen() int
// GetRoundID returns the round ID at index i
GetRoundID(i int) int
}
// RoundEvent contains event information for a given round.
// TODO: This is a half-baked interface and will be filled out later.
type RoundEvent interface {
// GetID returns the round ID for this round.
GetID() int
// GetStatus returns the status of this round.
GetStatus() int
} }
// RoundEventHandler handles round events happening on the cMix network. // RoundEventHandler handles round events happening on the cMix network.
......
...@@ -8,23 +8,15 @@ ...@@ -8,23 +8,15 @@
package cmd package cmd
import ( import (
"encoding/base64"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/golang/protobuf/proto"
"github.com/spf13/cobra" "github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper" "github.com/spf13/viper"
"gitlab.com/elixxir/primitives/switchboard"
"gitlab.com/elixxir/primitives/utils"
"gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"io/ioutil" "io/ioutil"
"os" "os"
"strconv" "strconv"
"strings"
"sync/atomic"
"time"
) )
var verbose bool var verbose bool
...@@ -63,319 +55,116 @@ func Execute() { ...@@ -63,319 +55,116 @@ func Execute() {
} }
} }
func sessionInitialization() (*id.ID, string, *api.Client) { // func setKeyParams(client *api.Client) {
var err error // jww.DEBUG.Printf("Trying to parse key parameters...")
register := false // minKeys, err := strconv.Atoi(keyParams[0])
// if err != nil {
var client *api.Client // return
// }
// Read in the network definition file and save as string
ndfBytes, err := utils.ReadFile(ndfPath) // maxKeys, err := strconv.Atoi(keyParams[1])
if err != nil { // if err != nil {
globals.Log.FATAL.Panicf("Could not read network definition file: %v", err) // return
} // }
// Check if the NDF verify flag is set // numRekeys, err := strconv.Atoi(keyParams[2])
if skipNDFVerification { // if err != nil {
ndfPubKey = "" // return
globals.Log.WARN.Println("Skipping NDF verification") // }
} else {
pkFile, err := os.Open(ndfPubKey) // ttlScalar, err := strconv.ParseFloat(keyParams[3], 64)
if err != nil { // if err != nil {
globals.Log.FATAL.Panicf("Could not open cert file: %v", // return
err) // }
}
// minNumKeys, err := strconv.Atoi(keyParams[4])
pkBytes, err := ioutil.ReadAll(pkFile) // if err != nil {
if err != nil { // return
globals.Log.FATAL.Panicf("Could not read cert file: %v", // }
err)
} // jww.DEBUG.Printf("Setting key generation parameters: %d, %d, %d, %f, %d",
ndfPubKey = string(pkBytes) // minKeys, maxKeys, numRekeys, ttlScalar, minNumKeys)
}
// params := client.GetKeyParams()
// Verify the signature // params.MinKeys = uint16(minKeys)
globals.Log.DEBUG.Println("Verifying NDF...") // params.MaxKeys = uint16(maxKeys)
ndfJSON := api.VerifyNDF(string(ndfBytes), ndfPubKey) // params.NumRekeys = uint16(numRekeys)
globals.Log.DEBUG.Printf(" NDF Verified") // params.TTLScalar = ttlScalar
// params.MinNumKeys = uint16(minNumKeys)
//If no session file is passed initialize with RAM Storage // }
if sessionFile == "" {
client, err = api.NewClient(&globals.RamStorage{}, "", "", ndfJSON) // type FallbackListener struct {
if err != nil { // MessagesReceived int64
globals.Log.ERROR.Printf("Could Not Initialize Ram Storage: %s\n", // }
err.Error())
return &id.ZeroUser, "", nil // func (l *FallbackListener) Hear(item switchboard.Item, isHeardElsewhere bool, i ...interface{}) {
} // if !isHeardElsewhere {
globals.Log.INFO.Println("Initialized Ram Storage") // message := item.(*parse.Message)
register = true // sender, ok := userRegistry.Users.GetUser(message.Sender)
} else { // var senderNick string
// if !ok {
var sessionA, sessionB string // jww.ERROR.Printf("Couldn't get sender %v", message.Sender)
// } else {
locs := strings.Split(sessionFile, ",") // senderNick = sender.Username
// }
if len(locs) == 2 { // atomic.AddInt64(&l.MessagesReceived, 1)
sessionA = locs[0] // jww.INFO.Printf("Message of type %v from %q, %v received with fallback: %s\n",
sessionB = locs[1] // message.MessageType, printIDNice(message.Sender), senderNick,
} else { // string(message.Body))
sessionA = sessionFile // }
sessionB = sessionFile + "-2" // }
}
// type TextListener struct {
//If a session file is passed, check if it's valid // MessagesReceived int64
_, err1 := os.Stat(sessionA) // }
_, err2 := os.Stat(sessionB)
// func (l *TextListener) Hear(item switchboard.Item, isHeardElsewhere bool, i ...interface{}) {
if err1 != nil && err2 != nil { // message := item.(*parse.Message)
//If the file does not exist, register a new user // jww.INFO.Println("Hearing a text message")
if os.IsNotExist(err1) && os.IsNotExist(err2) { // result := cmixproto.TextMessage{}
register = true // err := proto.Unmarshal(message.Body, &result)
} else { // if err != nil {
//Fail if any other error is received // jww.ERROR.Printf("Error unmarshaling text message: %v\n",
globals.Log.ERROR.Printf("Error with file paths: %s %s", // err.Error())
err1, err2) // }
return &id.ZeroUser, "", nil
} // sender, ok := userRegistry.Users.GetUser(message.Sender)
} // var senderNick string
//Initialize client with OS Storage // if !ok {
client, err = api.NewClient(nil, sessionA, sessionB, ndfJSON) // jww.INFO.Printf("First message from sender %v", printIDNice(message.Sender))
if err != nil { // u := userRegistry.Users.NewUser(message.Sender, base64.StdEncoding.EncodeToString(message.Sender[:]))
globals.Log.ERROR.Printf("Could Not Initialize OS Storage: %s\n", err.Error()) // userRegistry.Users.UpsertUser(u)
return &id.ZeroUser, "", nil // senderNick = u.Username
} // } else {
globals.Log.INFO.Println("Initialized OS Storage") // senderNick = sender.Username
// }
} // logMsg := fmt.Sprintf("Message from %v, %v Received: %s\n",
// printIDNice(message.Sender),
if noBlockingTransmission { // senderNick, result.Message)
globals.Log.INFO.Println("Disabling Blocking Transmissions") // jww.INFO.Printf("%s -- Timestamp: %s\n", logMsg,
client.DisableBlockingTransmission() // message.Timestamp.String())
} // fmt.Printf(logMsg)
// Handle parsing gateway addresses from the config file // atomic.AddInt64(&l.MessagesReceived, 1)
// }
//REVIEWER NOTE: Possibly need to remove/rearrange this,
// now that client may not know gw's upon client creation // type userSearcher struct {
/*gateways := client.GetNDF().Gateways // foundUserChan chan []byte
// If gwAddr was not passed via command line, check config file // }
if len(gateways) < 1 {
// No gateways in config file or passed via command line // func newUserSearcher() api.SearchCallback {
globals.Log.ERROR.Printf("Error: No gateway specified! Add to" + // us := userSearcher{}
" configuration file or pass via command line using -g!\n") // us.foundUserChan = make(chan []byte)
return &id.ZeroUser, "", nil // return &us
}*/ // }
if noTLS { // func (us *userSearcher) Callback(userID, pubKey []byte, err error) {
client.DisableTls() // if err != nil {
} // jww.ERROR.Printf("Could not find searched user: %+v", err)
// } else {
// InitNetwork to gateways, notificationBot and reg server // us.foundUserChan <- userID
err = client.InitNetwork() // }
if err != nil { // }
globals.Log.FATAL.Panicf("Could not call connect on client: %+v", err)
}
client.SetRateLimiting(rateLimiting)
// Holds the User ID
var uid *id.ID
// Register a new user if requested
if register {
globals.Log.INFO.Println("Registering...")
regCode := registrationCode
// If precanned user, use generated code instead
if userId != 0 {
precanned = true
uid := new(id.ID)
binary.BigEndian.PutUint64(uid[:], userId)
uid.SetType(id.User)
regCode = userRegistry.RegistrationCode(uid)
}
globals.Log.INFO.Printf("Building keys...")
var privKey *rsa.PrivateKey
if privateKeyPath != "" {
privateKeyBytes, err := utils.ReadFile(privateKeyPath)
if err != nil {
globals.Log.FATAL.Panicf("Could not load user private key PEM from "+
"path %s: %+v", privateKeyPath, err)
}
privKey, err = rsa.LoadPrivateKeyFromPem(privateKeyBytes)
if err != nil {
globals.Log.FATAL.Panicf("Could not load private key from PEM bytes: %+v", err)
}
}
//Generate keys for registration
err := client.GenerateKeys(privKey, sessFilePassword)
if err != nil {
globals.Log.FATAL.Panicf("%+v", err)
}
globals.Log.INFO.Printf("Attempting to register with code %s...", regCode)
errRegister := fmt.Errorf("")
//Attempt to register user with same keys until a success occurs
for errRegister != nil {
_, errRegister = client.RegisterWithPermissioning(precanned, regCode)
if errRegister != nil {
globals.Log.FATAL.Panicf("Could Not Register User: %s",
errRegister.Error())
}
}
err = client.RegisterWithNodes()
if err != nil {
globals.Log.FATAL.Panicf("Could Not Register User with nodes: %s",
err.Error())
}
uid = client.GetCurrentUser()
userbase64 := base64.StdEncoding.EncodeToString(uid[:])
globals.Log.INFO.Printf("Registered as user (uid, the var) %v", uid)
globals.Log.INFO.Printf("Registered as user (userID, the global) %v", userId)
globals.Log.INFO.Printf("Successfully registered user %s!", userbase64)
} else {
// hack for session persisting with cmd line
// doesn't support non pre canned users
uid := new(id.ID)
binary.BigEndian.PutUint64(uid[:], userId)
uid.SetType(id.User)
globals.Log.INFO.Printf("Skipped Registration, user: %v", uid)
}
if !precanned {
// If we are sending to a non precanned user we retrieve the uid from the session returned by client.login
uid, err = client.Login(sessFilePassword)
} else {
_, err = client.Login(sessFilePassword)
}
if err != nil {
globals.Log.FATAL.Panicf("Could not login: %v", err)
}
return uid, client.GetUsername(), client
}
func setKeyParams(client *api.Client) {
globals.Log.DEBUG.Printf("Trying to parse key parameters...")
minKeys, err := strconv.Atoi(keyParams[0])
if err != nil {
return
}
maxKeys, err := strconv.Atoi(keyParams[1])
if err != nil {
return
}
numRekeys, err := strconv.Atoi(keyParams[2])
if err != nil {
return
}
ttlScalar, err := strconv.ParseFloat(keyParams[3], 64)
if err != nil {
return
}
minNumKeys, err := strconv.Atoi(keyParams[4])
if err != nil {
return
}
globals.Log.DEBUG.Printf("Setting key generation parameters: %d, %d, %d, %f, %d",
minKeys, maxKeys, numRekeys, ttlScalar, minNumKeys)
params := client.GetKeyParams()
params.MinKeys = uint16(minKeys)
params.MaxKeys = uint16(maxKeys)
params.NumRekeys = uint16(numRekeys)
params.TTLScalar = ttlScalar
params.MinNumKeys = uint16(minNumKeys)
}
type FallbackListener struct {
MessagesReceived int64
}
func (l *FallbackListener) Hear(item switchboard.Item, isHeardElsewhere bool, i ...interface{}) {
if !isHeardElsewhere {
message := item.(*parse.Message)
sender, ok := userRegistry.Users.GetUser(message.Sender)
var senderNick string
if !ok {
globals.Log.ERROR.Printf("Couldn't get sender %v", message.Sender)
} else {
senderNick = sender.Username
}
atomic.AddInt64(&l.MessagesReceived, 1)
globals.Log.INFO.Printf("Message of type %v from %q, %v received with fallback: %s\n",
message.MessageType, printIDNice(message.Sender), senderNick,
string(message.Body))
}
}
type TextListener struct {
MessagesReceived int64
}
func (l *TextListener) Hear(item switchboard.Item, isHeardElsewhere bool, i ...interface{}) {
message := item.(*parse.Message)
globals.Log.INFO.Println("Hearing a text message")
result := cmixproto.TextMessage{}
err := proto.Unmarshal(message.Body, &result)
if err != nil {
globals.Log.ERROR.Printf("Error unmarshaling text message: %v\n",
err.Error())
}
sender, ok := userRegistry.Users.GetUser(message.Sender)
var senderNick string
if !ok {
globals.Log.INFO.Printf("First message from sender %v", printIDNice(message.Sender))
u := userRegistry.Users.NewUser(message.Sender, base64.StdEncoding.EncodeToString(message.Sender[:]))
userRegistry.Users.UpsertUser(u)
senderNick = u.Username
} else {
senderNick = sender.Username
}
logMsg := fmt.Sprintf("Message from %v, %v Received: %s\n",
printIDNice(message.Sender),
senderNick, result.Message)
globals.Log.INFO.Printf("%s -- Timestamp: %s\n", logMsg,
message.Timestamp.String())
fmt.Printf(logMsg)
atomic.AddInt64(&l.MessagesReceived, 1)
}
type userSearcher struct {
foundUserChan chan []byte
}
func newUserSearcher() api.SearchCallback {
us := userSearcher{}
us.foundUserChan = make(chan []byte)
return &us
}
func (us *userSearcher) Callback(userID, pubKey []byte, err error) {
if err != nil {
globals.Log.ERROR.Printf("Could not find searched user: %+v", err)
} else {
us.foundUserChan <- userID
}
}
// rootCmd represents the base command when called without any subcommands // rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
...@@ -399,7 +188,7 @@ var rootCmd = &cobra.Command{ ...@@ -399,7 +188,7 @@ var rootCmd = &cobra.Command{
} }
jww.SetLogOutput(logOutput) jww.SetLogOutput(logOutput)
if verbose { if verbose {
jww.SetLogThreshold(verbose) jww.SetLogThreshold(jww.LevelTrace)
} }
}, },
} }
...@@ -412,7 +201,7 @@ func isValidUser(usr []byte) (bool, *id.ID) { ...@@ -412,7 +201,7 @@ func isValidUser(usr []byte) (bool, *id.ID) {
if b != 0 { if b != 0 {
uid, err := id.Unmarshal(usr) uid, err := id.Unmarshal(usr)
if err != nil { if err != nil {
globals.Log.WARN.Printf("Could not unmarshal user: %s", err) jww.WARN.Printf("Could not unmarshal user: %s", err)
return false, nil return false, nil
} }
return true, uid return true, uid
......
...@@ -11,7 +11,7 @@ import ( ...@@ -11,7 +11,7 @@ import (
"gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/globals"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"strings" "strings"
"time" //"time"
) )
type callbackSearch struct{} type callbackSearch struct{}
...@@ -46,7 +46,7 @@ func parseUdbMessage(msg string, client *api.Client) { ...@@ -46,7 +46,7 @@ func parseUdbMessage(msg string, client *api.Client) {
keyword := args[0] keyword := args[0]
// Case-insensitive match the keyword to a command // Case-insensitive match the keyword to a command
if strings.EqualFold(keyword, "SEARCH") { if strings.EqualFold(keyword, "SEARCH") {
client.SearchForUser(args[2], searchCallback, 2*time.Minute) //client.SearchForUser(args[2], searchCallback, 2*time.Minute)
} else if strings.EqualFold(keyword, "REGISTER") { } else if strings.EqualFold(keyword, "REGISTER") {
globals.Log.ERROR.Printf("UDB REGISTER not allowed, it is already done during user registration") globals.Log.ERROR.Printf("UDB REGISTER not allowed, it is already done during user registration")
} else { } else {
......
...@@ -37,7 +37,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, error ...@@ -37,7 +37,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, error
partner, err := m.Session.E2e().GetPartner(msg.Recipient) partner, err := m.Session.E2e().GetPartner(msg.Recipient)
if err != nil { if err != nil {
return nil, errors.WithMessagef(err, "Could not send End to End encrypted "+ return nil, errors.WithMessagef(err, "Could not send End to End encrypted "+
"message, no relationship found with %s", partner) "message, no relationship found with %v", partner)
} }
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
......
...@@ -41,6 +41,18 @@ func (nm *MockNetworkManager) GetHealthTracker() context.HealthTracker { ...@@ -41,6 +41,18 @@ func (nm *MockNetworkManager) GetHealthTracker() context.HealthTracker {
return nil return nil
} }
func (nm *MockNetworkManager) GetRemoteVersion() (string, error) {
return "", nil
}
func (nm *MockNetworkManager) GetStoppable() stoppable.Stoppable {
return nil
}
func (nm *MockNetworkManager) RegisterWithPermissioning(string) ([]byte, error) {
return nil, nil
}
// Mock client comms object // Mock client comms object
type MockClientComms struct { type MockClientComms struct {
request chan bool request chan bool
......
package rounds package rounds
import ( import (
"encoding/binary"
"github.com/pkg/errors" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/network/gateway" "gitlab.com/elixxir/client/network/gateway"
"gitlab.com/elixxir/client/network/message" "gitlab.com/elixxir/client/network/message"
pb "gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
pb "gitlab.com/elixxir/comms/mixmessages"
jww "github.com/spf13/jwalterweatherman"
) )
type messageRetrievalComms interface { type messageRetrievalComms interface {
...@@ -39,6 +40,13 @@ func (m *Manager) processMessageRetrieval(comms messageRetrievalComms, ...@@ -39,6 +40,13 @@ func (m *Manager) processMessageRetrieval(comms messageRetrievalComms,
} }
} }
// TODO: remove me when api fixed
func uint64ToBytes(i uint64) []byte {
bs := make([]byte, 8)
binary.LittleEndian.PutUint64(bs, 31415926)
return bs
}
func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo, func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo,
comms messageRetrievalComms) (message.Bundle, error) { comms messageRetrievalComms) (message.Bundle, error) {
...@@ -55,7 +63,7 @@ func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo, ...@@ -55,7 +63,7 @@ func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo,
msgReq := &pb.GetMessages{ msgReq := &pb.GetMessages{
ClientID: m.Uid.Marshal(), ClientID: m.Uid.Marshal(),
//TODO: fix this, should not be a byte slice //TODO: fix this, should not be a byte slice
RoundID: uint64(rid), RoundID: uint64ToBytes(uint64(rid)),
} }
msgResp, err := comms.RequestMessages(gwHost, msgReq) msgResp, err := comms.RequestMessages(gwHost, msgReq)
// Fail the round if an error occurs so it can be tried again later // Fail the round if an error occurs so it can be tried again later
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment