From 1b61bc0e29d246a1d37fe8cef776381bed175591 Mon Sep 17 00:00:00 2001 From: mricher Date: Sun, 10 Apr 2016 23:01:20 +0200 Subject: [PATCH] [c] Persist contract signatures to a JSON file - Signatures are written to a file called `$email-$contractUUID.proof` - Close connection client-side - Preserve peer connections --- dfssc/sign.go | 8 +++++++ dfssc/sign/create_test.go | 2 -- dfssc/sign/persist.go | 49 +++++++++++++++++++++++++++++++++++++++ dfssc/sign/protocol.go | 20 ++++++++++++++++ dfssc/sign/starter.go | 7 ++++++ tests/sign_test.go | 27 +++++++++++++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 dfssc/sign/persist.go diff --git a/dfssc/sign.go b/dfssc/sign.go index b6d5969..2a92c8e 100644 --- a/dfssc/sign.go +++ b/dfssc/sign.go @@ -54,5 +54,13 @@ func signContract(args []string) { fmt.Fprintln(os.Stderr, err) os.Exit(5) } + // Persist evidencies, if any + err = manager.PersistSignaturesToFile() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(5) + } + + fmt.Println("Signature complete ! See .proof file for evidences.") } diff --git a/dfssc/sign/create_test.go b/dfssc/sign/create_test.go index 81b9966..4aa1a59 100644 --- a/dfssc/sign/create_test.go +++ b/dfssc/sign/create_test.go @@ -1,6 +1,5 @@ package sign -/* import ( "fmt" "io/ioutil" @@ -59,4 +58,3 @@ func TestComputeFile(t *testing.T) { assert.Equal(t, "37fd29decfb2d689439478b1f64b60441534c1e373a7023676c94ac6772639edab46f80139d167a2741f159e62b3064eca58bb331d32cd10770f29064af2a9de", fmt.Sprintf("%x", m.hash)) assert.Equal(t, "contract.txt", m.filename) } -*/ diff --git a/dfssc/sign/persist.go b/dfssc/sign/persist.go new file mode 100644 index 0000000..a3f0c9a --- /dev/null +++ b/dfssc/sign/persist.go @@ -0,0 +1,49 @@ +package sign + +import ( + "encoding/json" + "fmt" + "io/ioutil" + + cAPI "dfss/dfssc/api" + "dfss/dfssp/contract" +) + +// SignedContractJSON is an union of contract and realted signatures +type SignedContractJSON struct { + Contract contract.JSON + Signatures []cAPI.Signature +} + +// PersistSignaturesToFile save contract informations and signatures to disk +func (m *SignatureManager) PersistSignaturesToFile() error { + + // Check content, don't write an empty file + if len(m.archives.recievedSignatures) == 0 { + return fmt.Errorf("No stored signatures, cannot create an empty file (yes I'm a coward)") + } + + // Fill JSON struct + signedContract := SignedContractJSON{ + Contract: *m.contract, + Signatures: make( + []cAPI.Signature, + len(m.archives.sentSignatures)+len(m.archives.recievedSignatures), + ), + } + + for i, s := range m.archives.sentSignatures { + signedContract.Signatures[i] = *s + } + + for i, s := range m.archives.recievedSignatures { + signedContract.Signatures[len(m.archives.sentSignatures)+i] = *s + } + + proof, err := json.MarshalIndent(signedContract, "", " ") + if err != nil { + return err + } + + return ioutil.WriteFile(m.mail+"-"+m.contract.UUID+".proof", proof, 0600) +} diff --git a/dfssc/sign/protocol.go b/dfssc/sign/protocol.go index b28963a..ee8f079 100644 --- a/dfssc/sign/protocol.go +++ b/dfssc/sign/protocol.go @@ -66,6 +66,13 @@ func (m *SignatureManager) Sign() error { dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Exit signature round") + // Network's job is done, cleaning time + // Shutdown and platform client and TODO peer server & connections + err = m.platformConn.Close() + if err != nil { + return err + } + return nil } @@ -144,3 +151,16 @@ func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint3 } } } + +// closeAllPeerClient tries to close all established connection with other peers +func (m *SignatureManager) closeAllPeerClient() { + for k, client := range m.peersConn { + err := client.Close() + if err != nil { + // We don't care + } + // Remove associated grpc client + delete(m.peers, k) + fmt.Println("- Close connection to " + k) + } +} diff --git a/dfssc/sign/starter.go b/dfssc/sign/starter.go index d009618..97b7a59 100644 --- a/dfssc/sign/starter.go +++ b/dfssc/sign/starter.go @@ -24,6 +24,8 @@ type SignatureManager struct { localPort int contract *contract.JSON // contains the contractUUID, the list of the signers' hashes, the hash of the contract platform pAPI.PlatformClient + platformConn *grpc.ClientConn + peersConn map[string]*grpc.ClientConn peers map[string]*cAPI.ClientClient hashToID map[string]uint32 nbReady int @@ -75,7 +77,9 @@ func NewSignatureManager(fileCA, fileCert, fileKey, addrPort, passphrase string, } m.platform = pAPI.NewPlatformClient(conn) + m.platformConn = conn + m.peersConn = make(map[string]*grpc.ClientConn) m.peers = make(map[string]*cAPI.ClientClient) for _, u := range c.Signers { if u.Email != m.auth.Cert.Subject.CommonName { @@ -139,6 +143,9 @@ func (m *SignatureManager) addPeer(user *pAPI.User) (ready bool, err error) { client := cAPI.NewClientClient(conn) lastConnection := m.peers[user.Email] m.peers[user.Email] = &client + // The connection is encapsulated into the interface, so we + // need to create another way to access it + m.peersConn[user.Email] = conn ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/tests/sign_test.go b/tests/sign_test.go index 8bb624f..968c095 100644 --- a/tests/sign_test.go +++ b/tests/sign_test.go @@ -14,6 +14,17 @@ import ( "github.com/bmizerany/assert" ) +// TestSignContract unroll the whole signature process. +// +// GOOD CASE +// - Start platform +// - Register client1, client2 and client3 +// - Create contract `contract.txt` +// - Sign it +// - Check if all proof files are present +// +// TODO BAD CASES + func TestSignContract(t *testing.T) { // Cleanup eraseDatabase() @@ -101,4 +112,20 @@ func TestSignContract(t *testing.T) { assert.T(t, r.Match(output), "Regex is not satisfied: ", r.String()) } } + + // Ensure that all the files are present + proofFile := regexp.MustCompile(`client[0-9]+@example.com.*\.proof`) + files, _ := ioutil.ReadDir("./") + + matches := 0 + for _, file := range files { + if proofFile.Match([]byte(file.Name())) { + matches++ + err = os.Remove("./" + file.Name()) + assert.T(t, err == nil, "Cannot remove .proof matching file") + } + } + assert.T(t, matches == 3, "Missing proof file ?") + + time.Sleep(time.Second) } -- GitLab