diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go index 8d921698d0687bd93e32ef1ee9ed2f46d68fce57..d1b5aa3ef75e573c9e39c9aaff8001656ef5e476 100644 --- a/api/authenticatedChannel.go +++ b/api/authenticatedChannel.go @@ -3,6 +3,7 @@ package api import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/contact" + "gitlab.com/elixxir/client/storage/e2e" ) // CreateAuthenticatedChannel creates a 1-way authenticated channel @@ -29,3 +30,35 @@ func (c *Client) RegisterAuthRequestCb(cb func(contact contact.Contact, payload []byte)) { jww.INFO.Printf("RegisterAuthRequestCb(...)") } + +// Create an insecure e2e relationship with a precanned user +func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) contact.Contact { + + precan := c.MakePrecannedContact(precannedID) + + //add the precanned user as a e2e contact + sesParam := e2e.GetDefaultSessionParams() + c.storage.E2e().AddPartner(precan.ID, precan.DhPubKey, sesParam, sesParam) + + return precan +} + +// Create an insecure e2e contact object for a precanned user +func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact { + + e2eGrp := c.storage.E2e().GetGroup() + + //get the user definition + precanned := createPrecannedUser(precannedID, c.rng.GetStream(), + c.storage.Cmix().GetGroup(), e2eGrp) + + //compute their public e2e key + partnerPubKey := e2eGrp.ExpG(precanned.E2eDhPrivateKey, e2eGrp.NewInt(1)) + + return contact.Contact{ + ID: precanned.ID, + DhPubKey: partnerPubKey, + OwnershipProof: nil, + Facts: make([]contact.Fact, 0), + } +} \ No newline at end of file diff --git a/api/client.go b/api/client.go index da8603198def8b98bd217b8e7ccfc4543eb9815a..4b8aefc7c23ca78dcd675959b851a3d33a7fb3b9 100644 --- a/api/client.go +++ b/api/client.go @@ -56,7 +56,7 @@ type Client struct { // with the network. Note that this does not register a username/identity, but // merely creates a new cryptographic identity for adding such information // at a later date. -func NewClient(ndfJSON, storageDir string, password []byte, registrationCode string) (*Client, error) { +func NewClient(ndfJSON, storageDir string, password []byte, registrationCode string) error { // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) rngStream := rngStreamGen.GetStream() @@ -64,7 +64,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str // Parse the NDF def, err := parseNDF(ndfJSON) if err != nil { - return nil, err + return err } cmixGrp, e2eGrp := decodeGroups(def) @@ -75,7 +75,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str storageSess, err := storage.New(storageDir, passwordStr, protoUser, cmixGrp, e2eGrp, rngStreamGen) if err != nil { - return nil, err + return err } // Save NDF to be used in the future @@ -87,12 +87,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str //move the registration state to keys generated err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) if err != nil { - return nil, errors.WithMessage(err, "Failed to denote state "+ + return errors.WithMessage(err, "Failed to denote state "+ "change in session") } - //execute the rest of the loading as normal - return loadClient(storageSess, rngStreamGen) + //TODO: close the session + return nil } // NewPrecannedClient creates an insecure user with predetermined keys with nodes @@ -100,7 +100,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str // with the network. Note that this does not register a username/identity, but // merely creates a new cryptographic identity for adding such information // at a later date. -func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) (*Client, error) { +func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) error { // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) rngStream := rngStreamGen.GetStream() @@ -108,7 +108,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [ // Parse the NDF def, err := parseNDF(defJSON) if err != nil { - return nil, err + return err } cmixGrp, e2eGrp := decodeGroups(def) @@ -119,7 +119,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [ storageSess, err := storage.New(storageDir, passwordStr, protoUser, cmixGrp, e2eGrp, rngStreamGen) if err != nil { - return nil, err + return err } // Save NDF to be used in the future @@ -128,12 +128,12 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [ //move the registration state to keys generated err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) if err != nil { - return nil, errors.WithMessage(err, "Failed to denote state "+ + return errors.WithMessage(err, "Failed to denote state "+ "change in session") } - //execute the rest of the loading as normal - return loadClient(storageSess, rngStreamGen) + //TODO: close the session + return nil } // LoadClient initalizes a client object from existing storage. diff --git a/cmd/root.go b/cmd/root.go index df02bc00954d7ec5a67d6790c78d9647a983f3dc..ce181ec658c8c3ad2b51f1c3b86c4530dc290267 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -128,7 +128,7 @@ var rootCmd = &cobra.Command{ storeDir := viper.GetString("session") regCode := viper.GetString("regcode") - var client *api.Client + //create a new client if none exist if _, err := os.Stat(storeDir); os.IsNotExist(err) { // Load NDF ndfPath := viper.GetString("ndf") @@ -137,22 +137,23 @@ var rootCmd = &cobra.Command{ jww.FATAL.Panicf(err.Error()) } - client, err = api.NewClient(string(ndfJSON), storeDir, + err = api.NewClient(string(ndfJSON), storeDir, []byte(pass), regCode) if err != nil { jww.FATAL.Panicf("%+v", err) } - } else { - client, err = api.LoadClient(storeDir, []byte(pass)) - if err != nil { - jww.FATAL.Panicf("%+v", err) - } + } + + //load the client + client, err := api.LoadClient(storeDir, []byte(pass)) + if err != nil { + jww.FATAL.Panicf("%+v", err) } user := client.GetUser() jww.INFO.Printf("%s", user.ID) - err := client.StartNetworkFollower() + err = client.StartNetworkFollower() if err != nil { jww.FATAL.Panicf("%+v", err) } diff --git a/interfaces/contact.go b/interfaces/contact.go index d9890553979d9e8faefbe7fc9a8f74210f2ea229..41f285c73cf26eb7de446942733a3e24de95d203 100644 --- a/interfaces/contact.go +++ b/interfaces/contact.go @@ -3,13 +3,18 @@ package interfaces type Contact interface { GetID() []byte GetDHPublicKey() []byte - AddFact(Fact) Contact - NumFacts() int - GetFact(int) (Fact, error) + GetOwnershipProof() []byte + GetFactList() FactList Marshal() ([]byte, error) } +type FactList interface { + Num() int + Get(int) Fact + Add(string, int) error +} + type Fact interface { Get() string - GetType() int + Type() int } diff --git a/interfaces/contact/contact.go b/interfaces/contact/contact.go index 145363b192185a8ab8dbaa69219040a0c9a16123..f67175fc8197ed5ed6fc42cfc2a13da22222a4ca 100644 --- a/interfaces/contact/contact.go +++ b/interfaces/contact/contact.go @@ -4,7 +4,6 @@ import ( "encoding/json" "github.com/pkg/errors" "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/interfaces/contact/fact" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/xx_network/primitives/id" ) @@ -13,9 +12,10 @@ import ( // in go, the structure is meant to be edited directly, the functions are for // bindings compatibility type Contact struct { - ID *id.ID - DhPubKey *cyclic.Int - Facts []fact.Fact + ID *id.ID + DhPubKey *cyclic.Int + OwnershipProof []byte + Facts []Fact } // GetID returns the user ID for this user. @@ -23,32 +23,19 @@ func (c Contact) GetID() []byte { return c.ID.Bytes() } -// GetPublicKey returns the publickey bytes for this user. +// GetDHPublicKey returns the public key associated with the Contact. func (c Contact) GetDHPublicKey() []byte { return c.DhPubKey.Bytes() } -// Adds a fact to the contact. Because the contact is pass by value, this makes -// a new copy with the fact -func (c Contact) AddFact(f interfaces.Fact) interfaces.Contact { - fNew := fact.Fact{ - Fact: f.Get(), - T: fact.Type(f.GetType()), - } - c.Facts = append(c.Facts, fNew) - return c -} - -func (c Contact) NumFacts() int { - return len(c.Facts) +// GetDHPublicKey returns hash of a DH proof of key ownership. +func (c Contact) GetOwnershipProof() []byte { + return c.OwnershipProof } -func (c Contact) GetFact(i int) (interfaces.Fact, error) { - if i >= len(c.Facts) || i < 0 { - return nil, errors.Errorf("Cannot get a a fact at position %v, "+ - "only %v facts", i, len(c.Facts)) - } - return c.Facts[i], nil +// Returns a fact list for adding and getting facts to and from the contact +func (c Contact) GetFactList() interfaces.FactList { + return FactList{source: &c} } func (c Contact) Marshal() ([]byte, error) { diff --git a/interfaces/contact/fact/fact.go b/interfaces/contact/fact.go similarity index 67% rename from interfaces/contact/fact/fact.go rename to interfaces/contact/fact.go index 9aa96742fcbcc28623939d37d6de088577a7e24f..a5af2ab57b2c537889f640cef4f6c7f414787ba8 100644 --- a/interfaces/contact/fact/fact.go +++ b/interfaces/contact/fact.go @@ -1,31 +1,22 @@ -package fact +package contact import ( "github.com/pkg/errors" - "gitlab.com/elixxir/client/interfaces" ) type Fact struct { Fact string - T Type + T FactType } func (f Fact) Get() string { return f.Fact } -func (f Fact) GetType() int { +func (f Fact) Type() int { return int(f.T) } -func (f Fact) Copy() interfaces.Fact { - f2 := Fact{ - Fact: f.Fact, - T: f.T, - } - return &f2 -} - // marshal is for transmission for UDB, not a part of the fact interface func (f Fact) Marshal() []byte { serial := []byte(f.Fact) @@ -36,8 +27,8 @@ func (f Fact) Marshal() []byte { return b } -func Unmarshal(b []byte) (Fact, error) { - t := Type(b[0]) +func UnmarshalFact(b []byte) (Fact, error) { + t := FactType(b[0]) if !t.IsValid() { return Fact{}, errors.Errorf("Fact is not a valid type: %s", t) } diff --git a/interfaces/contact/fact/type.go b/interfaces/contact/fact/type.go deleted file mode 100644 index cc0ff89334bf031db54139d57c006539f54e8bbd..0000000000000000000000000000000000000000 --- a/interfaces/contact/fact/type.go +++ /dev/null @@ -1,28 +0,0 @@ -package fact - -import "fmt" - -type Type uint8 - -const ( - Username Type = 0 - Email Type = 1 - Phone Type = 2 -) - -func (t Type) String() string { - switch t { - case Username: - return "Username" - case Email: - return "Email" - case Phone: - return "Phone" - default: - return fmt.Sprintf("Unknown Fact Type: %d", t) - } -} - -func (t Type) IsValid() bool { - return t == Username || t == Email || t == Phone -} diff --git a/interfaces/contact/factList.go b/interfaces/contact/factList.go new file mode 100644 index 0000000000000000000000000000000000000000..5c39398fc3847d7c126802fda00d274e1737bd7e --- /dev/null +++ b/interfaces/contact/factList.go @@ -0,0 +1,30 @@ +package contact + +import ( + "github.com/pkg/errors" + "gitlab.com/elixxir/client/interfaces" +) + +type FactList struct { + source *Contact +} + +func (fl FactList) Num() int { + return len(fl.source.Facts) +} + +func (fl FactList) Get(i int) interfaces.Fact { + return fl.source.Facts[i] +} + +func (fl FactList) Add(fact string, factType int) error { + ft := FactType(factType) + if !ft.IsValid() { + return errors.New("Invalid fact type") + } + fl.source.Facts = append(fl.source.Facts, Fact{ + Fact: fact, + T: ft, + }) + return nil +} diff --git a/interfaces/contact/type.go b/interfaces/contact/type.go new file mode 100644 index 0000000000000000000000000000000000000000..1b9bb89892e2394a6aa0f06744ce7c5ce8ee6e44 --- /dev/null +++ b/interfaces/contact/type.go @@ -0,0 +1,28 @@ +package contact + +import "fmt" + +type FactType uint8 + +const ( + Username FactType = 0 + Email FactType = 1 + Phone FactType = 2 +) + +func (t FactType) String() string { + switch t { + case Username: + return "Username" + case Email: + return "Email" + case Phone: + return "Phone" + default: + return fmt.Sprintf("Unknown Fact FactType: %d", t) + } +} + +func (t FactType) IsValid() bool { + return t == Username || t == Email || t == Phone +} diff --git a/interfaces/user/user.go b/interfaces/user/user.go index d84f406b5ca3d7a70fd1b2ac0873728958cc5fef..298e61fc53693f0767291f6853cb7c120506b590 100644 --- a/interfaces/user/user.go +++ b/interfaces/user/user.go @@ -64,6 +64,6 @@ func (u User) GetContact() interfaces.Contact { return contact.Contact{ ID: u.ID.DeepCopy(), DhPubKey: u.E2eDhPublicKey, - Facts: nil, + Facts: make([]contact.Fact, 0), } } diff --git a/storage/user/user.go b/storage/user/user.go index 7abd5f2e2962e4ec84be4d141c53472c27d9b135..8e62c933cc2a741a791c096f80f0696b07ccb32c 100644 --- a/storage/user/user.go +++ b/storage/user/user.go @@ -45,4 +45,4 @@ func LoadUser(kv *versioned.KV) (*User, error) { func (u *User) GetCryptographicIdentity() *CryptographicIdentity { return u.ci -} +} \ No newline at end of file