From 6ad7dd04274d99d0591d78f58dcb05128b0ec700 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Mon, 28 Mar 2022 11:03:36 +0200 Subject: [PATCH 01/68] finished the http version scenario test --- integration/scenario_test.go | 492 +++++++++++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 integration/scenario_test.go diff --git a/integration/scenario_test.go b/integration/scenario_test.go new file mode 100644 index 000000000..0fa281eb9 --- /dev/null +++ b/integration/scenario_test.go @@ -0,0 +1,492 @@ +package integration + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "testing" + "time" + + "github.com/dedis/d-voting/contracts/evoting/types" + "github.com/stretchr/testify/require" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/suites" + "go.dedis.ch/kyber/v3/util/random" + "golang.org/x/xerrors" +) + +var suite = suites.MustFind("Ed25519") + +// Check the shuffled votes versus the cast votes on a few nodes +func TestScenario(t *testing.T) { + t.Run("Basic configuration", getScenarioTest()) + +} + +func getScenarioTest() func(*testing.T) { + return func(t *testing.T) { + const ( + loginEndpoint = "/evoting/login" + createElectionEndpoint = "/evoting/create" + openElectionEndpoint = "/evoting/open" + castVoteEndpoint = "/evoting/cast" + getAllElectionsIdsEndpoint = "/evoting/allids" + getElectionInfoEndpoint = "/evoting/info" + getAllElectionsInfoEndpoint = "/evoting/all" + closeElectionEndpoint = "/evoting/close" + shuffleBallotsEndpoint = "/evoting/shuffle" + beginDecryptionEndpoint = "/evoting/beginDecryption" + combineSharesEndpoint = "/evoting/combineShares" + getElectionResultEndpoint = "/evoting/result" + cancelElectionEndpoint = "/evoting/cancel" + initEndpoint = "/evoting/dkg/init" + ) + + const contentType = "application/json" + + t.Parallel() + proxyAddr1 := "http://localhost:8081" + proxyAddr2 := "http://localhost:8082" + proxyAddr3 := "http://localhost:8083" + + // ###################################### CREATE SIMPLE ELECTION ###### + create_election_js := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` + t.Logf("Create election") + t.Logf("create election js: %v", create_election_js) + + resp, err := http.Post(proxyAddr1+createElectionEndpoint, contentType, bytes.NewBuffer([]byte(create_election_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + + // var payload interface{} + var objmap map[string]interface{} + + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parse the body of the response from js: %v", err) + electionID := objmap["ElectionID"].(string) + t.Logf("ID of the election : " + electionID) + return + // ##################################### SETUP DKG ######################### + + t.Log("Init DKG") + + t.Log("Node 1") + + resp, err = http.Post(proxyAddr1+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + t.Log("Node 2") + resp, err = http.Post(proxyAddr2+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + t.Log("Node 3") + resp, err = http.Post(proxyAddr3+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + t.Log("Setup DKG") + resp, err = http.Post(proxyAddr1+"/evoting/dkg/setup", contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + pubkeyBuf, err := io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read body: %v", err) + t.Logf("DKG public key: %x", pubkeyBuf) + + pubKey := suite.Point() + err = pubKey.UnmarshalBinary(pubkeyBuf) + require.NoError(t, err, "failed to unmarshal pubkey: %v", err) + t.Logf("Pubkey: %v\n", pubKey) + + // ##################################### OPEN ELECTION ##################### + + t.Log("Open election") + resp, err = http.Post(proxyAddr1+"/evoting/open", contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + // ##################################### GET ELECTION INFO ################# + // Get election public key + + t.Log("Get election info") + create_info_js := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionpubkey := objmap["Pubkey"].(string) + electionStatus := objmap["Status"].(string) + t.Logf("Publickey of the election : " + electionpubkey) + t.Logf("Status of the election : " + electionStatus) + // ##################################### CAST BALLOTS ###################### + + t.Log("cast ballots") + + // Create the ballots + b1 := string("select:" + encodeID("bb") + ":0,0,1,0\n" + + "text:" + encodeID("ee") + ":eWVz\n\n") //encoding of "yes" + + b2 := string("select:" + encodeID("bb") + ":1,1,0,0\n" + + "text:" + encodeID("ee") + ":amE=\n\n") //encoding of "ja + + b3 := string("select:" + encodeID("bb") + ":0,0,0,1\n" + + "text:" + encodeID("ee") + "b3Vp\n\n") //encoding of "oui" + + // Ballot 1 + // chunk 255 by default + ballot1, err := marshallBallot_manual(b1, pubKey, 255) + require.NoError(t, err, "failed to encrypt ballot : %v", err) + + data1, err := json.Marshal(ballot1) + require.NoError(t, err, "failed to marshall ballot : %v", err) + + castVoteRequest := types.CastVoteRequest{ + ElectionID: electionID, + UserID: "user1", + Ballot: data1, + Token: "token", + } + + t.Logf("cast first ballot") + js_vote, err := json.Marshal(castVoteRequest) + resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + body, err = io.ReadAll(resp.Body) + resp.Body.Close() + t.Log("Response body: " + string(body)) + + // Ballot 2 + // chunk 255 by default + ballot2, err := marshallBallot_manual(b2, pubKey, 255) + require.NoError(t, err, "failed to encrypt ballot : %v", err) + + data2, err := json.Marshal(ballot2) + require.NoError(t, err, "failed to marshall ballot : %v", err) + + castVoteRequest = types.CastVoteRequest{ + ElectionID: electionID, + UserID: "user2", + Ballot: data2, + Token: "token", + } + + t.Logf("cast second ballot") + js_vote, _ = json.Marshal(castVoteRequest) + resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + body, _ = io.ReadAll(resp.Body) + resp.Body.Close() + t.Log("Response body: " + string(body)) + + // Ballot 3 + // chunk 255 by default + ballot3, err := marshallBallot_manual(b3, pubKey, 255) + require.NoError(t, err, "failed to encrypt ballot : %v", err) + + data3, err := json.Marshal(ballot3) + require.NoError(t, err, "failed to marshall ballot : %v", err) + + castVoteRequest = types.CastVoteRequest{ + ElectionID: electionID, + UserID: "user3", + Ballot: data3, + Token: "token", + } + + t.Logf("cast third ballot") + js_vote, err = json.Marshal(castVoteRequest) + resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + body, err = io.ReadAll(resp.Body) + resp.Body.Close() + t.Log("Response body: " + string(body)) + + // ############################# CLOSE ELECTION FOR REAL ################### + + t.Log("Close election (for real)") + + closeElectionRequest := types.CloseElectionRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err := json.Marshal(closeElectionRequest) + require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) + resp, err = http.Post(proxyAddr1+closeElectionEndpoint, contentType, bytes.NewBuffer(js)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + t.Log("Get election info") + create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = objmap["Status"].(string) + t.Logf("Status of the election : " + electionStatus) + + // ###################################### SHUFFLE BALLOTS ################## + + t.Log("shuffle ballots") + + shuffleBallotsRequest := types.ShuffleBallotsRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(shuffleBallotsRequest) + require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) + + resp, err = http.Post(proxyAddr1+shuffleBallotsEndpoint, contentType, bytes.NewBuffer(js)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = objmap["Status"].(string) + t.Logf("Status of the election : " + electionStatus) + + // ###################################### REQUEST PUBLIC SHARES ############ + + t.Log("request public shares") + + beginDecryptionRequest := types.BeginDecryptionRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(beginDecryptionRequest) + require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) + + resp, err = http.Post(proxyAddr1+beginDecryptionEndpoint, contentType, bytes.NewBuffer(js)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = objmap["Status"].(string) + t.Logf("Status of the election : " + electionStatus) + + // ###################################### DECRYPT BALLOTS ################## + + t.Log("decrypt ballots") + + decryptBallotsRequest := types.CombineSharesRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(decryptBallotsRequest) + require.NoError(t, err, "failed to set marshall types.CombineSharesRequest : %v", err) + + resp, err = http.Post(proxyAddr1+combineSharesEndpoint, contentType, bytes.NewBuffer(js)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = objmap["Status"].(string) + t.Logf("Status of the election : " + electionStatus) + + // ###################################### GET ELECTION RESULT ############## + + t.Log("Get election result") + + getElectionResultRequest := types.GetElectionResultRequest{ + ElectionID: electionID, + Token: "token", + } + + js, err = json.Marshal(getElectionResultRequest) + require.NoError(t, err, "failed to set marshall types.GetElectionResultRequest : %v", err) + + resp, err = http.Post(proxyAddr1+getElectionResultEndpoint, contentType, bytes.NewBuffer(js)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = objmap["Status"].(string) + t.Logf("Status of the election : " + electionStatus) + } +} + +// ----------------------------------------------------------------------------- +// Utility functions +func marshallBallot_manual(voteStr string, pubkey kyber.Point, chunks int) (types.Ciphervote, error) { + // chunk by default 1 + var ballot = make(types.Ciphervote, chunks) + vote := strings.NewReader(voteStr) + + buf := make([]byte, 29) + + for i := 0; i < chunks; i++ { + var K, C kyber.Point + var err error + + n, err := vote.Read(buf) + if err != nil { + return nil, xerrors.Errorf("failed to read: %v", err) + } + + K, C, _, err = Encrypt_manual(buf[:n], pubkey) + + if err != nil { + return types.Ciphervote{}, xerrors.Errorf("failed to encrypt the plaintext: %v", err) + } + + ballot[i] = types.EGPair{ + K: K, + C: C, + } + } + + return ballot, nil +} + +func Encrypt_manual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remainder []byte, + err error) { + + // Embed the message (or as much of it as will fit) into a curve point. + M := suite.Point().Embed(message, random.New()) + max := suite.Point().EmbedLen() + if max > len(message) { + max = len(message) + } + remainder = message[max:] + // ElGamal-encrypt the point to produce ciphertext (K,C). + k := suite.Scalar().Pick(random.New()) // ephemeral private key + K = suite.Point().Mul(k, nil) // ephemeral DH public key + S := suite.Point().Mul(k, pubkey) // ephemeral DH shared secret + C = S.Add(S, M) // message blinded with secret + + return K, C, remainder, nil +} From b12db46022a25327fe9db733131fd2d1e04a89e8 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Mon, 28 Mar 2022 17:12:31 +0200 Subject: [PATCH 02/68] added BallotSize in the response of evoting/info endpoint --- contracts/evoting/controller/handlers.go | 1 + contracts/evoting/types/http.go | 1 + 2 files changed, 2 insertions(+) diff --git a/contracts/evoting/controller/handlers.go b/contracts/evoting/controller/handlers.go index 0a4139e37..6b92d94e1 100644 --- a/contracts/evoting/controller/handlers.go +++ b/contracts/evoting/controller/handlers.go @@ -256,6 +256,7 @@ func (h *votingProxy) ElectionInfo(w http.ResponseWriter, r *http.Request) { Status: uint16(election.Status), Pubkey: hex.EncodeToString(pubkeyBuf), Result: election.DecryptedBallots, + BallotSize: election.BallotSize, } w.Header().Set("Content-Type", "application/json") diff --git a/contracts/evoting/types/http.go b/contracts/evoting/types/http.go index cf4d3ead9..8daf6e447 100644 --- a/contracts/evoting/types/http.go +++ b/contracts/evoting/types/http.go @@ -129,6 +129,7 @@ type GetElectionInfoResponse struct { Pubkey string Result []Ballot Format string + BallotSize int } // GetAllElectionsInfoRequest defines the HTTP request for getting all elections From a435ba21ad4df6c57b67248b25f7ccdb064022b1 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Mon, 4 Apr 2022 10:36:41 +0200 Subject: [PATCH 03/68] finished scenario_test --- integration/scenario_test.go | 120 +++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 27 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 0fa281eb9..d03b6d2bf 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -75,7 +75,7 @@ func getScenarioTest() func(*testing.T) { require.NoError(t, err, "failed to parse the body of the response from js: %v", err) electionID := objmap["ElectionID"].(string) t.Logf("ID of the election : " + electionID) - return + // ##################################### SETUP DKG ######################### t.Log("Init DKG") @@ -134,11 +134,16 @@ func getScenarioTest() func(*testing.T) { t.Log("response body:", string(body)) resp.Body.Close() err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + require.NoError(t, err, "failed to parse body of the response from js: %v", err) electionpubkey := objmap["Pubkey"].(string) - electionStatus := objmap["Status"].(string) + electionStatus := int(objmap["Status"].(float64)) + BallotSize := int(objmap["BallotSize"].(float64)) + Chunksperballot := ChunksPerBallot_manuel(BallotSize) t.Logf("Publickey of the election : " + electionpubkey) - t.Logf("Status of the election : " + electionStatus) + t.Logf("Status of the election : %v", electionStatus) + t.Logf("BallotSize of the election : %v", BallotSize) + t.Logf("Chunksperballot of the election : %v", Chunksperballot) + // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") @@ -154,12 +159,14 @@ func getScenarioTest() func(*testing.T) { "text:" + encodeID("ee") + "b3Vp\n\n") //encoding of "oui" // Ballot 1 - // chunk 255 by default - ballot1, err := marshallBallot_manual(b1, pubKey, 255) + ballot1, err := marshallBallot_manual(b1, pubKey, Chunksperballot) + t.Logf("1st ballot is: %v", ballot1) + require.NoError(t, err, "failed to encrypt ballot : %v", err) - data1, err := json.Marshal(ballot1) + data1, err := Encode_ciphervote(ballot1) require.NoError(t, err, "failed to marshall ballot : %v", err) + t.Logf("1st marshalled ballot is: %v", data1) castVoteRequest := types.CastVoteRequest{ ElectionID: electionID, @@ -170,19 +177,23 @@ func getScenarioTest() func(*testing.T) { t.Logf("cast first ballot") js_vote, err := json.Marshal(castVoteRequest) + require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) + + t.Logf("vote is: %v", castVoteRequest) resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) + resp.Body.Close() t.Log("Response body: " + string(body)) // Ballot 2 - // chunk 255 by default - ballot2, err := marshallBallot_manual(b2, pubKey, 255) + ballot2, err := marshallBallot_manual(b2, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data2, err := json.Marshal(ballot2) + data2, err := Encode_ciphervote(ballot2) require.NoError(t, err, "failed to marshall ballot : %v", err) castVoteRequest = types.CastVoteRequest{ @@ -193,20 +204,23 @@ func getScenarioTest() func(*testing.T) { } t.Logf("cast second ballot") - js_vote, _ = json.Marshal(castVoteRequest) + js_vote, err = json.Marshal(castVoteRequest) + require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) + resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - body, _ = io.ReadAll(resp.Body) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) + resp.Body.Close() t.Log("Response body: " + string(body)) // Ballot 3 - // chunk 255 by default - ballot3, err := marshallBallot_manual(b3, pubKey, 255) + ballot3, err := marshallBallot_manual(b3, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data3, err := json.Marshal(ballot3) + data3, err := Encode_ciphervote(ballot3) require.NoError(t, err, "failed to marshall ballot : %v", err) castVoteRequest = types.CastVoteRequest{ @@ -218,10 +232,14 @@ func getScenarioTest() func(*testing.T) { t.Logf("cast third ballot") js_vote, err = json.Marshal(castVoteRequest) + require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) + resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) + resp.Body.Close() t.Log("Response body: " + string(body)) @@ -262,8 +280,8 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = objmap["Status"].(string) - t.Logf("Status of the election : " + electionStatus) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) // ###################################### SHUFFLE BALLOTS ################## @@ -305,8 +323,8 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = objmap["Status"].(string) - t.Logf("Status of the election : " + electionStatus) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) // ###################################### REQUEST PUBLIC SHARES ############ @@ -348,8 +366,8 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = objmap["Status"].(string) - t.Logf("Status of the election : " + electionStatus) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) // ###################################### DECRYPT BALLOTS ################## @@ -391,8 +409,8 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = objmap["Status"].(string) - t.Logf("Status of the election : " + electionStatus) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) // ###################################### GET ELECTION RESULT ############## @@ -434,17 +452,18 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = objmap["Status"].(string) - t.Logf("Status of the election : " + electionStatus) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) } } // ----------------------------------------------------------------------------- // Utility functions func marshallBallot_manual(voteStr string, pubkey kyber.Point, chunks int) (types.Ciphervote, error) { - // chunk by default 1 + var ballot = make(types.Ciphervote, chunks) vote := strings.NewReader(voteStr) + fmt.Printf("votestr is: %v", voteStr) buf := make([]byte, 29) @@ -490,3 +509,50 @@ func Encrypt_manual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remai return K, C, remainder, nil } + +func ChunksPerBallot_manuel(BallotSize int) int { + if BallotSize%29 == 0 { + return BallotSize / 29 + } + + return BallotSize/29 + 1 +} + +// Encode implements serde.FormatEngine +func Encode_ciphervote(ciphervote types.Ciphervote) ([]byte, error) { + + m := make(CiphervoteJSON, len(ciphervote)) + + for i, egpair := range ciphervote { + k, err := egpair.K.MarshalBinary() + if err != nil { + return nil, xerrors.Errorf("failed to marshal k: %v", err) + } + + c, err := egpair.C.MarshalBinary() + if err != nil { + return nil, xerrors.Errorf("failed to marshal c: %v", err) + } + + m[i] = EGPairJSON{ + K: k, + C: c, + } + } + + data, err := json.Marshal(m) + if err != nil { + return nil, xerrors.Errorf("failed to marshal cipher vote json: %v", err) + } + + return data, nil +} + +// CiphervoteJSON is the JSON representation of a ciphervote +type CiphervoteJSON []EGPairJSON + +// EGPairJSON is the JSON representation of an ElGamal pair +type EGPairJSON struct { + K []byte + C []byte +} From 77c0195b6527a05de2d6c91c2ebce5998a35d68f Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Mon, 4 Apr 2022 23:16:04 +0200 Subject: [PATCH 04/68] Started to compare sendback result and voter's initial votes --- integration/scenario_test.go | 281 +++++++++++++++++++++++++++++++---- 1 file changed, 249 insertions(+), 32 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index d03b6d2bf..5ddd7eeda 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -2,15 +2,19 @@ package integration import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "io" + "math/rand" "net/http" + "strconv" "strings" "testing" "time" "github.com/dedis/d-voting/contracts/evoting/types" + "github.com/dedis/d-voting/internal/testing/fake" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/suites" @@ -47,11 +51,13 @@ func getScenarioTest() func(*testing.T) { const contentType = "application/json" - t.Parallel() + // t.Parallel() proxyAddr1 := "http://localhost:8081" proxyAddr2 := "http://localhost:8082" proxyAddr3 := "http://localhost:8083" + proxyArray := [3]string{proxyAddr1, proxyAddr2, proxyAddr3} + // ###################################### CREATE SIMPLE ELECTION ###### create_election_js := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` t.Logf("Create election") @@ -112,8 +118,10 @@ func getScenarioTest() func(*testing.T) { // ##################################### OPEN ELECTION ##################### - t.Log("Open election") - resp, err = http.Post(proxyAddr1+"/evoting/open", contentType, bytes.NewBuffer([]byte(electionID))) + randomproxy := proxyArray[rand.Intn(len(proxyArray))] + t.Logf("Open election send to proxy %v", randomproxy) + + resp, err = http.Post(randomproxy+"/evoting/open", contentType, bytes.NewBuffer([]byte(electionID))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -159,6 +167,8 @@ func getScenarioTest() func(*testing.T) { "text:" + encodeID("ee") + "b3Vp\n\n") //encoding of "oui" // Ballot 1 + t.Logf("1st ballot in str is: %v", b1) + ballot1, err := marshallBallot_manual(b1, pubKey, Chunksperballot) t.Logf("1st ballot is: %v", ballot1) @@ -175,12 +185,13 @@ func getScenarioTest() func(*testing.T) { Token: "token", } - t.Logf("cast first ballot") + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + t.Logf("cast first ballot to proxy %v", randomproxy) js_vote, err := json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) t.Logf("vote is: %v", castVoteRequest) - resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -207,7 +218,8 @@ func getScenarioTest() func(*testing.T) { js_vote, err = json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) - resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -234,7 +246,9 @@ func getScenarioTest() func(*testing.T) { js_vote, err = json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) - resp, err = http.Post(proxyAddr1+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -245,7 +259,9 @@ func getScenarioTest() func(*testing.T) { // ############################# CLOSE ELECTION FOR REAL ################### - t.Log("Close election (for real)") + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + t.Logf("Close election (for real) send to proxy %v", randomproxy) closeElectionRequest := types.CloseElectionRequest{ ElectionID: electionID, @@ -255,7 +271,8 @@ func getScenarioTest() func(*testing.T) { js, err := json.Marshal(closeElectionRequest) require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) - resp, err = http.Post(proxyAddr1+closeElectionEndpoint, contentType, bytes.NewBuffer(js)) + + resp, err = http.Post(randomproxy+closeElectionEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -268,7 +285,7 @@ func getScenarioTest() func(*testing.T) { t.Log("Get election info") create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -296,7 +313,9 @@ func getScenarioTest() func(*testing.T) { js, err = json.Marshal(shuffleBallotsRequest) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - resp, err = http.Post(proxyAddr1+shuffleBallotsEndpoint, contentType, bytes.NewBuffer(js)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+shuffleBallotsEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -311,7 +330,9 @@ func getScenarioTest() func(*testing.T) { t.Log("Get election info") create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -339,7 +360,9 @@ func getScenarioTest() func(*testing.T) { js, err = json.Marshal(beginDecryptionRequest) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - resp, err = http.Post(proxyAddr1+beginDecryptionEndpoint, contentType, bytes.NewBuffer(js)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+beginDecryptionEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -354,7 +377,9 @@ func getScenarioTest() func(*testing.T) { t.Log("Get election info") create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -382,7 +407,9 @@ func getScenarioTest() func(*testing.T) { js, err = json.Marshal(decryptBallotsRequest) require.NoError(t, err, "failed to set marshall types.CombineSharesRequest : %v", err) - resp, err = http.Post(proxyAddr1+combineSharesEndpoint, contentType, bytes.NewBuffer(js)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+combineSharesEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -397,7 +424,9 @@ func getScenarioTest() func(*testing.T) { t.Log("Get election info") create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -424,7 +453,9 @@ func getScenarioTest() func(*testing.T) { js, err = json.Marshal(getElectionResultRequest) require.NoError(t, err, "failed to set marshall types.GetElectionResultRequest : %v", err) - resp, err = http.Post(proxyAddr1+getElectionResultEndpoint, contentType, bytes.NewBuffer(js)) + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + + resp, err = http.Post(randomproxy+getElectionResultEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -435,25 +466,22 @@ func getScenarioTest() func(*testing.T) { t.Log("Response body: " + string(body)) resp.Body.Close() - time.Sleep(10 * time.Second) + var sendback_ballots []types.Ballot + _ = json.Unmarshal(body, sendback_ballots) + t.Logf("Response body unmarshalled is %v", sendback_ballots) + return + // ###################################### VALIDATE ELECTION RESULT ############## - t.Log("Get election info") - create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + fake_configuration := fake.BasicConfiguration + t.Logf("configuration is: %v", fake_configuration) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + b1_marshal, err := Unmarshal_Ballot_Manual(b1, fake_configuration) + // b2_marshal, err := Unmarshal_Ballot_Manual(b2, fake_configuration) + // b3_marshal, err := Unmarshal_Ballot_Manual(b3, fake_configuration) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + t.Logf("1st ballot in marshalled object is: %v", b1_marshal) + return - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = int(objmap["Status"].(float64)) - t.Logf("Status of the election : %v", electionStatus) } } @@ -556,3 +584,192 @@ type EGPairJSON struct { K []byte C []byte } + +// Unmarshal decodes the given string according to the format described in +// "state of smart contract.md" +func Unmarshal_Ballot_Manual(marshalledBallot string, configuration types.Configuration) (types.Ballot, error) { + invalidate := func(b types.Ballot) { + b.RankResultIDs = nil + b.RankResult = nil + b.TextResultIDs = nil + b.TextResult = nil + b.SelectResultIDs = nil + b.SelectResult = nil + } + + var b types.Ballot + BallotSize := configuration.MaxBallotSize() + if len(marshalledBallot) > BallotSize { + invalidate(b) + return b, fmt.Errorf("ballot has an unexpected size %d, expected <= %d", + len(marshalledBallot), BallotSize) + } + + lines := strings.Split(marshalledBallot, "\n") + + b.SelectResultIDs = make([]types.ID, 0) + b.SelectResult = make([][]bool, 0) + + b.RankResultIDs = make([]types.ID, 0) + b.RankResult = make([][]int8, 0) + + b.TextResultIDs = make([]types.ID, 0) + b.TextResult = make([][]string, 0) + + //TODO: Loads of code duplication, can be re-thought + for _, line := range lines { + if line == "" { + // empty line, the valid part of the ballot is over + break + } + + question := strings.Split(line, ":") + + if len(question) != 3 { + invalidate(b) + return b, xerrors.Errorf("a line in the ballot has length != 3: %s", line) + } + + _, err := base64.StdEncoding.DecodeString(question[1]) + if err != nil { + return b, xerrors.Errorf("could not decode question ID: %v", err) + } + questionID := question[1] + + q := configuration.GetQuestion(types.ID(questionID)) + + if q == nil { + invalidate(b) + return b, fmt.Errorf("wrong question ID: the question doesn't exist") + } + + switch question[0] { + + case "select": + selections := strings.Split(question[2], ",") + + if len(selections) != q.GetChoicesLength() { + invalidate(b) + return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ + "", questionID, q.GetChoicesLength(), len(selections)) + } + + b.SelectResultIDs = append(b.SelectResultIDs, types.ID(questionID)) + b.SelectResult = append(b.SelectResult, make([]bool, 0)) + + index := len(b.SelectResult) - 1 + var selected uint = 0 + + for _, selection := range selections { + s, err := strconv.ParseBool(selection) + + if err != nil { + invalidate(b) + return b, fmt.Errorf("could not parse selection value for Q.%s: %v", + questionID, err) + } + + if s { + selected++ + } + + b.SelectResult[index] = append(b.SelectResult[index], s) + } + + if selected > q.GetMaxN() { + invalidate(b) + return b, fmt.Errorf("question %s has too many selected answers", questionID) + } else if selected < q.GetMinN() { + invalidate(b) + return b, fmt.Errorf("question %s has not enough selected answers", questionID) + } + + case "rank": + ranks := strings.Split(question[2], ",") + + if len(ranks) != q.GetChoicesLength() { + invalidate(b) + return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ + "", questionID, q.GetChoicesLength(), len(ranks)) + } + + b.RankResultIDs = append(b.RankResultIDs, types.ID(questionID)) + b.RankResult = append(b.RankResult, make([]int8, 0)) + + index := len(b.RankResult) - 1 + var selected uint = 0 + for _, rank := range ranks { + if len(rank) > 0 { + selected++ + + r, err := strconv.ParseInt(rank, 10, 8) + if err != nil { + invalidate(b) + return b, fmt.Errorf("could not parse rank value for Q.%s : %v", + questionID, err) + } + + if r < 0 || uint(r) >= q.GetMaxN() { + invalidate(b) + return b, fmt.Errorf("invalid rank not in range [0, MaxN[") + } + + b.RankResult[index] = append(b.RankResult[index], int8(r)) + } else { + b.RankResult[index] = append(b.RankResult[index], int8(-1)) + } + } + + if selected > q.GetMaxN() { + invalidate(b) + return b, fmt.Errorf("question %s has too many selected answers", questionID) + } else if selected < q.GetMinN() { + invalidate(b) + return b, fmt.Errorf("question %s has not enough selected answers", questionID) + } + + case "text": + texts := strings.Split(question[2], ",") + + if len(texts) != q.GetChoicesLength() { + invalidate(b) + return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ + "", questionID, q.GetChoicesLength(), len(texts)) + } + + b.TextResultIDs = append(b.TextResultIDs, types.ID(questionID)) + b.TextResult = append(b.TextResult, make([]string, 0)) + + index := len(b.TextResult) - 1 + var selected uint = 0 + + for _, text := range texts { + if len(text) > 0 { + selected++ + } + + t, err := base64.StdEncoding.DecodeString(text) + if err != nil { + return b, fmt.Errorf("could not decode text for Q. %s: %v", questionID, err) + } + + b.TextResult[index] = append(b.TextResult[index], string(t)) + } + + if selected > q.GetMaxN() { + invalidate(b) + return b, fmt.Errorf("question %s has too many selected answers", questionID) + } else if selected < q.GetMinN() { + invalidate(b) + return b, fmt.Errorf("question %s has not enough selected answers", questionID) + } + + default: + invalidate(b) + return b, fmt.Errorf("question type is unknown") + } + + } + + return b, nil +} From f02064e50312d8394dd4e5deed2c78ee9ee0f459 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Tue, 5 Apr 2022 12:41:20 +0200 Subject: [PATCH 05/68] Finished comparaison between front end votes and decrypted votes --- integration/scenario_test.go | 77 ++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 5ddd7eeda..319c6fa1e 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -8,6 +8,7 @@ import ( "io" "math/rand" "net/http" + "reflect" "strconv" "strings" "testing" @@ -51,7 +52,7 @@ func getScenarioTest() func(*testing.T) { const contentType = "application/json" - // t.Parallel() + t.Parallel() proxyAddr1 := "http://localhost:8081" proxyAddr2 := "http://localhost:8082" proxyAddr3 := "http://localhost:8083" @@ -166,6 +167,30 @@ func getScenarioTest() func(*testing.T) { b3 := string("select:" + encodeID("bb") + ":0,0,0,1\n" + "text:" + encodeID("ee") + "b3Vp\n\n") //encoding of "oui" + var votesfrontend [3]map[string]interface{} + + fake_configuration := fake.BasicConfiguration + t.Logf("configuration is: %v", fake_configuration) + + b1_marshal, _ := Unmarshal_Ballot_Manual(b1, fake_configuration) + ballot_byte, _ := json.Marshal(b1_marshal) + // var temp_obj map[string]interface{} + _ = json.Unmarshal(ballot_byte, &votesfrontend[0]) + // t.Logf("b1_marshal is: %v", temp_obj) + + b2_marshal, _ := Unmarshal_Ballot_Manual(b2, fake_configuration) + ballot_byte, _ = json.Marshal(b2_marshal) + _ = json.Unmarshal(ballot_byte, &votesfrontend[1]) + // t.Logf("b2_marshal is: %v", temp_obj) + // votesfrontend[1] = temp_obj + + b3_marshal, _ := Unmarshal_Ballot_Manual(b3, fake_configuration) + ballot_byte, _ = json.Marshal(b3_marshal) + _ = json.Unmarshal(ballot_byte, &votesfrontend[2]) + // t.Logf("b1_marshal is: %v", temp_obj) + // votesfrontend[2] = temp_obj + t.Logf("b123_marshal is: %v", votesfrontend) + // Ballot 1 t.Logf("1st ballot in str is: %v", b1) @@ -466,20 +491,50 @@ func getScenarioTest() func(*testing.T) { t.Log("Response body: " + string(body)) resp.Body.Close() - var sendback_ballots []types.Ballot - _ = json.Unmarshal(body, sendback_ballots) - t.Logf("Response body unmarshalled is %v", sendback_ballots) - return // ###################################### VALIDATE ELECTION RESULT ############## - fake_configuration := fake.BasicConfiguration - t.Logf("configuration is: %v", fake_configuration) + // body1 := `{"Result":[{"SelectResultIDs":["YmI="],"SelectResult":[[false,false,true,false]],"RankResultIDs":[],"RankResult":[],"TextResultIDs":["ZWU="],"TextResult":[["yes"]]},{"SelectResultIDs":["YmI="],"SelectResult":[[true,true,false,false]],"RankResultIDs":[],"RankResult":[],"TextResultIDs":["ZWU="],"TextResult":[["ja"]]},{"SelectResultIDs":null,"SelectResult":null,"RankResultIDs":null,"RankResult":null,"TextResultIDs":null,"TextResult":null}]}` + + // var objmap1 map[string]interface{} + // _ = json.Unmarshal([]byte(body1), &objmap1) + // tmp_ballots := (objmap1["Result"]).([]interface{}) + // tmp_map := tmp_ballots[0].(map[string]interface{}) + + // require.Equal(t, temp_obj, tmp_map) + // return + + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + + tmp_ballots := (objmap["Result"]).([]interface{}) + var tmp_comp map[string]interface{} + var tmp_count bool + for _, ballot_intem := range tmp_ballots { + tmp_comp = ballot_intem.(map[string]interface{}) + tmp_count = false + for _, vote_front := range votesfrontend { + t.Logf("vote_front: %v", vote_front) + t.Logf("tmp_comp: %v", tmp_comp) + + tmp_count = reflect.DeepEqual(tmp_comp, vote_front) + t.Logf("tmp_count: %v", tmp_count) + + if tmp_count { + break + } + } + } + require.True(t, tmp_count, "front end votes are different from decrypted votes") + + // // tmp_ballots := (objmap["Result"]).([]types.Ballot) - b1_marshal, err := Unmarshal_Ballot_Manual(b1, fake_configuration) - // b2_marshal, err := Unmarshal_Ballot_Manual(b2, fake_configuration) - // b3_marshal, err := Unmarshal_Ballot_Manual(b3, fake_configuration) + // t.Logf("Response body tmp_ballots is %v", tmp_ballots[0]) + // b_test, _ := tmp_ballots[0]["RankResult"] + // t.Logf("Response body tmp_ballots RankResult is %v", b_test) - t.Logf("1st ballot in marshalled object is: %v", b1_marshal) + // // var sendback_ballots types.Ballot + // // _ = json.Unmarshal(b_test, sendback_ballots) + // // t.Logf("Response body unmarshalled is %v", sendback_ballots) return } From 39de03241c0aac25ca23511a63b524b03f2db579 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang Date: Thu, 7 Apr 2022 14:40:46 +0200 Subject: [PATCH 06/68] added chunksperballot in response to getelectioninfo request --- contracts/evoting/controller/handlers.go | 14 ++++++++------ contracts/evoting/types/http.go | 15 ++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/contracts/evoting/controller/handlers.go b/contracts/evoting/controller/handlers.go index 6b92d94e1..d770aa2c3 100644 --- a/contracts/evoting/controller/handlers.go +++ b/contracts/evoting/controller/handlers.go @@ -251,12 +251,13 @@ func (h *votingProxy) ElectionInfo(w http.ResponseWriter, r *http.Request) { } response := types.GetElectionInfoResponse{ - ElectionID: string(election.ElectionID), - Configuration: election.Configuration, - Status: uint16(election.Status), - Pubkey: hex.EncodeToString(pubkeyBuf), - Result: election.DecryptedBallots, - BallotSize: election.BallotSize, + ElectionID: string(election.ElectionID), + Configuration: election.Configuration, + Status: uint16(election.Status), + Pubkey: hex.EncodeToString(pubkeyBuf), + Result: election.DecryptedBallots, + BallotSize: election.BallotSize, + Chunksperballot: election.ChunksPerBallot(), } w.Header().Set("Content-Type", "application/json") @@ -307,6 +308,7 @@ func (h *votingProxy) AllElectionInfo(w http.ResponseWriter, r *http.Request) { Status: uint16(election.Status), Pubkey: hex.EncodeToString(pubkeyBuf), Result: election.DecryptedBallots, + BallotSize: election.BallotSize, } allElectionsInfo[i] = info diff --git a/contracts/evoting/types/http.go b/contracts/evoting/types/http.go index 8daf6e447..6a369bc04 100644 --- a/contracts/evoting/types/http.go +++ b/contracts/evoting/types/http.go @@ -123,13 +123,14 @@ type GetElectionInfoRequest struct { // info type GetElectionInfoResponse struct { // ElectionID is hex-encoded - ElectionID string - Configuration Configuration - Status uint16 - Pubkey string - Result []Ballot - Format string - BallotSize int + ElectionID string + Configuration Configuration + Status uint16 + Pubkey string + Result []Ballot + Format string + BallotSize int + Chunksperballot int } // GetAllElectionsInfoRequest defines the HTTP request for getting all elections From d26a5558a3ab06d5c20e79ee492b95b9a8cddc30 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang <51890833+JBGYZ@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:46:00 +0200 Subject: [PATCH 07/68] Fixed bug in ballot coding --- integration/scenario_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 319c6fa1e..4ae0db1e9 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -165,7 +165,7 @@ func getScenarioTest() func(*testing.T) { "text:" + encodeID("ee") + ":amE=\n\n") //encoding of "ja b3 := string("select:" + encodeID("bb") + ":0,0,0,1\n" + - "text:" + encodeID("ee") + "b3Vp\n\n") //encoding of "oui" + "text:" + encodeID("ee") + ":b3Vp\n\n") //encoding of "oui" var votesfrontend [3]map[string]interface{} @@ -499,6 +499,7 @@ func getScenarioTest() func(*testing.T) { // _ = json.Unmarshal([]byte(body1), &objmap1) // tmp_ballots := (objmap1["Result"]).([]interface{}) // tmp_map := tmp_ballots[0].(map[string]interface{}) + // unmarshal in a ballot object // require.Equal(t, temp_obj, tmp_map) // return From f28b25d3111242abe3ee20fd668db236f832ed44 Mon Sep 17 00:00:00 2001 From: Guanyu Zhang <51890833+JBGYZ@users.noreply.github.com> Date: Wed, 27 Apr 2022 22:19:32 +0200 Subject: [PATCH 08/68] Added timer for performance test --- integration/scenario_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 4ae0db1e9..aaec2bd30 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -340,9 +340,14 @@ func getScenarioTest() func(*testing.T) { randomproxy = proxyArray[rand.Intn(len(proxyArray))] + oldTime := time.Now() + resp, err = http.Post(randomproxy+shuffleBallotsEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + currentTime := time.Now() + diff := currentTime.Sub(oldTime) + t.Logf("Shuffle takes: %v sec", diff.Seconds()) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the body of the response: %v", err) @@ -387,9 +392,13 @@ func getScenarioTest() func(*testing.T) { randomproxy = proxyArray[rand.Intn(len(proxyArray))] + oldTime = time.Now() resp, err = http.Post(randomproxy+beginDecryptionEndpoint, contentType, bytes.NewBuffer(js)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + currentTime = time.Now() + diff = currentTime.Sub(oldTime) + t.Logf("Request public shares takes: %v sec", diff.Seconds()) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the body of the response: %v", err) From cb13d5ec5ee3c89f96b217c645ac016574d34c92 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Thu, 28 Apr 2022 16:54:00 +0200 Subject: [PATCH 09/68] add test with variable to scenario_test --- integration/scenario_test.go | 606 +++++++++++++++++++++++++++++++---- 1 file changed, 536 insertions(+), 70 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index aaec2bd30..e24701041 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -11,6 +11,7 @@ import ( "reflect" "strconv" "strings" + "sync" "testing" "time" @@ -28,7 +29,7 @@ var suite = suites.MustFind("Ed25519") // Check the shuffled votes versus the cast votes on a few nodes func TestScenario(t *testing.T) { t.Run("Basic configuration", getScenarioTest()) - + t.Run("Differents combination ", testVariableNode(3, 6, 1)) } func getScenarioTest() func(*testing.T) { @@ -60,11 +61,11 @@ func getScenarioTest() func(*testing.T) { proxyArray := [3]string{proxyAddr1, proxyAddr2, proxyAddr3} // ###################################### CREATE SIMPLE ELECTION ###### - create_election_js := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` + createElectionJs := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` t.Logf("Create election") - t.Logf("create election js: %v", create_election_js) + t.Logf("create election js: %v", createElectionJs) - resp, err := http.Post(proxyAddr1+createElectionEndpoint, contentType, bytes.NewBuffer([]byte(create_election_js))) + resp, err := http.Post(proxyAddr1+createElectionEndpoint, contentType, bytes.NewBuffer([]byte(createElectionJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -130,9 +131,9 @@ func getScenarioTest() func(*testing.T) { // Get election public key t.Log("Get election info") - create_info_js := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + createInfoJs := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -147,7 +148,7 @@ func getScenarioTest() func(*testing.T) { electionpubkey := objmap["Pubkey"].(string) electionStatus := int(objmap["Status"].(float64)) BallotSize := int(objmap["BallotSize"].(float64)) - Chunksperballot := ChunksPerBallot_manuel(BallotSize) + Chunksperballot := ChunksPerBallotManuel(BallotSize) t.Logf("Publickey of the election : " + electionpubkey) t.Logf("Status of the election : %v", electionStatus) t.Logf("BallotSize of the election : %v", BallotSize) @@ -158,35 +159,35 @@ func getScenarioTest() func(*testing.T) { t.Log("cast ballots") // Create the ballots - b1 := string("select:" + encodeID("bb") + ":0,0,1,0\n" + - "text:" + encodeID("ee") + ":eWVz\n\n") //encoding of "yes" + b1 := string("select:" + encodeIDBallot("bb") + ":0,0,1,0\n" + + "text:" + encodeIDBallot("ee") + ":eWVz\n\n") //encoding of "yes" - b2 := string("select:" + encodeID("bb") + ":1,1,0,0\n" + - "text:" + encodeID("ee") + ":amE=\n\n") //encoding of "ja + b2 := string("select:" + encodeIDBallot("bb") + ":1,1,0,0\n" + + "text:" + encodeIDBallot("ee") + ":amE=\n\n") //encoding of "ja - b3 := string("select:" + encodeID("bb") + ":0,0,0,1\n" + - "text:" + encodeID("ee") + ":b3Vp\n\n") //encoding of "oui" + b3 := string("select:" + encodeIDBallot("bb") + ":0,0,0,1\n" + + "text:" + encodeIDBallot("ee") + ":b3Vp\n\n") //encoding of "oui" var votesfrontend [3]map[string]interface{} - fake_configuration := fake.BasicConfiguration - t.Logf("configuration is: %v", fake_configuration) + fakeConfiguration := fake.BasicConfiguration + t.Logf("configuration is: %v", fakeConfiguration) - b1_marshal, _ := Unmarshal_Ballot_Manual(b1, fake_configuration) - ballot_byte, _ := json.Marshal(b1_marshal) + b1Marshal, _ := UnmarshalBallotManual(b1, fakeConfiguration) + ballotByte, _ := json.Marshal(b1Marshal) // var temp_obj map[string]interface{} - _ = json.Unmarshal(ballot_byte, &votesfrontend[0]) + _ = json.Unmarshal(ballotByte, &votesfrontend[0]) // t.Logf("b1_marshal is: %v", temp_obj) - b2_marshal, _ := Unmarshal_Ballot_Manual(b2, fake_configuration) - ballot_byte, _ = json.Marshal(b2_marshal) - _ = json.Unmarshal(ballot_byte, &votesfrontend[1]) + b2Marshal, _ := UnmarshalBallotManual(b2, fakeConfiguration) + ballotByte, _ = json.Marshal(b2Marshal) + _ = json.Unmarshal(ballotByte, &votesfrontend[1]) // t.Logf("b2_marshal is: %v", temp_obj) // votesfrontend[1] = temp_obj - b3_marshal, _ := Unmarshal_Ballot_Manual(b3, fake_configuration) - ballot_byte, _ = json.Marshal(b3_marshal) - _ = json.Unmarshal(ballot_byte, &votesfrontend[2]) + b3Marshal, _ := UnmarshalBallotManual(b3, fakeConfiguration) + ballotByte, _ = json.Marshal(b3Marshal) + _ = json.Unmarshal(ballotByte, &votesfrontend[2]) // t.Logf("b1_marshal is: %v", temp_obj) // votesfrontend[2] = temp_obj t.Logf("b123_marshal is: %v", votesfrontend) @@ -194,12 +195,12 @@ func getScenarioTest() func(*testing.T) { // Ballot 1 t.Logf("1st ballot in str is: %v", b1) - ballot1, err := marshallBallot_manual(b1, pubKey, Chunksperballot) + ballot1, err := marshallBallotManual(b1, pubKey, Chunksperballot) t.Logf("1st ballot is: %v", ballot1) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data1, err := Encode_ciphervote(ballot1) + data1, err := EncodeCiphervote(ballot1) require.NoError(t, err, "failed to marshall ballot : %v", err) t.Logf("1st marshalled ballot is: %v", data1) @@ -212,11 +213,11 @@ func getScenarioTest() func(*testing.T) { randomproxy = proxyArray[rand.Intn(len(proxyArray))] t.Logf("cast first ballot to proxy %v", randomproxy) - js_vote, err := json.Marshal(castVoteRequest) + jsVote, err := json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) t.Logf("vote is: %v", castVoteRequest) - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -226,10 +227,10 @@ func getScenarioTest() func(*testing.T) { t.Log("Response body: " + string(body)) // Ballot 2 - ballot2, err := marshallBallot_manual(b2, pubKey, Chunksperballot) + ballot2, err := marshallBallotManual(b2, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data2, err := Encode_ciphervote(ballot2) + data2, err := EncodeCiphervote(ballot2) require.NoError(t, err, "failed to marshall ballot : %v", err) castVoteRequest = types.CastVoteRequest{ @@ -240,11 +241,11 @@ func getScenarioTest() func(*testing.T) { } t.Logf("cast second ballot") - js_vote, err = json.Marshal(castVoteRequest) + jsVote, err = json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -254,10 +255,10 @@ func getScenarioTest() func(*testing.T) { t.Log("Response body: " + string(body)) // Ballot 3 - ballot3, err := marshallBallot_manual(b3, pubKey, Chunksperballot) + ballot3, err := marshallBallotManual(b3, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data3, err := Encode_ciphervote(ballot3) + data3, err := EncodeCiphervote(ballot3) require.NoError(t, err, "failed to marshall ballot : %v", err) castVoteRequest = types.CastVoteRequest{ @@ -268,12 +269,12 @@ func getScenarioTest() func(*testing.T) { } t.Logf("cast third ballot") - js_vote, err = json.Marshal(castVoteRequest) + jsVote, err = json.Marshal(castVoteRequest) require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(js_vote)) + resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -308,9 +309,9 @@ func getScenarioTest() func(*testing.T) { resp.Body.Close() t.Log("Get election info") - create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -358,11 +359,11 @@ func getScenarioTest() func(*testing.T) { time.Sleep(10 * time.Second) t.Log("Get election info") - create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -409,11 +410,11 @@ func getScenarioTest() func(*testing.T) { time.Sleep(10 * time.Second) t.Log("Get election info") - create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -456,11 +457,11 @@ func getScenarioTest() func(*testing.T) { time.Sleep(10 * time.Second) t.Log("Get election info") - create_info_js = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(create_info_js))) + resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -506,8 +507,8 @@ func getScenarioTest() func(*testing.T) { // var objmap1 map[string]interface{} // _ = json.Unmarshal([]byte(body1), &objmap1) - // tmp_ballots := (objmap1["Result"]).([]interface{}) - // tmp_map := tmp_ballots[0].(map[string]interface{}) + // tmpBallots := (objmap1["Result"]).([]interface{}) + // tmp_map := tmpBallots[0].(map[string]interface{}) // unmarshal in a ballot object // require.Equal(t, temp_obj, tmp_map) @@ -516,31 +517,31 @@ func getScenarioTest() func(*testing.T) { err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - tmp_ballots := (objmap["Result"]).([]interface{}) - var tmp_comp map[string]interface{} - var tmp_count bool - for _, ballot_intem := range tmp_ballots { - tmp_comp = ballot_intem.(map[string]interface{}) - tmp_count = false - for _, vote_front := range votesfrontend { - t.Logf("vote_front: %v", vote_front) - t.Logf("tmp_comp: %v", tmp_comp) + tmpBallots := (objmap["Result"]).([]interface{}) + var tmpComp map[string]interface{} + var tmpCount bool + for _, ballotIntem := range tmpBallots { + tmpComp = ballotIntem.(map[string]interface{}) + tmpCount = false + for _, voteFront := range votesfrontend { + t.Logf("voteFront: %v", voteFront) + t.Logf("tmpComp: %v", tmpComp) - tmp_count = reflect.DeepEqual(tmp_comp, vote_front) - t.Logf("tmp_count: %v", tmp_count) + tmpCount = reflect.DeepEqual(tmpComp, voteFront) + t.Logf("tmpCount: %v", tmpCount) - if tmp_count { + if tmpCount { break } } } - require.True(t, tmp_count, "front end votes are different from decrypted votes") + require.True(t, tmpCount, "front end votes are different from decrypted votes") - // // tmp_ballots := (objmap["Result"]).([]types.Ballot) + // // tmpBallots := (objmap["Result"]).([]types.Ballot) - // t.Logf("Response body tmp_ballots is %v", tmp_ballots[0]) - // b_test, _ := tmp_ballots[0]["RankResult"] - // t.Logf("Response body tmp_ballots RankResult is %v", b_test) + // t.Logf("Response body tmpBallots is %v", tmpBallots[0]) + // b_test, _ := tmpBallots[0]["RankResult"] + // t.Logf("Response body tmpBallots RankResult is %v", b_test) // // var sendback_ballots types.Ballot // // _ = json.Unmarshal(b_test, sendback_ballots) @@ -550,9 +551,471 @@ func getScenarioTest() func(*testing.T) { } } +func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing.T) { + return func(t *testing.T) { + + proxyList := make([]string, numNodes) + + for i := 1; i <= numNodes; i++ { + if i < 10 { + proxyList[i-1] = "http://localhost:808" + strconv.Itoa(i) + } else { + proxyList[i-1] = "http://localhost:809" + strconv.Itoa(i-10) + } + fmt.Println(proxyList[i-1]) + } + + var wg sync.WaitGroup + + for i := 0; i < numElection; i++ { + fmt.Println("Starting worker", i) + wg.Add(1) + + go startElectionProcess(&wg, numNodes, numVotes, proxyList, t, numElection) + time.Sleep(2 * time.Second) + + } + + fmt.Println("Waiting for workers to finish") + wg.Wait() + + return + + } +} + +func postRequest(addr string, body []byte) (*http.Response, error) { + + resp, err := http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) + for resp.StatusCode != http.StatusOK { + resp, err = http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) + //fmt.Printf("error" +err) + fmt.Println("retry: " + addr) + time.Sleep(4 * time.Second) + } + + return resp, err + +} + +func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyList []string, t *testing.T, numElection int) { + defer wg.Done() + const ( + loginEndpoint = "/evoting/login" + createElectionEndpoint = "/evoting/create" + openElectionEndpoint = "/evoting/open" + castVoteEndpoint = "/evoting/cast" + getAllElectionsIdsEndpoint = "/evoting/allids" + getElectionInfoEndpoint = "/evoting/info" + getAllElectionsInfoEndpoint = "/evoting/all" + closeElectionEndpoint = "/evoting/close" + shuffleBallotsEndpoint = "/evoting/shuffle" + beginDecryptionEndpoint = "/evoting/beginDecryption" + combineSharesEndpoint = "/evoting/combineShares" + getElectionResultEndpoint = "/evoting/result" + cancelElectionEndpoint = "/evoting/cancel" + initEndpoint = "/evoting/dkg/init" + ) + const contentType = "application/json" + + // ###################################### CREATE SIMPLE ELECTION ###### + + createElectionJs := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` + t.Logf("Create election") + + resp, err := postRequest(proxyList[0]+createElectionEndpoint, []byte(createElectionJs)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + + // var payload interface{} + var objmap map[string]interface{} + + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parse the body of the response from js: %v", err) + electionID := objmap["ElectionID"].(string) + t.Log("electionID", electionID) + + // ##################################### SETUP DKG ######################### + + t.Log("Init DKG") + + for i := 0; i < len(proxyList); i++ { + t.Log("Node" + strconv.Itoa(i)) + resp, err = http.Post(proxyList[i]+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + } + + t.Log("Setup DKG") + resp, err = postRequest(proxyList[0]+"/evoting/dkg/setup", []byte(electionID)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + pubkeyBuf, err := io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read body: %v", err) + t.Logf("DKG public key: %x", pubkeyBuf) + + pubKey := suite.Point() + err = pubKey.UnmarshalBinary(pubkeyBuf) + require.NoError(t, err, "failed to unmarshal pubkey: %v", err) + t.Logf("Pubkey: %v\n", pubKey) + + // ##################################### OPEN ELECTION ##################### + + randomproxy := proxyList[rand.Intn(len(proxyList))] + t.Logf("Open election send to proxy %v", randomproxy) + + resp, err = postRequest(proxyList[0]+"/evoting/open", []byte(electionID)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + // ##################################### GET ELECTION INFO ################# + + proxyAddr1 := proxyList[0] + + t.Log("Get election info") + createInfoJs := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = postRequest(proxyAddr1+getElectionInfoEndpoint, []byte(createInfoJs)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parse body of the response from js: %v", err) + electionpubkey := objmap["Pubkey"].(string) + electionStatus := int(objmap["Status"].(float64)) + BallotSize := int(objmap["BallotSize"].(float64)) + Chunksperballot := ChunksPerBallotManuel(BallotSize) + t.Logf("Publickey of the election : " + electionpubkey) + t.Logf("Status of the election : %v", electionStatus) + t.Logf("BallotSize of the election : %v", BallotSize) + t.Logf("Chunksperballot of the election : %v", Chunksperballot) + + // ##################################### CAST BALLOTS ###################### + + t.Log("cast ballots") + + //make List of ballots + b1 := string("select:" + encodeIDBallot("bb") + ":0,0,1,0\n" + "text:" + encodeIDBallot("ee") + ":eWVz\n\n") //encoding of "yes" + + ballotList := make([]string, numVotes) + for i := 1; i <= numVotes; i++ { + ballotList[i-1] = b1 + } + + votesfrontend := make([]map[string]interface{}, numVotes) + + fakeConfiguration := fake.BasicConfiguration + t.Logf("configuration is: %v", fakeConfiguration) + + for i := 0; i < numVotes; i++ { + bMarshal, _ := UnmarshalBallotManual(ballotList[i], fakeConfiguration) + ballotByte, _ := json.Marshal(bMarshal) + _ = json.Unmarshal(ballotByte, &votesfrontend[i]) + } + + t.Logf("b123_marshal is: %v", votesfrontend) + + for i := 0; i < numVotes; i++ { + + t.Logf(" ballot in str is: %v", ballotList[i]) + + ballot, err := marshallBallotManual(ballotList[i], pubKey, Chunksperballot) + t.Logf(" ballot is: %v", ballot) + + require.NoError(t, err, "failed to encrypt ballot : %v", err) + + data, err := EncodeCiphervote(ballot) + require.NoError(t, err, "failed to marshall ballot : %v", err) + t.Logf(" marshalled ballot is: %v", data) + + castVoteRequest := types.CastVoteRequest{ + ElectionID: electionID, + UserID: "user" + strconv.Itoa(i+1), + Ballot: data, + Token: "token", + } + + randomproxy = proxyList[rand.Intn(len(proxyList))] + t.Logf("cast ballot to proxy %v", randomproxy) + jsVote, err := json.Marshal(castVoteRequest) + require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) + + t.Logf("vote is: %v", castVoteRequest) + resp, err = postRequest(randomproxy+castVoteEndpoint, jsVote) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) + + resp.Body.Close() + t.Log("Response body: " + string(body)) + } + + // ############################# CLOSE ELECTION FOR REAL ################### + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + t.Logf("Close election (for real) send to proxy %v", randomproxy) + + closeElectionRequest := types.CloseElectionRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err := json.Marshal(closeElectionRequest) + require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) + + resp, err = postRequest(randomproxy+closeElectionEndpoint, js) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + t.Log("Get election info") + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) + + // ###################################### SHUFFLE BALLOTS ################## + + t.Log("shuffle ballots") + + shuffleBallotsRequest := types.ShuffleBallotsRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(shuffleBallotsRequest) + require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+shuffleBallotsEndpoint, js) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) + + // ###################################### REQUEST PUBLIC SHARES ############ + + t.Log("request public shares") + + beginDecryptionRequest := types.BeginDecryptionRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(beginDecryptionRequest) + require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+beginDecryptionEndpoint, js) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) + + // ###################################### DECRYPT BALLOTS ################## + + t.Log("decrypt ballots") + + decryptBallotsRequest := types.CombineSharesRequest{ + ElectionID: electionID, + UserID: "adminId", + Token: "token", + } + + js, err = json.Marshal(decryptBallotsRequest) + require.NoError(t, err, "failed to set marshall types.CombineSharesRequest : %v", err) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+combineSharesEndpoint, js) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + time.Sleep(10 * time.Second) + + t.Log("Get election info") + createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + electionStatus = int(objmap["Status"].(float64)) + t.Logf("Status of the election : %v", electionStatus) + + // ###################################### GET ELECTION RESULT ############## + + t.Log("Get election result") + + getElectionResultRequest := types.GetElectionResultRequest{ + ElectionID: electionID, + Token: "token", + } + + js, err = json.Marshal(getElectionResultRequest) + require.NoError(t, err, "failed to set marshall types.GetElectionResultRequest : %v", err) + + randomproxy = proxyList[rand.Intn(len(proxyList))] + + resp, err = postRequest(randomproxy+getElectionResultEndpoint, js) + + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + body, err = io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("Response body: " + string(body)) + resp.Body.Close() + + // ###################################### VALIDATE ELECTION RESULT ############## + + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) + + tmpBallots := (objmap["Result"]).([]interface{}) + var tmpComp map[string]interface{} + var tmpCount bool + for _, ballotIntem := range tmpBallots { + tmpComp = ballotIntem.(map[string]interface{}) + tmpCount = false + for _, voteFront := range votesfrontend { + t.Logf("voteFront: %v", voteFront) + t.Logf("tmpComp: %v", tmpComp) + + tmpCount = reflect.DeepEqual(tmpComp, voteFront) + t.Logf("tmpCount: %v", tmpCount) + + if tmpCount { + break + } + } + } + require.True(t, tmpCount, "front end votes are different from decrypted votes") + +} + // ----------------------------------------------------------------------------- // Utility functions -func marshallBallot_manual(voteStr string, pubkey kyber.Point, chunks int) (types.Ciphervote, error) { +func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (types.Ciphervote, error) { var ballot = make(types.Ciphervote, chunks) vote := strings.NewReader(voteStr) @@ -569,7 +1032,7 @@ func marshallBallot_manual(voteStr string, pubkey kyber.Point, chunks int) (type return nil, xerrors.Errorf("failed to read: %v", err) } - K, C, _, err = Encrypt_manual(buf[:n], pubkey) + K, C, _, err = EncryptManual(buf[:n], pubkey) if err != nil { return types.Ciphervote{}, xerrors.Errorf("failed to encrypt the plaintext: %v", err) @@ -584,8 +1047,7 @@ func marshallBallot_manual(voteStr string, pubkey kyber.Point, chunks int) (type return ballot, nil } -func Encrypt_manual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remainder []byte, - err error) { +func EncryptManual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remainder []byte, err error) { // Embed the message (or as much of it as will fit) into a curve point. M := suite.Point().Embed(message, random.New()) @@ -603,7 +1065,7 @@ func Encrypt_manual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remai return K, C, remainder, nil } -func ChunksPerBallot_manuel(BallotSize int) int { +func ChunksPerBallotManuel(BallotSize int) int { if BallotSize%29 == 0 { return BallotSize / 29 } @@ -612,7 +1074,7 @@ func ChunksPerBallot_manuel(BallotSize int) int { } // Encode implements serde.FormatEngine -func Encode_ciphervote(ciphervote types.Ciphervote) ([]byte, error) { +func EncodeCiphervote(ciphervote types.Ciphervote) ([]byte, error) { m := make(CiphervoteJSON, len(ciphervote)) @@ -652,7 +1114,7 @@ type EGPairJSON struct { // Unmarshal decodes the given string according to the format described in // "state of smart contract.md" -func Unmarshal_Ballot_Manual(marshalledBallot string, configuration types.Configuration) (types.Ballot, error) { +func UnmarshalBallotManual(marshalledBallot string, configuration types.Configuration) (types.Ballot, error) { invalidate := func(b types.Ballot) { b.RankResultIDs = nil b.RankResult = nil @@ -838,3 +1300,7 @@ func Unmarshal_Ballot_Manual(marshalledBallot string, configuration types.Config return b, nil } + +func encodeIDBallot(ID string) types.ID { + return types.ID(base64.StdEncoding.EncodeToString([]byte(ID))) +} From 272b7e0af55fd0ee3c8f092419d63438ff8bfee9 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Thu, 28 Apr 2022 17:00:26 +0200 Subject: [PATCH 10/68] add log for error --- integration/scenario_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index e24701041..db30ec4dc 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -589,8 +589,10 @@ func postRequest(addr string, body []byte) (*http.Response, error) { resp, err := http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) for resp.StatusCode != http.StatusOK { resp, err = http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) - //fmt.Printf("error" +err) + fmt.Println("retry: " + addr) + fmt.Println(err) + time.Sleep(4 * time.Second) } From 07b32f4933ef2521a3e0ce4c310c05b7268a3061 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Fri, 29 Apr 2022 08:27:59 +0200 Subject: [PATCH 11/68] change request with new api --- contracts/evoting/controller/handlers.go | 765 ----------------------- contracts/evoting/types/http.go | 175 ------ integration/scenario_test.go | 507 +++++++-------- proxy/election.go | 12 +- proxy/types/election.go | 14 +- 5 files changed, 240 insertions(+), 1233 deletions(-) delete mode 100644 contracts/evoting/controller/handlers.go delete mode 100644 contracts/evoting/types/http.go diff --git a/contracts/evoting/controller/handlers.go b/contracts/evoting/controller/handlers.go deleted file mode 100644 index d770aa2c3..000000000 --- a/contracts/evoting/controller/handlers.go +++ /dev/null @@ -1,765 +0,0 @@ -package controller - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/dedis/d-voting/contracts/evoting" - "github.com/dedis/d-voting/contracts/evoting/types" - uuid "github.com/satori/go.uuid" - "go.dedis.ch/dela/core/ordering" - "go.dedis.ch/dela/serde" - "golang.org/x/xerrors" -) - -// Login responds with the user token. -func (h *votingProxy) Login(w http.ResponseWriter, r *http.Request) { - userID := uuid.NewV4() - userToken := token - - response := types.LoginResponse{ - UserID: userID.String(), - Token: userToken, - } - - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write response: "+err.Error(), http.StatusInternalServerError) - return - } -} - -// CreateElection allows creating an election. -func (h *votingProxy) CreateElection(w http.ResponseWriter, r *http.Request) { - req := &types.CreateElectionRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode CreateElectionRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - createElection := types.CreateElection{ - Configuration: req.Configuration, - AdminID: req.AdminID, - } - - data, err := createElection.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal CreateElectionTransaction: "+err.Error(), - http.StatusInternalServerError) - return - } - - txID, err := h.submitAndWaitForTxn(r.Context(), evoting.CmdCreateElection, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - hash := sha256.New() - hash.Write(txID) - electionID := hash.Sum(nil) - - response := types.CreateElectionResponse{ - ElectionID: hex.EncodeToString(electionID), - } - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// OpenElection allows opening an election, which sets the public key based on -// the DKG actor. -// Body: hex-encoded electionID -func (h *votingProxy) OpenElection(w http.ResponseWriter, r *http.Request) { - // hex-encoded string as byte array - buff, err := ioutil.ReadAll(r.Body) - if err != nil { - http.Error(w, "failed to read body: "+err.Error(), http.StatusInternalServerError) - return - } - - // hex-encoded string - electionID := string(buff) - - // sanity check that it is a hex-encoded string - _, err = hex.DecodeString(electionID) - if err != nil { - http.Error(w, "failed to decode electionID: "+electionID, http.StatusBadRequest) - return - } - - openElection := types.OpenElection{ - ElectionID: electionID, - } - - data, err := openElection.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal OpenElectionTransaction: "+err.Error(), - http.StatusInternalServerError) - return - } - - _, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdOpenElection, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") -} - -// CastVote is used to cast a vote in an election. -func (h *votingProxy) CastVote(w http.ResponseWriter, r *http.Request) { - req := &types.CastVoteRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode CastVoteRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - if req.Token != token { - http.Error(w, "invalid token", http.StatusUnauthorized) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - fmt.Println("election metadata:", elecMD, req.ElectionID) - - if !elecMD.ElectionsIDs.Contains(req.ElectionID) { - http.Error(w, "the election does not exist", http.StatusNotFound) - return - } - - msg, err := h.ciphervoteFac.Deserialize(h.context, req.Ballot) - if err != nil { - http.Error(w, "failed to deserialize ballot: "+err.Error(), http.StatusInternalServerError) - return - } - - ciphervote, ok := msg.(types.Ciphervote) - if !ok { - http.Error(w, fmt.Sprintf("wrong type of ciphervote: %T", msg), http.StatusInternalServerError) - return - } - - castVote := types.CastVote{ - ElectionID: req.ElectionID, - UserID: req.UserID, - Ballot: ciphervote, - } - - data, err := castVote.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal CastVoteTransaction: "+err.Error(), - http.StatusInternalServerError) - return - } - - _, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdCastVote, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - response := types.CastVoteResponse{} - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// ElectionIDs returns a list of all election IDs. -func (h *votingProxy) ElectionIDs(w http.ResponseWriter, r *http.Request) { - req := &types.GetAllElectionsIDsRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode GetElectionInfoRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - response := types.GetAllElectionsIDsResponse{ElectionsIDs: elecMD.ElectionsIDs} - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// ElectionInfo returns the information for a given election. -func (h *votingProxy) ElectionInfo(w http.ResponseWriter, r *http.Request) { - req := &types.GetElectionInfoRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode GetElectionInfoRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - election, err := getElection(h.context, h.electionFac, req.ElectionID, h.orderingSvc) - if err != nil { - http.Error(w, xerrors.Errorf(getElectionErr, err).Error(), - http.StatusInternalServerError) - return - } - - var pubkeyBuf []byte - - if election.Pubkey != nil { - pubkeyBuf, err = election.Pubkey.MarshalBinary() - if err != nil { - http.Error(w, "failed to marshal pubkey: "+err.Error(), - http.StatusInternalServerError) - return - } - } - - response := types.GetElectionInfoResponse{ - ElectionID: string(election.ElectionID), - Configuration: election.Configuration, - Status: uint16(election.Status), - Pubkey: hex.EncodeToString(pubkeyBuf), - Result: election.DecryptedBallots, - BallotSize: election.BallotSize, - Chunksperballot: election.ChunksPerBallot(), - } - - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// AllElectionInfo returns the information for all elections. -func (h *votingProxy) AllElectionInfo(w http.ResponseWriter, r *http.Request) { - req := &types.GetAllElectionsInfoRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode GetAllElectionsInfoRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - allElectionsInfo := make([]types.GetElectionInfoResponse, len(elecMD.ElectionsIDs)) - - for i, id := range elecMD.ElectionsIDs { - election, err := getElection(h.context, h.electionFac, id, h.orderingSvc) - if err != nil { - http.Error(w, xerrors.Errorf(getElectionErr, err).Error(), - http.StatusInternalServerError) - } - - pubkeyBuf, err := election.Pubkey.MarshalBinary() - if err != nil { - http.Error(w, "failed to marshal pubkey: "+err.Error(), - http.StatusInternalServerError) - } - - info := types.GetElectionInfoResponse{ - ElectionID: string(election.ElectionID), - Configuration: election.Configuration, - Status: uint16(election.Status), - Pubkey: hex.EncodeToString(pubkeyBuf), - Result: election.DecryptedBallots, - BallotSize: election.BallotSize, - } - - allElectionsInfo[i] = info - } - - response := types.GetAllElectionsInfoResponse{AllElectionsInfo: allElectionsInfo} - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// CloseElection closes an election. -func (h *votingProxy) CloseElection(w http.ResponseWriter, r *http.Request) { - req := &types.CloseElectionRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode CloseElectionRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "the election does not exist", http.StatusNotFound) - return - } - - closeElection := types.CloseElection{ - ElectionID: req.ElectionID, - UserID: req.UserID, - } - - data, err := closeElection.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal CloseElectionTransaction: "+err.Error(), - http.StatusInternalServerError) - return - } - - _, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdCloseElection, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - response := types.CloseElectionResponse{} - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// ShuffleBallots shuffles the ballots in an election. -func (h *votingProxy) ShuffleBallots(w http.ResponseWriter, r *http.Request) { - req := &types.ShuffleBallotsRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode ShuffleBallotsRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "the election does not exist", http.StatusNotFound) - return - } - - election, err := getElection(h.context, h.electionFac, req.ElectionID, h.orderingSvc) - if err != nil { - http.Error(w, xerrors.Errorf(getElectionErr, err).Error(), - http.StatusInternalServerError) - } - - if election.Status != types.Closed { - http.Error(w, "The election must be closed !", http.StatusUnauthorized) - return - } - - if len(election.Suffragia.Ciphervotes) <= 1 { - http.Error(w, "only one vote has been casted !", http.StatusNotAcceptable) - return - } - - if election.AdminID != req.UserID { - http.Error(w, "only the admin can shuffle the ballots !", http.StatusUnauthorized) - return - } - - electionIDBuff, err := hex.DecodeString(req.ElectionID) - if err != nil { - http.Error(w, "failed to decode electionID: "+err.Error(), - http.StatusInternalServerError) - return - } - - err = h.shuffleActor.Shuffle(electionIDBuff) - if err != nil { - http.Error(w, "failed to shuffle: "+err.Error(), http.StatusInternalServerError) - return - } - - response := types.ShuffleBallotsResponse{ - Message: "shuffle started", - } - - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// BeginDecryption starts the decryption process by gather the pubShares -func (h *votingProxy) BeginDecryption(w http.ResponseWriter, r *http.Request) { - req := &types.BeginDecryptionRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode BeginDecryptionRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "The election does not exist", http.StatusNotFound) - return - } - - electionIDBuf, err := hex.DecodeString(req.ElectionID) - if err != nil { - http.Error(w, "failed to decode electionID: "+err.Error(), - http.StatusInternalServerError) - return - } - - election, err := getElection(h.context, h.electionFac, req.ElectionID, h.orderingSvc) - if err != nil { - http.Error(w, xerrors.Errorf(getElectionErr, err).Error(), - http.StatusInternalServerError) - return - } - - if election.Status != types.ShuffledBallots { - http.Error(w, "the ballots must have been shuffled !", http.StatusUnauthorized) - return - } - - if election.AdminID != req.UserID { - http.Error(w, "only the admin can decrypt the ballots!", http.StatusUnauthorized) - return - } - - if len(election.ShuffleInstances) == 0 { - http.Error(w, "no shuffled instances", http.StatusInternalServerError) - return - } - - actor, exists := h.dkg.GetActor(electionIDBuf) - if !exists { - http.Error(w, "failed to get actor: "+err.Error(), http.StatusInternalServerError) - return - } - - err = actor.ComputePubshares() - if err != nil { - http.Error(w, "failed to request the public shares: "+err.Error(), - http.StatusInternalServerError) - return - } - - response := types.BeginDecryptionResponse{ - Message: "Decryption process started. Gathering public shares...", - } - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } - -} - -// CombineShares decrypts the shuffled ballots in an election. -func (h *votingProxy) CombineShares(w http.ResponseWriter, r *http.Request) { - req := &types.CombineSharesRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode CombineSharesRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "The election does not exist", http.StatusNotFound) - return - } - - election, err := getElection(h.context, h.electionFac, req.ElectionID, h.orderingSvc) - if err != nil { - http.Error(w, "failed to get election: "+err.Error(), - http.StatusInternalServerError) - return - } - if election.Status != types.PubSharesSubmitted { - http.Error(w, "the submission of public shares must be over!", - http.StatusUnauthorized) - return - } - - if election.AdminID != req.UserID { - http.Error(w, "only the admin can decrypt the ballots!", http.StatusUnauthorized) - return - } - - decryptBallots := types.CombineShares{ - ElectionID: req.ElectionID, - UserID: req.UserID, - } - - data, err := decryptBallots.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal decryptBallots: "+err.Error(), - http.StatusInternalServerError) - return - } - - _, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdCombineShares, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - response := types.CombineSharesResponse{} - - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// ElectionResult calculates and returns the results of the election. -func (h *votingProxy) ElectionResult(w http.ResponseWriter, r *http.Request) { - req := &types.GetElectionResultRequest{} - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode GetElectionResultRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "The election does not exist", http.StatusNotFound) - return - } - - election, err := getElection(h.context, h.electionFac, req.ElectionID, h.orderingSvc) - if err != nil { - http.Error(w, xerrors.Errorf(getElectionErr, err).Error(), - http.StatusInternalServerError) - } - - if election.Status != types.ResultAvailable { - http.Error(w, "The result is not available.", http.StatusUnauthorized) - return - } - - response := types.GetElectionResultResponse{ - Result: election.DecryptedBallots, - } - - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// CancelElection cancels an election. -func (h *votingProxy) CancelElection(w http.ResponseWriter, r *http.Request) { - req := new(types.CancelElectionRequest) - - err := json.NewDecoder(r.Body).Decode(req) - if err != nil { - http.Error(w, "failed to decode CancelElectionRequest: "+err.Error(), - http.StatusBadRequest) - return - } - - elecMD, err := h.getElectionsMetadata() - if err != nil { - http.Error(w, "failed to get election metadata", http.StatusNotFound) - return - } - - if !contains(elecMD.ElectionsIDs, req.ElectionID) { - http.Error(w, "the election does not exist", http.StatusNotFound) - return - } - - cancelElection := types.CancelElection{ - ElectionID: req.ElectionID, - UserID: req.UserID, - } - - data, err := cancelElection.Serialize(h.context) - if err != nil { - http.Error(w, "failed to marshal CancelElection: "+err.Error(), - http.StatusInternalServerError) - return - } - - _, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdCancelElection, evoting.ElectionArg, data) - if err != nil { - http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError) - return - } - - response := types.CancelElectionResponse{} - - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(response) - if err != nil { - http.Error(w, "failed to write in ResponseWriter: "+err.Error(), - http.StatusInternalServerError) - return - } -} - -// submitAndWaitForTxn submits a transaction and waits for it to be included. -// Returns the transaction ID. -func (h *votingProxy) submitAndWaitForTxn(ctx context.Context, cmd evoting.Command, - cmdArg string, payload []byte) ([]byte, error) { - h.Lock() - defer h.Unlock() - - manager := getManager(h.signer, h.client) - - err := manager.Sync() - if err != nil { - return nil, xerrors.Errorf("failed to sync manager: %v", err) - } - - tx, err := createTransaction(manager, cmd, cmdArg, payload) - if err != nil { - return nil, xerrors.Errorf("failed to create transaction: %v", err) - } - - watchCtx, cancel := context.WithTimeout(ctx, inclusionTimeout) - defer cancel() - - events := h.orderingSvc.Watch(watchCtx) - - err = h.pool.Add(tx) - if err != nil { - return nil, xerrors.Errorf("failed to add transaction to the pool: %v", err) - } - - ok := h.waitForTxnID(events, tx.GetID()) - if !ok { - return nil, xerrors.Errorf("transaction not processed within timeout") - } - - return tx.GetID(), nil -} - -// getElection gets the election from the snap. Returns the election ID NOT hex -// encoded. -func getElection(ctx serde.Context, electionFac serde.Factory, electionIDHex string, - srv ordering.Service) (types.Election, error) { - - var election types.Election - - electionID, err := hex.DecodeString(electionIDHex) - if err != nil { - return election, xerrors.Errorf("failed to decode electionIDHex: %v", err) - } - - proof, err := srv.GetProof(electionID) - if err != nil { - return election, xerrors.Errorf("failed to get proof: %v", err) - } - - electionBuff := proof.GetValue() - if len(electionBuff) == 0 { - return election, xerrors.Errorf("election does not exist") - } - - message, err := electionFac.Deserialize(ctx, electionBuff) - if err != nil { - return election, xerrors.Errorf("failed to deserialize Election: %v", err) - } - - election, ok := message.(types.Election) - if !ok { - return election, xerrors.Errorf("wrong message type: %T", message) - } - - return election, nil -} diff --git a/contracts/evoting/types/http.go b/contracts/evoting/types/http.go deleted file mode 100644 index 6a369bc04..000000000 --- a/contracts/evoting/types/http.go +++ /dev/null @@ -1,175 +0,0 @@ -package types - -import ( - "go.dedis.ch/kyber/v3/suites" -) - -var suite = suites.MustFind("Ed25519") - -// LoginResponse defines the HTPP request for login -type LoginResponse struct { - UserID string - Token string -} - -// CreateElectionRequest defines the HTTP request for creating an election -type CreateElectionRequest struct { - Configuration Configuration - AdminID string -} - -// OpenElectionRequest defines the HTTP request for opening an election -type OpenElectionRequest struct { - // ElectionID is hex-encoded - ElectionID string -} - -// CreateElectionResponse defines the HTTP response when creating an election -type CreateElectionResponse struct { - // ElectionID is hex-encoded - ElectionID string -} - -// CastVoteRequest defines the HTTP request for casting a vote -type CastVoteRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - // Marshalled representation of Ciphervote - Ballot []byte - Token string -} - -// CastVoteResponse degines the HTTP response when casting a vote -type CastVoteResponse struct { -} - -// CloseElectionRequest degines the HTTP request for closing an election -type CloseElectionRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - Token string -} - -// CloseElectionResponse defines the HTTP response when closing an election -type CloseElectionResponse struct { -} - -// ShuffleBallotsRequest defines the HTTP request for shuffling the ballots -type ShuffleBallotsRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - Token string -} - -// ShuffleBallotsResponse defines the HTTP response when shuffling the ballots -type ShuffleBallotsResponse struct { - Message string -} - -// BeginDecryptionRequest defines the HTTP request for beginning the decryption -// process by asking the nodes to send their public shares. -type BeginDecryptionRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - Token string -} - -// BeginDecryptionResponse defines the HTTP response confirming the decryption -// process began. -type BeginDecryptionResponse struct { - Message string -} - -// CombineSharesRequest defines the HTTP request for decrypting the ballots -type CombineSharesRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - Token string -} - -// CombineSharesResponse defines the HTTP response when decrypting the ballots -type CombineSharesResponse struct { -} - -// GetElectionResultRequest defines the HTTP request for getting the election -// result. -type GetElectionResultRequest struct { - // ElectionID is hex-encoded - ElectionID string - // UserId string - Token string -} - -// GetElectionResultResponse defines the HTTP response when getting the election -// result. -type GetElectionResultResponse struct { - Result []Ballot -} - -// GetElectionInfoRequest defines the HTTP request for getting the election info -type GetElectionInfoRequest struct { - // ElectionID is hex-encoded - ElectionID string - // UserId string - Token string -} - -// GetElectionInfoResponse defines the HTTP response when getting the election -// info -type GetElectionInfoResponse struct { - // ElectionID is hex-encoded - ElectionID string - Configuration Configuration - Status uint16 - Pubkey string - Result []Ballot - Format string - BallotSize int - Chunksperballot int -} - -// GetAllElectionsInfoRequest defines the HTTP request for getting all elections -// infos. -type GetAllElectionsInfoRequest struct { - // UserId string - Token string -} - -// GetAllElectionsInfoResponse defines the HTTP response when getting all -// elections infos. -type GetAllElectionsInfoResponse struct { - // UserId string - AllElectionsInfo []GetElectionInfoResponse -} - -// GetAllElectionsIDsRequest defines the HTTP request for getting all election -// IDs. -type GetAllElectionsIDsRequest struct { - // UserId string - Token string -} - -// GetAllElectionsIDsResponse defines the HTTP response when getting all -// election IDs. -type GetAllElectionsIDsResponse struct { - // UserId string - // ElectionsIDs is a slice of hex-encoded election IDs - ElectionsIDs []string -} - -// CancelElectionRequest defines the HTTP request for canceling an election -type CancelElectionRequest struct { - // ElectionID is hex-encoded - ElectionID string - UserID string - Token string -} - -// CancelElectionResponse defines the HTTP response when canceling an election -type CancelElectionResponse struct { -} diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 38649e0a9..69dd85a43 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -2,23 +2,32 @@ package integration import ( "bytes" + "crypto/sha256" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" "io" "math/rand" - "net/http" "reflect" + "time" + + //"math/rand" + "net/http" + //"reflect" "strconv" "strings" - "sync" + + //"sync" "testing" - "time" + //"time" "github.com/dedis/d-voting/contracts/evoting/types" "github.com/dedis/d-voting/internal/testing/fake" + ptypes "github.com/dedis/d-voting/proxy/types" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/sign/schnorr" "go.dedis.ch/kyber/v3/suites" "go.dedis.ch/kyber/v3/util/random" "golang.org/x/xerrors" @@ -28,44 +37,39 @@ var suite = suites.MustFind("Ed25519") // Check the shuffled votes versus the cast votes on a few nodes func TestScenario(t *testing.T) { - //t.Run("Basic configuration", getScenarioTest()) - t.Run("Differents combination ", testVariableNode(3, 3, 1)) + t.Run("Basic configuration", getScenarioTest()) + //t.Run("Differents combination ", testVariableNode(3, 3, 1)) } func getScenarioTest() func(*testing.T) { return func(t *testing.T) { - const ( - loginEndpoint = "/evoting/login" - createElectionEndpoint = "/evoting/create" - openElectionEndpoint = "/evoting/open" - castVoteEndpoint = "/evoting/cast" - getAllElectionsIdsEndpoint = "/evoting/allids" - getElectionInfoEndpoint = "/evoting/info" - getAllElectionsInfoEndpoint = "/evoting/all" - closeElectionEndpoint = "/evoting/close" - shuffleBallotsEndpoint = "/evoting/shuffle" - beginDecryptionEndpoint = "/evoting/beginDecryption" - combineSharesEndpoint = "/evoting/combineShares" - getElectionResultEndpoint = "/evoting/result" - cancelElectionEndpoint = "/evoting/cancel" - initEndpoint = "/evoting/dkg/init" - ) const contentType = "application/json" - + secretkeyBuf, err := hex.DecodeString("28912721dfd507e198b31602fb67824856eb5a674c021d49fdccbe52f0234409") + secret := suite.Scalar() + err = secret.UnmarshalBinary(secretkeyBuf) t.Parallel() - proxyAddr1 := "http://localhost:8081" - proxyAddr2 := "http://localhost:8082" - proxyAddr3 := "http://localhost:8083" + + proxyAddr1 := "http://localhost:9080" + proxyAddr2 := "http://localhost:9081" + proxyAddr3 := "http://localhost:9082" proxyArray := [3]string{proxyAddr1, proxyAddr2, proxyAddr3} // ###################################### CREATE SIMPLE ELECTION ###### - createElectionJs := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` + t.Logf("Create election") - t.Logf("create election js: %v", createElectionJs) - resp, err := http.Post(proxyAddr1+createElectionEndpoint, contentType, bytes.NewBuffer([]byte(createElectionJs))) + configuration := fake.BasicConfiguration + + createSimpleElectionRequest := ptypes.CreateElectionRequest{ + Configuration: configuration, + AdminID: "adminId", + } + fmt.Println(secret) + signed, err := createSignedRequest(secret, createSimpleElectionRequest) + require.NoError(t, err, "fail to create singature") + resp, err := http.Post(proxyAddr1+"/evoting/elections", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -76,7 +80,6 @@ func getScenarioTest() func(*testing.T) { t.Log("response body:", string(body)) resp.Body.Close() - // var payload interface{} var objmap map[string]interface{} err = json.Unmarshal(body, &objmap) @@ -90,70 +93,58 @@ func getScenarioTest() func(*testing.T) { t.Log("Node 1") - resp, err = http.Post(proxyAddr1+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + err = initDKG(secret, proxyAddr1, electionID, t) + require.NoError(t, err, "failed to init dkg 1: %v", err) t.Log("Node 2") - resp, err = http.Post(proxyAddr2+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + err = initDKG(secret, proxyAddr2, electionID, t) + require.NoError(t, err, "failed to init dkg 2: %v", err) t.Log("Node 3") - resp, err = http.Post(proxyAddr3+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + err = initDKG(secret, proxyAddr3, electionID, t) + require.NoError(t, err, "failed to init dkg 3: %v", err) t.Log("Setup DKG") - resp, err = http.Post(proxyAddr1+"/evoting/dkg/setup", contentType, bytes.NewBuffer([]byte(electionID))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - pubkeyBuf, err := io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read body: %v", err) - t.Logf("DKG public key: %x", pubkeyBuf) + msg := ptypes.UpdateDKG{ + Action: "setup", + } + signed, err = createSignedRequest(secret, msg) - pubKey := suite.Point() - err = pubKey.UnmarshalBinary(pubkeyBuf) - require.NoError(t, err, "failed to unmarshal pubkey: %v", err) - t.Logf("Pubkey: %v\n", pubKey) + req, err := http.NewRequest(http.MethodPut, proxyAddr1+"/evoting/services/dkg/actors/"+electionID, bytes.NewBuffer(signed)) + require.NoError(t, err, "failed to create request: %v", err) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err, "failed to setup dkg on node 1: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) // ##################################### OPEN ELECTION ##################### randomproxy := proxyArray[rand.Intn(len(proxyArray))] t.Logf("Open election send to proxy %v", randomproxy) - resp, err = http.Post(randomproxy+"/evoting/open", contentType, bytes.NewBuffer([]byte(electionID))) + _, err = updateElection(secret, proxyAddr1, electionID, "open", t) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) // ##################################### GET ELECTION INFO ################# - // Get election public key - - t.Log("Get election info") - createInfoJs := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - resp, err = http.Post(proxyAddr1+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parse body of the response from js: %v", err) electionpubkey := objmap["Pubkey"].(string) electionStatus := int(objmap["Status"].(float64)) BallotSize := int(objmap["BallotSize"].(float64)) Chunksperballot := ChunksPerBallotManuel(BallotSize) t.Logf("Publickey of the election : " + electionpubkey) t.Logf("Status of the election : %v", electionStatus) + + require.NoError(t, err, "failed to unmarshal pubkey: %v", err) t.Logf("BallotSize of the election : %v", BallotSize) t.Logf("Chunksperballot of the election : %v", Chunksperballot) + // Get election public key + + pubkeyBuf, err := hex.DecodeString(electionpubkey) + pubKey := suite.Point() + err = pubKey.UnmarshalBinary(pubkeyBuf) // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") @@ -175,21 +166,16 @@ func getScenarioTest() func(*testing.T) { b1Marshal, _ := UnmarshalBallotManual(b1, fakeConfiguration) ballotByte, _ := json.Marshal(b1Marshal) - // var temp_obj map[string]interface{} _ = json.Unmarshal(ballotByte, &votesfrontend[0]) - // t.Logf("b1_marshal is: %v", temp_obj) b2Marshal, _ := UnmarshalBallotManual(b2, fakeConfiguration) ballotByte, _ = json.Marshal(b2Marshal) _ = json.Unmarshal(ballotByte, &votesfrontend[1]) - // t.Logf("b2_marshal is: %v", temp_obj) - // votesfrontend[1] = temp_obj b3Marshal, _ := UnmarshalBallotManual(b3, fakeConfiguration) ballotByte, _ = json.Marshal(b3Marshal) _ = json.Unmarshal(ballotByte, &votesfrontend[2]) - // t.Logf("b1_marshal is: %v", temp_obj) - // votesfrontend[2] = temp_obj + t.Logf("b123_marshal is: %v", votesfrontend) // Ballot 1 @@ -200,24 +186,18 @@ func getScenarioTest() func(*testing.T) { require.NoError(t, err, "failed to encrypt ballot : %v", err) - data1, err := EncodeCiphervote(ballot1) - require.NoError(t, err, "failed to marshall ballot : %v", err) - t.Logf("1st marshalled ballot is: %v", data1) - - castVoteRequest := types.CastVoteRequest{ - ElectionID: electionID, - UserID: "user1", - Ballot: data1, - Token: "token", + castVoteRequest := ptypes.CastVoteRequest{ + UserID: "user1", + Ballot: ballot1, } randomproxy = proxyArray[rand.Intn(len(proxyArray))] t.Logf("cast first ballot to proxy %v", randomproxy) - jsVote, err := json.Marshal(castVoteRequest) - require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) t.Logf("vote is: %v", castVoteRequest) - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) + signed, err = createSignedRequest(secret, castVoteRequest) + require.NoError(t, err, "failed to sign: %v", err) + resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -230,23 +210,18 @@ func getScenarioTest() func(*testing.T) { ballot2, err := marshallBallotManual(b2, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data2, err := EncodeCiphervote(ballot2) - require.NoError(t, err, "failed to marshall ballot : %v", err) - - castVoteRequest = types.CastVoteRequest{ - ElectionID: electionID, - UserID: "user2", - Ballot: data2, - Token: "token", + castVoteRequest = ptypes.CastVoteRequest{ + UserID: "user2", + Ballot: ballot2, } t.Logf("cast second ballot") - jsVote, err = json.Marshal(castVoteRequest) - require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + + signed, err = createSignedRequest(secret, castVoteRequest) + require.NoError(t, err, "failed to sign: %v", err) + resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) @@ -258,24 +233,18 @@ func getScenarioTest() func(*testing.T) { ballot3, err := marshallBallotManual(b3, pubKey, Chunksperballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data3, err := EncodeCiphervote(ballot3) - require.NoError(t, err, "failed to marshall ballot : %v", err) - - castVoteRequest = types.CastVoteRequest{ - ElectionID: electionID, - UserID: "user3", - Ballot: data3, - Token: "token", + castVoteRequest = ptypes.CastVoteRequest{ + UserID: "user3", + Ballot: ballot3, } t.Logf("cast third ballot") - jsVote, err = json.Marshal(castVoteRequest) - require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+castVoteEndpoint, contentType, bytes.NewBuffer(jsVote)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) + signed, err = createSignedRequest(secret, castVoteRequest) + require.NoError(t, err, "failed to sign: %v", err) + resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) @@ -289,63 +258,38 @@ func getScenarioTest() func(*testing.T) { t.Logf("Close election (for real) send to proxy %v", randomproxy) - closeElectionRequest := types.CloseElectionRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } - - js, err := json.Marshal(closeElectionRequest) + _, err = updateElection(secret, randomproxy, electionID, "close", t) require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) - resp, err = http.Post(randomproxy+closeElectionEndpoint, contentType, bytes.NewBuffer(js)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() - - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 2, electionStatus) // ###################################### SHUFFLE BALLOTS ################## t.Log("shuffle ballots") - shuffleBallotsRequest := types.ShuffleBallotsRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", + shuffleBallotsRequest := ptypes.UpdateShuffle{ + Action: "shuffle", } - js, err = json.Marshal(shuffleBallotsRequest) + //js, err = json.Marshal(shuffleBallotsRequest) + signed, err = createSignedRequest(secret, shuffleBallotsRequest) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] oldTime := time.Now() - resp, err = http.Post(randomproxy+shuffleBallotsEndpoint, contentType, bytes.NewBuffer(js)) + req, err = http.NewRequest(http.MethodPut, randomproxy+"/evoting/services/shuffle/"+electionID, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err, "failed to execute the shuffle query: %v", err) + currentTime := time.Now() diff := currentTime.Sub(oldTime) t.Logf("Shuffle takes: %v sec", diff.Seconds()) @@ -358,165 +302,52 @@ func getScenarioTest() func(*testing.T) { time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + getElectionInfo(objmap, proxyAddr1, electionID, t) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 3, electionStatus) // ###################################### REQUEST PUBLIC SHARES ############ t.Log("request public shares") - beginDecryptionRequest := types.BeginDecryptionRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + oldTime = time.Now() - js, err = json.Marshal(beginDecryptionRequest) + _, err = updateDKG(secret, randomproxy, electionID, "computePubshares", t) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - oldTime = time.Now() - resp, err = http.Post(randomproxy+beginDecryptionEndpoint, contentType, bytes.NewBuffer(js)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) currentTime = time.Now() diff = currentTime.Sub(oldTime) - t.Logf("Request public shares takes: %v sec", diff.Seconds()) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 4, electionStatus) // ###################################### DECRYPT BALLOTS ################## t.Log("decrypt ballots") - decryptBallotsRequest := types.CombineSharesRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } - - js, err = json.Marshal(decryptBallotsRequest) - require.NoError(t, err, "failed to set marshall types.CombineSharesRequest : %v", err) - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = http.Post(randomproxy+combineSharesEndpoint, contentType, bytes.NewBuffer(js)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() + _, err = updateElection(secret, randomproxy, electionID, "combineShares", t) + require.NoError(t, err, "failed to combine shares: %v", err) time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - resp, err = http.Post(randomproxy+getElectionInfoEndpoint, contentType, bytes.NewBuffer([]byte(createInfoJs))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) - - // ###################################### GET ELECTION RESULT ############## - - t.Log("Get election result") - - getElectionResultRequest := types.GetElectionResultRequest{ - ElectionID: electionID, - Token: "token", - } - - js, err = json.Marshal(getElectionResultRequest) - require.NoError(t, err, "failed to set marshall types.GetElectionResultRequest : %v", err) - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - resp, err = http.Post(randomproxy+getElectionResultEndpoint, contentType, bytes.NewBuffer(js)) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() + require.Equal(t, 5, electionStatus) // ###################################### VALIDATE ELECTION RESULT ############## - // body1 := `{"Result":[{"SelectResultIDs":["YmI="],"SelectResult":[[false,false,true,false]],"RankResultIDs":[],"RankResult":[],"TextResultIDs":["ZWU="],"TextResult":[["yes"]]},{"SelectResultIDs":["YmI="],"SelectResult":[[true,true,false,false]],"RankResultIDs":[],"RankResult":[],"TextResultIDs":["ZWU="],"TextResult":[["ja"]]},{"SelectResultIDs":null,"SelectResult":null,"RankResultIDs":null,"RankResult":null,"TextResultIDs":null,"TextResult":null}]}` - - // var objmap1 map[string]interface{} - // _ = json.Unmarshal([]byte(body1), &objmap1) - // tmpBallots := (objmap1["Result"]).([]interface{}) - // tmp_map := tmpBallots[0].(map[string]interface{}) - // unmarshal in a ballot object - - // require.Equal(t, temp_obj, tmp_map) - // return - - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - tmpBallots := (objmap["Result"]).([]interface{}) var tmpComp map[string]interface{} var tmpCount bool @@ -537,20 +368,12 @@ func getScenarioTest() func(*testing.T) { } require.True(t, tmpCount, "front end votes are different from decrypted votes") - // // tmpBallots := (objmap["Result"]).([]types.Ballot) - - // t.Logf("Response body tmpBallots is %v", tmpBallots[0]) - // b_test, _ := tmpBallots[0]["RankResult"] - // t.Logf("Response body tmpBallots RankResult is %v", b_test) - - // // var sendback_ballots types.Ballot - // // _ = json.Unmarshal(b_test, sendback_ballots) - // // t.Logf("Response body unmarshalled is %v", sendback_ballots) return } } +/* func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing.T) { return func(t *testing.T) { @@ -1014,11 +837,13 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL } +*/ + // ----------------------------------------------------------------------------- // Utility functions -func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (types.Ciphervote, error) { +func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (ptypes.CiphervoteJSON, error) { - var ballot = make(types.Ciphervote, chunks) + var ballot = make(ptypes.CiphervoteJSON, chunks) vote := strings.NewReader(voteStr) fmt.Printf("votestr is: %v", voteStr) @@ -1036,12 +861,22 @@ func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (types K, C, _, err = EncryptManual(buf[:n], pubkey) if err != nil { - return types.Ciphervote{}, xerrors.Errorf("failed to encrypt the plaintext: %v", err) + return ptypes.CiphervoteJSON{}, xerrors.Errorf("failed to encrypt the plaintext: %v", err) + } + + kbuff, err := K.MarshalBinary() + if err != nil { + return ptypes.CiphervoteJSON{}, xerrors.Errorf("failed to marshal K: %v", err) + } + + cbuff, err := C.MarshalBinary() + if err != nil { + return ptypes.CiphervoteJSON{}, xerrors.Errorf("failed to marshal C: %v", err) } - ballot[i] = types.EGPair{ - K: K, - C: C, + ballot[i] = ptypes.EGPairJSON{ + K: kbuff, + C: cbuff, } } @@ -1305,3 +1140,111 @@ func UnmarshalBallotManual(marshalledBallot string, configuration types.Configur func encodeIDBallot(ID string) types.ID { return types.ID(base64.StdEncoding.EncodeToString([]byte(ID))) } + +func createSignedRequest(secret kyber.Scalar, msg interface{}) ([]byte, error) { + jsonMsg, err := json.Marshal(msg) + if err != nil { + return nil, xerrors.Errorf("failed to marshal json: %v", err) + } + + payload := base64.URLEncoding.EncodeToString(jsonMsg) + + hash := sha256.New() + + hash.Write([]byte(payload)) + md := hash.Sum(nil) + + signature, err := schnorr.Sign(suite, secret, md) + if err != nil { + return nil, xerrors.Errorf("failed to sign: %v", err) + } + + signed := ptypes.SignedRequest{ + Payload: payload, + Signature: hex.EncodeToString(signature), + } + + signedJSON, err := json.Marshal(signed) + if err != nil { + return nil, xerrors.Errorf("failed to create json signed: %v", err) + } + + return signedJSON, nil +} +func initDKG(secret kyber.Scalar, proxyAddr, electionIDHex string, t *testing.T) error { + setupDKG := ptypes.NewDKGRequest{ + ElectionID: electionIDHex, + } + + signed, err := createSignedRequest(secret, setupDKG) + require.NoError(t, err, "fail to create singature") + + resp, err := http.Post(proxyAddr+"/evoting/services/dkg/actors", "application/json", bytes.NewBuffer(signed)) + if err != nil { + return xerrors.Errorf("failed to post request: %v", err) + } + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + return nil +} + +func updateElection(secret kyber.Scalar, proxyAddr, electionIDHex, action string, t *testing.T) (int, error) { + msg := ptypes.UpdateElectionRequest{ + Action: action, + } + + signed, err := createSignedRequest(secret, msg) + require.NoError(t, err, "fail to create singature") + + req, err := http.NewRequest(http.MethodPut, proxyAddr+"/evoting/elections/"+electionIDHex, bytes.NewBuffer(signed)) + if err != nil { + return 0, xerrors.Errorf("failed to create request: %v", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return 0, xerrors.Errorf("failed retrieve the decryption from the server: %v", err) + } + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + return 0, nil +} +func updateDKG(secret kyber.Scalar, proxyAddr, electionIDHex, action string, t *testing.T) (int, error) { + msg := ptypes.UpdateDKG{ + Action: action, + } + + signed, err := createSignedRequest(secret, msg) + require.NoError(t, err, "fail to create singature") + + req, err := http.NewRequest(http.MethodPut, proxyAddr+"/evoting/services/dkg/actors/"+electionIDHex, bytes.NewBuffer(signed)) + if err != nil { + return 0, xerrors.Errorf("failed to create request: %v", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return 0, xerrors.Errorf("failed to execute the query: %v", err) + } + + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + + return 0, nil +} + +func getElectionInfo(objmap map[string]interface{}, proxyAddr, electionID string, t *testing.T) { + t.Log("Get election info") + resp, err := http.Get(proxyAddr + "/evoting/elections" + "/" + electionID) + + require.NoError(t, err, "failed to get the election: %v", err) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err, "failed to read the body of the response: %v", err) + + t.Log("response body:", string(body)) + resp.Body.Close() + err = json.Unmarshal(body, &objmap) + require.NoError(t, err, "failed to parse body of the response from js: %v", err) + +} diff --git a/proxy/election.go b/proxy/election.go index 44cf362d2..c1b6180ff 100644 --- a/proxy/election.go +++ b/proxy/election.go @@ -374,11 +374,13 @@ func (h *election) Election(w http.ResponseWriter, r *http.Request) { } response := ptypes.GetElectionResponse{ - ElectionID: string(election.ElectionID), - Configuration: election.Configuration, - Status: uint16(election.Status), - Pubkey: hex.EncodeToString(pubkeyBuf), - Result: election.DecryptedBallots, + ElectionID: string(election.ElectionID), + Configuration: election.Configuration, + Status: uint16(election.Status), + Pubkey: hex.EncodeToString(pubkeyBuf), + Result: election.DecryptedBallots, + BallotSize: election.BallotSize, + Chunksperballot: election.ChunksPerBallot(), } w.Header().Set("Content-Type", "application/json") diff --git a/proxy/types/election.go b/proxy/types/election.go index 1c69be652..24d371db7 100644 --- a/proxy/types/election.go +++ b/proxy/types/election.go @@ -39,12 +39,14 @@ type UpdateElectionRequest struct { // GetElectionResponse defines the HTTP response when getting the election info type GetElectionResponse struct { // ElectionID is hex-encoded - ElectionID string - Configuration etypes.Configuration - Status uint16 - Pubkey string - Result []etypes.Ballot - Format string + ElectionID string + Configuration etypes.Configuration + Status uint16 + Pubkey string + Result []etypes.Ballot + Format string + BallotSize int + Chunksperballot int } // GetElections defines the HTTP request for getting all elections infos. From 054c90bbc77c746aa2094d745b8f7b890de39480 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Fri, 29 Apr 2022 14:37:51 +0200 Subject: [PATCH 12/68] can setup and run n node with script --- Setup13node.sh | 272 -------------------------- Setup3node.sh | 92 --------- Setup5node.sh | 127 ------------ integration/scenario_test.go | 365 +++++++++++------------------------ many.sh | 40 ---- many2.sh | 19 -- runNode.sh | 29 +++ setupnNode.sh | 171 ++++++++++++++++ 8 files changed, 308 insertions(+), 807 deletions(-) delete mode 100755 Setup13node.sh delete mode 100755 Setup3node.sh delete mode 100755 Setup5node.sh delete mode 100755 many.sh delete mode 100755 many2.sh create mode 100755 runNode.sh create mode 100755 setupnNode.sh diff --git a/Setup13node.sh b/Setup13node.sh deleted file mode 100755 index 11c009abb..000000000 --- a/Setup13node.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/usr/bin/env bash - -# This script is creating a new chain and setting up the services needed to run -# an evoting system. It ends by starting the http server needed by the frontend -# to communicate with the blockchain. This operation is blocking. - -set -e - -GREEN='\033[0;32m' -NC='\033[0m' # No Color - - - - -echo "${GREEN}[1/7]${NC} connect nodes" - -memcoin --config /tmp/node2 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node3 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node4 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node5 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node6 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node7 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node8 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node9 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node10 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node11 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node12 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node13 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) - -echo "${GREEN}[2/7]${NC} create a chain" -memcoin --config /tmp/node1 ordering setup\ - --member $(memcoin --config /tmp/node1 ordering export)\ - --member $(memcoin --config /tmp/node2 ordering export)\ - --member $(memcoin --config /tmp/node3 ordering export)\ - --member $(memcoin --config /tmp/node4 ordering export)\ - --member $(memcoin --config /tmp/node5 ordering export)\ - --member $(memcoin --config /tmp/node6 ordering export)\ - --member $(memcoin --config /tmp/node7 ordering export)\ - --member $(memcoin --config /tmp/node8 ordering export)\ - --member $(memcoin --config /tmp/node9 ordering export)\ - --member $(memcoin --config /tmp/node10 ordering export)\ - --member $(memcoin --config /tmp/node11 ordering export)\ - --member $(memcoin --config /tmp/node12 ordering export)\ - --member $(memcoin --config /tmp/node13 ordering export)\ - -echo "${GREEN}[3/7]${NC} setup access rights on each node" -memcoin --config /tmp/node1 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node2 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node3 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node4 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node5 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node6 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node7 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node8 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node9 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node10 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node11 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node12 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node13 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) - -echo "${GREEN}[4/7]${NC} grant access on the chain" -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node1/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node2/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node3/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node4/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node5/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node6/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node7/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node8/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node9/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node10/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node11/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node12/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node13/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -echo "${GREEN}[5/7]${NC} init shuffle" -memcoin --config /tmp/node1 shuffle init --signer /tmp/node1/private.key -memcoin --config /tmp/node2 shuffle init --signer /tmp/node2/private.key -memcoin --config /tmp/node3 shuffle init --signer /tmp/node3/private.key -memcoin --config /tmp/node4 shuffle init --signer /tmp/node4/private.key -memcoin --config /tmp/node5 shuffle init --signer /tmp/node5/private.key -memcoin --config /tmp/node6 shuffle init --signer /tmp/node6/private.key -memcoin --config /tmp/node7 shuffle init --signer /tmp/node7/private.key -memcoin --config /tmp/node8 shuffle init --signer /tmp/node8/private.key -memcoin --config /tmp/node9 shuffle init --signer /tmp/node9/private.key -memcoin --config /tmp/node10 shuffle init --signer /tmp/node10/private.key -memcoin --config /tmp/node11 shuffle init --signer /tmp/node11/private.key -memcoin --config /tmp/node12 shuffle init --signer /tmp/node12/private.key -memcoin --config /tmp/node13 shuffle init --signer /tmp/node13/private.key - -echo "${GREEN}[6/7]${NC} starting http proxy" -memcoin --config /tmp/node1 proxy start --clientaddr 127.0.0.1:8081 -memcoin --config /tmp/node1 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node1 dkg registerHandlers - -memcoin --config /tmp/node2 proxy start --clientaddr 127.0.0.1:8082 -memcoin --config /tmp/node2 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node2 dkg registerHandlers - -memcoin --config /tmp/node3 proxy start --clientaddr 127.0.0.1:8083 -memcoin --config /tmp/node3 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node3 dkg registerHandlers - -memcoin --config /tmp/node4 proxy start --clientaddr 127.0.0.1:8084 -memcoin --config /tmp/node4 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node4 dkg registerHandlers - -memcoin --config /tmp/node5 proxy start --clientaddr 127.0.0.1:8085 -memcoin --config /tmp/node5 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node5 dkg registerHandlers - -memcoin --config /tmp/node6 proxy start --clientaddr 127.0.0.1:8086 -memcoin --config /tmp/node6 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node6 dkg registerHandlers - -memcoin --config /tmp/node7 proxy start --clientaddr 127.0.0.1:8087 -memcoin --config /tmp/node7 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node7 dkg registerHandlers - -memcoin --config /tmp/node8 proxy start --clientaddr 127.0.0.1:8088 -memcoin --config /tmp/node8 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node8 dkg registerHandlers - -memcoin --config /tmp/node9 proxy start --clientaddr 127.0.0.1:8089 -memcoin --config /tmp/node9 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node9 dkg registerHandlers - -memcoin --config /tmp/node10 proxy start --clientaddr 127.0.0.1:8090 -memcoin --config /tmp/node10 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node10 dkg registerHandlers - -memcoin --config /tmp/node11 proxy start --clientaddr 127.0.0.1:8091 -memcoin --config /tmp/node11 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node11 dkg registerHandlers - -memcoin --config /tmp/node12 proxy start --clientaddr 127.0.0.1:8092 -memcoin --config /tmp/node12 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node12 dkg registerHandlers - -memcoin --config /tmp/node13 proxy start --clientaddr 127.0.0.1:8093 -memcoin --config /tmp/node13 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node13 dkg registerHandlers \ No newline at end of file diff --git a/Setup3node.sh b/Setup3node.sh deleted file mode 100755 index 87491def2..000000000 --- a/Setup3node.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash - -# This script is creating a new chain and setting up the services needed to run -# an evoting system. It ends by starting the http server needed by the frontend -# to communicate with the blockchain. This operation is blocking. - -set -e - -GREEN='\033[0;32m' -NC='\033[0m' # No Color - -echo "${GREEN}[1/7]${NC} connect nodes" -memcoin --config /tmp/node2 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node3 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) - -echo "${GREEN}[2/7]${NC} create a chain" -memcoin --config /tmp/node1 ordering setup\ - --member $(memcoin --config /tmp/node1 ordering export)\ - --member $(memcoin --config /tmp/node2 ordering export)\ - --member $(memcoin --config /tmp/node3 ordering export) - -echo "${GREEN}[3/7]${NC} setup access rights on each node" -memcoin --config /tmp/node1 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node2 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node3 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) - -echo "${GREEN}[4/7]${NC} grant access on the chain" -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node1/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node2/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node3/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -echo "${GREEN}[5/7]${NC} init shuffle" -memcoin --config /tmp/node1 shuffle init --signer /tmp/node1/private.key -memcoin --config /tmp/node2 shuffle init --signer /tmp/node2/private.key -memcoin --config /tmp/node3 shuffle init --signer /tmp/node3/private.key - -echo "${GREEN}[6/7]${NC} starting http proxy" -memcoin --config /tmp/node1 proxy start --clientaddr 127.0.0.1:8081 -memcoin --config /tmp/node1 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node1 dkg registerHandlers - -memcoin --config /tmp/node2 proxy start --clientaddr 127.0.0.1:8082 -memcoin --config /tmp/node2 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node2 dkg registerHandlers - -memcoin --config /tmp/node3 proxy start --clientaddr 127.0.0.1:8083 -memcoin --config /tmp/node3 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node3 dkg registerHandlers - -# If an election is created with ID "deadbeef" then one must set up DKG -# on each node before the election can proceed: -# memcoin --config /tmp/node1 dkg init --electionID deadbeef -# memcoin --config /tmp/node2 dkg init --electionID deadbeef -# memcoin --config /tmp/node3 dkg init --electionID deadbeef -# memcoin --config /tmp/node1 dkg setup --electionID deadbeef diff --git a/Setup5node.sh b/Setup5node.sh deleted file mode 100755 index 86c031887..000000000 --- a/Setup5node.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -# This script is creating a new chain and setting up the services needed to run -# an evoting system. It ends by starting the http server needed by the frontend -# to communicate with the blockchain. This operation is blocking. - -set -e - -GREEN='\033[0;32m' -NC='\033[0m' # No Color - - - - -echo "${GREEN}[1/7]${NC} connect nodes" - -memcoin --config /tmp/node2 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node3 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node4 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) -memcoin --config /tmp/node5 minogrpc join \ - --address 127.0.0.1:2001 $(memcoin --config /tmp/node1 minogrpc token) - -echo "${GREEN}[2/7]${NC} create a chain" -memcoin --config /tmp/node1 ordering setup\ - --member $(memcoin --config /tmp/node1 ordering export)\ - --member $(memcoin --config /tmp/node2 ordering export)\ - --member $(memcoin --config /tmp/node3 ordering export)\ - --member $(memcoin --config /tmp/node4 ordering export)\ - --member $(memcoin --config /tmp/node5 ordering export)\ - -echo "${GREEN}[3/7]${NC} setup access rights on each node" -memcoin --config /tmp/node1 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node2 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node3 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node4 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) -memcoin --config /tmp/node5 access add \ - --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) - -echo "${GREEN}[4/7]${NC} grant access on the chain" -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node1/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node2/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node3/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node4/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -memcoin --config /tmp/node1 pool add\ - --key private.key\ - --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ - --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ - --args access:grant_contract --args go.dedis.ch/dela.Evoting\ - --args access:grant_command --args all\ - --args access:identity --args $(crypto bls signer read --path /tmp/node5/private.key --format BASE64_PUBKEY)\ - --args access:command --args GRANT - -echo "${GREEN}[5/7]${NC} init shuffle" -memcoin --config /tmp/node1 shuffle init --signer /tmp/node1/private.key -memcoin --config /tmp/node2 shuffle init --signer /tmp/node2/private.key -memcoin --config /tmp/node3 shuffle init --signer /tmp/node3/private.key -memcoin --config /tmp/node4 shuffle init --signer /tmp/node4/private.key -memcoin --config /tmp/node5 shuffle init --signer /tmp/node5/private.key - -echo "${GREEN}[6/7]${NC} starting http proxy" -memcoin --config /tmp/node1 proxy start --clientaddr 127.0.0.1:8081 -memcoin --config /tmp/node1 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node1 dkg registerHandlers - -memcoin --config /tmp/node2 proxy start --clientaddr 127.0.0.1:8082 -memcoin --config /tmp/node2 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node2 dkg registerHandlers - -memcoin --config /tmp/node3 proxy start --clientaddr 127.0.0.1:8083 -memcoin --config /tmp/node3 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node3 dkg registerHandlers - -memcoin --config /tmp/node4 proxy start --clientaddr 127.0.0.1:8084 -memcoin --config /tmp/node4 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node4 dkg registerHandlers - -memcoin --config /tmp/node5 proxy start --clientaddr 127.0.0.1:8085 -memcoin --config /tmp/node5 e-voting registerHandlers --signer private.key -memcoin --config /tmp/node5 dkg registerHandlers \ No newline at end of file diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 69dd85a43..38e3e5c24 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -10,6 +10,7 @@ import ( "io" "math/rand" "reflect" + "sync" "time" //"math/rand" @@ -38,7 +39,7 @@ var suite = suites.MustFind("Ed25519") // Check the shuffled votes versus the cast votes on a few nodes func TestScenario(t *testing.T) { t.Run("Basic configuration", getScenarioTest()) - //t.Run("Differents combination ", testVariableNode(3, 3, 1)) + t.Run("Differents combination ", testVariableNode(3, 3, 1)) } func getScenarioTest() func(*testing.T) { @@ -46,8 +47,12 @@ func getScenarioTest() func(*testing.T) { const contentType = "application/json" secretkeyBuf, err := hex.DecodeString("28912721dfd507e198b31602fb67824856eb5a674c021d49fdccbe52f0234409") + require.NoError(t, err, "failed to decode key: %v", err) + secret := suite.Scalar() err = secret.UnmarshalBinary(secretkeyBuf) + require.NoError(t, err, "failed to Unmarshal key: %v", err) + t.Parallel() proxyAddr1 := "http://localhost:9080" @@ -110,7 +115,7 @@ func getScenarioTest() func(*testing.T) { Action: "setup", } signed, err = createSignedRequest(secret, msg) - + require.NoError(t, err, "failed to sign: %v", err) req, err := http.NewRequest(http.MethodPut, proxyAddr1+"/evoting/services/dkg/actors/"+electionID, bytes.NewBuffer(signed)) require.NoError(t, err, "failed to create request: %v", err) resp, err = http.DefaultClient.Do(req) @@ -143,8 +148,12 @@ func getScenarioTest() func(*testing.T) { // Get election public key pubkeyBuf, err := hex.DecodeString(electionpubkey) + require.NoError(t, err, "failed to decode key: %v", err) + pubKey := suite.Point() err = pubKey.UnmarshalBinary(pubkeyBuf) + require.NoError(t, err, "failed to Unmarshal key: %v", err) + // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") @@ -222,6 +231,7 @@ func getScenarioTest() func(*testing.T) { signed, err = createSignedRequest(secret, castVoteRequest) require.NoError(t, err, "failed to sign: %v", err) resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) + require.NoError(t, err, "failed to cast ballot: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) @@ -245,6 +255,7 @@ func getScenarioTest() func(*testing.T) { signed, err = createSignedRequest(secret, castVoteRequest) require.NoError(t, err, "failed to sign: %v", err) resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) + require.NoError(t, err, "failed to cast ballot: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) @@ -320,6 +331,7 @@ func getScenarioTest() func(*testing.T) { currentTime = time.Now() diff = currentTime.Sub(oldTime) + t.Logf("Shuffle takes: %v sec", diff.Seconds()) time.Sleep(10 * time.Second) @@ -373,19 +385,18 @@ func getScenarioTest() func(*testing.T) { } } -/* func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing.T) { return func(t *testing.T) { proxyList := make([]string, numNodes) - for i := 1; i <= numNodes; i++ { + for i := 0; i < numNodes; i++ { if i < 10 { - proxyList[i-1] = "http://localhost:808" + strconv.Itoa(i) + proxyList[i] = "http://localhost:908" + strconv.Itoa(i) } else { - proxyList[i-1] = "http://localhost:809" + strconv.Itoa(i-10) + proxyList[i] = "http://localhost:909" + strconv.Itoa(i-10) } - fmt.Println(proxyList[i-1]) + fmt.Println(proxyList[i]) } var wg sync.WaitGroup @@ -407,47 +418,31 @@ func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing } } -func postRequest(addr string, body []byte) (*http.Response, error) { - - resp, err := http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) - for resp.StatusCode != http.StatusOK { - fmt.Println("retry: " + addr) - fmt.Println(resp.StatusCode) - resp, err = http.Post(addr, "application/json", bytes.NewBuffer([]byte(body))) - - time.Sleep(4 * time.Second) - } - - return resp, err - -} - -func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyList []string, t *testing.T, numElection int) { +func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyArray []string, t *testing.T, numElection int) { defer wg.Done() - const ( - loginEndpoint = "/evoting/login" - createElectionEndpoint = "/evoting/create" - openElectionEndpoint = "/evoting/open" - castVoteEndpoint = "/evoting/cast" - getAllElectionsIdsEndpoint = "/evoting/allids" - getElectionInfoEndpoint = "/evoting/info" - getAllElectionsInfoEndpoint = "/evoting/all" - closeElectionEndpoint = "/evoting/close" - shuffleBallotsEndpoint = "/evoting/shuffle" - beginDecryptionEndpoint = "/evoting/beginDecryption" - combineSharesEndpoint = "/evoting/combineShares" - getElectionResultEndpoint = "/evoting/result" - cancelElectionEndpoint = "/evoting/cancel" - initEndpoint = "/evoting/dkg/init" - ) + const contentType = "application/json" + secretkeyBuf, err := hex.DecodeString("28912721dfd507e198b31602fb67824856eb5a674c021d49fdccbe52f0234409") + require.NoError(t, err, "failed to decode key: %v", err) + + secret := suite.Scalar() + err = secret.UnmarshalBinary(secretkeyBuf) + require.NoError(t, err, "failed to Unmarshal key: %v", err) // ###################################### CREATE SIMPLE ELECTION ###### - createElectionJs := `{"Configuration":{"MainTitle":"electionTitle","Scaffold":[{"ID":"YWE=","Title":"subject1","Order":null,"Subjects":null,"Selects":[{"ID":"YmI=","Title":"Select your favorite snacks","MaxN":3,"MinN":0,"Choices":["snickers","mars","vodka","babibel"]}],"Ranks":[],"Texts":null},{"ID":"ZGQ=","Title":"subject2","Order":null,"Subjects":null,"Selects":null,"Ranks":null,"Texts":[{"ID":"ZWU=","Title":"dissertation","MaxN":1,"MinN":1,"MaxLength":3,"Regex":"","Choices":["write yes in your language"]}]}]},"AdminID":"adminId"}` t.Logf("Create election") - resp, err := postRequest(proxyList[0]+createElectionEndpoint, []byte(createElectionJs)) + configuration := fake.BasicConfiguration + + createSimpleElectionRequest := ptypes.CreateElectionRequest{ + Configuration: configuration, + AdminID: "adminId", + } + fmt.Println(secret) + signed, err := createSignedRequest(secret, createSimpleElectionRequest) + require.NoError(t, err, "fail to create singature") + resp, err := http.Post(proxyArray[0]+"/evoting/elections", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -458,79 +453,70 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL t.Log("response body:", string(body)) resp.Body.Close() - // var payload interface{} var objmap map[string]interface{} err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parse the body of the response from js: %v", err) electionID := objmap["ElectionID"].(string) - t.Log("electionID", electionID) + t.Logf("ID of the election : " + electionID) // ##################################### SETUP DKG ######################### t.Log("Init DKG") - for i := 0; i < len(proxyList); i++ { + for i := 0; i < len(proxyArray); i++ { t.Log("Node" + strconv.Itoa(i)) - resp, err = http.Post(proxyList[i]+initEndpoint, contentType, bytes.NewBuffer([]byte(electionID))) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - + fmt.Println(proxyArray[i]) + err = initDKG(secret, proxyArray[i], electionID, t) + require.NoError(t, err, "failed to init dkg 1: %v", err) } t.Log("Setup DKG") - resp, err = postRequest(proxyList[0]+"/evoting/dkg/setup", []byte(electionID)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - pubkeyBuf, err := io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read body: %v", err) - t.Logf("DKG public key: %x", pubkeyBuf) - - pubKey := suite.Point() - err = pubKey.UnmarshalBinary(pubkeyBuf) - require.NoError(t, err, "failed to unmarshal pubkey: %v", err) - t.Logf("Pubkey: %v\n", pubKey) + msg := ptypes.UpdateDKG{ + Action: "setup", + } + signed, err = createSignedRequest(secret, msg) + require.NoError(t, err, "failed to sign: %v", err) + req, err := http.NewRequest(http.MethodPut, proxyArray[0]+"/evoting/services/dkg/actors/"+electionID, bytes.NewBuffer(signed)) + require.NoError(t, err, "failed to create request: %v", err) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err, "failed to setup dkg on node 1: %v", err) + require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) // ##################################### OPEN ELECTION ##################### - randomproxy := proxyList[rand.Intn(len(proxyList))] + randomproxy := proxyArray[rand.Intn(len(proxyArray))] t.Logf("Open election send to proxy %v", randomproxy) - resp, err = postRequest(proxyList[0]+"/evoting/open", []byte(electionID)) - + _, err = updateElection(secret, randomproxy, electionID, "open", t) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - // ##################################### GET ELECTION INFO ################# - proxyAddr1 := proxyList[0] - - t.Log("Get election info") - createInfoJs := fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - resp, err = postRequest(proxyAddr1+getElectionInfoEndpoint, []byte(createInfoJs)) + proxyAddr1 := proxyArray[0] - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parse body of the response from js: %v", err) electionpubkey := objmap["Pubkey"].(string) electionStatus := int(objmap["Status"].(float64)) BallotSize := int(objmap["BallotSize"].(float64)) Chunksperballot := ChunksPerBallotManuel(BallotSize) t.Logf("Publickey of the election : " + electionpubkey) t.Logf("Status of the election : %v", electionStatus) + + require.NoError(t, err, "failed to unmarshal pubkey: %v", err) t.Logf("BallotSize of the election : %v", BallotSize) t.Logf("Chunksperballot of the election : %v", Chunksperballot) + // Get election public key + + pubkeyBuf, err := hex.DecodeString(electionpubkey) + require.NoError(t, err, "failed to decode key: %v", err) + + pubKey := suite.Point() + err = pubKey.UnmarshalBinary(pubkeyBuf) + require.NoError(t, err, "failed to Unmarshal key: %v", err) + // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") @@ -557,33 +543,25 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL t.Logf("b123_marshal is: %v", votesfrontend) for i := 0; i < numVotes; i++ { - - t.Logf(" ballot in str is: %v", ballotList[i]) + t.Logf("1st ballot in str is: %v", ballotList[i]) ballot, err := marshallBallotManual(ballotList[i], pubKey, Chunksperballot) - t.Logf(" ballot is: %v", ballot) + t.Logf("1st ballot is: %v", ballot) require.NoError(t, err, "failed to encrypt ballot : %v", err) - data, err := EncodeCiphervote(ballot) - require.NoError(t, err, "failed to marshall ballot : %v", err) - t.Logf(" marshalled ballot is: %v", data) - - castVoteRequest := types.CastVoteRequest{ - ElectionID: electionID, - UserID: "user" + strconv.Itoa(i+1), - Ballot: data, - Token: "token", + castVoteRequest := ptypes.CastVoteRequest{ + UserID: "user" + strconv.Itoa(i+1), + Ballot: ballot, } - randomproxy = proxyList[rand.Intn(len(proxyList))] + randomproxy = proxyArray[rand.Intn(len(proxyArray))] t.Logf("cast ballot to proxy %v", randomproxy) - jsVote, err := json.Marshal(castVoteRequest) - require.NoError(t, err, "failed to marshal castVoteRequest: %v", err) t.Logf("vote is: %v", castVoteRequest) - resp, err = postRequest(randomproxy+castVoteEndpoint, jsVote) - + signed, err = createSignedRequest(secret, castVoteRequest) + require.NoError(t, err, "failed to sign: %v", err) + resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) body, err = io.ReadAll(resp.Body) @@ -591,72 +569,49 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL resp.Body.Close() t.Log("Response body: " + string(body)) + } // ############################# CLOSE ELECTION FOR REAL ################### - - randomproxy = proxyList[rand.Intn(len(proxyList))] + randomproxy = proxyArray[rand.Intn(len(proxyArray))] t.Logf("Close election (for real) send to proxy %v", randomproxy) - closeElectionRequest := types.CloseElectionRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } - - js, err := json.Marshal(closeElectionRequest) + _, err = updateElection(secret, randomproxy, electionID, "close", t) require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) - resp, err = postRequest(randomproxy+closeElectionEndpoint, js) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() - - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + getElectionInfo(objmap, proxyAddr1, electionID, t) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 2, electionStatus) // ###################################### SHUFFLE BALLOTS ################## t.Log("shuffle ballots") - shuffleBallotsRequest := types.ShuffleBallotsRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", + shuffleBallotsRequest := ptypes.UpdateShuffle{ + Action: "shuffle", } - js, err = json.Marshal(shuffleBallotsRequest) + //js, err = json.Marshal(shuffleBallotsRequest) + signed, err = createSignedRequest(secret, shuffleBallotsRequest) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - randomproxy = proxyList[rand.Intn(len(proxyList))] + randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = postRequest(randomproxy+shuffleBallotsEndpoint, js) + oldTime := time.Now() + req, err = http.NewRequest(http.MethodPut, randomproxy+"/evoting/services/shuffle/"+electionID, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err, "failed to execute the shuffle query: %v", err) + + currentTime := time.Now() + diff := currentTime.Sub(oldTime) + t.Logf("Shuffle takes: %v sec", diff.Seconds()) body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the body of the response: %v", err) @@ -666,155 +621,53 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyList[rand.Intn(len(proxyList))] - - resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 3, electionStatus) // ###################################### REQUEST PUBLIC SHARES ############ t.Log("request public shares") - beginDecryptionRequest := types.BeginDecryptionRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } + randomproxy = proxyArray[rand.Intn(len(proxyArray))] + oldTime = time.Now() - js, err = json.Marshal(beginDecryptionRequest) + _, err = updateDKG(secret, randomproxy, electionID, "computePubshares", t) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - randomproxy = proxyList[rand.Intn(len(proxyList))] - - resp, err = postRequest(randomproxy+beginDecryptionEndpoint, js) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() + currentTime = time.Now() + diff = currentTime.Sub(oldTime) + t.Logf("Shuffle takes: %v sec", diff.Seconds()) time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyList[rand.Intn(len(proxyList))] - - resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + getElectionInfo(objmap, proxyAddr1, electionID, t) - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) + require.Equal(t, 4, electionStatus) // ###################################### DECRYPT BALLOTS ################## t.Log("decrypt ballots") - decryptBallotsRequest := types.CombineSharesRequest{ - ElectionID: electionID, - UserID: "adminId", - Token: "token", - } - - js, err = json.Marshal(decryptBallotsRequest) - require.NoError(t, err, "failed to set marshall types.CombineSharesRequest : %v", err) - - randomproxy = proxyList[rand.Intn(len(proxyList))] + randomproxy = proxyArray[rand.Intn(len(proxyArray))] - resp, err = postRequest(randomproxy+combineSharesEndpoint, js) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() + _, err = updateElection(secret, randomproxy, electionID, "combineShares", t) + require.NoError(t, err, "failed to combine shares: %v", err) time.Sleep(10 * time.Second) - t.Log("Get election info") - createInfoJs = fmt.Sprintf(`{"ElectionID":"%v","Token":"token"}`, electionID) - - randomproxy = proxyList[rand.Intn(len(proxyList))] + getElectionInfo(objmap, proxyAddr1, electionID, t) - resp, err = postRequest(randomproxy+getElectionInfoEndpoint, []byte(createInfoJs)) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("response body:", string(body)) - resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) - - // ###################################### GET ELECTION RESULT ############## - - t.Log("Get election result") - - getElectionResultRequest := types.GetElectionResultRequest{ - ElectionID: electionID, - Token: "token", - } - - js, err = json.Marshal(getElectionResultRequest) - require.NoError(t, err, "failed to set marshall types.GetElectionResultRequest : %v", err) - - randomproxy = proxyList[rand.Intn(len(proxyList))] - - resp, err = postRequest(randomproxy+getElectionResultEndpoint, js) - - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() + require.Equal(t, 5, electionStatus) // ###################################### VALIDATE ELECTION RESULT ############## - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - tmpBallots := (objmap["Result"]).([]interface{}) var tmpComp map[string]interface{} var tmpCount bool @@ -837,8 +690,6 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyL } -*/ - // ----------------------------------------------------------------------------- // Utility functions func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (ptypes.CiphervoteJSON, error) { diff --git a/many.sh b/many.sh deleted file mode 100755 index 00acc58d8..000000000 --- a/many.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - - - - - - -if [ $1 -eq 3 ] -then - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node1 start --port 2001" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node2 start --port 2002" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node3 start --port 2003" -elif [ $1 -eq 5 ] -then - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node1 start --port 2001" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node2 start --port 2002" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node3 start --port 2003" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node4 start --port 2004" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node5 start --port 2005" -elif [ $1 -eq 13 ] -then - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node1 start --port 2001" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node2 start --port 2002" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node3 start --port 2003" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node4 start --port 2004" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node5 start --port 2005" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node6 start --port 2006" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node7 start --port 2007" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node8 start --port 2008" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node9 start --port 2009" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node10 start --port 2010" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node11 start --port 2011" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node12 start --port 2012" - gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node13 start --port 2013" -else - echo "give 3, 5 or 13 " -fi - - - diff --git a/many2.sh b/many2.sh deleted file mode 100755 index bb67c1a80..000000000 --- a/many2.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - - - - - -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node1 start --postinstall --promaddr :9100 --proxyaddr :9080 --port 2001" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node2 start --postinstall --promaddr :9101 --proxyaddr :9081 --port 2002" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node3 start --postinstall --promaddr :9102 --proxyaddr :9082 --port 2003" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node4 start --postinstall --promaddr :9103 --proxyaddr :9083 --port 2004" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node5 start --postinstall --promaddr :9104 --proxyaddr :9084 --port 2005" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node6 start --postinstall --promaddr :9105 --proxyaddr :9085 --port 2006" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node7 start --postinstall --promaddr :9106 --proxyaddr :9086 --port 2007" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node8 start --postinstall --promaddr :9107 --proxyaddr :9087 --port 2008" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node9 start --postinstall --promaddr :9108 --proxyaddr :9088 --port 2009" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node10 start --postinstall --promaddr :9109 --proxyaddr :9089 --port 2010" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node11 start --postinstall --promaddr :9110 --proxyaddr :9090 --port 2011" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node12 start --postinstall --promaddr :9111 --proxyaddr :9091 --port 2012" -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node13 start --postinstall --promaddr :9112 --proxyaddr :9092 --port 2013" diff --git a/runNode.sh b/runNode.sh new file mode 100755 index 000000000..ebdb2e851 --- /dev/null +++ b/runNode.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Basic while loop + +pk=adbacd10fdb9822c71025d6d00092b8a4abb5ebcb673d28d863f7c7c5adaddf3 + + + + +from=0 +fromb=1 +to=$1 +ne=0 +while [ $fromb -le $to ] +do +if [ $from -le 9 ] +then +gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node$fromb start --postinstall --promaddr :910$from --proxyaddr :908$from --proxykey $pk --listen tcp://0.0.0.0:200$fromb --public //localhost:200$fromb" + +else + + + +gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node$fromb start --postinstall --promaddr :91$from --proxyaddr :909$ne --proxykey $pk --listen tcp://0.0.0.0:20$fromb --public //localhost:20$fromb" +((ne++)) +fi +((fromb++)) +((from++)) +done + diff --git a/setupnNode.sh b/setupnNode.sh new file mode 100755 index 000000000..4913465a4 --- /dev/null +++ b/setupnNode.sh @@ -0,0 +1,171 @@ +#!/usr/bin/env bash + +# This script is creating a new chain and setting up the services needed to run +# an evoting system. It ends by starting the http server needed by the frontend +# to communicate with the blockchain. This operation is blocking. It is expected +# that the "memcoin" binary is at the root. You can build it with: +# go build ./cli/memcoin + +set -e + +GREEN='\033[0;32m' +NC='\033[0m' # No Color + + +echo "${GREEN}[1/7]${NC} connect nodes" + +fromb=2 +to=$1 +while [ $fromb -le $to ] +do +./memcoin --config /tmp/node$fromb minogrpc join \ + --address //localhost:2001 $(./memcoin --config /tmp/node1 minogrpc token) + +((fromb++)) +done + +echo "${GREEN}[2/7]${NC} create a chain" +if [ $1 -eq 3 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export) + +elif [ $1 -eq 4 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export) + +elif [ $1 -eq 5 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export)\ + --member $(./memcoin --config /tmp/node5 ordering export) + +elif [ $1 -eq 6 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export)\ + --member $(./memcoin --config /tmp/node5 ordering export)\ + --member $(./memcoin --config /tmp/node6 ordering export) + +elif [ $1 -eq 10 ] +then +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export)\ + --member $(./memcoin --config /tmp/node5 ordering export)\ + --member $(./memcoin --config /tmp/node6 ordering export)\ + --member $(./memcoin --config /tmp/node7 ordering export)\ + --member $(./memcoin --config /tmp/node8 ordering export)\ + --member $(./memcoin --config /tmp/node9 ordering export)\ + --member $(./memcoin --config /tmp/node10 ordering export) +elif [ $1 -eq 13 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export)\ + --member $(./memcoin --config /tmp/node5 ordering export)\ + --member $(./memcoin --config /tmp/node6 ordering export)\ + --member $(./memcoin --config /tmp/node7 ordering export)\ + --member $(./memcoin --config /tmp/node8 ordering export)\ + --member $(./memcoin --config /tmp/node9 ordering export)\ + --member $(./memcoin --config /tmp/node10 ordering export)\ + --member $(./memcoin --config /tmp/node11 ordering export)\ + --member $(./memcoin --config /tmp/node12 ordering export)\ + --member $(./memcoin --config /tmp/node13 ordering export) + + +else + echo "give 3,4,5,6,10 or 13 " +fi + +echo "${GREEN}[3/7]${NC} setup access rights on each node" + +fromb=1 + +while [ $fromb -le $to ] +do +./memcoin --config /tmp/node$fromb access add \ + --identity $(crypto bls signer read --path private.key --format BASE64_PUBKEY) + +((fromb++)) +done + + +echo "${GREEN}[4/7]${NC} grant access on the chain" + +./memcoin --config /tmp/node1 pool add\ + --key private.key\ + --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ + --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ + --args access:grant_contract --args go.dedis.ch/dela.Evoting\ + --args access:grant_command --args all\ + --args access:identity --args $(crypto bls signer read --path private.key --format BASE64_PUBKEY)\ + --args access:command --args GRANT + + +fromb=1 + +while [ $fromb -le $to ] +do + +./memcoin --config /tmp/node1 pool add\ + --key private.key\ + --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access\ + --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000\ + --args access:grant_contract --args go.dedis.ch/dela.Evoting\ + --args access:grant_command --args all\ + --args access:identity --args $(crypto bls signer read --path /tmp/node$fromb/private.key --format BASE64_PUBKEY)\ + --args access:command --args GRANT + + +((fromb++)) +done + +# The following is not needed anymore thanks to the "postinstall" functionality. +# See #65. + +# echo "${GREEN}[5/7]${NC} init shuffle" +# ./memcoin --config /tmp/node1 shuffle init --signer /tmp/node1/private.key +# ./memcoin --config /tmp/node2 shuffle init --signer /tmp/node2/private.key +# ./memcoin --config /tmp/node3 shuffle init --signer /tmp/node3/private.key + +# echo "${GREEN}[6/7]${NC} starting http proxy" +# ./memcoin --config /tmp/node1 proxy start --clientaddr 127.0.0.1:8081 +# ./memcoin --config /tmp/node1 e-voting registerHandlers --signer private.key +# ./memcoin --config /tmp/node1 dkg registerHandlers + +# ./memcoin --config /tmp/node2 proxy start --clientaddr 127.0.0.1:8082 +# ./memcoin --config /tmp/node2 e-voting registerHandlers --signer private.key +# ./memcoin --config /tmp/node2 dkg registerHandlers + +# ./memcoin --config /tmp/node3 proxy start --clientaddr 127.0.0.1:8083 +# ./memcoin --config /tmp/node3 e-voting registerHandlers --signer private.key +# ./memcoin --config /tmp/node3 dkg registerHandlers + +# If an election is created with ID "deadbeef" then one must set up DKG +# on each node before the election can proceed: +# ./memcoin --config /tmp/node1 dkg init --electionID deadbeef +# ./memcoin --config /tmp/node2 dkg init --electionID deadbeef +# ./memcoin --config /tmp/node3 dkg init --electionID deadbeef +# ./memcoin --config /tmp/node1 dkg setup --electionID deadbeef From 358ac97627b0f9ecbf7b970fdc748c061445270b Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Fri, 29 Apr 2022 14:47:09 +0200 Subject: [PATCH 13/68] correct lint and vet --- integration/scenario_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 38e3e5c24..da7a94b83 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -358,7 +358,7 @@ func getScenarioTest() func(*testing.T) { t.Logf("Status of the election : %v", electionStatus) require.Equal(t, 5, electionStatus) - // ###################################### VALIDATE ELECTION RESULT ############## + //##################################### VALIDATE ELECTION RESULT ############ tmpBallots := (objmap["Result"]).([]interface{}) var tmpComp map[string]interface{} @@ -380,8 +380,6 @@ func getScenarioTest() func(*testing.T) { } require.True(t, tmpCount, "front end votes are different from decrypted votes") - return - } } @@ -413,8 +411,6 @@ func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing fmt.Println("Waiting for workers to finish") wg.Wait() - return - } } @@ -666,7 +662,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Logf("Status of the election : %v", electionStatus) require.Equal(t, 5, electionStatus) - // ###################################### VALIDATE ELECTION RESULT ############## + //#################################### VALIDATE ELECTION RESULT ############## tmpBallots := (objmap["Result"]).([]interface{}) var tmpComp map[string]interface{} From 76001e0c42f7834515e8640f5453f619897ad96a Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Sun, 1 May 2022 19:10:53 +0200 Subject: [PATCH 14/68] Modify Footer, adds vote action & ui election show --- .../src/components/utils/VoteButton.tsx | 26 +++++++ .../src/components/utils/useChangeAction.tsx | 2 + web/frontend/src/layout/App.tsx | 4 +- web/frontend/src/layout/Footer.css | 9 --- web/frontend/src/layout/Footer.tsx | 20 +++-- web/frontend/src/pages/election/Index.css | 6 -- web/frontend/src/pages/election/Index.tsx | 2 +- web/frontend/src/pages/election/Show.tsx | 65 ++++++++--------- .../election/components/StatusTimeline.tsx | 73 +++++++++++++++++++ 9 files changed, 142 insertions(+), 65 deletions(-) create mode 100644 web/frontend/src/components/utils/VoteButton.tsx delete mode 100644 web/frontend/src/layout/Footer.css create mode 100644 web/frontend/src/pages/election/components/StatusTimeline.tsx diff --git a/web/frontend/src/components/utils/VoteButton.tsx b/web/frontend/src/components/utils/VoteButton.tsx new file mode 100644 index 000000000..f8fc496e1 --- /dev/null +++ b/web/frontend/src/components/utils/VoteButton.tsx @@ -0,0 +1,26 @@ +import { AuthContext } from 'index'; +import { useContext } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import { ROUTE_BALLOT_SHOW } from 'Routes'; +import { STATUS } from 'types/election'; +import { ROLE } from 'types/userRole'; + +const VoteButton = ({ status, electionID }) => { + const authCtx = useContext(AuthContext); + const { t } = useTranslation(); + + const isAuthorized = + authCtx.role === ROLE.Admin || authCtx.role === ROLE.Operator || authCtx.role === ROLE.Voter; + + return ( + isAuthorized && + status === STATUS.Open && + authCtx.isLogged && ( + + + + ) + ); +}; +export default VoteButton; diff --git a/web/frontend/src/components/utils/useChangeAction.tsx b/web/frontend/src/components/utils/useChangeAction.tsx index 0033306c2..9d12d547e 100644 --- a/web/frontend/src/components/utils/useChangeAction.tsx +++ b/web/frontend/src/components/utils/useChangeAction.tsx @@ -11,6 +11,7 @@ import CancelButton from './CancelButton'; import OpenButton from './OpenButton'; import DecryptButton from './DecryptButton'; import ResultButton from './ResultButton'; +import VoteButton from './VoteButton'; const useChangeAction = ( status: STATUS, @@ -188,6 +189,7 @@ const useChangeAction = ( + ); case STATUS.Closed: diff --git a/web/frontend/src/layout/App.tsx b/web/frontend/src/layout/App.tsx index 9af2a99c7..f6a9af142 100644 --- a/web/frontend/src/layout/App.tsx +++ b/web/frontend/src/layout/App.tsx @@ -48,12 +48,12 @@ const App = () => {
-
+
+ className=" mb-auto max-w-[80rem] mx-auto flex flex-row justify-center items-center w-full"> ( -
-
- - © 2021 DEDIS LAB -{' '} - https://github.com/dedis/dela - {' '} -
+
+
); diff --git a/web/frontend/src/pages/election/Index.css b/web/frontend/src/pages/election/Index.css index abed946f0..cc211fc9f 100644 --- a/web/frontend/src/pages/election/Index.css +++ b/web/frontend/src/pages/election/Index.css @@ -1,9 +1,3 @@ -.election-wrapper { - padding-top: 3%; - background-color: #f6f6fa; - padding-right: 3%; - padding-left: 3%; -} .election-box { padding-bottom: 5%; diff --git a/web/frontend/src/pages/election/Index.tsx b/web/frontend/src/pages/election/Index.tsx index 9822f5ccc..ac0ff5c5f 100644 --- a/web/frontend/src/pages/election/Index.tsx +++ b/web/frontend/src/pages/election/Index.tsx @@ -36,7 +36,7 @@ const ElectionIndex: FC = () => { }; return ( -
+
{t('listElection')} {!loading ? ( showElection() diff --git a/web/frontend/src/pages/election/Show.tsx b/web/frontend/src/pages/election/Show.tsx index 914cb88f7..6f3c1a09d 100644 --- a/web/frontend/src/pages/election/Show.tsx +++ b/web/frontend/src/pages/election/Show.tsx @@ -1,5 +1,5 @@ -import React, { FC, useContext, useEffect, useState } from 'react'; -import { Link, useParams } from 'react-router-dom'; +import React, { FC, useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; @@ -9,15 +9,11 @@ import useGetResults from 'components/utils/useGetResults'; import { STATUS } from 'types/election'; import Status from './components/Status'; import Action from './components/Action'; -import { ROUTE_BALLOT_SHOW, ROUTE_ELECTION_INDEX } from 'Routes'; -import TextButton from 'components/buttons/TextButton'; -import { AuthContext } from 'index'; -import { ROLE } from 'types/userRole'; +import StatusTimeline from './components/StatusTimeline'; const ElectionShow: FC = () => { const { t } = useTranslation(); const { electionId } = useParams(); - const authCtx = useContext(AuthContext); const { loading, electionID, status, setStatus, setResult, configObj, setIsResultSet } = useElection(electionId); @@ -31,42 +27,39 @@ const ElectionShow: FC = () => { if (status === STATUS.ResultAvailable && isResultAvailable) { getResults(electionID, setError, setResult, setIsResultSet); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isResultAvailable, status]); return ( -
+
{!loading ? ( -
-
-

+ <> +
+
{configObj.MainTitle} -

-
- {t('status')}: - {t('action')}: - +
+

Election ID : {electionId}

+
+
Workflow
+ +
+ {t('status')}: + +
+
+
+
{t('action')}
+
+ +
-
- {status === STATUS.Open && - authCtx.isLogged && - (authCtx.role === ROLE.Admin || - authCtx.role === ROLE.Operator || - authCtx.role === ROLE.Voter) ? ( - - {t('navBarVote')} - - ) : null} - - {t('back')} - -
-
+ ) : (

{t('loading')}

)} diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx new file mode 100644 index 000000000..b18b98c10 --- /dev/null +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -0,0 +1,73 @@ +import { AuthContext } from 'index'; +import { FC, useContext } from 'react'; +import { STATUS } from 'types/election'; +import { ROLE } from 'types/userRole'; + +type StatusTimelineProps = { + status: STATUS; +}; + +const completeSteps = [ + { name: 'Initial', status: 'complete' }, + { name: 'Initialized', status: 'current' }, + { name: 'On Going Setup', status: 'upcoming' }, + { name: 'Setup', status: 'upcoming' }, + { name: 'Open', status: 'upcoming' }, + // { name: 'Canceled', status: 'upcoming' }, + { name: 'Closed', status: 'upcoming' }, + { name: 'On Going Shuffle', status: 'upcoming' }, + { name: 'Shuffled Ballots', status: 'upcoming' }, + { name: 'On Going Decryption', status: 'upcoming' }, + { name: 'Decrypted Ballots', status: 'upcoming' }, + { name: 'Result Available', status: 'upcoming' }, +]; + +const simpleSteps = [ + { name: 'Initial', status: 'complete' }, + { name: 'Open', status: 'current' }, + // { name: 'Canceled', status: 'upcoming' }, + { name: 'Closed', status: 'upcoming' }, + { name: 'Shuffled Ballots', status: 'upcoming' }, + { name: 'Decrypted Ballots', status: 'upcoming' }, + { name: 'Result Available', status: 'upcoming' }, +]; + +const StatusTimeline: FC = ({ status }) => { + const authCtx = useContext(AuthContext); + const steps = + authCtx.role === ROLE.Admin || authCtx.role === ROLE.Operator ? completeSteps : simpleSteps; + + return ( + <> +
    + {steps.map((step) => ( +
  1. + {step.status === 'complete' ? ( +
    + + {step.name} + +
    + ) : step.status === 'current' ? ( +
    + + {step.name} + +
    + ) : ( +
    + + {step.name} + +
    + )} +
  2. + ))} +
+ + ); +}; + +export default StatusTimeline; From a9eb015727d6d66c3c4367162986773bf09ac295 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Mon, 2 May 2022 09:53:52 +0200 Subject: [PATCH 15/68] fix typo and add time counter --- integration/scenario_test.go | 46 ++++++++++++++++++++++-------------- setupnNode.sh | 12 ++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index da7a94b83..2972f7c64 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -30,6 +30,7 @@ import ( "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/sign/schnorr" "go.dedis.ch/kyber/v3/suites" + "go.dedis.ch/kyber/v3/util/encoding" "go.dedis.ch/kyber/v3/util/random" "golang.org/x/xerrors" ) @@ -147,11 +148,7 @@ func getScenarioTest() func(*testing.T) { // Get election public key - pubkeyBuf, err := hex.DecodeString(electionpubkey) - require.NoError(t, err, "failed to decode key: %v", err) - - pubKey := suite.Point() - err = pubKey.UnmarshalBinary(pubkeyBuf) + pubKey, err := encoding.StringHexToPoint(suite, electionpubkey) require.NoError(t, err, "failed to Unmarshal key: %v", err) // ##################################### CAST BALLOTS ###################### @@ -460,7 +457,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Log("Init DKG") - for i := 0; i < len(proxyArray); i++ { + for i := 0; i < numNodes; i++ { t.Log("Node" + strconv.Itoa(i)) fmt.Println(proxyArray[i]) err = initDKG(secret, proxyArray[i], electionID, t) @@ -490,7 +487,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA // ##################################### GET ELECTION INFO ################# proxyAddr1 := proxyArray[0] - + time.Sleep(time.Second * 3) getElectionInfo(objmap, proxyAddr1, electionID, t) electionpubkey := objmap["Pubkey"].(string) @@ -506,13 +503,8 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA // Get election public key - pubkeyBuf, err := hex.DecodeString(electionpubkey) - require.NoError(t, err, "failed to decode key: %v", err) - - pubKey := suite.Point() - err = pubKey.UnmarshalBinary(pubkeyBuf) + pubKey, err := encoding.StringHexToPoint(suite, electionpubkey) require.NoError(t, err, "failed to Unmarshal key: %v", err) - // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") @@ -576,8 +568,9 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA _, err = updateElection(secret, randomproxy, electionID, "close", t) require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) - getElectionInfo(objmap, proxyAddr1, electionID, t) + time.Sleep(time.Second * 3) + getElectionInfo(objmap, proxyAddr1, electionID, t) require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) @@ -597,16 +590,21 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA randomproxy = proxyArray[rand.Intn(len(proxyArray))] + timeTable := make([]float64, 3) + oldTime := time.Now() req, err = http.NewRequest(http.MethodPut, randomproxy+"/evoting/services/shuffle/"+electionID, bytes.NewBuffer(signed)) + require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) resp, err = http.DefaultClient.Do(req) + require.NoError(t, err, "failed to execute the shuffle query: %v", err) currentTime := time.Now() diff := currentTime.Sub(oldTime) + timeTable[0] = diff.Seconds() t.Logf("Shuffle takes: %v sec", diff.Seconds()) body, err = io.ReadAll(resp.Body) @@ -615,7 +613,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Log("Response body: " + string(body)) resp.Body.Close() - time.Sleep(10 * time.Second) + //time.Sleep(10 * time.Second) getElectionInfo(objmap, proxyAddr1, electionID, t) @@ -635,7 +633,9 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA currentTime = time.Now() diff = currentTime.Sub(oldTime) - t.Logf("Shuffle takes: %v sec", diff.Seconds()) + timeTable[1] = diff.Seconds() + + t.Logf("Request public share takes: %v sec", diff.Seconds()) time.Sleep(10 * time.Second) @@ -650,13 +650,21 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Log("decrypt ballots") randomproxy = proxyArray[rand.Intn(len(proxyArray))] + oldTime = time.Now() _, err = updateElection(secret, randomproxy, electionID, "combineShares", t) require.NoError(t, err, "failed to combine shares: %v", err) - time.Sleep(10 * time.Second) + currentTime = time.Now() + diff = currentTime.Sub(oldTime) + timeTable[2] = diff.Seconds() + + t.Logf("decryption takes: %v sec", diff.Seconds()) + + //time.Sleep(10 * time.Second) getElectionInfo(objmap, proxyAddr1, electionID, t) + time.Sleep(time.Second * 3) electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) @@ -683,7 +691,9 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA } } require.True(t, tmpCount, "front end votes are different from decrypted votes") - + t.Logf("shuffle time : %v", timeTable[0]) + t.Logf("Public share time : %v", timeTable[1]) + t.Logf("decryption time : %v", timeTable[2]) } // ----------------------------------------------------------------------------- diff --git a/setupnNode.sh b/setupnNode.sh index 4913465a4..1eb2337b7 100755 --- a/setupnNode.sh +++ b/setupnNode.sh @@ -63,6 +63,18 @@ then --member $(./memcoin --config /tmp/node5 ordering export)\ --member $(./memcoin --config /tmp/node6 ordering export) +elif [ $1 -eq 7 ] +then + +./memcoin --config /tmp/node1 ordering setup\ + --member $(./memcoin --config /tmp/node1 ordering export)\ + --member $(./memcoin --config /tmp/node2 ordering export)\ + --member $(./memcoin --config /tmp/node3 ordering export)\ + --member $(./memcoin --config /tmp/node4 ordering export)\ + --member $(./memcoin --config /tmp/node5 ordering export)\ + --member $(./memcoin --config /tmp/node6 ordering export)\ + --member $(./memcoin --config /tmp/node7 ordering export) + elif [ $1 -eq 10 ] then ./memcoin --config /tmp/node1 ordering setup\ From 888445337c22d87dd32ce78bc1ec6f948f5b37dc Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Mon, 2 May 2022 11:35:45 +0200 Subject: [PATCH 16/68] Changes UI Admin, adds timeout to mock API calls --- .../src/components/utils/SpinnerIcon.tsx | 23 +++ web/frontend/src/mocks/handlers.ts | 40 ++-- web/frontend/src/mocks/setupMockUserDB.ts | 30 +++ web/frontend/src/pages/Admin.tsx | 172 ++++++++++++------ web/frontend/src/pages/Home.tsx | 2 + web/frontend/src/pages/Notification.tsx | 54 ++++++ .../election/components/ElectionForm.tsx | 12 +- 7 files changed, 267 insertions(+), 66 deletions(-) create mode 100644 web/frontend/src/components/utils/SpinnerIcon.tsx create mode 100644 web/frontend/src/pages/Notification.tsx diff --git a/web/frontend/src/components/utils/SpinnerIcon.tsx b/web/frontend/src/components/utils/SpinnerIcon.tsx new file mode 100644 index 000000000..727f4f760 --- /dev/null +++ b/web/frontend/src/components/utils/SpinnerIcon.tsx @@ -0,0 +1,23 @@ +const SpinnerIcon = () => { + return ( + + + + + ); +}; + +export default SpinnerIcon; diff --git a/web/frontend/src/mocks/handlers.ts b/web/frontend/src/mocks/handlers.ts index 6b6454fae..27add4ae1 100644 --- a/web/frontend/src/mocks/handlers.ts +++ b/web/frontend/src/mocks/handlers.ts @@ -31,7 +31,7 @@ const { mockElections, mockResults } = setupMockElection(); var mockUserDB = setupMockUserDB(); export const handlers = [ - rest.get(ENDPOINT_PERSONAL_INFO, (req, res, ctx) => { + rest.get(ENDPOINT_PERSONAL_INFO, async (req, res, ctx) => { const isLogged = sessionStorage.getItem('is-authenticated') === 'true'; const userId = isLogged ? mockUserID : 0; const userInfos = isLogged @@ -42,6 +42,7 @@ export const handlers = [ sciper: userId, } : {}; + await new Promise((r) => setTimeout(r, 1000)); return res( ctx.status(200), @@ -52,10 +53,12 @@ export const handlers = [ ); }), - rest.get(ENDPOINT_GET_TEQ_KEY, (req, res, ctx) => { + rest.get(ENDPOINT_GET_TEQ_KEY, async (req, res, ctx) => { const url = ROUTE_LOGGED; sessionStorage.setItem('is-authenticated', 'true'); sessionStorage.setItem('id', '283205'); + await new Promise((r) => setTimeout(r, 1000)); + return res(ctx.status(200), ctx.json({ url: url })); }), @@ -64,7 +67,9 @@ export const handlers = [ return res(ctx.status(200)); }), - rest.get(endpoints.elections, (req, res, ctx) => { + rest.get(endpoints.elections, async (req, res, ctx) => { + await new Promise((r) => setTimeout(r, 1000)); + return res( ctx.status(200), ctx.json({ @@ -75,15 +80,18 @@ export const handlers = [ ); }), - rest.get(endpoints.election(':ElectionID'), (req, res, ctx) => { + rest.get(endpoints.election(':ElectionID'), async (req, res, ctx) => { const { ElectionID } = req.params; + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200), ctx.json(mockElections.get(ElectionID as ID))); }), - rest.post(endpoints.newElection, (req, res, ctx) => { + rest.post(endpoints.newElection, async (req, res, ctx) => { const body = req.body as NewElectionBody; + await new Promise((r) => setTimeout(r, 1000)); + const createElection = (configuration: any) => { const newElectionID = uid(); @@ -108,8 +116,9 @@ export const handlers = [ ); }), - rest.post(endpoints.newElectionVote(':ElectionID'), (req, res, ctx) => { + rest.post(endpoints.newElectionVote(':ElectionID'), async (req, res, ctx) => { const { Ballot }: NewElectionVoteBody = JSON.parse(req.body.toString()); + await new Promise((r) => setTimeout(r, 1000)); return res( ctx.status(200), @@ -119,7 +128,7 @@ export const handlers = [ ); }), - rest.put(endpoints.editElection(':ElectionID'), (req, res, ctx) => { + rest.put(endpoints.editElection(':ElectionID'), async (req, res, ctx) => { const body = req.body as EditElectionBody; const { ElectionID } = req.params; var Status = STATUS.Initial; @@ -144,45 +153,52 @@ export const handlers = [ ...mockElections.get(ElectionID as string), Status, }); + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200), ctx.text('Action successfully done')); }), - rest.put(endpoints.editShuffle(':ElectionID'), (req, res, ctx) => { + rest.put(endpoints.editShuffle(':ElectionID'), async (req, res, ctx) => { const { ElectionID } = req.params; mockElections.set(ElectionID as string, { ...mockElections.get(ElectionID as string), Status: STATUS.ShuffledBallots, }); + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200), ctx.text('Action successfully done')); }), - rest.put(endpoints.editDKGActors(':ElectionID'), (req, res, ctx) => { + rest.put(endpoints.editDKGActors(':ElectionID'), async (req, res, ctx) => { const { ElectionID } = req.params; mockElections.set(ElectionID as string, { ...mockElections.get(ElectionID as string), Result: mockResults.get(ElectionID as string), Status: STATUS.ResultAvailable, }); + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200), ctx.text('Action successfully done')); }), - rest.get(endpoints.ENDPOINT_USER_RIGHTS, (req, res, ctx) => { + rest.get(endpoints.ENDPOINT_USER_RIGHTS, async (req, res, ctx) => { + await new Promise((r) => setTimeout(r, 1000)); + return res(ctx.status(200), ctx.json(mockUserDB.filter((user) => user.role !== 'voter'))); }), - rest.post(endpoints.ENDPOINT_ADD_ROLE, (req, res, ctx) => { + rest.post(endpoints.ENDPOINT_ADD_ROLE, async (req, res, ctx) => { const body = req.body as NewUserRole; mockUserDB.push({ id: uid(), ...body }); + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200)); }), - rest.post(endpoints.ENDPOINT_REMOVE_ROLE, (req, res, ctx) => { + rest.post(endpoints.ENDPOINT_REMOVE_ROLE, async (req, res, ctx) => { const body = req.body as RemoveUserRole; mockUserDB = mockUserDB.filter((user) => user.sciper !== body.sciper); + await new Promise((r) => setTimeout(r, 1000)); return res(ctx.status(200)); }), diff --git a/web/frontend/src/mocks/setupMockUserDB.ts b/web/frontend/src/mocks/setupMockUserDB.ts index 04383377c..4ca7788d4 100644 --- a/web/frontend/src/mocks/setupMockUserDB.ts +++ b/web/frontend/src/mocks/setupMockUserDB.ts @@ -26,6 +26,36 @@ const setupMockUserDB = () => { userDB.push(mockUser1); userDB.push(mockUser2); userDB.push(mockUser3); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); + userDB.push({ + id: uid(), + sciper: uid().toString(), + role: ROLE.Operator, + }); return userDB; }; diff --git a/web/frontend/src/pages/Admin.tsx b/web/frontend/src/pages/Admin.tsx index 107b5359e..20d0349b6 100644 --- a/web/frontend/src/pages/Admin.tsx +++ b/web/frontend/src/pages/Admin.tsx @@ -1,23 +1,23 @@ -import React, { useEffect, useState } from 'react'; -import Button from '@mui/material/Button'; -import { DataGrid } from '@mui/x-data-grid'; +import { useEffect, useState } from 'react'; import { ENDPOINT_USER_RIGHTS } from 'components/utils/Endpoints'; +import { PlusIcon } from '@heroicons/react/outline'; + import AddAdminUserModal from 'components/modal/AddAdminUserModal'; -import RemoveAdminUserModal from 'components/modal/RemoveAdminUserModal'; -import './Admin.css'; -const Admin = () => { - const [rows, setRows] = useState([]); - const [newusrOpen, setNewusrOpen] = useState(false); +const SCIPERS_PER_PAGE = 10; - const [sciperToDelete, setSciperToDelete] = useState(0); +const Admin = () => { + const [users, setUsers] = useState([]); const [showDeleteModal, setShowDeleteModal] = useState(false); + const [newusrOpen, setNewusrOpen] = useState(false); + const [scipersToDisplay, setScipersToDisplay] = useState([]); + const [pageIndex, setPageIndex] = useState(0); const openModal = () => setNewusrOpen(true); useEffect(() => { - if (newusrOpen || showDeleteModal) { + if (showDeleteModal) { return; } @@ -25,60 +25,126 @@ const Admin = () => { .then((resp) => { const jsonData = resp.json(); jsonData.then((result) => { - console.log(result); - setRows(result); + setUsers(result); }); }) .catch((error) => { console.log(error); }); - }, [newusrOpen, showDeleteModal]); + }, [showDeleteModal]); + + const partitionArray = (array, size) => + array.map((v, i) => (i % size === 0 ? array.slice(i, i + size) : null)).filter((v) => v); - const columns = [ - { - field: 'sciper', - headerName: 'sciper', - width: 150, - }, - { - field: 'role', - headerName: 'role', - width: 150, - }, - { - field: 'action', - headerName: 'Action', - width: 150, - renderCell: function (params: any) { - function handledClick() { - setSciperToDelete(params.row.sciper); - setShowDeleteModal(true); - } - return ( - - ); - }, - }, - ]; + useEffect(() => { + if (users.length) { + setScipersToDisplay(partitionArray(users, SCIPERS_PER_PAGE)[pageIndex]); + } + }, [users, pageIndex]); + + const handleDelete = (sciper: number): void => { + console.log(sciper); + setShowDeleteModal(true); + }; + + const handlePrevious = (): void => { + if (pageIndex > 0) { + setPageIndex(pageIndex - 1); + } + }; + const handleNext = (): void => { + if (partitionArray(users, SCIPERS_PER_PAGE).length > pageIndex + 1) { + setPageIndex(pageIndex + 1); + } + }; return ( -
-
- - - - + +
+ +
+
+
+
+ + + + + + + + + + {scipersToDisplay.map((user) => ( + + + + + + ))} + +
+ Sciper + + Role + + Edit +
+ {user.sciper} + + {user.role} + +
handleDelete(user.sciper)}> + Delete +
+
+ +
+
+
); }; - export default Admin; diff --git a/web/frontend/src/pages/Home.tsx b/web/frontend/src/pages/Home.tsx index 630e1e683..7f4d80538 100644 --- a/web/frontend/src/pages/Home.tsx +++ b/web/frontend/src/pages/Home.tsx @@ -3,6 +3,7 @@ import React, { FC, useContext } from 'react'; import { useTranslation } from 'react-i18next'; import './Home.css'; +import Notification from './Notification'; const Home: FC = () => { const { t } = useTranslation(); @@ -12,6 +13,7 @@ const Home: FC = () => {

{t('homeTitle')}

{t('homeText')}
+
+
+
+
+
+ +
+
+ + ); +} diff --git a/web/frontend/src/pages/election/components/ElectionForm.tsx b/web/frontend/src/pages/election/components/ElectionForm.tsx index 0e5a7b0dd..e989981a0 100644 --- a/web/frontend/src/pages/election/components/ElectionForm.tsx +++ b/web/frontend/src/pages/election/components/ElectionForm.tsx @@ -14,6 +14,7 @@ import { Configuration, ID, Subject } from '../../../types/configuration'; import { emptyConfiguration, newSubject } from '../../../types/getObjectType'; import { marshalConfig } from '../../../types/JSONparser'; import DownloadButton from 'components/buttons/DownloadButton'; +import SpinnerIcon from 'components/utils/SpinnerIcon'; // notifyParent must be used by the child to tell the parent if the subject's // schema changed. @@ -32,6 +33,7 @@ const ElectionForm: FC = ({ setShowModal, setTextModal }) => const { t } = useTranslation(); const emptyConf: Configuration = emptyConfiguration(); const [conf, setConf] = useState(emptyConf); + const [loading, setLoading] = useState(false); const { MainTitle, Scaffold } = conf; async function createHandler() { @@ -55,6 +57,7 @@ const ElectionForm: FC = ({ setShowModal, setTextModal }) => } try { + setLoading(true); const res = await fetch(newElection, req); if (res.status !== 200) { const response = await res.text(); @@ -66,9 +69,11 @@ const ElectionForm: FC = ({ setShowModal, setTextModal }) => setShowModal(true); setConf(emptyConf); } + setLoading(false); } catch (error) { setTextModal(error.message); setShowModal(true); + setLoading(false); } } @@ -147,7 +152,12 @@ const ElectionForm: FC = ({ setShowModal, setTextModal }) => type="button" className="flex inline-flex my-2 ml-2 items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-500 hover:bg-indigo-600" onClick={createHandler}> -
-
- -
-
- - ); -} From 417041e36331be64443c673beb01202172da1210 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Mon, 2 May 2022 12:19:06 +0200 Subject: [PATCH 18/68] Cleans the StatusTimeline --- .../election/components/StatusTimeline.tsx | 146 ++++++++++++------ 1 file changed, 95 insertions(+), 51 deletions(-) diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx index b18b98c10..7ce83469a 100644 --- a/web/frontend/src/pages/election/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -7,66 +7,110 @@ type StatusTimelineProps = { status: STATUS; }; -const completeSteps = [ - { name: 'Initial', status: 'complete' }, - { name: 'Initialized', status: 'current' }, - { name: 'On Going Setup', status: 'upcoming' }, - { name: 'Setup', status: 'upcoming' }, - { name: 'Open', status: 'upcoming' }, - // { name: 'Canceled', status: 'upcoming' }, - { name: 'Closed', status: 'upcoming' }, - { name: 'On Going Shuffle', status: 'upcoming' }, - { name: 'Shuffled Ballots', status: 'upcoming' }, - { name: 'On Going Decryption', status: 'upcoming' }, - { name: 'Decrypted Ballots', status: 'upcoming' }, - { name: 'Result Available', status: 'upcoming' }, -]; - -const simpleSteps = [ - { name: 'Initial', status: 'complete' }, - { name: 'Open', status: 'current' }, - // { name: 'Canceled', status: 'upcoming' }, - { name: 'Closed', status: 'upcoming' }, - { name: 'Shuffled Ballots', status: 'upcoming' }, - { name: 'Decrypted Ballots', status: 'upcoming' }, - { name: 'Result Available', status: 'upcoming' }, -]; +const CanceledStep = { name: 'Canceled', state: 'upcoming', status: STATUS.Canceled }; const StatusTimeline: FC = ({ status }) => { const authCtx = useContext(AuthContext); + + const completeSteps = [ + { name: 'Initial', state: 'complete', status: STATUS.Initial }, + { name: 'Initialized', state: 'current', status: STATUS.InitializedNodes }, + { name: 'On Going Setup', state: 'upcoming', status: STATUS.Setup }, + { name: 'Setup', state: 'upcoming', status: STATUS.Setup }, + { name: 'Open', state: 'upcoming', status: STATUS.Open }, + { name: 'Closed', state: 'upcoming', status: STATUS.Closed }, + { name: 'On Going Shuffle', state: 'upcoming', status: STATUS.OnGoingShuffle }, + { name: 'Shuffled Ballots', state: 'upcoming', status: STATUS.ShuffledBallots }, + { name: 'On Going Decryption', state: 'upcoming', status: STATUS.OnGoingDecryption }, + { name: 'Decrypted Ballots', state: 'upcoming', status: STATUS.DecryptedBallots }, + { name: 'Result Available', state: 'upcoming', status: STATUS.ResultAvailable }, + ]; + + const simpleSteps = [ + { name: 'Initial', state: 'complete', status: STATUS.Initial }, + { name: 'Open', state: 'current', status: STATUS.Open }, + { name: 'Closed', state: 'upcoming', status: STATUS.Closed }, + { name: 'Shuffled Ballots', state: 'upcoming', status: STATUS.ShuffledBallots }, + { name: 'Decrypted Ballots', state: 'upcoming', status: STATUS.DecryptedBallots }, + { name: 'Result Available', state: 'upcoming', status: STATUS.ResultAvailable }, + ]; + const steps = authCtx.role === ROLE.Admin || authCtx.role === ROLE.Operator ? completeSteps : simpleSteps; + // If the status is Canceled we need to add the Canceled step to the steps + // array at the correct position in the workflow (after the Open step) + if (status === STATUS.Canceled) { + steps.splice( + steps.findIndex((step) => step.status === STATUS.Closed), + 0, + CanceledStep + ); + } + + const currentStep = steps.findIndex((step) => step.status === status); + + const DisplayStatus = ({ state, name }) => { + switch (state) { + case 'complete': + return ( + <> +
+ + {name} + +
+ + ); + case 'current': + return ( + <> +
+ + {name} + +
+ + ); + default: + return ( + <> +
+ + {name} + +
+ + ); + } + }; + return ( - <> -
    - {steps.map((step) => ( +
      + {steps.map((step, index) => { + if (index < currentStep) { + return ( +
    1. + +
    2. + ); + } + if (index === currentStep) { + return ( +
    3. + +
    4. + ); + } + return (
    5. - {step.status === 'complete' ? ( -
      - - {step.name} - -
      - ) : step.status === 'current' ? ( -
      - - {step.name} - -
      - ) : ( -
      - - {step.name} - -
      - )} +
    6. - ))} -
    - + ); + })} +
); }; From 6c259066263e86d618ea7699e147cebb4b25ff75 Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Mon, 2 May 2022 14:43:22 +0200 Subject: [PATCH 19/68] make requested changes --- integration/scenario_test.go | 745 +++++------------------------------ 1 file changed, 88 insertions(+), 657 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 2972f7c64..9c72a80fb 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -9,19 +9,13 @@ import ( "fmt" "io" "math/rand" - "reflect" - "sync" - "time" - - //"math/rand" "net/http" - //"reflect" + "reflect" "strconv" "strings" - - //"sync" + "sync" "testing" - //"time" + "time" "github.com/dedis/d-voting/contracts/evoting/types" "github.com/dedis/d-voting/internal/testing/fake" @@ -39,365 +33,23 @@ var suite = suites.MustFind("Ed25519") // Check the shuffled votes versus the cast votes on a few nodes func TestScenario(t *testing.T) { - t.Run("Basic configuration", getScenarioTest()) - t.Run("Differents combination ", testVariableNode(3, 3, 1)) -} - -func getScenarioTest() func(*testing.T) { - return func(t *testing.T) { - - const contentType = "application/json" - secretkeyBuf, err := hex.DecodeString("28912721dfd507e198b31602fb67824856eb5a674c021d49fdccbe52f0234409") - require.NoError(t, err, "failed to decode key: %v", err) - - secret := suite.Scalar() - err = secret.UnmarshalBinary(secretkeyBuf) - require.NoError(t, err, "failed to Unmarshal key: %v", err) - - t.Parallel() - - proxyAddr1 := "http://localhost:9080" - proxyAddr2 := "http://localhost:9081" - proxyAddr3 := "http://localhost:9082" - - proxyArray := [3]string{proxyAddr1, proxyAddr2, proxyAddr3} - - // ###################################### CREATE SIMPLE ELECTION ###### - - t.Logf("Create election") - - configuration := fake.BasicConfiguration - - createSimpleElectionRequest := ptypes.CreateElectionRequest{ - Configuration: configuration, - AdminID: "adminId", - } - fmt.Println(secret) - signed, err := createSignedRequest(secret, createSimpleElectionRequest) - require.NoError(t, err, "fail to create singature") - resp, err := http.Post(proxyAddr1+"/evoting/elections", contentType, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - body, err := io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("response body:", string(body)) - resp.Body.Close() - - var objmap map[string]interface{} - - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parse the body of the response from js: %v", err) - electionID := objmap["ElectionID"].(string) - t.Logf("ID of the election : " + electionID) - - // ##################################### SETUP DKG ######################### - - t.Log("Init DKG") - - t.Log("Node 1") - - err = initDKG(secret, proxyAddr1, electionID, t) - require.NoError(t, err, "failed to init dkg 1: %v", err) - - t.Log("Node 2") - err = initDKG(secret, proxyAddr2, electionID, t) - require.NoError(t, err, "failed to init dkg 2: %v", err) - - t.Log("Node 3") - err = initDKG(secret, proxyAddr3, electionID, t) - require.NoError(t, err, "failed to init dkg 3: %v", err) - - t.Log("Setup DKG") - - msg := ptypes.UpdateDKG{ - Action: "setup", - } - signed, err = createSignedRequest(secret, msg) - require.NoError(t, err, "failed to sign: %v", err) - req, err := http.NewRequest(http.MethodPut, proxyAddr1+"/evoting/services/dkg/actors/"+electionID, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed to create request: %v", err) - resp, err = http.DefaultClient.Do(req) - require.NoError(t, err, "failed to setup dkg on node 1: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - - // ##################################### OPEN ELECTION ##################### - - randomproxy := proxyArray[rand.Intn(len(proxyArray))] - t.Logf("Open election send to proxy %v", randomproxy) - - _, err = updateElection(secret, proxyAddr1, electionID, "open", t) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - - // ##################################### GET ELECTION INFO ################# - - getElectionInfo(objmap, proxyAddr1, electionID, t) - - electionpubkey := objmap["Pubkey"].(string) - electionStatus := int(objmap["Status"].(float64)) - BallotSize := int(objmap["BallotSize"].(float64)) - Chunksperballot := ChunksPerBallotManuel(BallotSize) - t.Logf("Publickey of the election : " + electionpubkey) - t.Logf("Status of the election : %v", electionStatus) - - require.NoError(t, err, "failed to unmarshal pubkey: %v", err) - t.Logf("BallotSize of the election : %v", BallotSize) - t.Logf("Chunksperballot of the election : %v", Chunksperballot) - - // Get election public key - - pubKey, err := encoding.StringHexToPoint(suite, electionpubkey) - require.NoError(t, err, "failed to Unmarshal key: %v", err) - - // ##################################### CAST BALLOTS ###################### - - t.Log("cast ballots") - - // Create the ballots - b1 := string("select:" + encodeIDBallot("bb") + ":0,0,1,0\n" + - "text:" + encodeIDBallot("ee") + ":eWVz\n\n") //encoding of "yes" - - b2 := string("select:" + encodeIDBallot("bb") + ":1,1,0,0\n" + - "text:" + encodeIDBallot("ee") + ":amE=\n\n") //encoding of "ja - - b3 := string("select:" + encodeIDBallot("bb") + ":0,0,0,1\n" + - "text:" + encodeIDBallot("ee") + ":b3Vp\n\n") //encoding of "oui" - - var votesfrontend [3]map[string]interface{} - - fakeConfiguration := fake.BasicConfiguration - t.Logf("configuration is: %v", fakeConfiguration) - - b1Marshal, _ := UnmarshalBallotManual(b1, fakeConfiguration) - ballotByte, _ := json.Marshal(b1Marshal) - _ = json.Unmarshal(ballotByte, &votesfrontend[0]) - - b2Marshal, _ := UnmarshalBallotManual(b2, fakeConfiguration) - ballotByte, _ = json.Marshal(b2Marshal) - _ = json.Unmarshal(ballotByte, &votesfrontend[1]) - - b3Marshal, _ := UnmarshalBallotManual(b3, fakeConfiguration) - ballotByte, _ = json.Marshal(b3Marshal) - _ = json.Unmarshal(ballotByte, &votesfrontend[2]) - - t.Logf("b123_marshal is: %v", votesfrontend) - - // Ballot 1 - t.Logf("1st ballot in str is: %v", b1) - - ballot1, err := marshallBallotManual(b1, pubKey, Chunksperballot) - t.Logf("1st ballot is: %v", ballot1) - - require.NoError(t, err, "failed to encrypt ballot : %v", err) - - castVoteRequest := ptypes.CastVoteRequest{ - UserID: "user1", - Ballot: ballot1, - } - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - t.Logf("cast first ballot to proxy %v", randomproxy) - - t.Logf("vote is: %v", castVoteRequest) - signed, err = createSignedRequest(secret, castVoteRequest) - require.NoError(t, err, "failed to sign: %v", err) - resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) - - resp.Body.Close() - t.Log("Response body: " + string(body)) - - // Ballot 2 - ballot2, err := marshallBallotManual(b2, pubKey, Chunksperballot) - require.NoError(t, err, "failed to encrypt ballot : %v", err) - - castVoteRequest = ptypes.CastVoteRequest{ - UserID: "user2", - Ballot: ballot2, - } - - t.Logf("cast second ballot") - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - signed, err = createSignedRequest(secret, castVoteRequest) - require.NoError(t, err, "failed to sign: %v", err) - resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed to cast ballot: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) - - resp.Body.Close() - t.Log("Response body: " + string(body)) - - // Ballot 3 - ballot3, err := marshallBallotManual(b3, pubKey, Chunksperballot) - require.NoError(t, err, "failed to encrypt ballot : %v", err) - - castVoteRequest = ptypes.CastVoteRequest{ - UserID: "user3", - Ballot: ballot3, - } - - t.Logf("cast third ballot") - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - signed, err = createSignedRequest(secret, castVoteRequest) - require.NoError(t, err, "failed to sign: %v", err) - resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed to cast ballot: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) - - resp.Body.Close() - t.Log("Response body: " + string(body)) - - // ############################# CLOSE ELECTION FOR REAL ################### - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - t.Logf("Close election (for real) send to proxy %v", randomproxy) - - _, err = updateElection(secret, randomproxy, electionID, "close", t) - require.NoError(t, err, "failed to set marshall types.CloseElectionRequest : %v", err) - - getElectionInfo(objmap, proxyAddr1, electionID, t) - - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = int(objmap["Status"].(float64)) - t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 2, electionStatus) - - // ###################################### SHUFFLE BALLOTS ################## - - t.Log("shuffle ballots") - - shuffleBallotsRequest := ptypes.UpdateShuffle{ - Action: "shuffle", - } - - //js, err = json.Marshal(shuffleBallotsRequest) - signed, err = createSignedRequest(secret, shuffleBallotsRequest) - require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - oldTime := time.Now() - - req, err = http.NewRequest(http.MethodPut, randomproxy+"/evoting/services/shuffle/"+electionID, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - resp, err = http.DefaultClient.Do(req) - require.NoError(t, err, "failed to execute the shuffle query: %v", err) - - currentTime := time.Now() - diff := currentTime.Sub(oldTime) - t.Logf("Shuffle takes: %v sec", diff.Seconds()) - - body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) - - t.Log("Response body: " + string(body)) - resp.Body.Close() - - time.Sleep(10 * time.Second) - - getElectionInfo(objmap, proxyAddr1, electionID, t) - - electionStatus = int(objmap["Status"].(float64)) - t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 3, electionStatus) - - // ###################################### REQUEST PUBLIC SHARES ############ - - t.Log("request public shares") - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - oldTime = time.Now() - - _, err = updateDKG(secret, randomproxy, electionID, "computePubshares", t) - require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) - - currentTime = time.Now() - diff = currentTime.Sub(oldTime) - t.Logf("Shuffle takes: %v sec", diff.Seconds()) - - time.Sleep(10 * time.Second) - - getElectionInfo(objmap, proxyAddr1, electionID, t) - - electionStatus = int(objmap["Status"].(float64)) - t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 4, electionStatus) - - // ###################################### DECRYPT BALLOTS ################## - - t.Log("decrypt ballots") - - randomproxy = proxyArray[rand.Intn(len(proxyArray))] - - _, err = updateElection(secret, randomproxy, electionID, "combineShares", t) - require.NoError(t, err, "failed to combine shares: %v", err) - - time.Sleep(10 * time.Second) - - getElectionInfo(objmap, proxyAddr1, electionID, t) - - electionStatus = int(objmap["Status"].(float64)) - t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 5, electionStatus) - - //##################################### VALIDATE ELECTION RESULT ############ - - tmpBallots := (objmap["Result"]).([]interface{}) - var tmpComp map[string]interface{} - var tmpCount bool - for _, ballotIntem := range tmpBallots { - tmpComp = ballotIntem.(map[string]interface{}) - tmpCount = false - for _, voteFront := range votesfrontend { - t.Logf("voteFront: %v", voteFront) - t.Logf("tmpComp: %v", tmpComp) - - tmpCount = reflect.DeepEqual(tmpComp, voteFront) - t.Logf("tmpCount: %v", tmpCount) - - if tmpCount { - break - } - } - } - require.True(t, tmpCount, "front end votes are different from decrypted votes") - - } + t.Run("Basic configuration", getScenarioTest(3, 3, 1)) } -func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing.T) { +func getScenarioTest(numNodes int, numVotes int, numElection int) func(*testing.T) { return func(t *testing.T) { proxyList := make([]string, numNodes) for i := 0; i < numNodes; i++ { - if i < 10 { - proxyList[i] = "http://localhost:908" + strconv.Itoa(i) - } else { - proxyList[i] = "http://localhost:909" + strconv.Itoa(i-10) - } - fmt.Println(proxyList[i]) + proxyList[i] = fmt.Sprintf("http://localhost:90%02d", 80+i) + t.Log(proxyList[i]) } var wg sync.WaitGroup for i := 0; i < numElection; i++ { - fmt.Println("Starting worker", i) + t.Log("Starting worker", i) wg.Add(1) go startElectionProcess(&wg, numNodes, numVotes, proxyList, t, numElection) @@ -405,7 +57,7 @@ func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing } - fmt.Println("Waiting for workers to finish") + t.Log("Waiting for workers to finish") wg.Wait() } @@ -413,6 +65,7 @@ func testVariableNode(numNodes int, numVotes int, numElection int) func(*testing func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyArray []string, t *testing.T, numElection int) { defer wg.Done() + rand.Seed(0) const contentType = "application/json" secretkeyBuf, err := hex.DecodeString("28912721dfd507e198b31602fb67824856eb5a674c021d49fdccbe52f0234409") @@ -424,7 +77,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA // ###################################### CREATE SIMPLE ELECTION ###### - t.Logf("Create election") + t.Log("Create election") configuration := fake.BasicConfiguration @@ -432,25 +85,27 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA Configuration: configuration, AdminID: "adminId", } - fmt.Println(secret) + signed, err := createSignedRequest(secret, createSimpleElectionRequest) - require.NoError(t, err, "fail to create singature") + require.NoError(t, err, "failed to create signature") + resp, err := http.Post(proxyArray[0]+"/evoting/elections", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) - require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) body, err := io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + require.NoError(t, err, "failed to read the response body: %v", err) t.Log("response body:", string(body)) resp.Body.Close() - var objmap map[string]interface{} + var createElectionResponse ptypes.CreateElectionResponse + + err = json.Unmarshal(body, &createElectionResponse) + require.NoError(t, err, "failed to parse the response body from js: %v", err) + + electionID := createElectionResponse.ElectionID - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parse the body of the response from js: %v", err) - electionID := objmap["ElectionID"].(string) t.Logf("ID of the election : " + electionID) // ##################################### SETUP DKG ######################### @@ -459,9 +114,9 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA for i := 0; i < numNodes; i++ { t.Log("Node" + strconv.Itoa(i)) - fmt.Println(proxyArray[i]) + t.Log(proxyArray[i]) err = initDKG(secret, proxyArray[i], electionID, t) - require.NoError(t, err, "failed to init dkg 1: %v", err) + require.NoError(t, err, "failed to init dkg: %v", err) } t.Log("Setup DKG") @@ -471,8 +126,10 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA } signed, err = createSignedRequest(secret, msg) require.NoError(t, err, "failed to sign: %v", err) + req, err := http.NewRequest(http.MethodPut, proxyArray[0]+"/evoting/services/dkg/actors/"+electionID, bytes.NewBuffer(signed)) require.NoError(t, err, "failed to create request: %v", err) + resp, err = http.DefaultClient.Do(req) require.NoError(t, err, "failed to setup dkg on node 1: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) @@ -488,12 +145,13 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA proxyAddr1 := proxyArray[0] time.Sleep(time.Second * 3) - getElectionInfo(objmap, proxyAddr1, electionID, t) - electionpubkey := objmap["Pubkey"].(string) - electionStatus := int(objmap["Status"].(float64)) - BallotSize := int(objmap["BallotSize"].(float64)) - Chunksperballot := ChunksPerBallotManuel(BallotSize) + getElectionResponse := getElectionInfo(proxyAddr1, electionID, t) + electionpubkey := getElectionResponse.Pubkey + electionStatus := getElectionResponse.Status + BallotSize := getElectionResponse.BallotSize + Chunksperballot := chunksPerBallot(BallotSize) + t.Logf("Publickey of the election : " + electionpubkey) t.Logf("Status of the election : %v", electionStatus) @@ -502,11 +160,10 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Logf("Chunksperballot of the election : %v", Chunksperballot) // Get election public key - pubKey, err := encoding.StringHexToPoint(suite, electionpubkey) require.NoError(t, err, "failed to Unmarshal key: %v", err) - // ##################################### CAST BALLOTS ###################### + // ##################################### CAST BALLOTS ###################### t.Log("cast ballots") //make List of ballots @@ -517,27 +174,34 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA ballotList[i-1] = b1 } - votesfrontend := make([]map[string]interface{}, numVotes) + votesfrontend := make([]types.Ballot, numVotes) fakeConfiguration := fake.BasicConfiguration t.Logf("configuration is: %v", fakeConfiguration) for i := 0; i < numVotes; i++ { - bMarshal, _ := UnmarshalBallotManual(ballotList[i], fakeConfiguration) - ballotByte, _ := json.Marshal(bMarshal) - _ = json.Unmarshal(ballotByte, &votesfrontend[i]) - } - t.Logf("b123_marshal is: %v", votesfrontend) + var bMarshal types.Ballot + election := types.Election{ + Configuration: fakeConfiguration, + ElectionID: electionID, + BallotSize: BallotSize, + } + + err = bMarshal.Unmarshal(ballotList[i], election) + require.NoError(t, err, "failed to unmarshal ballot : %v", err) + + votesfrontend[i] = bMarshal + } for i := 0; i < numVotes; i++ { - t.Logf("1st ballot in str is: %v", ballotList[i]) + t.Logf("ballot in str is: %v", ballotList[i]) ballot, err := marshallBallotManual(ballotList[i], pubKey, Chunksperballot) - t.Logf("1st ballot is: %v", ballot) - require.NoError(t, err, "failed to encrypt ballot : %v", err) + t.Logf("ballot is: %v", ballot) + castVoteRequest := ptypes.CastVoteRequest{ UserID: "user" + strconv.Itoa(i+1), Ballot: ballot, @@ -549,9 +213,11 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Logf("vote is: %v", castVoteRequest) signed, err = createSignedRequest(secret, castVoteRequest) require.NoError(t, err, "failed to sign: %v", err) + resp, err = http.Post(randomproxy+"/evoting/elections/"+electionID+"/vote", contentType, bytes.NewBuffer(signed)) require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status: %s", resp.Status) + body, err = io.ReadAll(resp.Body) require.NoError(t, err, "failed to read the response of castVoteRequest: %v", err) @@ -570,11 +236,11 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA time.Sleep(time.Second * 3) - getElectionInfo(objmap, proxyAddr1, electionID, t) - require.NoError(t, err, "failed to parsethe body of the response from js: %v", err) - electionStatus = int(objmap["Status"].(float64)) + getElectionResponse = getElectionInfo(proxyAddr1, electionID, t) + electionStatus = getElectionResponse.Status + t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 2, electionStatus) + require.Equal(t, uint16(2), electionStatus) // ###################################### SHUFFLE BALLOTS ################## @@ -584,22 +250,19 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA Action: "shuffle", } - //js, err = json.Marshal(shuffleBallotsRequest) signed, err = createSignedRequest(secret, shuffleBallotsRequest) require.NoError(t, err, "failed to set marshall types.SimpleElection : %v", err) randomproxy = proxyArray[rand.Intn(len(proxyArray))] timeTable := make([]float64, 3) - oldTime := time.Now() req, err = http.NewRequest(http.MethodPut, randomproxy+"/evoting/services/shuffle/"+electionID, bytes.NewBuffer(signed)) - require.NoError(t, err, "failed retrieve the decryption from the server: %v", err) require.Equal(t, resp.StatusCode, http.StatusOK, "unexpected status: %s", resp.Status) - resp, err = http.DefaultClient.Do(req) + resp, err = http.DefaultClient.Do(req) require.NoError(t, err, "failed to execute the shuffle query: %v", err) currentTime := time.Now() @@ -608,18 +271,16 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Logf("Shuffle takes: %v sec", diff.Seconds()) body, err = io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + require.NoError(t, err, "failed to read the response body: %v", err) t.Log("Response body: " + string(body)) resp.Body.Close() - //time.Sleep(10 * time.Second) + getElectionResponse = getElectionInfo(proxyAddr1, electionID, t) + electionStatus = getElectionResponse.Status - getElectionInfo(objmap, proxyAddr1, electionID, t) - - electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 3, electionStatus) + require.Equal(t, uint16(3), electionStatus) // ###################################### REQUEST PUBLIC SHARES ############ @@ -639,11 +300,11 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA time.Sleep(10 * time.Second) - getElectionInfo(objmap, proxyAddr1, electionID, t) + getElectionResponse = getElectionInfo(proxyAddr1, electionID, t) + electionStatus = getElectionResponse.Status - electionStatus = int(objmap["Status"].(float64)) t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 4, electionStatus) + require.Equal(t, uint16(4), electionStatus) // ###################################### DECRYPT BALLOTS ################## @@ -661,22 +322,21 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA t.Logf("decryption takes: %v sec", diff.Seconds()) - //time.Sleep(10 * time.Second) - - getElectionInfo(objmap, proxyAddr1, electionID, t) time.Sleep(time.Second * 3) - electionStatus = int(objmap["Status"].(float64)) + getElectionResponse = getElectionInfo(proxyAddr1, electionID, t) + electionStatus = getElectionResponse.Status + t.Logf("Status of the election : %v", electionStatus) - require.Equal(t, 5, electionStatus) + require.Equal(t, uint16(5), electionStatus) //#################################### VALIDATE ELECTION RESULT ############## - tmpBallots := (objmap["Result"]).([]interface{}) - var tmpComp map[string]interface{} + tmpBallots := getElectionResponse.Result var tmpCount bool + for _, ballotIntem := range tmpBallots { - tmpComp = ballotIntem.(map[string]interface{}) + tmpComp := ballotIntem tmpCount = false for _, voteFront := range votesfrontend { t.Logf("voteFront: %v", voteFront) @@ -690,6 +350,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA } } } + require.True(t, tmpCount, "front end votes are different from decrypted votes") t.Logf("shuffle time : %v", timeTable[0]) t.Logf("Public share time : %v", timeTable[1]) @@ -700,7 +361,7 @@ func startElectionProcess(wg *sync.WaitGroup, numNodes int, numVotes int, proxyA // Utility functions func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (ptypes.CiphervoteJSON, error) { - var ballot = make(ptypes.CiphervoteJSON, chunks) + ballot := make(ptypes.CiphervoteJSON, chunks) vote := strings.NewReader(voteStr) fmt.Printf("votestr is: %v", voteStr) @@ -715,7 +376,7 @@ func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (ptype return nil, xerrors.Errorf("failed to read: %v", err) } - K, C, _, err = EncryptManual(buf[:n], pubkey) + K, C, _, err = encryptManual(buf[:n], pubkey) if err != nil { return ptypes.CiphervoteJSON{}, xerrors.Errorf("failed to encrypt the plaintext: %v", err) @@ -740,7 +401,7 @@ func marshallBallotManual(voteStr string, pubkey kyber.Point, chunks int) (ptype return ballot, nil } -func EncryptManual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remainder []byte, err error) { +func encryptManual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remainder []byte, err error) { // Embed the message (or as much of it as will fit) into a curve point. M := suite.Point().Embed(message, random.New()) @@ -758,241 +419,7 @@ func EncryptManual(message []byte, pubkey kyber.Point) (K, C kyber.Point, remain return K, C, remainder, nil } -func ChunksPerBallotManuel(BallotSize int) int { - if BallotSize%29 == 0 { - return BallotSize / 29 - } - - return BallotSize/29 + 1 -} - -// Encode implements serde.FormatEngine -func EncodeCiphervote(ciphervote types.Ciphervote) ([]byte, error) { - - m := make(CiphervoteJSON, len(ciphervote)) - - for i, egpair := range ciphervote { - k, err := egpair.K.MarshalBinary() - if err != nil { - return nil, xerrors.Errorf("failed to marshal k: %v", err) - } - - c, err := egpair.C.MarshalBinary() - if err != nil { - return nil, xerrors.Errorf("failed to marshal c: %v", err) - } - - m[i] = EGPairJSON{ - K: k, - C: c, - } - } - - data, err := json.Marshal(m) - if err != nil { - return nil, xerrors.Errorf("failed to marshal cipher vote json: %v", err) - } - - return data, nil -} - -// CiphervoteJSON is the JSON representation of a ciphervote -type CiphervoteJSON []EGPairJSON - -// EGPairJSON is the JSON representation of an ElGamal pair -type EGPairJSON struct { - K []byte - C []byte -} - -// Unmarshal decodes the given string according to the format described in -// "state of smart contract.md" -func UnmarshalBallotManual(marshalledBallot string, configuration types.Configuration) (types.Ballot, error) { - invalidate := func(b types.Ballot) { - b.RankResultIDs = nil - b.RankResult = nil - b.TextResultIDs = nil - b.TextResult = nil - b.SelectResultIDs = nil - b.SelectResult = nil - } - - var b types.Ballot - BallotSize := configuration.MaxBallotSize() - if len(marshalledBallot) > BallotSize { - invalidate(b) - return b, fmt.Errorf("ballot has an unexpected size %d, expected <= %d", - len(marshalledBallot), BallotSize) - } - - lines := strings.Split(marshalledBallot, "\n") - - b.SelectResultIDs = make([]types.ID, 0) - b.SelectResult = make([][]bool, 0) - - b.RankResultIDs = make([]types.ID, 0) - b.RankResult = make([][]int8, 0) - - b.TextResultIDs = make([]types.ID, 0) - b.TextResult = make([][]string, 0) - - //TODO: Loads of code duplication, can be re-thought - for _, line := range lines { - if line == "" { - // empty line, the valid part of the ballot is over - break - } - - question := strings.Split(line, ":") - - if len(question) != 3 { - invalidate(b) - return b, xerrors.Errorf("a line in the ballot has length != 3: %s", line) - } - - _, err := base64.StdEncoding.DecodeString(question[1]) - if err != nil { - return b, xerrors.Errorf("could not decode question ID: %v", err) - } - questionID := question[1] - - q := configuration.GetQuestion(types.ID(questionID)) - - if q == nil { - invalidate(b) - return b, fmt.Errorf("wrong question ID: the question doesn't exist") - } - - switch question[0] { - - case "select": - selections := strings.Split(question[2], ",") - - if len(selections) != q.GetChoicesLength() { - invalidate(b) - return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ - "", questionID, q.GetChoicesLength(), len(selections)) - } - - b.SelectResultIDs = append(b.SelectResultIDs, types.ID(questionID)) - b.SelectResult = append(b.SelectResult, make([]bool, 0)) - - index := len(b.SelectResult) - 1 - var selected uint = 0 - - for _, selection := range selections { - s, err := strconv.ParseBool(selection) - - if err != nil { - invalidate(b) - return b, fmt.Errorf("could not parse selection value for Q.%s: %v", - questionID, err) - } - - if s { - selected++ - } - - b.SelectResult[index] = append(b.SelectResult[index], s) - } - - if selected > q.GetMaxN() { - invalidate(b) - return b, fmt.Errorf("question %s has too many selected answers", questionID) - } else if selected < q.GetMinN() { - invalidate(b) - return b, fmt.Errorf("question %s has not enough selected answers", questionID) - } - - case "rank": - ranks := strings.Split(question[2], ",") - - if len(ranks) != q.GetChoicesLength() { - invalidate(b) - return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ - "", questionID, q.GetChoicesLength(), len(ranks)) - } - - b.RankResultIDs = append(b.RankResultIDs, types.ID(questionID)) - b.RankResult = append(b.RankResult, make([]int8, 0)) - - index := len(b.RankResult) - 1 - var selected uint = 0 - for _, rank := range ranks { - if len(rank) > 0 { - selected++ - - r, err := strconv.ParseInt(rank, 10, 8) - if err != nil { - invalidate(b) - return b, fmt.Errorf("could not parse rank value for Q.%s : %v", - questionID, err) - } - - if r < 0 || uint(r) >= q.GetMaxN() { - invalidate(b) - return b, fmt.Errorf("invalid rank not in range [0, MaxN[") - } - - b.RankResult[index] = append(b.RankResult[index], int8(r)) - } else { - b.RankResult[index] = append(b.RankResult[index], int8(-1)) - } - } - - if selected > q.GetMaxN() { - invalidate(b) - return b, fmt.Errorf("question %s has too many selected answers", questionID) - } else if selected < q.GetMinN() { - invalidate(b) - return b, fmt.Errorf("question %s has not enough selected answers", questionID) - } - - case "text": - texts := strings.Split(question[2], ",") - - if len(texts) != q.GetChoicesLength() { - invalidate(b) - return b, fmt.Errorf("question %s has a wrong number of answers: expected %d got %d"+ - "", questionID, q.GetChoicesLength(), len(texts)) - } - - b.TextResultIDs = append(b.TextResultIDs, types.ID(questionID)) - b.TextResult = append(b.TextResult, make([]string, 0)) - - index := len(b.TextResult) - 1 - var selected uint = 0 - - for _, text := range texts { - if len(text) > 0 { - selected++ - } - - t, err := base64.StdEncoding.DecodeString(text) - if err != nil { - return b, fmt.Errorf("could not decode text for Q. %s: %v", questionID, err) - } - - b.TextResult[index] = append(b.TextResult[index], string(t)) - } - - if selected > q.GetMaxN() { - invalidate(b) - return b, fmt.Errorf("question %s has too many selected answers", questionID) - } else if selected < q.GetMinN() { - invalidate(b) - return b, fmt.Errorf("question %s has not enough selected answers", questionID) - } - - default: - invalidate(b) - return b, fmt.Errorf("question type is unknown") - } - - } - - return b, nil -} +func chunksPerBallot(size int) int { return (size-1)/29 + 1 } func encodeIDBallot(ID string) types.ID { return types.ID(base64.StdEncoding.EncodeToString([]byte(ID))) @@ -1028,13 +455,14 @@ func createSignedRequest(secret kyber.Scalar, msg interface{}) ([]byte, error) { return signedJSON, nil } + func initDKG(secret kyber.Scalar, proxyAddr, electionIDHex string, t *testing.T) error { setupDKG := ptypes.NewDKGRequest{ ElectionID: electionIDHex, } signed, err := createSignedRequest(secret, setupDKG) - require.NoError(t, err, "fail to create singature") + require.NoError(t, err, "failed to create signature") resp, err := http.Post(proxyAddr+"/evoting/services/dkg/actors", "application/json", bytes.NewBuffer(signed)) if err != nil { @@ -1051,7 +479,7 @@ func updateElection(secret kyber.Scalar, proxyAddr, electionIDHex, action string } signed, err := createSignedRequest(secret, msg) - require.NoError(t, err, "fail to create singature") + require.NoError(t, err, "failed to create signature") req, err := http.NewRequest(http.MethodPut, proxyAddr+"/evoting/elections/"+electionIDHex, bytes.NewBuffer(signed)) if err != nil { @@ -1067,13 +495,14 @@ func updateElection(secret kyber.Scalar, proxyAddr, electionIDHex, action string return 0, nil } + func updateDKG(secret kyber.Scalar, proxyAddr, electionIDHex, action string, t *testing.T) (int, error) { msg := ptypes.UpdateDKG{ Action: action, } signed, err := createSignedRequest(secret, msg) - require.NoError(t, err, "fail to create singature") + require.NoError(t, err, "failed to create signature") req, err := http.NewRequest(http.MethodPut, proxyAddr+"/evoting/services/dkg/actors/"+electionIDHex, bytes.NewBuffer(signed)) if err != nil { @@ -1090,18 +519,20 @@ func updateDKG(secret kyber.Scalar, proxyAddr, electionIDHex, action string, t * return 0, nil } -func getElectionInfo(objmap map[string]interface{}, proxyAddr, electionID string, t *testing.T) { +func getElectionInfo(proxyAddr, electionID string, t *testing.T) ptypes.GetElectionResponse { t.Log("Get election info") - resp, err := http.Get(proxyAddr + "/evoting/elections" + "/" + electionID) + resp, err := http.Get(proxyAddr + "/evoting/elections" + "/" + electionID) require.NoError(t, err, "failed to get the election: %v", err) - body, err := io.ReadAll(resp.Body) - require.NoError(t, err, "failed to read the body of the response: %v", err) + var infoElection ptypes.GetElectionResponse + decoder := json.NewDecoder(resp.Body) + + err = decoder.Decode(&infoElection) + require.NoError(t, err, "failed to decode getInfoElection: %v", err) - t.Log("response body:", string(body)) resp.Body.Close() - err = json.Unmarshal(body, &objmap) - require.NoError(t, err, "failed to parse body of the response from js: %v", err) + + return infoElection } From 099135e39c90fd9ca822fb076c06c1d859da9410 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Mon, 2 May 2022 15:25:56 +0200 Subject: [PATCH 20/68] Adds Icons to result button --- web/frontend/src/components/utils/ResultButton.tsx | 6 +++++- web/frontend/src/pages/election/Show.tsx | 10 ++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/web/frontend/src/components/utils/ResultButton.tsx b/web/frontend/src/components/utils/ResultButton.tsx index 7104dfe31..f230548ac 100644 --- a/web/frontend/src/components/utils/ResultButton.tsx +++ b/web/frontend/src/components/utils/ResultButton.tsx @@ -1,13 +1,17 @@ import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { STATUS } from 'types/election'; +import { ChartSquareBarIcon } from '@heroicons/react/outline'; const ResultButton = ({ status, electionID }) => { const { t } = useTranslation(); return ( status === STATUS.ResultAvailable && ( - +
+
) ); diff --git a/web/frontend/src/pages/election/Show.tsx b/web/frontend/src/pages/election/Show.tsx index 6f3c1a09d..bb4348eab 100644 --- a/web/frontend/src/pages/election/Show.tsx +++ b/web/frontend/src/pages/election/Show.tsx @@ -7,7 +7,6 @@ import useElection from 'components/utils/useElection'; import './Show.css'; import useGetResults from 'components/utils/useGetResults'; import { STATUS } from 'types/election'; -import Status from './components/Status'; import Action from './components/Action'; import StatusTimeline from './components/StatusTimeline'; @@ -40,15 +39,14 @@ const ElectionShow: FC = () => {

Election ID : {electionId}

-
Workflow
+
{t('status')}
-
- {t('status')}: +
-
-
{t('action')}
+
+
{t('action')}
Date: Mon, 2 May 2022 15:38:09 +0200 Subject: [PATCH 21/68] Adds Icons to rest of actions buttons --- web/frontend/src/components/utils/CancelButton.tsx | 11 ++++++++++- web/frontend/src/components/utils/CloseButton.tsx | 11 ++++++++++- web/frontend/src/components/utils/DecryptButton.tsx | 8 +++++++- web/frontend/src/components/utils/ShuffleButton.tsx | 8 +++++++- web/frontend/src/components/utils/VoteButton.tsx | 8 +++++++- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/web/frontend/src/components/utils/CancelButton.tsx b/web/frontend/src/components/utils/CancelButton.tsx index 1cdef1259..00736720e 100644 --- a/web/frontend/src/components/utils/CancelButton.tsx +++ b/web/frontend/src/components/utils/CancelButton.tsx @@ -1,3 +1,4 @@ +import { XIcon } from '@heroicons/react/outline'; import { AuthContext } from 'index'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,7 +11,15 @@ const CancelButton = ({ status, handleCancel }) => { const isAuthorized = authCtx.role === 'admin' || authCtx.role === 'operator'; return ( - isAuthorized && status === STATUS.Open && + isAuthorized && + status === STATUS.Open && ( + + ) ); }; export default CancelButton; diff --git a/web/frontend/src/components/utils/CloseButton.tsx b/web/frontend/src/components/utils/CloseButton.tsx index 7e3130185..b8920c509 100644 --- a/web/frontend/src/components/utils/CloseButton.tsx +++ b/web/frontend/src/components/utils/CloseButton.tsx @@ -1,3 +1,4 @@ +import { LockClosedIcon } from '@heroicons/react/outline'; import { AuthContext } from 'index'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -11,7 +12,15 @@ const CloseButton = ({ status, handleClose }) => { const isAuthorized = authCtx.role === ROLE.Admin || authCtx.role === ROLE.Operator; return ( - isAuthorized && status === STATUS.Open && + isAuthorized && + status === STATUS.Open && ( + + ) ); }; export default CloseButton; diff --git a/web/frontend/src/components/utils/DecryptButton.tsx b/web/frontend/src/components/utils/DecryptButton.tsx index 14866cbea..6dd3c7314 100644 --- a/web/frontend/src/components/utils/DecryptButton.tsx +++ b/web/frontend/src/components/utils/DecryptButton.tsx @@ -1,3 +1,4 @@ +import { KeyIcon } from '@heroicons/react/outline'; import { AuthContext } from 'index'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -17,7 +18,12 @@ const DecryptButton = ({ status, isDecrypting, handleDecrypt }) => {

{t('statusOnGoingDecryption')}

) : ( - + )) ); diff --git a/web/frontend/src/components/utils/ShuffleButton.tsx b/web/frontend/src/components/utils/ShuffleButton.tsx index 66797dc49..5581b319e 100644 --- a/web/frontend/src/components/utils/ShuffleButton.tsx +++ b/web/frontend/src/components/utils/ShuffleButton.tsx @@ -1,3 +1,4 @@ +import { EyeOffIcon } from '@heroicons/react/outline'; import { AuthContext } from 'index'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -17,7 +18,12 @@ const ShuffleButton = ({ status, isShuffling, handleShuffle }) => {

{t('statusOnGoingShuffle')}

) : ( - + )) ); diff --git a/web/frontend/src/components/utils/VoteButton.tsx b/web/frontend/src/components/utils/VoteButton.tsx index f8fc496e1..d5b9261fc 100644 --- a/web/frontend/src/components/utils/VoteButton.tsx +++ b/web/frontend/src/components/utils/VoteButton.tsx @@ -1,3 +1,4 @@ +import { PencilAltIcon } from '@heroicons/react/outline'; import { AuthContext } from 'index'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -18,7 +19,12 @@ const VoteButton = ({ status, electionID }) => { status === STATUS.Open && authCtx.isLogged && ( - + ) ); From be823af3d8a72d3a7be8a15350642801f4d6758f Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 08:14:55 +0200 Subject: [PATCH 22/68] Adds translation support for StatusTimeline --- .../election/components/StatusTimeline.tsx | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx index 7ce83469a..7446ea802 100644 --- a/web/frontend/src/pages/election/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -1,5 +1,6 @@ import { AuthContext } from 'index'; import { FC, useContext } from 'react'; +import { useTranslation } from 'react-i18next'; import { STATUS } from 'types/election'; import { ROLE } from 'types/userRole'; @@ -11,28 +12,29 @@ const CanceledStep = { name: 'Canceled', state: 'upcoming', status: STATUS.Cance const StatusTimeline: FC = ({ status }) => { const authCtx = useContext(AuthContext); + const { t } = useTranslation(); const completeSteps = [ - { name: 'Initial', state: 'complete', status: STATUS.Initial }, - { name: 'Initialized', state: 'current', status: STATUS.InitializedNodes }, - { name: 'On Going Setup', state: 'upcoming', status: STATUS.Setup }, - { name: 'Setup', state: 'upcoming', status: STATUS.Setup }, - { name: 'Open', state: 'upcoming', status: STATUS.Open }, - { name: 'Closed', state: 'upcoming', status: STATUS.Closed }, - { name: 'On Going Shuffle', state: 'upcoming', status: STATUS.OnGoingShuffle }, - { name: 'Shuffled Ballots', state: 'upcoming', status: STATUS.ShuffledBallots }, - { name: 'On Going Decryption', state: 'upcoming', status: STATUS.OnGoingDecryption }, - { name: 'Decrypted Ballots', state: 'upcoming', status: STATUS.DecryptedBallots }, - { name: 'Result Available', state: 'upcoming', status: STATUS.ResultAvailable }, + { name: 'statusInitial', state: 'complete', status: STATUS.Initial }, + { name: 'statusInitializedNodes', state: 'current', status: STATUS.InitializedNodes }, + { name: 'statusOnGoingSetup', state: 'upcoming', status: STATUS.Setup }, + { name: 'statusSetup', state: 'upcoming', status: STATUS.Setup }, + { name: 'statusOpen', state: 'upcoming', status: STATUS.Open }, + { name: 'statusClose', state: 'upcoming', status: STATUS.Closed }, + { name: 'statusOnGoingShuffle', state: 'upcoming', status: STATUS.OnGoingShuffle }, + { name: 'statusShuffle', state: 'upcoming', status: STATUS.ShuffledBallots }, + { name: 'statusOnGoingDecryption', state: 'upcoming', status: STATUS.OnGoingDecryption }, + { name: 'statusDecrypted', state: 'upcoming', status: STATUS.DecryptedBallots }, + { name: 'statusResultAvailable', state: 'upcoming', status: STATUS.ResultAvailable }, ]; const simpleSteps = [ - { name: 'Initial', state: 'complete', status: STATUS.Initial }, - { name: 'Open', state: 'current', status: STATUS.Open }, - { name: 'Closed', state: 'upcoming', status: STATUS.Closed }, - { name: 'Shuffled Ballots', state: 'upcoming', status: STATUS.ShuffledBallots }, - { name: 'Decrypted Ballots', state: 'upcoming', status: STATUS.DecryptedBallots }, - { name: 'Result Available', state: 'upcoming', status: STATUS.ResultAvailable }, + { name: 'statusInitial', state: 'complete', status: STATUS.Initial }, + { name: 'statusOpen', state: 'current', status: STATUS.Open }, + { name: 'statusClose', state: 'upcoming', status: STATUS.Closed }, + { name: 'statusShuffle', state: 'upcoming', status: STATUS.ShuffledBallots }, + { name: 'statusDecrypted', state: 'upcoming', status: STATUS.DecryptedBallots }, + { name: 'statusResultAvailable', state: 'upcoming', status: STATUS.ResultAvailable }, ]; const steps = @@ -54,35 +56,29 @@ const StatusTimeline: FC = ({ status }) => { switch (state) { case 'complete': return ( - <> -
- - {name} - -
- +
+ + {t(name)} + +
); case 'current': return ( - <> -
- - {name} - -
- +
+ + {t(name)} + +
); default: return ( - <> -
- - {name} - -
- +
+ + {t(name)} + +
); } }; From 563eaea3cb75c616061b6f025babf3d75d6e4d3c Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 08:19:11 +0200 Subject: [PATCH 23/68] Removes unused state key in StatusTimeline --- .../election/components/StatusTimeline.tsx | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx index 7446ea802..09fc687f8 100644 --- a/web/frontend/src/pages/election/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -8,33 +8,33 @@ type StatusTimelineProps = { status: STATUS; }; -const CanceledStep = { name: 'Canceled', state: 'upcoming', status: STATUS.Canceled }; +const CanceledStep = { name: 'Canceled', status: STATUS.Canceled }; const StatusTimeline: FC = ({ status }) => { const authCtx = useContext(AuthContext); const { t } = useTranslation(); const completeSteps = [ - { name: 'statusInitial', state: 'complete', status: STATUS.Initial }, - { name: 'statusInitializedNodes', state: 'current', status: STATUS.InitializedNodes }, - { name: 'statusOnGoingSetup', state: 'upcoming', status: STATUS.Setup }, - { name: 'statusSetup', state: 'upcoming', status: STATUS.Setup }, - { name: 'statusOpen', state: 'upcoming', status: STATUS.Open }, - { name: 'statusClose', state: 'upcoming', status: STATUS.Closed }, - { name: 'statusOnGoingShuffle', state: 'upcoming', status: STATUS.OnGoingShuffle }, - { name: 'statusShuffle', state: 'upcoming', status: STATUS.ShuffledBallots }, - { name: 'statusOnGoingDecryption', state: 'upcoming', status: STATUS.OnGoingDecryption }, - { name: 'statusDecrypted', state: 'upcoming', status: STATUS.DecryptedBallots }, - { name: 'statusResultAvailable', state: 'upcoming', status: STATUS.ResultAvailable }, + { name: 'statusInitial', status: STATUS.Initial }, + { name: 'statusInitializedNodes', status: STATUS.InitializedNodes }, + { name: 'statusOnGoingSetup', status: STATUS.Setup }, + { name: 'statusSetup', status: STATUS.Setup }, + { name: 'statusOpen', status: STATUS.Open }, + { name: 'statusClose', status: STATUS.Closed }, + { name: 'statusOnGoingShuffle', status: STATUS.OnGoingShuffle }, + { name: 'statusShuffle', status: STATUS.ShuffledBallots }, + { name: 'statusOnGoingDecryption', status: STATUS.OnGoingDecryption }, + { name: 'statusDecrypted', status: STATUS.DecryptedBallots }, + { name: 'statusResultAvailable', status: STATUS.ResultAvailable }, ]; const simpleSteps = [ - { name: 'statusInitial', state: 'complete', status: STATUS.Initial }, - { name: 'statusOpen', state: 'current', status: STATUS.Open }, - { name: 'statusClose', state: 'upcoming', status: STATUS.Closed }, - { name: 'statusShuffle', state: 'upcoming', status: STATUS.ShuffledBallots }, - { name: 'statusDecrypted', state: 'upcoming', status: STATUS.DecryptedBallots }, - { name: 'statusResultAvailable', state: 'upcoming', status: STATUS.ResultAvailable }, + { name: 'statusInitial', status: STATUS.Initial }, + { name: 'statusOpen', status: STATUS.Open }, + { name: 'statusClose', status: STATUS.Closed }, + { name: 'statusShuffle', status: STATUS.ShuffledBallots }, + { name: 'statusDecrypted', status: STATUS.DecryptedBallots }, + { name: 'statusResultAvailable', status: STATUS.ResultAvailable }, ]; const steps = From 583ab330e10ad389d75adcd708669cfe69fa78c6 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 08:39:45 +0200 Subject: [PATCH 24/68] Changes Action Modal --- .../src/components/modal/ConfirmModal.tsx | 93 ++++++++++++++----- web/frontend/src/language/en.json | 1 + .../election/components/StatusTimeline.tsx | 3 +- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/web/frontend/src/components/modal/ConfirmModal.tsx b/web/frontend/src/components/modal/ConfirmModal.tsx index c3795a266..ae019ce74 100644 --- a/web/frontend/src/components/modal/ConfirmModal.tsx +++ b/web/frontend/src/components/modal/ConfirmModal.tsx @@ -1,7 +1,10 @@ -import React, { FC } from 'react'; +import React, { FC, Fragment, useRef } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; +import { Dialog, Transition } from '@headlessui/react'; +import { ExclamationIcon } from '@heroicons/react/outline'; + type ConfirmModalProps = { showModal: boolean; setShowModal: (prev: boolean) => void; @@ -16,41 +19,85 @@ const ConfirmModal: FC = ({ setUserConfirmedAction, }) => { const { t } = useTranslation(); + const cancelButtonRef = useRef(null); const closeModal = () => { setShowModal(false); }; - const validateChoice = () => { + const confirmChoice = () => { setUserConfirmedAction(true); closeModal(); }; - const displayButtons = () => { + const Modal = () => { return ( -
- - -
+ + +
+ + + + + {/* This element is to trick the browser into centering the modal contents. */} + + +
+
+
+
+
+
+ + {t('actionChange')} + +
+

{textModal}

+
+
+
+
+
+ + +
+
+
+
+
+
); }; - return ( -
- {showModal ? ( -
-
-
{textModal}
-
{displayButtons()}
-
-
- ) : null} -
- ); + return
{showModal ? : null}
; }; ConfirmModal.propTypes = { diff --git a/web/frontend/src/language/en.json b/web/frontend/src/language/en.json index 525288150..fd81d204f 100644 --- a/web/frontend/src/language/en.json +++ b/web/frontend/src/language/en.json @@ -77,6 +77,7 @@ "voteSuccess": "Your vote was successfully submitted!", "voteSuccessful": "Vote successful", "errorTitle": "Error", + "actionChange": "Action Change", "voteFailure": "Your ballot hasn't been taken into account. It might be that the election has been closed or cancelled. Try refreshing the page.", "ballotFailure": "An error seemed to have occurred while sending your ballot. Please contact the administrator of this website", "incompleteBallot": "Some answers are not complete.", diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx index 09fc687f8..dd4befb66 100644 --- a/web/frontend/src/pages/election/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -41,7 +41,7 @@ const StatusTimeline: FC = ({ status }) => { authCtx.role === ROLE.Admin || authCtx.role === ROLE.Operator ? completeSteps : simpleSteps; // If the status is Canceled we need to add the Canceled step to the steps - // array at the correct position in the workflow (after the Open step) + // array at the correct position in the workflow (before the Closed step) if (status === STATUS.Canceled) { steps.splice( steps.findIndex((step) => step.status === STATUS.Closed), @@ -50,6 +50,7 @@ const StatusTimeline: FC = ({ status }) => { ); } + // Find the current step in the steps array (the status) const currentStep = steps.findIndex((step) => step.status === status); const DisplayStatus = ({ state, name }) => { From 4fa86f6f9f5a285200d0866157388d330eaa8a07 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 08:52:40 +0200 Subject: [PATCH 25/68] Removes Ballots Show page --- web/frontend/src/Routes.ts | 1 - .../src/components/modal/ConfirmModal.tsx | 2 +- .../src/components/utils/VoteButton.tsx | 2 +- web/frontend/src/language/en.json | 2 +- web/frontend/src/layout/App.tsx | 3 -- web/frontend/src/layout/NavBar.tsx | 18 ----------- web/frontend/src/mocks/mockData.ts | 5 +--- web/frontend/src/pages/ballot/Index.css | 30 ------------------- web/frontend/src/pages/ballot/Index.tsx | 24 --------------- web/frontend/src/pages/ballot/Show.tsx | 4 +-- 10 files changed, 6 insertions(+), 85 deletions(-) delete mode 100644 web/frontend/src/pages/ballot/Index.css delete mode 100644 web/frontend/src/pages/ballot/Index.tsx diff --git a/web/frontend/src/Routes.ts b/web/frontend/src/Routes.ts index 15de5a661..09b3f9e36 100644 --- a/web/frontend/src/Routes.ts +++ b/web/frontend/src/Routes.ts @@ -9,6 +9,5 @@ export const ROUTE_ELECTION_CREATE = '/election/create'; export const ROUTE_ELECTION_SHOW = '/elections/:electionID'; export const ROUTE_ELECTION_RESULT = '/elections/:electionID/result'; -export const ROUTE_BALLOT_INDEX = '/ballot/index'; export const ROUTE_BALLOT_CAST = '/ballot/cast'; export const ROUTE_BALLOT_SHOW = '/ballot/show'; diff --git a/web/frontend/src/components/modal/ConfirmModal.tsx b/web/frontend/src/components/modal/ConfirmModal.tsx index ae019ce74..c157928f1 100644 --- a/web/frontend/src/components/modal/ConfirmModal.tsx +++ b/web/frontend/src/components/modal/ConfirmModal.tsx @@ -1,4 +1,4 @@ -import React, { FC, Fragment, useRef } from 'react'; +import { FC, Fragment, useRef } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; diff --git a/web/frontend/src/components/utils/VoteButton.tsx b/web/frontend/src/components/utils/VoteButton.tsx index d5b9261fc..af0597966 100644 --- a/web/frontend/src/components/utils/VoteButton.tsx +++ b/web/frontend/src/components/utils/VoteButton.tsx @@ -22,7 +22,7 @@ const VoteButton = ({ status, electionID }) => { diff --git a/web/frontend/src/language/en.json b/web/frontend/src/language/en.json index fd81d204f..1d202637b 100644 --- a/web/frontend/src/language/en.json +++ b/web/frontend/src/language/en.json @@ -4,7 +4,7 @@ "navBarHome": "Home", "navBarStatus": "Elections", "navBarCreate": "Create", - "navBarVote": "Vote", + "vote": "Vote", "navBarResult": "Results", "navBarAbout": "About", "navBarAdmin": "Admin", diff --git a/web/frontend/src/layout/App.tsx b/web/frontend/src/layout/App.tsx index f6a9af142..bbe230b2e 100644 --- a/web/frontend/src/layout/App.tsx +++ b/web/frontend/src/layout/App.tsx @@ -4,7 +4,6 @@ import { Navigate, Route, BrowserRouter as Router, Routes, useLocation } from 'r import { ROUTE_ABOUT, ROUTE_ADMIN, - ROUTE_BALLOT_INDEX, ROUTE_BALLOT_SHOW, ROUTE_ELECTION_CREATE, ROUTE_ELECTION_INDEX, @@ -19,7 +18,6 @@ import ElectionIndex from '../pages/election/Index'; import ElectionCreate from '../pages/election/New'; import ElectionResult from '../pages/election/Result'; import ElectionShow from '../pages/election/Show'; -import BallotIndex from '../pages/ballot/Index'; import BallotShow from '../pages/ballot/Show'; import NavBar from './NavBar'; import Footer from './Footer'; @@ -65,7 +63,6 @@ const App = () => { /> } /> } /> - } /> ( } - {authCtx.isLogged && ( - - - - {t('navBarVote')} - - - - )} {authCtx.isLogged && (authCtx.role === 'admin' || authCtx.role === 'operator') && ( @@ -187,14 +177,6 @@ const LeftSideNavBar = ({ authCtx, t }) => ( className={'text-black text-lg hover:text-indigo-700'}> {t('navBarStatus')} - {authCtx.isLogged && (authCtx.role === 'admin' || authCtx.role === 'operator') && ( - - {t('navBarVote')} - - )} {authCtx.role === 'admin' && authCtx.isLogged && ( Admin diff --git a/web/frontend/src/mocks/mockData.ts b/web/frontend/src/mocks/mockData.ts index 885d5748c..b2897e12f 100644 --- a/web/frontend/src/mocks/mockData.ts +++ b/web/frontend/src/mocks/mockData.ts @@ -151,10 +151,7 @@ const mockElection2: any = { ID: (0xbeef).toString(), MaxN: 2, MinN: 1, - Choices: [ - 'INNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN', - 'SC', - ], + Choices: ['IN', 'SC'], }, ], Texts: [], diff --git a/web/frontend/src/pages/ballot/Index.css b/web/frontend/src/pages/ballot/Index.css deleted file mode 100644 index 765b28283..000000000 --- a/web/frontend/src/pages/ballot/Index.css +++ /dev/null @@ -1,30 +0,0 @@ -.vote-allowed { - padding-bottom: 3%; -} -.cast-ballot { - padding: 3%; - background-color: #f6f6fa; -} - -.ballot-indication { - padding-bottom: 2%; -} - -.cast-ballot-card { - padding: 0.5%; - background-color: #f6f6fa; - outline-style: solid; - outline-width: 1px; - outline-color: #ececf0; -} - -.cast-ballot-btn { - align-content: center; - border-radius: 8px; - cursor: pointer; -} - -.past-vote { - padding-top: 1%; - font-size: small; -} diff --git a/web/frontend/src/pages/ballot/Index.tsx b/web/frontend/src/pages/ballot/Index.tsx deleted file mode 100644 index 082afede8..000000000 --- a/web/frontend/src/pages/ballot/Index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { FC } from 'react'; -import { useTranslation } from 'react-i18next'; - -import SimpleTable from 'pages/election/components/SimpleTable'; -import './Index.css'; -import { ROUTE_BALLOT_SHOW } from 'Routes'; -import { STATUS } from 'types/election'; - -const BallotIndex: FC = () => { - const { t } = useTranslation(); - - return ( -
- -
- ); -}; - -export default BallotIndex; diff --git a/web/frontend/src/pages/ballot/Show.tsx b/web/frontend/src/pages/ballot/Show.tsx index 8bf5f1008..c51f4730a 100644 --- a/web/frontend/src/pages/ballot/Show.tsx +++ b/web/frontend/src/pages/ballot/Show.tsx @@ -6,7 +6,7 @@ import kyber from '@dedis/kyber'; import PropTypes from 'prop-types'; import { Buffer } from 'buffer'; -import { ROUTE_BALLOT_INDEX } from '../../Routes'; +import { ROUTE_ELECTION_INDEX } from '../../Routes'; import useElection from 'components/utils/useElection'; import usePostCall from 'components/utils/usePostCall'; import * as endpoints from 'components/utils/Endpoints'; @@ -179,7 +179,7 @@ const Ballot: FC = () => { return (
{t('voteImpossible')}
- + +
+
+

+ {t('admin')} +

+
+
{t('adminDetails')}
+
+
+
+ + + +
-
- - +
+
+ @@ -106,7 +118,7 @@ const Admin = () => {
handleDelete(user.sciper)}> - Delete + {t('delete')}
@@ -118,11 +130,11 @@ const Admin = () => { aria-label="Pagination">

- Showing {pageIndex + 1} to{' '} + {t('showing')} {pageIndex + 1} /{' '} {partitionArray(users, SCIPERS_PER_PAGE).length} {' '} - of {users.length} results + {t('of')} {users.length} {t('results')}

@@ -130,13 +142,13 @@ const Admin = () => { disabled={pageIndex === 0} onClick={handlePrevious} className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"> - Previous + {t('previous')}
diff --git a/web/frontend/src/pages/Home.css b/web/frontend/src/pages/Home.css deleted file mode 100644 index 76fc3469b..000000000 --- a/web/frontend/src/pages/Home.css +++ /dev/null @@ -1,28 +0,0 @@ -.home { - padding-bottom: 5%; -} - -h1 { - text-align: center; -} -.home-txt { - text-align: left; -} - -.signin-admin-btn { - display: block; - margin-top: 10px; - border-radius: 8px; - cursor: pointer; - width: 200px; - height: 30px; -} - -.signin-voter-btn { - display: block; - margin-top: 10px; - border-radius: 8px; - cursor: pointer; - width: 200px; - height: 30px; -} diff --git a/web/frontend/src/pages/Home.tsx b/web/frontend/src/pages/Home.tsx index 630e1e683..98bba83ed 100644 --- a/web/frontend/src/pages/Home.tsx +++ b/web/frontend/src/pages/Home.tsx @@ -2,19 +2,17 @@ import { FlashContext, FlashLevel } from 'index'; import React, { FC, useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import './Home.css'; - const Home: FC = () => { const { t } = useTranslation(); const fctx = useContext(FlashContext); return ( -
+

{t('homeTitle')}

-
{t('homeText')}
+
{t('homeText')}
+ + ) + ); +}; + +export default CombineButton; diff --git a/web/frontend/src/components/utils/Endpoints.tsx b/web/frontend/src/components/utils/Endpoints.tsx index c28d97a73..24c052ba6 100644 --- a/web/frontend/src/components/utils/Endpoints.tsx +++ b/web/frontend/src/components/utils/Endpoints.tsx @@ -9,9 +9,10 @@ export const ENDPOINT_REMOVE_ROLE = '/api/remove_role'; export const newElection = '/api/evoting/elections'; export const editElection = (ElectionID: string) => `/api/evoting/elections/${ElectionID}`; export const newElectionVote = (ElectionID: string) => `/api/evoting/elections/${ElectionID}/vote`; -export const editShuffle = (ElectionID: string) => `/evoting/services/shuffle/${ElectionID}`; +export const editShuffle = (ElectionID: string) => `/api/evoting/services/shuffle/${ElectionID}`; // Decrypt -export const editDKGActors = (ElectionID: string) => `/evoting/services/dkg/actors/${ElectionID}`; +export const editDKGActors = (ElectionID: string) => + `/api/evoting/services/dkg/actors/${ElectionID}`; // public information can be directly fetched from dela nodes export const election = (ElectionID: string) => diff --git a/web/frontend/src/components/utils/useChangeAction.tsx b/web/frontend/src/components/utils/useChangeAction.tsx index 9d12d547e..edacde48a 100644 --- a/web/frontend/src/components/utils/useChangeAction.tsx +++ b/web/frontend/src/components/utils/useChangeAction.tsx @@ -12,6 +12,7 @@ import OpenButton from './OpenButton'; import DecryptButton from './DecryptButton'; import ResultButton from './ResultButton'; import VoteButton from './VoteButton'; +import CombineButton from './CombineButton'; const useChangeAction = ( status: STATUS, @@ -159,15 +160,15 @@ const useChangeAction = ( const handleDecrypt = async () => { const decryptSuccess = await electionUpdate( - 'beginDecryption', + 'computePubshares', endpoints.editDKGActors(electionID.toString()) ); if (decryptSuccess && postError === null) { // TODO : setResultAvailable is undefined when the decryption is clicked - if (setResultAvailable !== null && setResultAvailable !== undefined) { - setResultAvailable(true); - } - setStatus(STATUS.ResultAvailable); + // if (setResultAvailable !== null && setResultAvailable !== undefined) { + // setResultAvailable(true); + // } + setStatus(STATUS.DecryptedBallots); } else { setShowModalError(true); setIsDecrypting(false); @@ -175,6 +176,20 @@ const useChangeAction = ( setPostError(null); }; + const handleCombine = async () => { + const combineSuccess = await electionUpdate( + 'combineShares', + endpoints.editElection(electionID.toString()) + ); + if (combineSuccess && postError === null) { + setStatus(STATUS.ResultAvailable); + } else { + setShowModalError(true); + setIsOpening(false); + } + setPostError(null); + }; + const getAction = () => { switch (status) { case STATUS.Initial: @@ -212,6 +227,12 @@ const useChangeAction = ( /> ); + case STATUS.DecryptedBallots: + return ( + + + + ); case STATUS.ResultAvailable: return ( diff --git a/web/frontend/src/mocks/handlers.ts b/web/frontend/src/mocks/handlers.ts index 27add4ae1..b1fe798f4 100644 --- a/web/frontend/src/mocks/handlers.ts +++ b/web/frontend/src/mocks/handlers.ts @@ -117,7 +117,7 @@ export const handlers = [ }), rest.post(endpoints.newElectionVote(':ElectionID'), async (req, res, ctx) => { - const { Ballot }: NewElectionVoteBody = JSON.parse(req.body.toString()); + const { Ballot }: NewElectionVoteBody = req.body as NewElectionVoteBody; await new Promise((r) => setTimeout(r, 1000)); return res( diff --git a/web/frontend/src/pages/ballot/Show.tsx b/web/frontend/src/pages/ballot/Show.tsx index c51f4730a..d65a20751 100644 --- a/web/frontend/src/pages/ballot/Show.tsx +++ b/web/frontend/src/pages/ballot/Show.tsx @@ -90,6 +90,9 @@ const Ballot: FC = () => { const newRequest = { method: 'POST', body: JSON.stringify(ballot), + headers: { + 'Content-Type': 'Application/json', + }, }; setPostRequest(newRequest); } catch (e) { From 65a4f667a939dd1553c7119ae0f238bb4a239aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mien=20Kocher?= Date: Tue, 3 May 2022 14:21:17 +0200 Subject: [PATCH 32/68] Updates the API spec for 'computePubshares' --- docs/api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api.md b/docs/api.md index 0d0e4f958..eae988f4c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -48,7 +48,7 @@ SC5:Close │ │ │ │ NS2:Shuffle │ │ │ ▼ - │ DK4:BeginDecryption + │ DK4:ComputePubshares │ ▼ SC6:CombineShares @@ -370,7 +370,7 @@ Return: ```json { - "Action": "beginDecryption" + "Action": "computePubshares" } ``` From 0a4f404c9e04cd7e35b2b00b0d9defb7f7157a39 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 15:12:19 +0200 Subject: [PATCH 33/68] Changes Vote Impossible page --- web/frontend/src/language/en.json | 7 +++- web/frontend/src/layout/NotFound.tsx | 11 ++++--- web/frontend/src/pages/Admin.tsx | 2 +- web/frontend/src/pages/ballot/Show.tsx | 3 +- .../ballot/components/ElectionClosed.tsx | 33 +++++++++++++++++++ 5 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 web/frontend/src/pages/ballot/components/ElectionClosed.tsx diff --git a/web/frontend/src/language/en.json b/web/frontend/src/language/en.json index 168b1491a..c23ce8a57 100644 --- a/web/frontend/src/language/en.json +++ b/web/frontend/src/language/en.json @@ -11,6 +11,9 @@ "admin": "Admin", "previous": "Previous", "next": "Next", + "notFound": "Page not found", + "notFoundDescription": "The page you are looking for does not exist.", + "notFoundLink": "Go to home page", "results": "results", "showing": "Showing", "adminDetails": "Add or remove roles of users from the admin table", @@ -115,7 +118,9 @@ "notEnoughBallot": "The operation failed because less than two ballots have been casted.", "operationFailure": "The operation failed. Try refreshing the page.", "shuffleFail": "The shuffle operation failed.", - "voteImpossible": "The election is not open for voting anymore.", + "voteImpossible": "Vote Impossible", + "notFoundVoteImpossible": "Go back to election table", + "voteImpossibleDescription": "The election is not open for voting anymore.", "yes": "Yes", "no": "No", "download": "Export results in JSON format", diff --git a/web/frontend/src/layout/NotFound.tsx b/web/frontend/src/layout/NotFound.tsx index cda419952..e37b34913 100644 --- a/web/frontend/src/layout/NotFound.tsx +++ b/web/frontend/src/layout/NotFound.tsx @@ -1,7 +1,10 @@ +import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { ROUTE_HOME } from 'Routes'; export default function NotFound() { + const { t } = useTranslation(); + return (
@@ -11,17 +14,15 @@ export default function NotFound() {

- Page not found + {t('notFound')}

-

- Please check the URL in the address bar and try again. -

+

{t('notFoundDescription')}

- Go back home + {t('notFoundLink')}
diff --git a/web/frontend/src/pages/Admin.tsx b/web/frontend/src/pages/Admin.tsx index 04d75dc9e..c63697b5c 100644 --- a/web/frontend/src/pages/Admin.tsx +++ b/web/frontend/src/pages/Admin.tsx @@ -32,7 +32,7 @@ const Admin = () => { .catch((error) => { console.log(error); }); - }, [showDeleteModal]); + }, [showDeleteModal, newusrOpen]); const partitionArray = (array: any[], size: number) => array.map((v, i) => (i % size === 0 ? array.slice(i, i + size) : null)).filter((v) => v); diff --git a/web/frontend/src/pages/ballot/Show.tsx b/web/frontend/src/pages/ballot/Show.tsx index 80379bc3e..8e705e2da 100644 --- a/web/frontend/src/pages/ballot/Show.tsx +++ b/web/frontend/src/pages/ballot/Show.tsx @@ -22,6 +22,7 @@ import Rank, { handleOnDragEnd } from './components/Rank'; import Text from './components/Text'; import { ballotIsValid } from './components/ValidateAnswers'; import { STATUS } from 'types/election'; +import ElectionClosed from './components/ElectionClosed'; const Ballot: FC = () => { const { t } = useTranslation(); @@ -204,7 +205,7 @@ const Ballot: FC = () => { {loading ? (

{t('loading')}

) : ( -
{status === STATUS.Open ? ballotDisplay() : electionClosedDisplay()}
+
{status === STATUS.Open ? ballotDisplay() : }
)}
); diff --git a/web/frontend/src/pages/ballot/components/ElectionClosed.tsx b/web/frontend/src/pages/ballot/components/ElectionClosed.tsx new file mode 100644 index 000000000..bb6c25ee0 --- /dev/null +++ b/web/frontend/src/pages/ballot/components/ElectionClosed.tsx @@ -0,0 +1,33 @@ +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import { ROUTE_ELECTION_INDEX } from 'Routes'; + +export default function ElectionClosed() { + const { t } = useTranslation(); + + return ( +
+
+
+
+
+
+

+ {t('voteImpossible')} +

+

{t('voteImpossibleDescription')}

+
+
+ + {t('notFoundVoteImpossible')} + +
+
+
+
+
+
+ ); +} From 281f36718892d71570da070969a4a91756c5d958 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 16:10:09 +0200 Subject: [PATCH 34/68] Changes modal of add user in Admin page --- .../components/modal/AddAdminUserModal.tsx | 191 ++++++++++++------ web/frontend/src/language/en.json | 1 + .../election/components/ElectionForm.tsx | 4 +- 3 files changed, 135 insertions(+), 61 deletions(-) diff --git a/web/frontend/src/components/modal/AddAdminUserModal.tsx b/web/frontend/src/components/modal/AddAdminUserModal.tsx index 5ad2891da..4c9583a4a 100644 --- a/web/frontend/src/components/modal/AddAdminUserModal.tsx +++ b/web/frontend/src/components/modal/AddAdminUserModal.tsx @@ -1,16 +1,12 @@ -import React, { FC, useState } from 'react'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import Typography from '@mui/material/Typography'; -import Modal from '@mui/material/Modal'; -import Input from '@mui/material/Input'; -import InputLabel from '@mui/material/InputLabel'; -import MenuItem from '@mui/material/MenuItem'; -import FormControl from '@mui/material/FormControl'; -import Select from '@mui/material/Select'; +import React, { FC, Fragment, useRef, useState } from 'react'; import PropTypes from 'prop-types'; +import { Dialog, Listbox, Transition } from '@headlessui/react'; +import { CheckIcon, SelectorIcon } from '@heroicons/react/solid'; import { ENDPOINT_ADD_ROLE } from 'components/utils/Endpoints'; +import { useTranslation } from 'react-i18next'; +import SpinnerIcon from 'components/utils/SpinnerIcon'; +import { UserAddIcon } from '@heroicons/react/outline'; const style = { position: 'absolute', @@ -29,29 +25,29 @@ type AddAdminUserModalProps = { setOpen(opened: boolean): void; }; -const AddAdminUserModal: FC = ({ open, setOpen }) => { - const handleClose = () => setOpen(false); - const ariaLabel = { 'aria-label': 'description' }; +const roles = ['Admin', 'Operator']; +const AddAdminUserModal: FC = ({ open, setOpen }) => { + const { t } = useTranslation(); + const [loading, setLoading] = useState(false); const [sciperValue, setSciperValue] = useState(''); + const [selectedRole, setSelectedRole] = useState(roles[0]); - const [roleValue, setRoleValue] = useState(''); - - const handleChange = (event: any) => { - setRoleValue(event.target.value); - }; + const handleClose = () => setOpen(false); const handleUserInput = (e: any) => { setSciperValue(e.target.value); }; - const handleClick = () => { + const handleAddUser = () => { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ sciper: sciperValue, role: roleValue }), + body: JSON.stringify({ sciper: sciperValue, role: selectedRole }), }; + setLoading(true); fetch(ENDPOINT_ADD_ROLE, requestOptions).then((data) => { + setLoading(false); if (data.status === 200) { alert('User added successfully'); setOpen(false); @@ -60,47 +56,124 @@ const AddAdminUserModal: FC = ({ open, setOpen }) => { } }); }; + const cancelButtonRef = useRef(null); return ( -
- - - - Please give the sciper of the user - - -
-
- - - Role - - - -
- -
-
-
+ + +
+ + + + + {/* This element is to trick the browser into centering the modal contents. */} + + +
+
+
+ + {t('enterSciper')} + + +
+ +
+ + {selectedRole} + + + + + + {roles.map((role, personIdx) => ( + + `relative cursor-default select-none py-2 pl-10 pr-4 ${ + active ? 'bg-indigo-100 text-indigo-900' : 'text-gray-900' + }` + } + value={role}> + {({ selected }) => ( + <> + + {role} + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+
+
+
+
+
+ + +
+
+
+
+
+
); }; diff --git a/web/frontend/src/language/en.json b/web/frontend/src/language/en.json index c23ce8a57..c87bb6c2b 100644 --- a/web/frontend/src/language/en.json +++ b/web/frontend/src/language/en.json @@ -16,6 +16,7 @@ "notFoundLink": "Go to home page", "results": "results", "showing": "Showing", + "enterSciper": "Please give the sciper of the user", "adminDetails": "Add or remove roles of users from the admin table", "navBarCreateElection": "Create election", "homeTitle": "Welcome to our e-voting platform!", diff --git a/web/frontend/src/pages/election/components/ElectionForm.tsx b/web/frontend/src/pages/election/components/ElectionForm.tsx index e989981a0..ee5268e39 100644 --- a/web/frontend/src/pages/election/components/ElectionForm.tsx +++ b/web/frontend/src/pages/election/components/ElectionForm.tsx @@ -150,7 +150,7 @@ const ElectionForm: FC = ({ setShowModal, setTextModal }) =>
+ className="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"> Sciper - Role + className="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"> + {t('role')} - Edit + {t('edit')}
- - - - - - - {data.map((election) => { - return ( - - - - ); - })} - -
- {t('elecName')} -
- - {election.Title} - -
-
-
- ); - } else { - return
{textWhenNoData}
; - } - }; - - const showBallots = (elections: LightElectionInfo[]) => { - return displayBallotTable(ballotsToDisplay(elections)); - }; - - return ( -
- {!loading ? ( - showBallots(fetchedData.Elections) - ) : error === null ? ( -

{t('loading')}

- ) : ( -
{t('errorRetrievingElection')}
- )} -
- ); -}; - -SimpleTable.propTypes = { - statusToKeep: PropTypes.number.isRequired, - pathLink: PropTypes.string.isRequired, - textWhenData: PropTypes.string.isRequired, - textWhenNoData: PropTypes.string.isRequired, -}; - -export default SimpleTable; From 83c1e4cb22a0f81e54cf8e297a6c864fa81ad513 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 16:53:21 +0200 Subject: [PATCH 37/68] Removes unused css files --- .../components/modal/AddAdminUserModal.tsx | 18 -------- web/frontend/src/components/modal/Modal.css | 41 ------------------- web/frontend/src/components/modal/Modal.tsx | 2 - .../src/components/utils/useChangeAction.tsx | 2 +- 4 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 web/frontend/src/components/modal/Modal.css diff --git a/web/frontend/src/components/modal/AddAdminUserModal.tsx b/web/frontend/src/components/modal/AddAdminUserModal.tsx index c67be1909..f5c4a25b5 100644 --- a/web/frontend/src/components/modal/AddAdminUserModal.tsx +++ b/web/frontend/src/components/modal/AddAdminUserModal.tsx @@ -8,18 +8,6 @@ import { useTranslation } from 'react-i18next'; import SpinnerIcon from 'components/utils/SpinnerIcon'; import { UserAddIcon } from '@heroicons/react/outline'; -const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: 400, - bgcolor: 'background.paper', - border: '2px solid #000', - boxShadow: 24, - p: 4, -}; - type AddAdminUserModalProps = { open: boolean; setOpen(opened: boolean): void; @@ -40,12 +28,6 @@ const AddAdminUserModal: FC = ({ open, setOpen }) => { }; const handleAddUser = () => { - if (sciperValue.length !== 6) { - alert('Sciper required'); - setLoading(false); - return; - } - const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/web/frontend/src/components/modal/Modal.css b/web/frontend/src/components/modal/Modal.css deleted file mode 100644 index 72201f7db..000000000 --- a/web/frontend/src/components/modal/Modal.css +++ /dev/null @@ -1,41 +0,0 @@ -.modal-background { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.6); - z-index: 1; -} - -.modal-wrapper { - display: flex; - flex-direction: column; - justify-content: space-between; - position: fixed; - background: #f6f6fa; - max-width: 100%; - max-height: 100%; - min-height: 15%; - min-width: 10%; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - outline: #a9a9aa; - outline-style: solid; - outline-width: 1px; -} - -.text-container { - padding: 5%; -} - -.buttons-container { - overflow: hidden; - background-color: #177368; /* #177368 or #9bc0bc */ - padding: 3%; -} - -.btn-right { - float: right; -} diff --git a/web/frontend/src/components/modal/Modal.tsx b/web/frontend/src/components/modal/Modal.tsx index 49d2f5a31..5c7bb4a96 100644 --- a/web/frontend/src/components/modal/Modal.tsx +++ b/web/frontend/src/components/modal/Modal.tsx @@ -3,8 +3,6 @@ import PropTypes from 'prop-types'; import { Dialog, Transition } from '@headlessui/react'; -import './Modal.css'; - const Modal = ({ showModal, setShowModal, textModal, buttonRightText }) => { const closeModal = () => { setShowModal(false); diff --git a/web/frontend/src/components/utils/useChangeAction.tsx b/web/frontend/src/components/utils/useChangeAction.tsx index 9d12d547e..148639893 100644 --- a/web/frontend/src/components/utils/useChangeAction.tsx +++ b/web/frontend/src/components/utils/useChangeAction.tsx @@ -219,7 +219,7 @@ const useChangeAction = ( ); case STATUS.Canceled: - return --- ; + return ; default: return --- ; } From c65b03a96cb86e7490c5f8ca3c7d69091daf64ac Mon Sep 17 00:00:00 2001 From: giogio21 <> Date: Tue, 3 May 2022 17:14:33 +0200 Subject: [PATCH 38/68] use tmux instead of gnome-terminal --- runNode.sh | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/runNode.sh b/runNode.sh index ebdb2e851..7d1633d2b 100755 --- a/runNode.sh +++ b/runNode.sh @@ -1,29 +1,34 @@ #!/bin/bash -# Basic while loop -pk=adbacd10fdb9822c71025d6d00092b8a4abb5ebcb673d28d863f7c7c5adaddf3 +set -o errexit +command -v tmux >/dev/null 2>&1 || { echo >&2 "tmux is not on your PATH!"; exit 1; } -from=0 -fromb=1 -to=$1 -ne=0 -while [ $fromb -le $to ] -do -if [ $from -le 9 ] -then -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node$fromb start --postinstall --promaddr :910$from --proxyaddr :908$from --proxykey $pk --listen tcp://0.0.0.0:200$fromb --public //localhost:200$fromb" +pk=adbacd10fdb9822c71025d6d00092b8a4abb5ebcb673d28d863f7c7c5adaddf3 + + +# Launch session +s="d-voting-test" -else +tmux list-sessions | rg "^$TMUX_SESSION_NAME:" >/dev/null 2>&1 && { echo >&2 "A session with the name $TMUX_SESSION_NAME already exists; kill it and try again"; exit 1; } +tmux new-session -d -s $s -gnome-terminal --tab --title="test" --command="./memcoin --config /tmp/node$fromb start --postinstall --promaddr :91$from --proxyaddr :909$ne --proxykey $pk --listen tcp://0.0.0.0:20$fromb --public //localhost:20$fromb" -((ne++)) -fi -((fromb++)) +from=1 +to=$1 +while [ $from -le $to ] +do + +echo $from +tmux new-window -t $s +window=$from +tmux send-keys -t $s:$window "LLVL=info ./memcoin --config /tmp/node$from start --postinstall --promaddr :$((9099 + $from)) --proxyaddr :$((9079 + $from)) --proxykey $pk --listen tcp://0.0.0.0:$((2000 + $from)) --public //localhost:$((2000 + $from))" C-m ((from++)) + done + +tmux a From d07a83372b728719855ab64806b3fc4317ffe2e7 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 18:10:21 +0200 Subject: [PATCH 39/68] Changes location of extra text in ElectionIndex --- web/frontend/src/pages/election/Index.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/frontend/src/pages/election/Index.tsx b/web/frontend/src/pages/election/Index.tsx index fe4a91eee..812ae42ee 100644 --- a/web/frontend/src/pages/election/Index.tsx +++ b/web/frontend/src/pages/election/Index.tsx @@ -23,12 +23,13 @@ const ElectionIndex: FC = () => { return (
{data.Elections.length > 0 ? ( -
-
{t('clickElection')}
-
+ <> + {t('listElection')} +
{t('clickElection')}
+
-
+ ) : (
{t('noElection')}
)} @@ -38,7 +39,6 @@ const ElectionIndex: FC = () => { return (
- {t('listElection')} {!loading ? ( showElection() ) : error === null ? ( From 05248a17b604ea2851aa409180651b35c63ee6fe Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 19:01:23 +0200 Subject: [PATCH 40/68] Adds Title for ElectionTable and same pages width --- web/frontend/src/language/en.json | 1 + web/frontend/src/pages/Admin.tsx | 2 +- web/frontend/src/pages/election/Index.tsx | 31 +++++++------- web/frontend/src/pages/election/Show.tsx | 41 +++++++++---------- .../election/components/StatusTimeline.tsx | 2 +- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/web/frontend/src/language/en.json b/web/frontend/src/language/en.json index c87bb6c2b..86e23017a 100644 --- a/web/frontend/src/language/en.json +++ b/web/frontend/src/language/en.json @@ -5,6 +5,7 @@ "navBarStatus": "Elections", "navBarCreate": "Create", "vote": "Vote", + "elections": "Elections", "navBarResult": "Results", "navBarAbout": "About", "navBarAdmin": "Admin", diff --git a/web/frontend/src/pages/Admin.tsx b/web/frontend/src/pages/Admin.tsx index c63697b5c..fd0aa09fc 100644 --- a/web/frontend/src/pages/Admin.tsx +++ b/web/frontend/src/pages/Admin.tsx @@ -60,7 +60,7 @@ const Admin = () => { }; return ( -
+
diff --git a/web/frontend/src/pages/election/Index.tsx b/web/frontend/src/pages/election/Index.tsx index 812ae42ee..88dc92d4a 100644 --- a/web/frontend/src/pages/election/Index.tsx +++ b/web/frontend/src/pages/election/Index.tsx @@ -20,25 +20,26 @@ const ElectionIndex: FC = () => { /*Show all the elections retrieved if any */ const showElection = () => { - return ( -
- {data.Elections.length > 0 ? ( - <> - {t('listElection')} -
{t('clickElection')}
-
- -
- - ) : ( -
{t('noElection')}
- )} -
+ return data.Elections.length > 0 ? ( + <> +
+

+ {t('elections')} +

+
{t('listElection')}
+
{t('clickElection')}
+
+
+ +
+ + ) : ( +
{t('noElection')}
); }; return ( -
+
{!loading ? ( showElection() ) : error === null ? ( diff --git a/web/frontend/src/pages/election/Show.tsx b/web/frontend/src/pages/election/Show.tsx index aeeb76ccd..bbb329631 100644 --- a/web/frontend/src/pages/election/Show.tsx +++ b/web/frontend/src/pages/election/Show.tsx @@ -31,31 +31,30 @@ const ElectionShow: FC = () => { }, [isResultAvailable, status]); return ( -
+
{!loading ? ( <> -
-
- {configObj.MainTitle} -
-

Election ID : {electionId}

-
-
{t('status')}
+

+ {configObj.MainTitle} +

+ +

Election ID : {electionId}

+
+
{t('status')}
-
- -
+
+
-
-
{t('action')}
-
- -
+
+
+
{t('action')}
+
+
diff --git a/web/frontend/src/pages/election/components/StatusTimeline.tsx b/web/frontend/src/pages/election/components/StatusTimeline.tsx index dd4befb66..92d967231 100644 --- a/web/frontend/src/pages/election/components/StatusTimeline.tsx +++ b/web/frontend/src/pages/election/components/StatusTimeline.tsx @@ -85,7 +85,7 @@ const StatusTimeline: FC = ({ status }) => { }; return ( -
    +
      {steps.map((step, index) => { if (index < currentStep) { return ( From ee83f26af19871f881c2e83040f0c4a34460e55f Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 19:18:40 +0200 Subject: [PATCH 41/68] Removes unused functions in ElectionForm --- web/frontend/src/pages/ballot/Show.tsx | 19 +------------------ .../election/components/ElectionForm.tsx | 1 - 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/web/frontend/src/pages/ballot/Show.tsx b/web/frontend/src/pages/ballot/Show.tsx index 4db27fd08..52fae617b 100644 --- a/web/frontend/src/pages/ballot/Show.tsx +++ b/web/frontend/src/pages/ballot/Show.tsx @@ -1,12 +1,10 @@ import { FC, useEffect, useState } from 'react'; -import { CloudUploadIcon } from '@heroicons/react/outline'; import { useTranslation } from 'react-i18next'; -import { Link, useParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import kyber from '@dedis/kyber'; import PropTypes from 'prop-types'; import { Buffer } from 'buffer'; -import { ROUTE_ELECTION_INDEX } from '../../Routes'; import useElection from 'components/utils/useElection'; import usePostCall from 'components/utils/usePostCall'; import * as endpoints from 'components/utils/Endpoints'; @@ -181,21 +179,6 @@ const Ballot: FC = () => { ); }; - const electionClosedDisplay = () => { - return ( -
      -
      {t('voteImpossible')}
      - - - -
      - ); - }; - return (
      = ({ setShowModal, setTextModal }) => ) : (
+ ) : ( + ); }; export default Admin; From dc4c6289ef0092d868dd97f75120a211804b6dcc Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 20:06:02 +0200 Subject: [PATCH 46/68] Removes comments --- web/frontend/src/pages/Admin.tsx | 85 -------------------------------- 1 file changed, 85 deletions(-) diff --git a/web/frontend/src/pages/Admin.tsx b/web/frontend/src/pages/Admin.tsx index dcd4237fe..7e221c4a3 100644 --- a/web/frontend/src/pages/Admin.tsx +++ b/web/frontend/src/pages/Admin.tsx @@ -174,88 +174,3 @@ const Admin = () => { ); }; export default Admin; - -// import React, { useEffect, useState } from 'react'; -// import Button from '@mui/material/Button'; -// import { DataGrid } from '@mui/x-data-grid'; - -// import { ENDPOINT_USER_RIGHTS } from 'components/utils/Endpoints'; -// import AddAdminUserModal from 'components/modal/AddAdminUserModal'; -// import RemoveAdminUserModal from 'components/modal/RemoveAdminUserModal'; -// import './Admin.css'; - -// const Admin = () => { -// const [rows, setRows] = useState([]); -// const [newusrOpen, setNewusrOpen] = useState(false); - -// const [sciperToDelete, setSciperToDelete] = useState(0); -// const [showDeleteModal, setShowDeleteModal] = useState(false); - -// const openModal = () => setNewusrOpen(true); - -// useEffect(() => { -// if (newusrOpen || showDeleteModal) { -// return; -// } - -// fetch(ENDPOINT_USER_RIGHTS) -// .then((resp) => { -// const jsonData = resp.json(); -// jsonData.then((result) => { -// console.log(result); -// setRows(result); -// }); -// }) -// .catch((error) => { -// console.log(error); -// }); -// }, [newusrOpen, showDeleteModal]); - -// const columns = [ -// { -// field: 'sciper', -// headerName: 'sciper', -// width: 150, -// }, -// { -// field: 'role', -// headerName: 'role', -// width: 150, -// }, -// { -// field: 'action', -// headerName: 'Action', -// width: 150, -// renderCell: function (params: any) { -// function handledClick() { -// setSciperToDelete(params.row.sciper); -// setShowDeleteModal(true); -// } -// return ( -// -// ); -// }, -// }, -// ]; - -// return ( -//
-//
-// -// -// -// -//
-//
-// ); -// }; - -// export default Admin; From 5aa9f26aa5a366770c0531b39c32e88a8127ad6b Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 20:15:44 +0200 Subject: [PATCH 47/68] Removes unused css files --- web/frontend/src/pages/election/Index.css | 63 ----------------------- web/frontend/src/pages/election/Index.tsx | 5 +- web/frontend/src/pages/election/New.tsx | 12 +++-- web/frontend/src/pages/election/Show.css | 27 ---------- web/frontend/src/pages/election/Show.tsx | 1 - 5 files changed, 9 insertions(+), 99 deletions(-) delete mode 100644 web/frontend/src/pages/election/Index.css delete mode 100644 web/frontend/src/pages/election/Show.css diff --git a/web/frontend/src/pages/election/Index.css b/web/frontend/src/pages/election/Index.css deleted file mode 100644 index cc211fc9f..000000000 --- a/web/frontend/src/pages/election/Index.css +++ /dev/null @@ -1,63 +0,0 @@ - -.election-box { - padding-bottom: 5%; -} -.click-info { - padding-bottom: 3%; -} -.election-btn { - border-radius: 8px; - margin: 4px 2px; - cursor: pointer; -} - -.election-status { - display: inline-flex; - margin: 20px 20px; - margin-left: 3%; -} - -.election-status-text { - display: inline-flex; - margin: 0px 5px; -} - -.election-status-on { - display: inline-block; - height: 15px; - width: 15px; - margin-top: 1.5%; - background-color: green; - border-radius: 50%; -} - -.election-status-closed { - display: inline-block; - height: 15px; - width: 15px; - margin-top: 1.5%; - background-color: grey; - border-radius: 50%; -} - -.election-status-cancelled { - display: inline-block; - height: 15px; - width: 15px; - margin-top: 1.5%; - background-color: red; - border-radius: 50%; -} - -.loading { - background-color: #9bc0bc; -} - -.error-retrieving { - padding-top: 10%; - padding-bottom: 10%; -} - -.no-election { - padding-bottom: 3%; -} diff --git a/web/frontend/src/pages/election/Index.tsx b/web/frontend/src/pages/election/Index.tsx index 88dc92d4a..9eaf04dce 100644 --- a/web/frontend/src/pages/election/Index.tsx +++ b/web/frontend/src/pages/election/Index.tsx @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'; import ElectionTable from './components/ElectionTable'; import useFetchCall from 'components/utils/useFetchCall'; import * as endpoints from 'components/utils/Endpoints'; -import './Index.css'; import Loading from 'pages/Loading'; const ElectionIndex: FC = () => { @@ -34,7 +33,7 @@ const ElectionIndex: FC = () => {
) : ( -
{t('noElection')}
+
{t('noElection')}
); }; @@ -45,7 +44,7 @@ const ElectionIndex: FC = () => { ) : error === null ? ( ) : ( -
+
{t('errorRetrievingElection')} - {error.toString()}
)} diff --git a/web/frontend/src/pages/election/New.tsx b/web/frontend/src/pages/election/New.tsx index 58fa6d050..0c86eb556 100644 --- a/web/frontend/src/pages/election/New.tsx +++ b/web/frontend/src/pages/election/New.tsx @@ -10,17 +10,19 @@ const ElectionCreate: FC = () => { const [textModal, setTextModal] = useState(''); return ( -
+
-

- {t('navBarCreate')} -

-

{t('create')}

+
+

+ {t('navBarCreate')} +

+
{t('create')}
+
diff --git a/web/frontend/src/pages/election/Show.css b/web/frontend/src/pages/election/Show.css deleted file mode 100644 index aab3861b4..000000000 --- a/web/frontend/src/pages/election/Show.css +++ /dev/null @@ -1,27 +0,0 @@ -.election-candidates { - list-style: none; - display: flexbox; - padding-bottom: 3%; -} - -.election-candidate { - list-style: disc; - margin-left: 4%; -} -.election-details-box { - background-color: #f6f6fa; - padding-left: 2%; - padding-bottom: 2%; -} - -.election-action { - margin-left: 5%; -} -.back-btn { - margin-top: 3%; -} -h1 { - padding-top: 2%; - text-align: left; - color: #177368; -} diff --git a/web/frontend/src/pages/election/Show.tsx b/web/frontend/src/pages/election/Show.tsx index bbb329631..7826a9d8d 100644 --- a/web/frontend/src/pages/election/Show.tsx +++ b/web/frontend/src/pages/election/Show.tsx @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import useElection from 'components/utils/useElection'; -import './Show.css'; import useGetResults from 'components/utils/useGetResults'; import { STATUS } from 'types/election'; import Action from './components/Action'; From 70e0756f75bb29808fecd4d70a53fd46442080e2 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 20:19:59 +0200 Subject: [PATCH 48/68] Same width for About page --- web/frontend/src/pages/About.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/frontend/src/pages/About.tsx b/web/frontend/src/pages/About.tsx index d92ef0d33..2bb2e317e 100644 --- a/web/frontend/src/pages/About.tsx +++ b/web/frontend/src/pages/About.tsx @@ -6,8 +6,8 @@ const About: FC = () => { return ( -
-
+
+

{t('about1')}
From 6abef3ca254caa7c0e1eac9fc267b7d22f8bc263 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 20:28:13 +0200 Subject: [PATCH 49/68] Fixes useChangeStatus content --- .../src/components/utils/useChangeStatus.tsx | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/web/frontend/src/components/utils/useChangeStatus.tsx b/web/frontend/src/components/utils/useChangeStatus.tsx index a153320cd..1e803a082 100644 --- a/web/frontend/src/components/utils/useChangeStatus.tsx +++ b/web/frontend/src/components/utils/useChangeStatus.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useTranslation } from 'react-i18next'; import { STATUS } from 'types/election'; @@ -11,87 +10,87 @@ const useChangeStatus = (status: STATUS) => { switch (status) { case STATUS.Initial: return ( - - - {t('statusInitial')} - +
+
+
{t('statusInitial')}
+
); case STATUS.InitializedNodes: return ( - - - {t('statusInitializedNodes')} - +
+
+
{t('statusInitializedNodes')}
+
); case STATUS.OnGoingSetup: return ( - - - {t('statusOnGoingSetup')} - +
+
+
{t('statusOnGoingSetup')}
+
); case STATUS.Setup: return ( - - - {t('statusSetup')} - +
+
+
{t('statusSetup')}
+
); case STATUS.Open: return ( - - - {t('statusOpen')} - +
+
+
{t('statusOpen')}
+
); case STATUS.Closed: return ( - - - {t('statusClose')} - +
+
+
{t('statusClose')}
+
); case STATUS.OnGoingShuffle: return ( - - - {t('statusOnGoingShuffle')} - +
+
+
{t('statusOnGoingShuffle')}
+
); case STATUS.ShuffledBallots: return ( - - - {t('statusShuffle')} - +
+
+
{t('statusShuffle')}
+
); case STATUS.OnGoingDecryption: return ( - - - {t('statusOnGoingDecryption')} - +
+
+
{t('statusOnGoingDecryption')}
+
); case STATUS.DecryptedBallots: return ( - - - {t('statusDecrypted')} - +
+
+
{t('statusDecrypted')}
+
); case STATUS.ResultAvailable: return ( - - - {t('statusResultAvailable')} - +
+
+
{t('statusResultAvailable')}
+
); case STATUS.Canceled: return ( - - - {t('statusCancel')} - +
+
+
{t('statusCancel')}
+
); default: return null; From da53b1cb4a020431e697c7964d7f9f9466982041 Mon Sep 17 00:00:00 2001 From: badrlarhdir Date: Tue, 3 May 2022 20:41:26 +0200 Subject: [PATCH 50/68] Fixes ConfirmModal --- web/frontend/src/components/modal/AddAdminUserModal.tsx | 2 +- web/frontend/src/components/modal/ConfirmModal.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/frontend/src/components/modal/AddAdminUserModal.tsx b/web/frontend/src/components/modal/AddAdminUserModal.tsx index f5c4a25b5..aeb447dc6 100644 --- a/web/frontend/src/components/modal/AddAdminUserModal.tsx +++ b/web/frontend/src/components/modal/AddAdminUserModal.tsx @@ -77,7 +77,7 @@ const AddAdminUserModal: FC = ({ open, setOpen }) => { leave="ease-in duration-200" leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"> -
+
diff --git a/web/frontend/src/components/modal/ConfirmModal.tsx b/web/frontend/src/components/modal/ConfirmModal.tsx index c157928f1..df679ed5a 100644 --- a/web/frontend/src/components/modal/ConfirmModal.tsx +++ b/web/frontend/src/components/modal/ConfirmModal.tsx @@ -33,8 +33,8 @@ const ConfirmModal: FC = ({ const Modal = () => { return ( - -
+ +
= ({ {/* This element is to trick the browser into centering the modal contents. */} -