Skip to content
Snippets Groups Projects
Commit f7bf7971 authored by Benjamin Wenger's avatar Benjamin Wenger
Browse files

implemented first pass of auth storage. No tests written

parent 173f923a
Branches
Tags
No related merge requests found
...@@ -14,9 +14,9 @@ require ( ...@@ -14,9 +14,9 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/viper v1.7.1 github.com/spf13/viper v1.7.1
gitlab.com/elixxir/comms v0.0.0-20201006010513-3353fb46569a gitlab.com/elixxir/comms v0.0.0-20201006010513-3353fb46569a
gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e gitlab.com/elixxir/crypto v0.0.0-20201014182120-fb12f042858e
gitlab.com/elixxir/ekv v0.1.3 gitlab.com/elixxir/ekv v0.1.3
gitlab.com/elixxir/primitives v0.0.0-20201006010327-c2f93eb587e3 gitlab.com/elixxir/primitives v0.0.0-20201007223554-4a62c355bb0b
gitlab.com/xx_network/comms v0.0.0-20200924225518-0c867207b1e6 gitlab.com/xx_network/comms v0.0.0-20200924225518-0c867207b1e6
gitlab.com/xx_network/crypto v0.0.0-20200812183430-c77a5281c686 gitlab.com/xx_network/crypto v0.0.0-20200812183430-c77a5281c686
gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031 gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031
......
...@@ -342,6 +342,8 @@ gitlab.com/elixxir/crypto v0.0.0-20201005231932-7d290c959bdb h1:dGnOhkotUPp+RYZR ...@@ -342,6 +342,8 @@ gitlab.com/elixxir/crypto v0.0.0-20201005231932-7d290c959bdb h1:dGnOhkotUPp+RYZR
gitlab.com/elixxir/crypto v0.0.0-20201005231932-7d290c959bdb/go.mod h1:gK5V2MmeMFouEIxQdQ0MsYrWlvArKfFKm3XMgIc0CYs= gitlab.com/elixxir/crypto v0.0.0-20201005231932-7d290c959bdb/go.mod h1:gK5V2MmeMFouEIxQdQ0MsYrWlvArKfFKm3XMgIc0CYs=
gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e h1:EcK8J7n0QJ5UhDqkDKt/TW5maUFbBVMIn0gAO9Y/HOs= gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e h1:EcK8J7n0QJ5UhDqkDKt/TW5maUFbBVMIn0gAO9Y/HOs=
gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e/go.mod h1:W/lkTsgaqA+8A1FKZnXFtetNLHV9VNn6IPzMYzgOiBY= gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e/go.mod h1:W/lkTsgaqA+8A1FKZnXFtetNLHV9VNn6IPzMYzgOiBY=
gitlab.com/elixxir/crypto v0.0.0-20201014182120-fb12f042858e h1:u8tp5BrblsTuaEjQMFlGSTrkjDr4P5KN9OFmxhWkSwE=
gitlab.com/elixxir/crypto v0.0.0-20201014182120-fb12f042858e/go.mod h1:P180AwIwARAbBsmaC0NO92XhXngb1l12JVl3KlxWPsM=
gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842 h1:m1zDQ6UadpuMnV7nvnyR+DUXE3AisRnVjajTb1xZE4c= gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842 h1:m1zDQ6UadpuMnV7nvnyR+DUXE3AisRnVjajTb1xZE4c=
gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s= gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s=
gitlab.com/elixxir/ekv v0.1.1 h1:Em3rF8sv+tNbQGXbcpYzAS2blWRAP708JGhYlkN74Kg= gitlab.com/elixxir/ekv v0.1.1 h1:Em3rF8sv+tNbQGXbcpYzAS2blWRAP708JGhYlkN74Kg=
...@@ -369,6 +371,8 @@ gitlab.com/elixxir/primitives v0.0.0-20201005231810-020916f67bd6 h1:ZE7ee4VIr7j4 ...@@ -369,6 +371,8 @@ gitlab.com/elixxir/primitives v0.0.0-20201005231810-020916f67bd6 h1:ZE7ee4VIr7j4
gitlab.com/elixxir/primitives v0.0.0-20201005231810-020916f67bd6/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= gitlab.com/elixxir/primitives v0.0.0-20201005231810-020916f67bd6/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
gitlab.com/elixxir/primitives v0.0.0-20201006010327-c2f93eb587e3 h1:nQG+LWzYfXiDT+4xPQ2U9sHUM6J51zmL220aSjIEvx4= gitlab.com/elixxir/primitives v0.0.0-20201006010327-c2f93eb587e3 h1:nQG+LWzYfXiDT+4xPQ2U9sHUM6J51zmL220aSjIEvx4=
gitlab.com/elixxir/primitives v0.0.0-20201006010327-c2f93eb587e3/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= gitlab.com/elixxir/primitives v0.0.0-20201006010327-c2f93eb587e3/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
gitlab.com/elixxir/primitives v0.0.0-20201007223554-4a62c355bb0b h1:NrbVrvj14JYBaXXwHYyXdG4rMWByVzmolqNKh7ShTJ8=
gitlab.com/elixxir/primitives v0.0.0-20201007223554-4a62c355bb0b/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba h1:7nozLSNBX0CfP53DDiDNLJx9obhYGfGf5na0/c9rMso= gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba h1:7nozLSNBX0CfP53DDiDNLJx9obhYGfGf5na0/c9rMso=
gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY= gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY=
......
package auth
import "gitlab.com/elixxir/crypto/cyclic"
type FingerprintType uint
const (
General FingerprintType = 1
Specific FingerprintType = 2
)
type fingerprint struct {
Type FingerprintType
//only populated if ti is general
PrivKey *cyclic.Int
//only populated if it is specific
Request *request
}
package auth
import (
"gitlab.com/elixxir/client/interfaces/contact"
"sync"
)
type requestType uint
const (
Sent requestType = 0
Receive requestType = 1
)
type request struct {
rt requestType
//data if sent
sent *SentRequest
//data if receive
receive *contact.Contact
//mux to ensure there isnt concurent access
mux sync.Mutex
}
type requestDisk struct {
T uint
ID []byte
}
package auth
import (
"encoding/json"
"github.com/pkg/errors"
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id"
"time"
)
const currentSentRequestVersion = 0
type SentRequest struct {
kv *versioned.KV
partner *id.ID
myPrivKey *cyclic.Int
myPubKey *cyclic.Int
fingerprint format.Fingerprint
}
type sentRequestDisk struct {
MyPrivKey []byte
MyPubKey []byte
Fingerprint []byte
}
func loadSentRequest(kv *versioned.KV, partner *id.ID, grp *cyclic.Group) (*SentRequest, error) {
obj, err := kv.Get(versioned.MakePartnerPrefix(partner))
if err != nil {
return nil, errors.WithMessagef(err, "Failed to Load "+
"SentRequest Auth with %s", partner)
}
ipd := &sentRequestDisk{}
if err := json.Unmarshal(obj.Data, ipd); err != nil {
return nil, errors.WithMessagef(err, "Failed to Unmarshal "+
"SentRequest Auth with %s", partner)
}
myPrivKey := grp.NewInt(1)
if err = myPrivKey.GobDecode(ipd.MyPubKey); err != nil {
return nil, errors.WithMessagef(err, "Failed to decode private "+
"key with %s for SentRequest Auth", partner)
}
myPubKey := grp.NewInt(1)
if err = myPubKey.GobDecode(ipd.MyPubKey); err != nil {
return nil, errors.WithMessagef(err, "Failed to decode public "+
"key with %s for SentRequest Auth", partner)
}
fp := format.Fingerprint{}
copy(fp[:], ipd.Fingerprint)
return &SentRequest{
kv: kv,
partner: partner,
myPrivKey: myPrivKey,
myPubKey: myPubKey,
fingerprint: fp,
}, nil
}
func (ip *SentRequest) save() error {
privKey, err := ip.myPrivKey.GobEncode()
if err != nil {
return err
}
pubKey, err := ip.myPubKey.GobEncode()
if err != nil {
return err
}
ipd := sentRequestDisk{
MyPrivKey: privKey,
MyPubKey: pubKey,
Fingerprint: ip.fingerprint[:],
}
data, err := json.Marshal(&ipd)
if err != nil {
return err
}
obj := versioned.Object{
Version: currentSentRequestVersion,
Timestamp: time.Now(),
Data: data,
}
return ip.kv.Set(versioned.MakePartnerPrefix(ip.partner), &obj)
}
func (ip *SentRequest) delete() error {
return ip.kv.Delete(versioned.MakePartnerPrefix(ip.partner))
}
func (ip *SentRequest) GetPartner() *id.ID {
return ip.partner
}
func (ip *SentRequest) GetMyPrivKey() *cyclic.Int {
return ip.myPrivKey
}
func (ip *SentRequest) GetMyPubKey() *cyclic.Int {
return ip.myPubKey
}
func (ip *SentRequest) GetFingerprint() format.Fingerprint {
return ip.fingerprint
}
package auth
import (
"encoding/json"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces/contact"
"gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/e2e/auth"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id"
"sync"
"time"
)
const storePrefix = "requestMap"
const requestMapKey = "map"
const requestMapVersion = 0
type Store struct {
kv *versioned.KV
grp *cyclic.Group
requests map[id.ID]*request
fingerprints map[format.Fingerprint]fingerprint
mux sync.RWMutex
}
// creates a new store. all passed in private keys are added as fingerprints so
// they can be used to trigger requests
func NewStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*Store, error) {
kv = kv.Prefix(storePrefix)
s := &Store{
kv: kv,
grp: grp,
requests: make(map[id.ID]*request),
fingerprints: make(map[format.Fingerprint]fingerprint),
}
for _, key := range privKeys {
fp := auth.MakeRequestFingerprint(key)
s.fingerprints[fp] = fingerprint{
Type: General,
PrivKey: key,
Request: nil,
}
}
return s, s.save()
}
// loads an extant new store. all passed in private keys are added as
// fingerprints so they can be used to trigger requests
func LoadStore(kv *versioned.KV, grp *cyclic.Group, privKeys []*cyclic.Int) (*Store, error) {
kv = kv.Prefix(storePrefix)
sentObj, err := kv.Get(requestMapKey)
if err != nil {
return nil, errors.WithMessagef(err, "Failed to Load "+
"requestMap")
}
s := &Store{
kv: kv,
grp: grp,
requests: make(map[id.ID]*request),
}
for _, key := range privKeys {
fp := auth.MakeRequestFingerprint(key)
s.fingerprints[fp] = fingerprint{
Type: General,
PrivKey: key,
Request: nil,
}
}
var requestList []requestDisk
if err := json.Unmarshal(sentObj.Data, &requestList); err != nil {
return nil, errors.WithMessagef(err, "Failed to "+
"Unmarshal SentRequestMap")
}
for _, rDisk := range requestList {
r := &request{
rt: requestType(rDisk.T),
}
partner, err := id.Unmarshal(rDisk.ID)
if err != nil {
jww.FATAL.Panicf("Failed to load stored id: %+v", err)
}
switch r.rt {
case Sent:
sr, err := loadSentRequest(kv, partner, grp)
if err != nil {
jww.FATAL.Panicf("Failed to load stored sentRequest: %+v",
err)
}
r.sent = sr
s.fingerprints[sr.fingerprint] = fingerprint{
Type: Specific,
PrivKey: nil,
Request: r,
}
case Receive:
c, err := utility.LoadContact(kv, partner)
if err != nil {
jww.FATAL.Panicf("Failed to load stored contact for: %+v",
err)
}
r.receive = &c
default:
jww.FATAL.Panicf("Unknown request type: %d", r.rt)
}
}
return s, nil
}
func (s *Store) save() error {
requestIDList := make([]requestDisk, len(s.requests))
index := 0
for pid, r := range s.requests {
rDisk := requestDisk{
T: uint(r.rt),
ID: pid.Marshal(),
}
requestIDList[index] = rDisk
index++
}
data, err := json.Marshal(&requestIDList)
if err != nil {
return err
}
obj := versioned.Object{
Version: requestMapVersion,
Timestamp: time.Now(),
Data: data,
}
return s.kv.Set(requestMapKey, &obj)
}
func (s *Store) AddSent(partner *id.ID, myPrivKey, myPubKey *cyclic.Int,
fp format.Fingerprint) error {
s.mux.Lock()
defer s.mux.Unlock()
if _, ok := s.requests[*partner]; ok {
return errors.Errorf("Cannot make new sentRequest for partner "+
"%s, one already exists", partner)
}
sr := &SentRequest{
kv: s.kv,
partner: partner,
myPrivKey: myPrivKey,
myPubKey: myPubKey,
fingerprint: fp,
}
if err := sr.save(); err != nil {
jww.FATAL.Panicf("Failed to save Sent Request for partenr %s",
partner)
}
r := &request{
rt: Sent,
sent: sr,
receive: nil,
mux: sync.Mutex{},
}
s.requests[*partner] = r
if err := s.save(); err != nil {
jww.FATAL.Panicf("Failed to save Sent Request Map after adding"+
" partern %s", partner)
}
return nil
}
func (s *Store) AddReceived(c contact.Contact) error {
s.mux.Lock()
defer s.mux.Unlock()
if _, ok := s.requests[*c.ID]; ok {
return errors.Errorf("Cannot add contact for partner "+
"%s, one already exists", c.ID)
}
if err := utility.StoreContact(s.kv, c); err != nil {
jww.FATAL.Panicf("Failed to save contact for partenr %s",
c.ID)
}
r := &request{
rt: Receive,
sent: nil,
receive: &c,
mux: sync.Mutex{},
}
s.requests[*c.ID] = r
if err := s.save(); err != nil {
jww.FATAL.Panicf("Failed to save Sent Request Map after adding"+
" partern %s", c.ID)
}
return nil
}
// Can return either a private key or a sentRequest if the fingerprint is found
// if it returns a sentRequest, it takes the lock to ensure there is only one
// operator at a time. The user of the API must release the lock by calling
// store.Delete() or store.Failed() with the partner ID
func (s *Store) GetFingerprint(fp format.Fingerprint) (FingerprintType,
*SentRequest, *cyclic.Int, error) {
s.mux.RLock()
r, ok := s.fingerprints[fp]
s.mux.RUnlock()
if !ok {
return 0, nil, nil,
errors.Errorf("Fingerprint cannot be found: %s", fp)
}
switch r.Type {
//if its general, just return the private key
case General:
return General, nil, r.PrivKey, nil
//if specific, take the request lock and return it
case Specific:
r.Request.mux.Lock()
//check that the request still exists, it could have been deleted
//while the lock was taken
s.mux.RLock()
_, ok := s.requests[*r.Request.receive.ID]
s.mux.RUnlock()
if !ok {
return 0, nil, nil, errors.Errorf("Fingerprint cannot be "+
"found: %s", fp)
}
//return the request
return Specific, r.Request.sent, nil, nil
default:
return 0, nil, nil, errors.Errorf("Unknown fingerprint type")
}
}
// returns the contact representing the receive request if it exists.
// if it returns, it takes the lock to ensure there is only one
// operator at a time. The user of the API must release the lock by calling
// store.Delete() or store.Failed() with the partner ID
func (s *Store) GetReceivedRequest(partner *id.ID) (contact.Contact, error) {
s.mux.RLock()
r, ok := s.requests[*partner]
s.mux.RUnlock()
if !ok {
return contact.Contact{}, errors.Errorf("Received request not "+
"found: %s", partner)
}
//take the lock to ensure there is only one operator at a time
r.mux.Lock()
//check that the request still exists, it could have been deleted
//while the lock was taken
s.mux.RLock()
_, ok = s.requests[*partner]
s.mux.RUnlock()
if !ok {
return contact.Contact{}, errors.Errorf("Received request not "+
"found: %s", partner)
}
return *r.receive, nil
}
// returns the contact representing the receive request if it exists.
// Does not take the lock, is only meant to return the contact to an external
// API user
func (s *Store) GetReceivedRequestData(partner *id.ID) (contact.Contact, error) {
s.mux.RLock()
r, ok := s.requests[*partner]
s.mux.RUnlock()
if !ok {
return contact.Contact{}, errors.Errorf("Received request not "+
"found: %s", partner)
}
return *r.receive, nil
}
// One of two calls after using a request. This one to be used when the use
// is unsuccessful. It will allow any thread waiting on access to continue
// using the structure
func (s *Store) Fail(partner *id.ID) error {
s.mux.RLock()
r, ok := s.requests[*partner]
s.mux.RUnlock()
if !ok {
return errors.Errorf("Request not found: %s", partner)
}
r.mux.Unlock()
return nil
}
// One of two calls after using a request. This one to be used when the use
// is unsuccessful. It deletes all references to the request associated with the
// passed partner if it exists. It will allow any thread waiting on access to
// continue. They should fail due to the deletion of the structure
func (s *Store) Delete(partner *id.ID) error {
s.mux.Lock()
defer s.mux.Unlock()
r, ok := s.requests[*partner]
if !ok {
return errors.Errorf("Request not found: %s", partner)
}
switch r.rt {
case Sent:
delete(s.fingerprints, r.sent.fingerprint)
if err := r.sent.delete(); err != nil {
jww.FATAL.Panicf("Failed to delete sent request: %+v", err)
}
case Receive:
if err := utility.DeleteContact(s.kv, r.receive.ID); err != nil {
jww.FATAL.Panicf("Failed to delete recieved request "+
"contact: %+v", err)
}
}
delete(s.requests, *partner)
if err := s.save(); err != nil {
jww.FATAL.Panicf("Failed to store updated request map after "+
"deletion: %+v", err)
}
r.mux.Unlock()
return nil
}
package utility
import (
"fmt"
"gitlab.com/elixxir/client/interfaces/contact"
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/xx_network/primitives/id"
"time"
)
const currentContactVersion = 0
func StoreContact(kv *versioned.KV, c contact.Contact) error {
now := time.Now()
data, err := c.Marshal()
if err != nil {
return err
}
obj := versioned.Object{
Version: currentContactVersion,
Timestamp: now,
Data: data,
}
return kv.Set(makeContactKey(c.ID), &obj)
}
func LoadContact(kv *versioned.KV, cid *id.ID) (contact.Contact, error) {
vo, err := kv.Get(makeContactKey(cid))
if err != nil {
return contact.Contact{}, err
}
return contact.Unmarshal(vo.Data)
}
func DeleteContact(kv *versioned.KV, cid *id.ID) error {
return kv.Delete(makeContactKey(cid))
}
func makeContactKey(cid *id.ID) string {
return fmt.Sprintf("Contact:%s", cid)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment