diff --git a/pisa/pisad.py b/pisa/pisad.py index fc09f6b..0e8160b 100644 --- a/pisa/pisad.py +++ b/pisa/pisad.py @@ -7,7 +7,7 @@ from pisa.logger import Logger from pisa.api import start_api from pisa.watcher import Watcher from pisa.builder import Builder -from pisa.conf import BTC_NETWORK +from pisa.conf import BTC_NETWORK, PISA_SECRET_KEY from pisa.responder import Responder from pisa.db_manager import DBManager from pisa.block_processor import BlockProcessor @@ -49,7 +49,10 @@ if __name__ == "__main__": watcher_appointments_data = db_manager.load_watcher_appointments() responder_trackers_data = db_manager.load_responder_trackers() - watcher = Watcher(db_manager) + with open(PISA_SECRET_KEY, "rb") as key_file: + secret_key_der = key_file.read() + + watcher = Watcher(db_manager, secret_key_der) if len(watcher_appointments_data) == 0 and len(responder_trackers_data) == 0: logger.info("Fresh bootstrap") diff --git a/pisa/watcher.py b/pisa/watcher.py index 15797b0..25c7db8 100644 --- a/pisa/watcher.py +++ b/pisa/watcher.py @@ -10,7 +10,7 @@ from pisa.cleaner import Cleaner from pisa.responder import Responder from pisa.block_processor import BlockProcessor from pisa.utils.zmq_subscriber import ZMQSubscriber -from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS, PISA_SECRET_KEY +from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS logger = Logger("Watcher") @@ -32,7 +32,7 @@ class Watcher: Args: db_manager (:obj:`DBManager `): a ``DBManager`` instance to interact with the database. - pisa_sk_file (:obj:`str`): a path to the private key used to sign appointment receipts (signaling acceptance). + sk_der (:obj:`bytes`): a DER encoded private key used to sign appointment receipts (signaling acceptance). responder (:obj:`Responder `): a ``Responder`` instance. If ``None`` is passed, a new instance is created. Populated instances are useful when bootstrapping the system from backed-up data. max_appointments(:obj:`int`): the maximum amount of appointments that the :obj:`Watcher` will keep at any given @@ -58,7 +58,7 @@ class Watcher: """ - def __init__(self, db_manager, pisa_sk_file=PISA_SECRET_KEY, responder=None, max_appointments=MAX_APPOINTMENTS): + def __init__(self, db_manager, sk_der, responder=None, max_appointments=MAX_APPOINTMENTS): self.appointments = dict() self.locator_uuid_map = dict() self.asleep = True @@ -66,17 +66,11 @@ class Watcher: self.max_appointments = max_appointments self.zmq_subscriber = None self.db_manager = db_manager + self.signing_key = Cryptographer.load_private_key_der(sk_der) if not isinstance(responder, Responder): self.responder = Responder(db_manager) - if pisa_sk_file is None: - raise ValueError("No signing key provided. Please fix your pisa.conf") - else: - with open(PISA_SECRET_KEY, "rb") as key_file: - secret_key_der = key_file.read() - self.signing_key = Cryptographer.load_private_key_der(secret_key_der) - @staticmethod def compute_locator(tx_id): """ diff --git a/test/unit/test_api.py b/test/unit/test_api.py index d7d2462..c7ed0ad 100644 --- a/test/unit/test_api.py +++ b/test/unit/test_api.py @@ -3,6 +3,7 @@ import pytest import requests from time import sleep from threading import Thread +from cryptography.hazmat.primitives import serialization from pisa.api import start_api from pisa.watcher import Watcher @@ -10,7 +11,13 @@ from pisa.tools import bitcoin_cli from pisa import HOST, PORT, c_logger from pisa.conf import MAX_APPOINTMENTS -from test.unit.conftest import generate_block, generate_blocks, get_random_value_hex, generate_dummy_appointment_data +from test.unit.conftest import ( + generate_block, + generate_blocks, + get_random_value_hex, + generate_dummy_appointment_data, + generate_keypair, +) from common.constants import LOCATOR_LEN_BYTES @@ -25,7 +32,13 @@ locator_dispute_tx_map = {} @pytest.fixture(scope="module") def run_api(db_manager): - watcher = Watcher(db_manager) + sk, pk = generate_keypair() + sk_der = sk.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + watcher = Watcher(db_manager, sk_der) api_thread = Thread(target=start_api, args=[watcher]) api_thread.daemon = True diff --git a/test/unit/test_watcher.py b/test/unit/test_watcher.py index e5fb5ff..cd2db0d 100644 --- a/test/unit/test_watcher.py +++ b/test/unit/test_watcher.py @@ -2,13 +2,20 @@ import pytest from uuid import uuid4 from threading import Thread from queue import Queue, Empty +from cryptography.hazmat.primitives import serialization from pisa import c_logger from pisa.watcher import Watcher from pisa.responder import Responder from pisa.tools import bitcoin_cli -from test.unit.conftest import generate_block, generate_blocks, generate_dummy_appointment, get_random_value_hex -from pisa.conf import EXPIRY_DELTA, PISA_SECRET_KEY, MAX_APPOINTMENTS +from test.unit.conftest import ( + generate_block, + generate_blocks, + generate_dummy_appointment, + get_random_value_hex, + generate_keypair, +) +from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS from common.tools import check_sha256_hex_format from common.cryptographer import Cryptographer @@ -20,15 +27,18 @@ START_TIME_OFFSET = 1 END_TIME_OFFSET = 1 TEST_SET_SIZE = 200 -with open(PISA_SECRET_KEY, "rb") as key_file_der: - sk_der = key_file_der.read() - signing_key = Cryptographer.load_private_key_der(sk_der) - public_key = signing_key.public_key() + +signing_key, public_key = generate_keypair() +sk_der = signing_key.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), +) @pytest.fixture(scope="module") def watcher(db_manager): - return Watcher(db_manager) + return Watcher(db_manager, sk_der) @pytest.fixture(scope="module") @@ -69,15 +79,6 @@ def test_init(watcher): assert type(watcher.responder) is Responder -def test_init_no_key(db_manager): - try: - Watcher(db_manager, pisa_sk_file=None) - assert False - - except ValueError: - assert True - - def test_add_appointment(run_bitcoind, watcher): # The watcher automatically fires do_watch and do_subscribe on adding an appointment if it is asleep (initial state) # Avoid this by setting the state to awake.