aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/gnunet/voting/BallotTool.java
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2013-10-21 18:48:51 +0000
committerFlorian Dold <florian.dold@gmail.com>2013-10-21 18:48:51 +0000
commit8ceb5e95568a0a5be9ca6fd28a31fe6b07e06f28 (patch)
treedffd85c26a583a68cce3435375263a51bf43618c /src/main/java/org/gnunet/voting/BallotTool.java
parent4cbf5731c126695bbd964552b92e7ae9151561e1 (diff)
downloadgnunet-java-8ceb5e95568a0a5be9ca6fd28a31fe6b07e06f28.tar.gz
gnunet-java-8ceb5e95568a0a5be9ca6fd28a31fe6b07e06f28.zip
- use identity in voting
- group certificate tool instead of ca daemon - consensus api fully implemented, consensus+testbed test - authorities use consensus - some progress on transport api
Diffstat (limited to 'src/main/java/org/gnunet/voting/BallotTool.java')
-rw-r--r--src/main/java/org/gnunet/voting/BallotTool.java502
1 files changed, 311 insertions, 191 deletions
diff --git a/src/main/java/org/gnunet/voting/BallotTool.java b/src/main/java/org/gnunet/voting/BallotTool.java
index fe83789..452e606 100644
--- a/src/main/java/org/gnunet/voting/BallotTool.java
+++ b/src/main/java/org/gnunet/voting/BallotTool.java
@@ -25,221 +25,341 @@ import com.google.common.base.Charsets;
25import com.google.common.io.ByteStreams; 25import com.google.common.io.ByteStreams;
26import com.google.common.io.Files; 26import com.google.common.io.Files;
27import com.google.common.io.OutputSupplier; 27import com.google.common.io.OutputSupplier;
28import org.gnunet.identity.Identity;
29import org.gnunet.identity.IdentityCallback;
30import org.gnunet.mesh.Mesh;
31import org.gnunet.mesh.MeshRunabout;
32import org.gnunet.mesh.TunnelEndHandler;
33import org.gnunet.testbed.CompressedConfig;
34import org.gnunet.util.AbsoluteTime;
35import org.gnunet.util.Configuration;
36import org.gnunet.util.PeerIdentity;
28import org.gnunet.util.Program; 37import org.gnunet.util.Program;
29import org.gnunet.util.crypto.EcdsaPrivateKey; 38import org.gnunet.util.crypto.EddsaSignature;
30import org.gnunet.util.getopt.Argument; 39import org.gnunet.util.getopt.Argument;
31import org.gnunet.util.getopt.ArgumentAction; 40import org.gnunet.util.getopt.ArgumentAction;
41import org.gnunet.voting.messages.*;
32 42
33import java.io.File; 43import java.io.File;
34import java.io.FileOutputStream; 44import java.io.FileOutputStream;
35import java.io.IOException; 45import java.io.IOException;
36import java.io.InputStream; 46import java.io.InputStream;
47import java.util.List;
48import java.util.Random;
37 49
38/** 50/**
39 * Tool for creating, manipulating and submitting ballot files. 51 * Tool for creating, manipulating and submitting ballot files.
40 */ 52 */
41public class BallotTool { 53public class BallotTool extends Program {
42 public static void main(String[] args) { 54 @Argument(
43 new Program(args) { 55 shortname = "e",
44 @Argument( 56 longname = "ego",
45 shortname = "q", 57 action = ArgumentAction.STORE_STRING,
46 longname = "query", 58 description = "ego to use for the operation")
47 action = ArgumentAction.SET, 59 String egoName = null;
48 description = "query election result")
49 boolean query = false;
50
51 @Argument(
52 shortname = "s",
53 longname = "submit",
54 action = ArgumentAction.SET,
55 description = "submit the vote to the authorities")
56 boolean submit = false;
57
58 @Argument(
59 shortname = "r",
60 longname = "register",
61 action = ArgumentAction.SET,
62 description = "register an election with the authorities")
63 boolean register = false;
64
65 @Argument(
66 shortname = "i",
67 longname = "issue",
68 action = ArgumentAction.SET,
69 description = "sign the ballot as issuer")
70 boolean issue = false;
71
72 @Argument(
73 shortname = "x",
74 longname = "select",
75 action = ArgumentAction.STORE_STRING,
76 argumentName = "CHOICE",
77 description = "select and encrypt a vote option")
78 String select = null;
79
80 @Argument(
81 shortname = "V",
82 longname = "verify",
83 action = ArgumentAction.SET,
84 description = "verify signatures in the ballot and show information")
85 boolean verify = false;
86
87 @Argument(
88 shortname = "t",
89 longname = "template",
90 action = ArgumentAction.SET,
91 description = "write a template ballot to the give ballot file")
92 boolean template = false;
93
94 @Override
95 protected String makeHelpText() {
96 return "gnunet-ballot [OPTIONS]... BALLOT [PRIVKEYFILE]\n" +
97 "Create, modify and execute operation on ballots.";
98 }
99 60
100 private void runTemplate(String filename) { 61 @Argument(
101 File f = new File(filename); 62 shortname = "q",
102 if (f.exists()) { 63 longname = "query",
103 System.err.println("file already exists, not overwriting"); 64 action = ArgumentAction.SET,
104 return; 65 description = "query election result")
105 } 66 boolean query = false;
106 InputStream is = getClass().getResourceAsStream("template.espec");
107 OutputSupplier<FileOutputStream> oss = Files.newOutputStreamSupplier(f);
108 try {
109 ByteStreams.copy(is, oss);
110 } catch (IOException e) {
111 System.err.println("could not copy template file: " + e.getMessage());
112 }
113 }
114 67
115 private void runIssue(String ballotFilename, String privKeyFilename) { 68 @Argument(
116 File bf = new File(ballotFilename); 69 shortname = "s",
117 if (!bf.exists()) { 70 longname = "submit",
118 System.err.println("ballot file does not exist"); 71 action = ArgumentAction.SET,
119 return; 72 description = "submit the vote to the authorities")
120 } 73 boolean submit = false;
121 File kf = new File(privKeyFilename);
122 if (!kf.exists()) {
123 System.err.println("private-key file does not exist");
124 return;
125 }
126 Ballot b = new Ballot(ballotFilename);
127 EcdsaPrivateKey privateKey = EcdsaPrivateKey.fromFile(privKeyFilename);
128 if (privateKey == null) {
129 System.err.println("keyfile invalid");
130 return;
131 }
132 b.issue(privateKey);
133 try {
134 Files.write(b.serialize(), bf, Charsets.UTF_8);
135 } catch (IOException e) {
136 System.err.println("could not write ballot file: " + e.getMessage());
137 }
138 }
139 74
140 public void runSelect(String ballotFilename, String privKeyFilename, String choice) { 75 @Argument(
141 File bf = new File(ballotFilename); 76 shortname = "r",
142 if (!bf.exists()) { 77 longname = "register",
143 System.err.println("ballot file does not exist"); 78 action = ArgumentAction.SET,
144 return; 79 description = "register an election with the authorities")
145 } 80 boolean register = false;
146 File kf = new File(privKeyFilename); 81
147 if (!kf.exists()) { 82 @Argument(
148 System.err.println("private-key file does not exist"); 83 shortname = "i",
149 return; 84 longname = "issue",
150 } 85 action = ArgumentAction.SET,
151 EcdsaPrivateKey privateKey = EcdsaPrivateKey.fromFile(privKeyFilename); 86 description = "sign the ballot as issuer (use with -e)")
152 if (privateKey == null) { 87 boolean issue = false;
153 System.err.println("keyfile invalid");
154 return;
155 }
156 Ballot ballot = new Ballot(ballotFilename);
157 ballot.encodeChoice(choice, privateKey);
158 try {
159 Files.write(ballot.serialize(), bf, Charsets.UTF_8);
160 } catch (IOException e) {
161 System.err.println("can not write to ballot file");
162 return;
163 }
164 System.out.println("vote written to ballot file");
165 }
166 88
89 @Argument(
90 shortname = "x",
91 longname = "select",
92 action = ArgumentAction.STORE_STRING,
93 argumentName = "CHOICE",
94 description = "select and encrypt a vote option (use with -e)")
95 String select = null;
96
97 @Argument(
98 shortname = "V",
99 longname = "verify",
100 action = ArgumentAction.SET,
101 description = "verify signatures in the ballot and show information")
102 boolean verify = false;
103
104 @Argument(
105 shortname = "g",
106 longname = "group",
107 action = ArgumentAction.STORE_STRING,
108 description = "incorporate the group cert into the ballot")
109 String groupCertFile = null;
110
111
112 @Argument(
113 shortname = "t",
114 longname = "template",
115 action = ArgumentAction.SET,
116 description = "write a template ballot to the give ballot file")
117 boolean template = false;
118
119 private Identity.Ego ego;
120
121 private Ballot ballot;
122 private String ballotFilename;
123
124 private Mesh mesh;
125 private Mesh.Tunnel tunnel;
126
127 private PeerIdentity currentAuthority;
128
129 /**
130 * Are we finished with communicating over the mesh tunnel and don't need to worry about
131 * disconnection?
132 */
133 private boolean tunnelCommunicationFinished;
134
135 public class BallotTunnelEndHandler implements TunnelEndHandler {
136 @Override
137 public void onTunnelEnd(Mesh.Tunnel tunnel) {
138 // FIXME
139 }
140 }
141
142 public class BallotRegisterReceiver extends MeshRunabout {
143 public void visit(BallotRegisterSuccessMessage m) {
144 System.out.println("ballot successfully registered");
145 ballot.addRegistrationSignature(currentAuthority, m.registrationSignature);
146 writeBallot();
147 tunnel.destroy();
148 mesh.destroy();
149 }
150
151 public void visit(BallotRegisterFailureMessage m) {
152 System.out.println("registering failed: " + m.reason);
153 tunnel.destroy();
154 mesh.destroy();
155 }
156
157 }
167 158
168 public void runVerify(String ballotFilename) { 159 public class QueryReceiver extends MeshRunabout {
169 File bf = new File(ballotFilename); 160 public void visit(QueryResponseMessage m) {
170 if (!bf.exists()) { 161 if (m.results.length != ballot.choices.size()) {
171 System.err.println("ballot file does not exist"); 162 System.out.println("failure to query result: malformed response");
172 return; 163 } else {
164 System.out.println("got results:");
165 for (int i = 0; i < m.results.length; i++) {
166 System.out.println("'" + ballot.choices.get(i) + "': " + m.results[i]);
173 } 167 }
174 Ballot ballot = new Ballot(ballotFilename);
175 System.out.print(ballot.describe());
176 } 168 }
177 169
178 @Override 170 tunnel.destroy();
179 public void run() { 171 mesh.destroy();
180 if (template) { 172 }
181 if (this.unprocessedArgs.length != 1) {
182 System.err.println("-t/--template requires exactly one positional argument");
183 return;
184 }
185 runTemplate(unprocessedArgs[0]);
186 return;
187 }
188 173
189 if (register) { 174 public void visit(QueryFailureMessage m) {
190 if (this.unprocessedArgs.length != 1) { 175 System.out.println("failure to query result: authority refused");
191 System.err.println("-r/--register requires exactly one positional argument"); 176 tunnel.destroy();
192 return; 177 mesh.destroy();
193 } 178 }
194 RegisterCommand c = new RegisterCommand(getConfiguration(), unprocessedArgs[0]); 179 }
195 c.run(); 180
196 return; 181 public class SubmitReceiver extends MeshRunabout {
197 } 182
198 if (issue) { 183 public void visit(SubmitSuccessMessage m) {
199 if (this.unprocessedArgs.length != 2) { 184 System.out.println("vote successfully submitted");
200 System.err.println("-i/--issue requires exactly two positional arguments"); 185 ballot.addConfirmation(currentAuthority, m.confirmationSig);
201 return; 186 writeBallot();
202 } 187 tunnel.destroy();
203 runIssue(unprocessedArgs[0], unprocessedArgs[1]); 188 mesh.destroy();
204 return; 189 }
205 } 190
206 if (select != null) { 191 public void visit(SubmitFailureMessage m) {
207 if (this.unprocessedArgs.length != 2) { 192 System.out.println("vote not submitted: " + m.reason);
208 System.err.println("-x/--select requires exactly two positional argument"); 193 tunnel.destroy();
209 return; 194 mesh.destroy();
210 } 195 }
211 runSelect(unprocessedArgs[0], unprocessedArgs[1], select); 196 }
212 return; 197
213 } 198 @Override
214 if (submit) { 199 protected String makeHelpText() {
215 if (this.unprocessedArgs.length != 1) { 200 return "gnunet-ballot [OPTIONS]... BALLOT\n" +
216 System.err.println("-s/--submit requires exactly one positional argument"); 201 "Create, modify and execute operation on ballots.";
217 return; 202 }
218 } 203
219 SubmitCommand c = new SubmitCommand(getConfiguration(), unprocessedArgs[0]); 204 private void runTemplate() {
220 c.run(); 205 File f = new File(ballotFilename);
221 return; 206 if (f.exists()) {
222 } 207 System.err.println("file already exists, not overwriting");
223 if (verify) { 208 return;
224 if (this.unprocessedArgs.length != 1) { 209 }
225 System.err.println("-V/--verify requires exactly one positional argument"); 210 InputStream is = getClass().getResourceAsStream("ballot-template.espec");
226 return; 211 OutputSupplier<FileOutputStream> oss = Files.newOutputStreamSupplier(f);
227 } 212 try {
228 runVerify(unprocessedArgs[0]); 213 ByteStreams.copy(is, oss);
229 return; 214 } catch (IOException e) {
215 System.err.println("could not copy template file: " + e.getMessage());
216 }
217 }
218
219 private void writeBallot() {
220 try {
221 Files.write(ballot.serialize(), new File(ballotFilename), Charsets.UTF_8);
222 } catch (IOException e) {
223 System.err.println("could not write ballot file: " + e.getMessage());
224 }
225 }
226
227 void doCommands() {
228 if (null != groupCertFile) {
229 Configuration groupCertConfig = new Configuration();
230 groupCertConfig.parse(groupCertFile);
231 GroupCert groupCert = GroupCert.fromGroupCertConfig(groupCertConfig);
232 ballot.encodeGroup(groupCert);
233 writeBallot();
234 return;
235 }
236 if (register) {
237 List<PeerIdentity> remainingAuthorities = ballot.getRemainingRegisterAuthorities();
238 if (remainingAuthorities.isEmpty()) {
239 System.err.println("all authorities already received the ballot");
240 return;
241 }
242 Random r = new Random();
243 currentAuthority = remainingAuthorities.get(r.nextInt(remainingAuthorities.size()));
244 System.out.println("registering ballot with authority " + currentAuthority.toString());
245 mesh = new Mesh(getConfiguration(), new BallotTunnelEndHandler(), new BallotRegisterReceiver());
246 tunnel = mesh.createTunnel(currentAuthority, TallyAuthorityDaemon.MESH_PORT, true, true, null);
247 BallotRegisterRequestMessage m = new BallotRegisterRequestMessage();
248 CompressedConfig ccfg = new CompressedConfig(ballot.toConfiguration());
249 m.compressedBallotConfig = ccfg.compressed_data;
250 tunnel.send(m);
251 return;
252 }
253 if (issue) {
254 if (null == ego) {
255 System.out.println("no ego given");
256 return;
257 }
258 ballot.issue(ego.getPrivateKey());
259 writeBallot();
260 return;
261 }
262 if (select != null) {
263 if (null == ego) {
264 System.out.println("no ego given");
265 return;
266 }
267 ballot.encodeChoice(select, ego.getPrivateKey());
268 writeBallot();
269 return;
270 }
271 if (submit) {
272 List<PeerIdentity> remainingAuthorities = ballot.getRemainingSubmitAuthorities();
273 if (remainingAuthorities.isEmpty()) {
274 System.err.println("all authorities already received the ballot");
275 return;
276 }
277 Random r = new Random();
278 PeerIdentity authority = remainingAuthorities.get(r.nextInt(remainingAuthorities.size()));
279 System.out.println("submitting to authority" + authority.toString());
280 currentAuthority = authority;
281 mesh = new Mesh(cfg, new BallotTunnelEndHandler(), new SubmitReceiver());
282 tunnel = mesh.createTunnel(authority, TallyAuthorityDaemon.MESH_PORT, true, true, null);
283 SubmitMessage m = new SubmitMessage();
284 if (ballot.voterPub == null) {
285 throw new InvalidBallotException("no voter in ballot");
286 }
287 m.voterPub = ballot.voterPub;
288 if (ballot.groupCert == null) {
289 throw new InvalidBallotException("no group cert in ballot");
290 }
291 m.groupCertExpiration = ballot.groupCert.getExpiration().asMessage();
292 m.groupCert = ballot.groupCert.getSignature();
293 m.ballotGuid = ballot.getBallotGuid();
294 m.choiceId = ballot.choiceId;
295 tunnel.send(m);
296 return;
297 }
298 if (verify) {
299 System.out.print(ballot.describe());
300 return;
301 }
302 if (query) {
303 List<PeerIdentity> remainingAuthorities = ballot.getAuthorities();
304 if (remainingAuthorities.isEmpty()) {
305 System.err.println("no authorities available");
306 return;
307 }
308 Random r = new Random();
309 PeerIdentity authority = remainingAuthorities.get(r.nextInt(remainingAuthorities.size()));
310 System.out.println("querying authority" + authority.toString());
311 mesh = new Mesh(cfg, new BallotTunnelEndHandler(), new QueryReceiver());
312 tunnel = mesh.createTunnel(authority, TallyAuthorityDaemon.MESH_PORT, true, true, null);
313 QueryMessage m = new QueryMessage();
314 m.ballotGUID = ballot.getBallotGuid();
315 tunnel.send(m);
316 return;
317 }
318 }
319
320 @Override
321 public void run() {
322 if (unprocessedArgs.length != 1) {
323 System.err.println("no ballot file specified");
324 setReturnValue(1);
325 return;
326 }
327 ballotFilename = unprocessedArgs[0];
328 if (template) {
329 runTemplate();
330 return;
331 }
332 // all other commands need a loaded ballot file
333 File bf = new File(ballotFilename);
334 if (!bf.exists()) {
335 System.err.println("ballot file does not exist");
336 return;
337 }
338 ballot = new Ballot(ballotFilename);
339 if (null != egoName) {
340 Identity.lookup(getConfiguration(), egoName, new IdentityCallback() {
341 @Override
342 public void onEgo(Identity.Ego ego) {
343 BallotTool.this.ego = ego;
344 doCommands();
230 } 345 }
231 if (query) { 346 @Override
232 if (this.unprocessedArgs.length != 1) { 347 public void onError(String errorMessage) {
233 System.err.println("-q/--query requires exactly one positional argument"); 348 System.err.println("can't retrieve ego: " + errorMessage);
234 return; 349 setReturnValue(1);
235 }
236 QueryCommand c = new QueryCommand(getConfiguration(), unprocessedArgs[0]);
237 c.run();
238 return;
239 } 350 }
240 } 351 });
241 }.start(); 352 } else {
353 doCommands();
354 }
355 }
242 356
357 private BallotTool(String[] args) {
358 super(args);
243 } 359 }
244 360
361 public static void main(String args[]) {
362 Program tool = new BallotTool(args);
363 tool.start();
364 }
245} 365}