From 6693c0d79add86c515c64d66e7fb7f1710284d2c Mon Sep 17 00:00:00 2001
From: Benjamin Wenger <ben@elixxir.ioo>
Date: Sat, 29 Feb 2020 13:25:12 -0800
Subject: [PATCH] reorgonized the structures

---
 connect/host.go                             |   5 +
 network/dataStructures/ndf.go               |  92 ++++++++++++++++-
 network/dataStructures/roundData_test.go    |  28 +++++
 network/dataStructures/roundUpdates_test.go |  23 -----
 network/instance.go                         | 108 ++++++++++++++++++++
 network/securedNdf.go                       |  49 +++++++++
 network/securedNdf_test.go                  |  14 +++
 7 files changed, 293 insertions(+), 26 deletions(-)
 create mode 100644 network/instance.go
 create mode 100644 network/securedNdf.go
 create mode 100644 network/securedNdf_test.go

diff --git a/connect/host.go b/connect/host.go
index b388b04a..22b02e8c 100644
--- a/connect/host.go
+++ b/connect/host.go
@@ -116,6 +116,11 @@ func (h *Host) IsDynamicHost() bool {
 	return h.dynamicHost
 }
 
+// Simple getter for the public key
+func (h *Host) GetPubKey() *rsa.PublicKey {
+	return h.rsaPublicKey
+}
+
 // Connected checks if the given Host's connection is alive
 func (h *Host) Connected() bool {
 	h.mux.RLock()
diff --git a/network/dataStructures/ndf.go b/network/dataStructures/ndf.go
index ea2c7c4a..75f305d6 100644
--- a/network/dataStructures/ndf.go
+++ b/network/dataStructures/ndf.go
@@ -1,11 +1,97 @@
 package dataStructures
 
-import "gitlab.com/elixxir/primitives/ndf"
+import (
+	"bytes"
+	"crypto/sha256"
+	"github.com/pkg/errors"
+	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/primitives/ndf"
+	"sync"
+)
 
 type Ndf struct{
-	f ndf.NetworkDefinition
+	f *ndf.NetworkDefinition
+	pb *pb.NDF
 	hash []byte
+	lock sync.RWMutex
 }
 
+//Updates to a new NDF if the passed NDF is valid
+func(file *Ndf)Update(m *pb.NDF)error{
+
+	//build the ndf object
+	decoded, _, err := ndf.DecodeNDF(string(m.Ndf))
+
+	if err!=nil{
+		return errors.WithMessage(err,"Could not decode the NDF")
+	}
+
+	file.lock.Lock()
+	defer file.lock.Unlock()
+
+	file.pb = m
+	file.f = decoded
+
+	//set the ndf hash
+	marshaled, err := file.f.Marshal()
+	if err != nil {
+		return errors.WithMessage(err,
+			"Could not marshal NDF for hashing")
+	}
+
+	// Serialize then hash the constructed ndf
+	hash := sha256.New()
+	hash.Write(marshaled)
+	file.hash = hash.Sum(nil)
+
+	return nil
+}
+
+//returns the ndf object
+//fix-me: return a copy instead to ensure edits to not impact the
+//original version
+func(file *Ndf)Get()*ndf.NetworkDefinition{
+	file.lock.RLock()
+	defer file.lock.RUnlock()
+	return file.f
+}
+
+//returns the ndf hash
+func(file *Ndf)GetHash()[]byte{
+	file.lock.RLock()
+	defer file.lock.RUnlock()
+	rtn := make([]byte, len(file.hash))
+	copy(rtn,file.hash)
+	return rtn
+}
+
+//returns the ndf hash
+//fix-me: return a copy instead to ensure edits to not impact the
+//original version
+func(file *Ndf)GetPb()*pb.NDF{
+	file.lock.RLock()
+	defer file.lock.RUnlock()
+	return file.pb
+}
+
+//evaluates if the passed ndf hash is the same as the stored one
+//returns an error if no ndf is available, returns false if they are different
+//and true if they are the same
+func(file *Ndf)CompareHash(h []byte)(bool, error){
+	file.lock.RLock()
+	defer file.lock.RUnlock()
+	//return the NO_NDF error if no NDF is available
+	if len(file.hash) == 0 {
+		errMsg := errors.Errorf(ndf.NO_NDF)
+		return false, errMsg
+	}
+
+	//return true if the hashes are the same
+	if bytes.Compare(file.hash, h) == 0 {
+		return true, nil
+	}
+
+	//return false if the hashes are different
+	return false, nil
+}
 
-func(ndf *Ndf)Update(
diff --git a/network/dataStructures/roundData_test.go b/network/dataStructures/roundData_test.go
index 6d2cb10f..54e17276 100644
--- a/network/dataStructures/roundData_test.go
+++ b/network/dataStructures/roundData_test.go
@@ -1 +1,29 @@
 package dataStructures
+
+import (
+	"gitlab.com/elixxir/comms/mixmessages"
+	"testing"
+)
+
+func TestData_UpsertRound(t *testing.T) {
+	d := Data{}
+	err := d.UpsertRound(&mixmessages.RoundInfo{
+		ID:       0,
+		UpdateID: 0,
+	})
+	if err != nil {
+		t.Errorf("Failed to upsert round: %+v", err)
+	}
+}
+
+func TestData_GetRound(t *testing.T) {
+	d := Data{}
+	_ = d.UpsertRound(&mixmessages.RoundInfo{
+		ID:       0,
+		UpdateID: 3,
+	})
+	_, err := d.GetRound(0)
+	if err != nil {
+		t.Errorf("Failed to get roundinfo with proper id")
+	}
+}
diff --git a/network/dataStructures/roundUpdates_test.go b/network/dataStructures/roundUpdates_test.go
index 6ff5f52f..a1b1dafd 100644
--- a/network/dataStructures/roundUpdates_test.go
+++ b/network/dataStructures/roundUpdates_test.go
@@ -5,29 +5,6 @@ import (
 	"testing"
 )
 
-func TestData_UpsertRound(t *testing.T) {
-	d := Data{}
-	err := d.UpsertRound(&mixmessages.RoundInfo{
-		ID:       0,
-		UpdateID: 0,
-	})
-	if err != nil {
-		t.Errorf("Failed to upsert round: %+v", err)
-	}
-}
-
-func TestData_GetRound(t *testing.T) {
-	d := Data{}
-	_ = d.UpsertRound(&mixmessages.RoundInfo{
-		ID:       0,
-		UpdateID: 3,
-	})
-	_, err := d.GetRound(0)
-	if err != nil {
-		t.Errorf("Failed to get roundinfo with proper id")
-	}
-}
-
 func TestUpdates_AddRound(t *testing.T) {
 	u := Updates{}
 	err := u.AddRound(&mixmessages.RoundInfo{
diff --git a/network/instance.go b/network/instance.go
new file mode 100644
index 00000000..55cbe90f
--- /dev/null
+++ b/network/instance.go
@@ -0,0 +1,108 @@
+package network
+
+import(
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/comms/connect"
+	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/signature"
+	"gitlab.com/elixxir/primitives/id"
+	"sync"
+)
+
+type Instance struct {
+	comm *connect.ProtoComms
+
+	partial *SecuredNdf
+	full *SecuredNdf
+	roundUpdates *ds.Updates
+	roundData *ds.Data
+
+	roundlock sync.RWMutex
+}
+
+
+func NewInstance(c *connect.ProtoComms)*Instance{
+	return &Instance{
+		c,
+		NewSecuredNdf(),
+		NewSecuredNdf(),
+		&ds.Updates{},
+		&ds.Data{},
+		sync.RWMutex{},
+	}
+}
+
+//update the partial ndf
+func (i *Instance)UpdatePartialNdf(m *pb.NDF)error{
+	perm, success := i.comm.GetHost(id.PERMISSIONING)
+
+	if !success{
+		return errors.New("Could not get permissioning Public Key" +
+			"for NDF partial verification")
+	}
+
+	return i.partial.update(m,perm.GetPubKey())
+}
+
+//update the full ndf
+func (i *Instance)UpdateFullNdf(m *pb.NDF)error{
+	perm, success := i.comm.GetHost(id.PERMISSIONING)
+
+	if !success{
+		return errors.New("Could not get permissioning Public Key" +
+			"for full NDF verification")
+	}
+
+	return i.full.update(m,perm.GetPubKey())
+}
+
+func (i *Instance)GetPartialNdf()*SecuredNdf{
+	return i.partial
+}
+
+func (i *Instance)GetFullNdf()*SecuredNdf{
+	return i.full
+}
+
+func (i *Instance)RoundUpdate(info *pb.RoundInfo)error{
+	perm, success := i.comm.GetHost(id.PERMISSIONING)
+
+	if !success{
+		return errors.New("Could not get permissioning Public Key" +
+			"for round info verification")
+	}
+
+	err := signature.Verify(info, perm.GetPubKey())
+	if err!=nil{
+		return errors.WithMessage(err, "Could not validate NDF")
+	}
+
+	i.roundlock.Lock()
+	defer i.roundlock.Unlock()
+
+	err = i.roundUpdates.AddRound(info)
+	if err!=nil{
+		return err
+	}
+
+	err = i.roundData.UpsertRound(info)
+	if err!=nil{
+		return err
+	}
+
+	return nil
+}
+
+func (i *Instance)GetRound(id id.Round)(*pb.RoundInfo, error){
+	return i.roundData.GetRound(int(id))
+}
+
+func (i *Instance)GetRoundUpdate(updateID int)(*pb.RoundInfo, error){
+	return i.roundUpdates.GetUpdate(updateID)
+}
+
+func (i *Instance)GetRoundUpdates(id id.Round)([]*pb.RoundInfo, error){
+	return nil, nil
+}
+
diff --git a/network/securedNdf.go b/network/securedNdf.go
new file mode 100644
index 00000000..bcc92a67
--- /dev/null
+++ b/network/securedNdf.go
@@ -0,0 +1,49 @@
+package network
+
+import(
+	"github.com/pkg/errors"
+	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/elixxir/crypto/signature"
+	"gitlab.com/elixxir/crypto/signature/rsa"
+	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/primitives/ndf"
+)
+
+// wraps the ndf data structure, expoting all the functionality expect the
+// ability to change the ndf
+type SecuredNdf struct{
+	f *ds.Ndf
+}
+
+func NewSecuredNdf()*SecuredNdf{
+	return &SecuredNdf{
+		&ds.Ndf{},
+	}
+}
+
+// unexported NDF update code
+func (sndf *SecuredNdf)update(m *pb.NDF, key *rsa.PublicKey)error{
+	err := signature.Verify(m, key)
+	if err!=nil{
+		return errors.WithMessage(err, "Could not validate NDF")
+	}
+
+	return sndf.f.Update(m)
+}
+
+func (sndf *SecuredNdf)Get()*ndf.NetworkDefinition{
+	return sndf.f.Get()
+}
+
+func (sndf *SecuredNdf)GetHash()[]byte{
+	return sndf.f.GetHash()
+}
+
+func (sndf *SecuredNdf)GetPb()*pb.NDF{
+	return sndf.f.GetPb()
+}
+
+func(sndf *SecuredNdf)CompareHash(h []byte)(bool, error) {
+	return sndf.f.CompareHash(h)
+}
+
diff --git a/network/securedNdf_test.go b/network/securedNdf_test.go
new file mode 100644
index 00000000..20972f9a
--- /dev/null
+++ b/network/securedNdf_test.go
@@ -0,0 +1,14 @@
+package network
+
+import "testing"
+
+func TestNewSecuredNdf(t *testing.T) {
+	sndf := NewSecuredNdf()
+	if sndf==nil{
+		t.Errorf("Internal ndf object is nil")
+	}
+}
+
+func TestSecuredNdf_CompareHash(t *testing.T) {
+
+}
\ No newline at end of file
-- 
GitLab