From b55355e56480bcbd54978524e0650ec1cd2834c4 Mon Sep 17 00:00:00 2001 From: Salvatore Ingala <6681844+bigspider@users.noreply.github.com> Date: Fri, 25 Oct 2019 13:50:16 +0800 Subject: [PATCH] pisa-cli saving appointments and signatures to disk on success --- apps/cli/__init__.py | 3 ++- apps/cli/pisa-cli.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/apps/cli/__init__.py b/apps/cli/__init__.py index 3e4e530..59bcde7 100644 --- a/apps/cli/__init__.py +++ b/apps/cli/__init__.py @@ -1,5 +1,5 @@ import logging -from logger import Logger +from .logger import Logger # PISA-SERVER DEFAULT_PISA_API_SERVER = 'btc.pisa.watch' @@ -7,6 +7,7 @@ DEFAULT_PISA_API_PORT = 9814 # PISA-CLI CLIENT_LOG_FILE = 'pisa-cli.log' +APPOINTMENTS_FOLDER_NAME = 'appointments' # CRYPTO SUPPORTED_HASH_FUNCTIONS = ["SHA256"] diff --git a/apps/cli/pisa-cli.py b/apps/cli/pisa-cli.py index 97b5428..0a56f1d 100644 --- a/apps/cli/pisa-cli.py +++ b/apps/cli/pisa-cli.py @@ -3,11 +3,13 @@ import os import sys import json import requests +import time from sys import argv from hashlib import sha256 from binascii import unhexlify from getopt import getopt, GetoptError from requests import ConnectTimeout, ConnectionError +from uuid import uuid4 from cryptography.hazmat.backends import default_backend @@ -18,7 +20,7 @@ from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm from apps.cli.blob import Blob from apps.cli.help import help_add_appointment, help_get_appointment -from apps.cli import DEFAULT_PISA_API_SERVER, DEFAULT_PISA_API_PORT, PISA_PUBLIC_KEY +from apps.cli import DEFAULT_PISA_API_SERVER, DEFAULT_PISA_API_PORT, PISA_PUBLIC_KEY, APPOINTMENTS_FOLDER_NAME from apps.cli import logger @@ -45,7 +47,7 @@ def generate_dummy_appointment(): # Loads Pisa's public key from disk and verifies that the appointment signature is a valid signature from Pisa, # returning True or False accordingly. # Will raise NotFoundError or IOError if the attempts to open and read the public key file fail. -# Will raise ValueError if it the public key file was present but it failed to be unserialized. +# Will raise ValueError if it the public key file was present but it failed to be deserialized. def is_appointment_signature_valid(appointment, signature): # Load the key from disk try: @@ -53,7 +55,7 @@ def is_appointment_signature_valid(appointment, signature): pubkey_pem = key_file.read().encode("utf-8") pisa_public_key = load_pem_public_key(pubkey_pem, backend=default_backend()) except UnsupportedAlgorithm: - raise ValueError("Could not unserialize the public key (unsupported algorithm).") + raise ValueError("Could not deserialize the public key (unsupported algorithm).") try: sig_bytes = unhexlify(signature.encode('utf-8')) @@ -65,6 +67,24 @@ def is_appointment_signature_valid(appointment, signature): return True +def save_signed_appointment(appointment, signature): + # Create the appointments directory if it doesn't already exist + try: + os.makedirs(APPOINTMENTS_FOLDER_NAME) + except FileExistsError: + # directory already exists + pass + + timestamp = int(time.time()*1000) + locator = appointment['locator'] + uuid = uuid4() # prevent filename collisions + filename = "{}/appointment-{}-{}-{}.json".format(APPOINTMENTS_FOLDER_NAME, timestamp, locator, uuid) + data = {"appointment": appointment, "signature": signature} + + with open(filename, "w") as f: + json.dump(data, f) + + def add_appointment(args): appointment_data = None use_help = "Use 'help add_appointment' for help of how to use the command." @@ -106,16 +126,20 @@ def add_appointment(args): try: r = requests.post(url=add_appointment_endpoint, json=appointment_json, timeout=5) - logger.info("{} (code: {}).".format(r.json(), r.status_code)) - response_json = r.json() + print(response_json) if r.status_code == HTTP_OK: if 'signature' not in response_json: logger.error("The response does not contain the signature of the appointment.") else: + signature = response_json['signature'] # verify that the returned signature is valid - if not is_appointment_signature_valid(appointment, response_json['signature']): + if is_appointment_signature_valid(appointment, signature): + logger.info("Appointment accepted and signed by Pisa.") + # TODO: store on disk + save_signed_appointment(appointment, signature) + else: logger.error("The returned appointment's signature is invalid.") else: if 'error' not in response_json: