From 34cd04934a8f9e1d3f77ed737b25f646af6c296b Mon Sep 17 00:00:00 2001 From: David Florness Date: Thu, 25 Jun 2020 13:28:46 -0600 Subject: [PATCH] Don't generate an identity if we've joined this election before --- config.go | 4 ++-- main.go | 63 +++++++++++++++++++++++++++++++++++-------------------- merkle.go | 14 +++++++++++++ ui.go | 34 ++++++++++++------------------ 4 files changed, 69 insertions(+), 46 deletions(-) diff --git a/config.go b/config.go index 91c1b6a..c7fadf3 100644 --- a/config.go +++ b/config.go @@ -28,8 +28,8 @@ type ElectionConfig struct{ type ElectionConfigs map[string]*ElectionConfig -// sees if we've joined this election before and attempt to retrieve the data we -// stored for it +// sees if we've joined this election before and attempts to retrieve the data +// we stored for it func getElectionConfigMaybe(electionKey string) *ElectionConfig { root := path.Join(xdg.ConfigHome(), "tallyard") file, err := os.OpenFile(path.Join(root, "elections.json"), os.O_RDONLY|os.O_CREATE, 0600) diff --git a/main.go b/main.go index c7559e1..175d3b9 100644 --- a/main.go +++ b/main.go @@ -21,27 +21,28 @@ import ( ) const protocolID = protocol.ID("/tallyard/0.0.0") + var logger = log.Logger("tallyard") -func bootstrap(election *Election, me *Me, merkleRoot []byte) { +func bootstrap(election *Election, me *Me, merkleRoot []byte, hostOpts ...libp2p.Option) { me.ctx = context.Background() election.remoteVoters = make(map[peer.ID]*Voter) - var err error - me.Host, err = libp2p.New(me.ctx, - libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) { - var err error - me.kdht, err = dht.New(me.ctx, h) - if err != nil { - return me.kdht, err - } - logger.Info("boostrapping the DHT") - if err = me.kdht.Bootstrap(me.ctx); err != nil { - panic(err) - } + routing := libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) { + var err error + me.kdht, err = dht.New(me.ctx, h) + if err != nil { return me.kdht, err - }), - ) + } + logger.Info("boostrapping the DHT") + if err = me.kdht.Bootstrap(me.ctx); err != nil { + panic(err) + } + return me.kdht, err + }) + + var err error + me.Host, err = libp2p.New(me.ctx, append(hostOpts, routing)...) if err != nil { panic(err) } @@ -173,24 +174,40 @@ func main() { } var ( - election *Election - me = new(Me) - merkleRoot []byte + election *Election + electionKey string + identityOpt libp2p.Option = libp2p.RandomIdentity + me *Me = new(Me) + merkleRoot []byte ) - // check if election key was given via cli - if electionKey := flag.Arg(0); electionKey != "" { + // check if election key was given via CLI args + if electionKey = flag.Arg(0); electionKey != "" { election = new(Election) merkleRoot, election.masterID = splitElectionKey(electionKey) } else { - election, merkleRoot = tui() - // tui button was never pressed + // create/join election via TUI + election, merkleRoot, electionKey = tui() if election == nil { + // tui form wasn't submitted (maybe the user hit ^C) os.Exit(0) } } - bootstrap(election, me, merkleRoot) + if electionKey != "" { // we are a slave + // try to recover election info if we've joined before + if electionConfig := getElectionConfigMaybe(electionKey); electionConfig != nil { + // ensure public key from config is same as one derived + // from private key + if !electionConfig.PrivKey.GetPublic().Equals(electionConfig.PubKey) { + // TODO: handle properly + panic("public keys do not match") + } + identityOpt = libp2p.Identity(electionConfig.PrivKey) + } + } + + bootstrap(election, me, merkleRoot, identityOpt) startVoting(election, me) } diff --git a/merkle.go b/merkle.go index 4c72da8..39e2d6c 100644 --- a/merkle.go +++ b/merkle.go @@ -90,3 +90,17 @@ func splitElectionKey(electionKey string) (merkleRoot []byte, masterID peer.ID) logger.Info("master ID:", masterID) return merkleRoot, masterID } + +func (e *Election) createMerkle(candidates []Candidate) (merkleRoot []byte) { + e.rendezvousNonce = NewNonce() + content := []merkletree.Content{e.rendezvousNonce} + for _, cand := range candidates { + content = append(content, cand) + } + optionsMerkle, err := merkletree.NewTree(content) + if err != nil { + panic(err) + } + merkleRoot = optionsMerkle.MerkleRoot() + return merkleRoot +} diff --git a/ui.go b/ui.go index eb5a1b4..884ac26 100644 --- a/ui.go +++ b/ui.go @@ -6,21 +6,21 @@ import ( "strconv" "unicode" - "github.com/cbergoon/merkletree" - "github.com/libp2p/go-libp2p-core/peer" "github.com/rivo/tview" ) -func tui() (election *Election, merkleRoot []byte) { +func tui() (election *Election, merkleRoot []byte, electionKey string) { app := tview.NewApplication() done := func(buttonIndex int, buttonLabel string) { app.Stop() election = new(Election) switch buttonLabel { case "Create Election": - merkleRoot, election.rendezvousNonce, election.candidates = createElection() + election.candidates = createElection() + merkleRoot = election.createMerkle(election.candidates) case "Join Election": - merkleRoot, election.masterID = joinElection() + electionKey := joinElection() + merkleRoot, election.masterID = splitElectionKey(electionKey) } } modal := tview.NewModal(). @@ -30,10 +30,10 @@ func tui() (election *Election, merkleRoot []byte) { if err := app.SetRoot(modal, false).EnableMouse(true).Run(); err != nil { panic(err) } - return election, merkleRoot + return election, merkleRoot, electionKey } -func createElection() (merkleRoot []byte, rendezvousNonce Nonce, candidates []Candidate) { +func createElection() (candidates []Candidate) { var form *tview.Form n := 3 app := tview.NewApplication() @@ -52,18 +52,10 @@ func createElection() (merkleRoot []byte, rendezvousNonce Nonce, candidates []Ca done := func() { // TODO: ensure none of the candidates are empty app.Stop() - rendezvousNonce = NewNonce() - content := []merkletree.Content{rendezvousNonce} for i := 0; i < n-1; i++ { - eo := Candidate(form.GetFormItem(i).(*tview.InputField).GetText()) - candidates = append(candidates, eo) - content = append(content, eo) + candidates = append(candidates, + Candidate(form.GetFormItem(i).(*tview.InputField).GetText())) } - optionsMerkle, err := merkletree.NewTree(content) - if err != nil { - panic(err) - } - merkleRoot = optionsMerkle.MerkleRoot() } form = tview.NewForm(). AddInputField("1.", "", 50, nil, nil). @@ -74,15 +66,15 @@ func createElection() (merkleRoot []byte, rendezvousNonce Nonce, candidates []Ca if err := app.SetRoot(form, true).EnableMouse(true).Run(); err != nil { panic(err) } - return merkleRoot, rendezvousNonce, candidates + return candidates } -func joinElection() (merkleRoot []byte, masterID peer.ID) { +func joinElection() (electionKey string) { app := tview.NewApplication() var form *tview.Form done := func() { app.Stop() - merkleRoot, masterID = splitElectionKey(form.GetFormItem(0).(*tview.InputField).GetText()) + electionKey = form.GetFormItem(0).(*tview.InputField).GetText() } form = tview.NewForm(). AddInputField("Election key:", "", 100, nil, nil). @@ -90,7 +82,7 @@ func joinElection() (merkleRoot []byte, masterID peer.ID) { if err := app.SetRoot(form, true).EnableMouse(true).Run(); err != nil { panic(err) } - return merkleRoot, masterID + return electionKey } // displays a voting UI to the user and returns the encoded ballot -- 2.38.4