def dequeue(): try: dequeue_task() except Exception as e: return make_response(dumps(dict(status=e.message)), 202) return make_response(dumps(dict(status="ok")), 202)
def return_election(task): input_data = task.get_data()['input_data'] election_id = input_data['election_id'] session_ids = input_data['session_ids'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session_data = [] for session_id in session_ids: # read into a string the pubkey privdata_path = app.config.get('PRIVATE_DATA_PATH', '') pubkey_path = os.path.join(privdata_path, str(election_id), session_id, 'publicKey_json') pubkey_file = open(pubkey_path, 'r') pubkey = pubkey_file.read() pubkey_file.close() session_data.append(dict( session_id=session_id, pubkey=json.loads(pubkey) )) # publish the pubkey pubdata_path = app.config.get('PUBLIC_DATA_PATH', '') pub_session_path = os.path.join(pubdata_path, str(election_id), session_id) pubkey_path2 = os.path.join(pub_session_path, 'publicKey_json') if not os.path.exists(pub_session_path): mkdir_recursive(pub_session_path) shutil.copyfile(pubkey_path, pubkey_path2) # publish protInfo.xml too session_privpath = os.path.join(privdata_path, str(election_id), session_id) protinfo_privpath = os.path.join(session_privpath, 'protInfo.xml') protinfo_pubpath = os.path.join(pub_session_path, 'protInfo.xml') shutil.copyfile(protinfo_privpath, protinfo_pubpath) session = requests.sessions.Session() session.mount('http://', RejectAdapter()) callback_url = election.callback_url ret_data = { "status": "finished", "reference": { "election_id": election_id, "action": "POST /election" }, "session_data": session_data } print "callback_url, ", callback_url print dumps(ret_data) ssl_calist_path = app.config.get('SSL_CALIST_PATH', '') ssl_cert_path = app.config.get('SSL_CERT_PATH', '') ssl_key_path = app.config.get('SSL_KEY_PATH', '') print("\nFF callback_url2 " + callback_url) r = session.request('post', callback_url, data=dumps(ret_data), headers={'content-type': 'application/json'}, verify=ssl_calist_path, cert=(ssl_cert_path, ssl_key_path)) print r.text end_task()
def return_election(task): input_data = task.get_data()['input_data'] election_id = input_data['election_id'] session_ids = input_data['session_ids'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session_data = [] for session_id in session_ids: # read into a string the pubkey privdata_path = app.config.get('PRIVATE_DATA_PATH', '') pubkey_path = os.path.join(privdata_path, str(election_id), session_id, 'publicKey_json') pubkey_file = open(pubkey_path, 'r') pubkey = pubkey_file.read() pubkey_file.close() session_data.append( dict(session_id=session_id, pubkey=json.loads(pubkey))) # publish the pubkey pubdata_path = app.config.get('PUBLIC_DATA_PATH', '') pub_session_path = os.path.join(pubdata_path, str(election_id), session_id) pubkey_path2 = os.path.join(pub_session_path, 'publicKey_json') if not os.path.exists(pub_session_path): mkdir_recursive(pub_session_path) shutil.copyfile(pubkey_path, pubkey_path2) # publish protInfo.xml too session_privpath = os.path.join(privdata_path, str(election_id), session_id) protinfo_privpath = os.path.join(session_privpath, 'protInfo.xml') protinfo_pubpath = os.path.join(pub_session_path, 'protInfo.xml') shutil.copyfile(protinfo_privpath, protinfo_pubpath) session = requests.sessions.Session() callback_url = election.callback_url ret_data = { "status": "finished", "reference": { "election_id": election_id, "action": "POST /election" }, "session_data": session_data } print "callback_url, ", callback_url print dumps(ret_data) r = session.request('post', callback_url, data=dumps(ret_data), headers={'content-type': 'application/json'}, verify=False) print r.text end_task()
def handle_error(self, error): ''' When an error is propagated up to here, is time to return to the sender that this task failed ''' session = requests.sessions.Session() input_data = self.task.get_data()['input_data'] election_id = input_data['election_id'] callback_url = input_data['callback_url'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session = requests.sessions.Session() fail_data = { "status": "error", "reference": { "election_id": election_id, "action": "POST /tally" }, "data": { "message": "election tally failed for some reason" } } r = session.request('post', callback_url, data=dumps(fail_data), headers={'content-type': 'application/json'}, verify=False) print r.text end_task()
def handle_error(self, error): ''' When an error is propagated up to here, is time to return to the sender that this task failed ''' session = requests.sessions.Session() input_data = self.task.get_data()['input_data'] election_id = input_data['election_id'] election = db.session.query(Election)\ .filter(Election.session_id == election_id).first() session = requests.sessions.Session() callback_url = election.callback_url fail_data = { "status": "error", "reference": { "election_id": election_id, "action": "POST /election" }, "data": { "message": "election creation failed for some reason" } } r = session.request('post', callback_url, data=dumps(fail_data), verify=False) end_task()
def return_election(task): input_data = task.get_parent().get_data()['input_data'] election_id = input_data['election_id'] callback_url = input_data['callback_url'] pub_data_url = app.config.get('PUBLIC_DATA_BASE_URL', '') tally_url = pub_data_url + '/' + str(election_id) + '/tally.tar.gz' pub_data_path = app.config.get('PUBLIC_DATA_PATH', '') tally_hash_path = os.path.join(pub_data_path, str(election_id), 'tally.tar.gz.sha256') f = open(tally_hash_path, 'r') tally_hash = f.read() f.close() ret_data = { "status": "finished", "reference": { "election_id": election_id, "action": "POST /tally" }, "data": { "tally_url": tally_url, "tally_hash": "ni:///sha-256;" + tally_hash } } session = requests.sessions.Session() r = session.request('post', callback_url, data=dumps(ret_data), headers={'content-type': 'application/json'}, verify=False) print r.text end_task()
def handle_error(self, error): ''' When an error is propagated up to here, is time to return to the sender that this task failed ''' session = requests.sessions.Session() session.mount('http://', RejectAdapter()) input_data = self.task.get_data()['input_data'] election_id = input_data['election_id'] callback_url = input_data['callback_url'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session = requests.sessions.Session() fail_data = { "status": "error", "reference": { "election_id": election_id, "action": "POST /tally" }, "data": { "message": "election tally failed for some reason" } } ssl_calist_path = app.config.get('SSL_CALIST_PATH', '') ssl_cert_path = app.config.get('SSL_CERT_PATH', '') ssl_key_path = app.config.get('SSL_KEY_PATH', '') print("\nFF callback_url4 " + callback_url) r = session.request('post', callback_url, data=dumps(fail_data), headers={'content-type': 'application/json'}, verify=ssl_calist_path, cert=(ssl_cert_path, ssl_key_path)) print r.text end_task()
def execute(self): username = self.task.get_data()['input_data']['username'] print "our reservation: ", dumps(self.task.get_reservation_data()) print "others reservation: ", dumps(self.task.get_data()['input_data']) print "woke up! time to finish =)\n" server_name = app.config.get('SERVER_NAME') # free the port self.cancel_reservation() self.task.set_output_data("goodbye %s from port %d in server %s!" % ( username, self.task.get_reservation_data()['port'], app.config.get('SERVER_NAME') ))
def execute(self): username = self.task.get_data()['input_data']['username'] print("our reservation: " + dumps(self.task.get_reservation_data())) print("others reservation: " + dumps(self.task.get_data()['input_data'])) print("woke up! time to finish =)\n") server_name = app.config.get('SERVER_NAME') # free the port self.cancel_reservation() self.task.set_output_data( "goodbye %s from port %d in server %s!" % (username, self.task.get_reservation_data()['port'], app.config.get('SERVER_NAME')))
def post_tally(): ''' POST /tally Tallies an election, with the given input data. This involves communicating with the different election authorities to do the tally. Example request: POST /tally { "election_id": 111, "callback_url": "https://127.0.0.1:5000/public_api/receive_tally", "votes_url": "https://127.0.0.1:5000/public_data/vota4/encrypted_ciphertexts", "votes_hash": "ni:///sha-256;f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk" } On success, response is empty with status 202 Accepted and returns something like: { "task_id": "ba83ee09-aa83-1901-bb11-e645b52fc558", } When the election finally gets processed, the callback_url is called with POST similar to the following example: { "status": "finished", "reference": { "election_id": "d9e5ee09-03fa-4890-aa83-2fc558e645b5", "action": "POST /tally" }, "data": { "votes_url": "https://127.0.0.1:5000/public_data/vota4/tally.tar.bz2", "votes_hash": "ni:///sha-256;f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk" } } If there was an error, then the callback will be called following this example format: { "status": "error", "reference": { "election_id": "d9e5ee09-03fa-4890-aa83-2fc558e645b5", "action": "POST /tally" }, "data": { "message": "error message" } } ''' # first of all, parse input data data = request.get_json(force=True, silent=True) d = base64.b64encode(pickle.dumps(data)) queueid = queue_task(task='tally', data=d) return make_response(dumps(dict(queue_id=queueid)), 202)
def return_election(task): input_data = task.get_parent().get_data()['input_data'] election_id = input_data['election_id'] callback_url = input_data['callback_url'] pub_data_url = app.config.get('PUBLIC_DATA_BASE_URL', '') tally_url = pub_data_url + '/' + str(election_id) + '/tally.tar.gz' pub_data_path = app.config.get('PUBLIC_DATA_PATH', '') tally_hash_path = os.path.join(pub_data_path, str(election_id), 'tally.tar.gz.sha256') f = open(tally_hash_path, 'r') tally_hash = f.read() f.close() ret_data = { "status": "finished", "reference": { "election_id": election_id, "action": "POST /tally" }, "data": { "tally_url": tally_url, "tally_hash": "ni:///sha-256;" + tally_hash } } session = requests.sessions.Session() session.mount('http://', RejectAdapter()) ssl_calist_path = app.config.get('SSL_CALIST_PATH', '') ssl_cert_path = app.config.get('SSL_CERT_PATH', '') ssl_key_path = app.config.get('SSL_KEY_PATH', '') print("\nFF callback_url5 " + callback_url) r = session.request('post', callback_url, data=dumps(ret_data), headers={'content-type': 'application/json'}, verify=ssl_calist_path, cert=(ssl_cert_path, ssl_key_path)) print(r.text) end_task()
def handle_error(self, error): ''' When an error is propagated up to here, is time to return to the sender that this task failed ''' try: session = requests.sessions.Session() session.mount('http://', RejectAdapter()) input_data = self.task.get_data()['input_data'] election_id = input_data['election_id'] callback_url = input_data['callback_url'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session = requests.sessions.Session() fail_data = { "status": "error", "reference": { "election_id": election_id, "action": "POST /tally" }, "data": { "message": "election tally failed for some reason" } } ssl_calist_path = app.config.get('SSL_CALIST_PATH', '') ssl_cert_path = app.config.get('SSL_CERT_PATH', '') ssl_key_path = app.config.get('SSL_KEY_PATH', '') print("\nFF callback_url4 " + callback_url) r = session.request('post', callback_url, data=dumps(fail_data), headers={'content-type': 'application/json'}, verify=ssl_calist_path, cert=(ssl_cert_path, ssl_key_path)) print(r.text) finally: end_task()
def election_task(data): if not data: print("invalid json") return False try: check_election_data(data, True) except Exception as e: print("ERROR", e) return False e = Election(id=data['id'], title=data['title'][:255], description=data['description'], questions=dumps(data['questions']), start_date=data['start_date'], end_date=data['end_date'], callback_url=data['callback_url'], num_parties=len(data['authorities']), threshold_parties=len(data['authorities']), status='creating') db.session.add(e) for auth_data in data['authorities']: authority = Authority(name=auth_data['name'], ssl_cert=auth_data['ssl_cert'], orchestra_url=auth_data['orchestra_url'], election_id=data['id']) db.session.add(authority) db.session.commit() task = SimpleTask(receiver_url=app.config.get('ROOT_URL', ''), action="create_election", queue="launch_task", data={'election_id': data['id']}) task.create_and_send() return task
def election_task(data): if not data: print("invalid json") return False try: check_election_data(data, True) except Exception, e: print("ERROR", e) return False e = Election(id=data['id'], title=data['title'][:255], description=data['description'], questions=dumps(data['questions']), start_date=data['start_date'], end_date=data['end_date'], callback_url=data['callback_url'], num_parties=len(data['authorities']), threshold_parties=len(data['authorities']), status='creating') db.session.add(e) for auth_data in data['authorities']: authority = Authority(name=auth_data['name'], ssl_cert=auth_data['ssl_cert'], orchestra_url=auth_data['orchestra_url'], election_id=data['id']) db.session.add(authority) db.session.commit()
def error(status, message=""): if message: data = json.dumps(dict(message=message)) else: data = "" return make_response(data, status) @public_api.route('/dequeue', methods=['GET']) def dequeue(): try: dequeue_task() except Exception, e: return make_response(dumps(dict(status=e.message)), 202) return make_response(dumps(dict(status="ok")), 202) @public_api.route('/election', methods=['POST']) def post_election(): ''' POST /election Creates an election, with the given input data. This involves communicating with the different election authorities to generate the joint public key. Example request: POST /election { "id": 1110, "title": "Votación de candidatos",
def post_election(): ''' POST /election Creates an election, with the given input data. This involves communicating with the different election authorities to generate the joint public key. Example request: POST /election { "id": 1110, "title": "Votación de candidatos", "description": "Selecciona los documentos político, ético y organizativo con los que Podemos", "director": "wadobo-auth1", "authorities": "openkratio-authority", "layout": "pcandidates-election", "presentation": { "share_text": "lo que sea", "theme": "foo", "urls": [ { "title": "", "url": "" } ], "theme_css": "whatever" }, "end_date": "2013-12-09T18:17:14.457000", "start_date": "2013-12-06T18:17:14.457000", "questions": [ { "description": "", "layout": "pcandidates-election", "max": 1, "min": 0, "num_winners": 1, "title": "Secretaría General", "randomize_answer_order": true, "tally_type": "plurality-at-large", "answer_total_votes_percentage": "over-total-valid-votes", "answers": [ { "id": 0, "category": "Equipo de Enfermeras", "details": "", "sort_order": 1, "urls": [ { "title": "", "url": "" } ], "text": "Fulanita de tal", } ] } ], "authorities": [ { "name": "Asociación Sugus GNU/Linux", "orchestra_url": "https://sugus.eii.us.es/orchestra", "ssl_cert": "-----BEGIN CERTIFICATE-----\nMIIFATCCA+mgAwIBAgIQAOli4NZQEWpKZeYX25jjwDANBgkqhkiG9w0BAQUFADBz\n8YOltJ6QfO7jNHU9jh/AxeiRf6MibZn6fvBHvFCrVBvDD43M0gdhMkVEDVNkPaak\nC7AHA/waXZ2EwW57Chr2hlZWAkwkFvsWxNt9BgJAJJt4CIVhN/iau/SaXD0l0t1N\nT0ye54QPYl38Eumvc439Yd1CeVS/HYbP0ISIfpNkkFA5TiQdoA==\n-----END CERTIFICATE-----" }, { "name": "Agora Ciudadana", "orchestra_url": "https://agoravoting.com:6874/orchestra", "ssl_cert": "-----BEGIN CERTIFICATE-----\nMIIFATCCA+mgAwIBAgIQAOli4NZQEWpKZeYX25jjwDANBgkqhkiG9w0BAQUFADBz\n8YOltJ6QfO7jNHU9jh/AxeiRf6MibZn6fvBHvFCrVBvDD43M0gdhMkVEDVNkPaak\nC7AHA/waXZ2EwW57Chr2hlZWAkwkFvsWxNt9BgJAJJt4CIVhN/iau/SaXD0l0t1N\nT0ye54QPYl38Eumvc439Yd1CeVS/HYbP0ISIfpNkkFA5TiQdoA==\n-----END CERTIFICATE-----" }, { "name": "Wadobo Labs", "orchestra_url": "https://wadobo.com:6874/orchestra", "ssl_cert": "-----BEGIN CERTIFICATE-----\nMIIFATCCA+mgAwIBAgIQAOli4NZQEWpKZeYX25jjwDANBgkqhkiG9w0BAQUFADBz\n8YOltJ6QfO7jNHU9jh/AxeiRf6MibZn6fvBHvFCrVBvDD43M0gdhMkVEDVNkPaak\nC7AHA/waXZ2EwW57Chr2hlZWAkwkFvsWxNt9BgJAJJt4CIVhN/iau/SaXD0l0t1N\nT0ye54QPYl38Eumvc439Yd1CeVS/HYbP0ISIfpNkkFA5TiQdoA==\n-----END CERTIFICATE-----" } ] } On success, response is empty with status 202 Accepted and returns something like: { "task_id": "ba83ee09-aa83-1901-bb11-e645b52fc558", } When the election finally gets processed, the callback_url is called with a POST containing the protInfo.xml file generated jointly by each authority, following this example response: { "status": "finished", "reference": { "election_id": "d9e5ee09-03fa-4890-aa83-2fc558e645b5", "action": "POST /election" }, "session_data": [{ "session_id": "deadbeef-03fa-4890-aa83-2fc558e645b5", "publickey": ["<pubkey codified in hexadecimal>"] }] } Note that this protInfo.xml will contain the election public key, but also some other information. In particular, it's worth noting that the http and hint servers' urls for each authority could change later, if election-orchestra needs it. If there was an error, then the callback will be called following this example format: { "status": "error", "reference": { "session_id": "d9e5ee09-03fa-4890-aa83-2fc558e645b5", "action": "POST /election" }, "data": { "message": "error message" } } ''' data = request.get_json(force=True, silent=True) d = base64.b64encode(pickle.dumps(data)) queueid = queue_task(task='election', data=d) return make_response(dumps(dict(queue_id=queueid)), 202)
def return_election(task): input_data = task.get_data()['input_data'] election_id = input_data['election_id'] session_ids = input_data['session_ids'] election = db.session.query(Election)\ .filter(Election.id == election_id).first() session_data = [] for session_id in session_ids: # read into a string the pubkey privdata_path = app.config.get('PRIVATE_DATA_PATH', '') pubkey_path = os.path.join(privdata_path, str(election_id), session_id, 'publicKey_json') pubkey_file = open(pubkey_path, 'r') pubkey = pubkey_file.read() pubkey_file.close() session_data.append( dict(session_id=session_id, pubkey=json.loads(pubkey))) # publish the pubkey pubdata_path = app.config.get('PUBLIC_DATA_PATH', '') pub_session_path = os.path.join(pubdata_path, str(election_id), session_id) pubkey_path2 = os.path.join(pub_session_path, 'publicKey_json') if not os.path.exists(pub_session_path): mkdir_recursive(pub_session_path) shutil.copyfile(pubkey_path, pubkey_path2) # publish protInfo.xml too session_privpath = os.path.join(privdata_path, str(election_id), session_id) protinfo_privpath = os.path.join(session_privpath, 'protInfo.xml') protinfo_pubpath = os.path.join(pub_session_path, 'protInfo.xml') shutil.copyfile(protinfo_privpath, protinfo_pubpath) session = requests.sessions.Session() session.mount('http://', RejectAdapter()) callback_url = election.callback_url ret_data = { "status": "finished", "reference": { "election_id": election_id, "action": "POST /election" }, "session_data": session_data } print("callback_url, " + callback_url + ", data = ") print(dumps(ret_data)) ssl_calist_path = app.config.get('SSL_CALIST_PATH', '') ssl_cert_path = app.config.get('SSL_CERT_PATH', '') ssl_key_path = app.config.get('SSL_KEY_PATH', '') try: r = session.request('post', callback_url, data=dumps(ret_data), headers={'content-type': 'application/json'}, verify=ssl_calist_path, cert=(ssl_cert_path, ssl_key_path)) except Exception as e: print("exception posting callback = ") print(e) raise e print("received text = ") print(r.text) end_task()
def dequeue(): try: dequeue_task() except Exception, e: return make_response(dumps(dict(status=e.message)), 202)
def election_task(data): if not data: print ("invalid json") return False try: check_election_data(data, True) except Exception, e: print("ERROR", e) return False e = Election( id = data['id'], title = data['title'][:255], description = data['description'], questions = dumps(data['questions']), start_date = data['start_date'], end_date = data['end_date'], callback_url = data['callback_url'], num_parties = len(data['authorities']), threshold_parties = len(data['authorities']), status = 'creating' ) db.session.add(e) for auth_data in data['authorities']: authority = Authority( name = auth_data['name'], ssl_cert = auth_data['ssl_cert'], orchestra_url = auth_data['orchestra_url'], election_id = data['id']
def error(status, message=""): if message: data = json.dumps(dict(message=message)) else: data="" return make_response(data, status) @public_api.route('/dequeue', methods=['GET']) def dequeue(): try: dequeue_task() except Exception, e: return make_response(dumps(dict(status=e.message)), 202) return make_response(dumps(dict(status="ok")), 202) @public_api.route('/election', methods=['POST']) def post_election(): ''' POST /election Creates an election, with the given input data. This involves communicating with the different election authorities to generate the joint public key. Example request: POST /election { "id": 1110, "title": "Votación de candidatos",