コード例 #1
0
def test_add_appointment(watcher, generate_dummy_appointment):
    # Simulate the user is registered
    user_sk, user_pk = generate_keypair()
    available_slots = 100
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(
        available_slots=available_slots,
        subscription_expiry=watcher.block_processor.get_block_count() + 1)

    appointment, dispute_tx = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               user_sk)

    response = watcher.add_appointment(appointment, appointment_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment_signature, response.get("start_block")),
                response.get("signature"),
            ))
    assert response.get("available_slots") == available_slots - 1

    # Check that we can also add an already added appointment (same locator)
    response = watcher.add_appointment(appointment, appointment_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment_signature, response.get("start_block")),
                response.get("signature"),
            ))
    # The slot count should not have been reduced and only one copy is kept.
    assert response.get("available_slots") == available_slots - 1
    assert len(watcher.locator_uuid_map[appointment.locator]) == 1

    # If two appointments with the same locator come from different users, they are kept.
    another_user_sk, another_user_pk = generate_keypair()
    another_user_id = Cryptographer.get_compressed_pk(another_user_pk)
    watcher.gatekeeper.registered_users[another_user_id] = UserInfo(
        available_slots=available_slots,
        subscription_expiry=watcher.block_processor.get_block_count() + 1)

    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               another_user_sk)
    response = watcher.add_appointment(appointment, appointment_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment_signature, response.get("start_block")),
                response.get("signature"),
            ))
    assert response.get("available_slots") == available_slots - 1
    assert len(watcher.locator_uuid_map[appointment.locator]) == 2
コード例 #2
0
def test_add_appointment_multiple_times_different_users(
        internal_api,
        client,
        appointment,
        block_processor,
        n=MULTIPLE_APPOINTMENTS):
    # If the same appointment comes from different users, all are kept
    # Create user keys and appointment signatures
    user_keys = [generate_keypair() for _ in range(n)]
    signatures = [
        Cryptographer.sign(appointment.serialize(), key[0])
        for key in user_keys
    ]
    tmp_user_ids = [Cryptographer.get_compressed_pk(pk) for _, pk in user_keys]

    # Add one slot per public key
    for pair in user_keys:
        user_id = Cryptographer.get_compressed_pk(pair[1])
        internal_api.watcher.gatekeeper.registered_users[user_id] = UserInfo(
            available_slots=1,
            subscription_expiry=block_processor.get_block_count() + 1)

    # Send the appointments
    for compressed_pk, signature in zip(tmp_user_ids, signatures):
        r = add_appointment(client, {
            "appointment": appointment.to_dict(),
            "signature": signature
        }, compressed_pk)
        assert r.status_code == HTTP_OK
        assert r.json.get("available_slots") == 0
        assert r.json.get("start_block") == block_processor.get_block_count()

    # Check that all the appointments have been added and that there are no duplicates
    assert len(set(
        internal_api.watcher.locator_uuid_map[appointment.locator])) == n
コード例 #3
0
def test_update_states_responder_misses_more(run_bitcoind, db_manager,
                                             gatekeeper, carrier,
                                             block_processor):
    w = Watcher(
        db_manager=db_manager,
        gatekeeper=gatekeeper,
        block_processor=block_processor,
        responder=Responder(db_manager, gatekeeper, carrier, block_processor),
        sk_der=generate_keypair()[0].to_der(),
        max_appointments=config.get("MAX_APPOINTMENTS"),
        blocks_in_cache=config.get("LOCATOR_CACHE_SIZE"),
    )

    blocks = []
    for _ in range(5):
        generate_block()
        blocks.append(bitcoin_cli(bitcoind_connect_params).getbestblockhash())

    # Updating the states should bring both to the same last known block.
    w.awake()
    w.responder.awake()
    Builder.update_states(w, blocks, blocks[1:])

    assert db_manager.load_last_block_hash_watcher() == blocks[-1]
    assert w.responder.last_known_block == blocks[-1]
コード例 #4
0
def test_add_too_many_appointments(watcher):
    # Simulate the user is registered
    user_sk, user_pk = generate_keypair()
    available_slots = 100
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(available_slots=available_slots, subscription_expiry=10)

    # Appointments on top of the limit should be rejected
    watcher.appointments = dict()

    for i in range(MAX_APPOINTMENTS):
        appointment, dispute_tx = generate_dummy_appointment()
        appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)

        response = watcher.add_appointment(appointment, appointment_signature)
        assert response.get("locator") == appointment.locator
        assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(appointment.serialize(), response.get("signature"))
        )
        assert response.get("available_slots") == available_slots - (i + 1)

    with pytest.raises(AppointmentLimitReached):
        appointment, dispute_tx = generate_dummy_appointment()
        appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)
        watcher.add_appointment(appointment, appointment_signature)
コード例 #5
0
def test_add_appointment_in_cache_invalid_transaction(
        watcher, generate_dummy_appointment):
    # Generate an appointment that cannot be decrypted and add the dispute txid to the cache
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(
        available_slots=1,
        subscription_expiry=watcher.block_processor.get_block_count() + 1)

    appointment, dispute_tx = generate_dummy_appointment()
    appointment.encrypted_blob = appointment.encrypted_blob[::-1]
    dispute_txid = watcher.block_processor.decode_raw_transaction(
        dispute_tx).get("txid")
    watcher.locator_cache.cache[appointment.locator] = dispute_txid

    # Try to add the appointment
    user_signature = Cryptographer.sign(appointment.serialize(), user_sk)
    response = watcher.add_appointment(appointment, user_signature)
    appointment_receipt = receipts.create_appointment_receipt(
        user_signature, response.get("start_block"))

    # The appointment is accepted but dropped (same as an invalid appointment that gets triggered)
    assert (response and response.get("locator") == appointment.locator
            and Cryptographer.get_compressed_pk(watcher.signing_key.public_key)
            == Cryptographer.get_compressed_pk(
                Cryptographer.recover_pk(appointment_receipt,
                                         response.get("signature"))))

    assert not watcher.locator_uuid_map.get(appointment.locator)
    assert appointment.locator not in [
        tracker.get("locator")
        for tracker in watcher.responder.trackers.values()
    ]
コード例 #6
0
def test_get_appointment_non_registered(internal_api, stub,
                                        generate_dummy_appointment):
    # If the user is not registered or the appointment does not belong to him the response should be NOT_FOUND
    stub.register(RegisterRequest(user_id=user_id))
    another_user_sk, another_user_pk = generate_keypair()

    # Send the appointment first
    appointment, _ = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               user_sk)
    send_appointment(stub, appointment, appointment_signature)

    # Request it back
    message = f"get appointment {appointment.locator}"
    request_signature = Cryptographer.sign(message.encode("utf-8"),
                                           another_user_sk)

    with pytest.raises(grpc.RpcError) as e:
        stub.get_appointment(
            GetAppointmentRequest(locator=appointment.locator,
                                  signature=request_signature))

    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    assert "Appointment not found" in e.value.details()

    # Notice how the request will succeed if `user` (user_id) requests it
    request_signature = Cryptographer.sign(message.encode("utf-8"), user_sk)
    response = stub.get_appointment(
        GetAppointmentRequest(locator=appointment.locator,
                              signature=request_signature))
    assert isinstance(response, GetAppointmentResponse)
コード例 #7
0
def test_inspect(run_bitcoind):
    # At this point every single check function has been already tested, let's test inspect with an invalid and a valid
    # appointments.

    client_sk, client_pk = generate_keypair()
    client_pk_hex = client_pk.format().hex()

    # Valid appointment
    locator = get_random_value_hex(LOCATOR_LEN_BYTES)
    start_time = block_processor.get_block_count() + 5
    end_time = start_time + 20
    to_self_delay = MIN_TO_SELF_DELAY
    encrypted_blob = get_random_value_hex(64)

    appointment_data = {
        "locator": locator,
        "start_time": start_time,
        "end_time": end_time,
        "to_self_delay": to_self_delay,
        "encrypted_blob": encrypted_blob,
    }

    signature = Cryptographer.sign(
        Appointment.from_dict(appointment_data).serialize(), client_sk)

    appointment = inspector.inspect(appointment_data, signature, client_pk_hex)

    assert (type(appointment) == Appointment and appointment.locator == locator
            and appointment.start_time == start_time
            and appointment.end_time == end_time
            and appointment.to_self_delay == to_self_delay
            and appointment.encrypted_blob.data == encrypted_blob)
コード例 #8
0
def test_add_appointment_in_cache(watcher):
    # Generate an appointment and add the dispute txid to the cache
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(available_slots=1, subscription_expiry=10)

    appointment, dispute_tx = generate_dummy_appointment()
    dispute_txid = watcher.block_processor.decode_raw_transaction(dispute_tx).get("txid")
    watcher.locator_cache.cache[appointment.locator] = dispute_txid

    # Try to add the appointment
    response = watcher.add_appointment(appointment, Cryptographer.sign(appointment.serialize(), user_sk))

    # The appointment is accepted but it's not in the Watcher
    assert (
        response
        and response.get("locator") == appointment.locator
        and Cryptographer.get_compressed_pk(watcher.signing_key.public_key)
        == Cryptographer.get_compressed_pk(Cryptographer.recover_pk(appointment.serialize(), response.get("signature")))
    )
    assert not watcher.locator_uuid_map.get(appointment.locator)

    # It went to the Responder straightaway
    assert appointment.locator in [tracker.get("locator") for tracker in watcher.responder.trackers.values()]

    # Trying to send it again should fail since it is already in the Responder
    with pytest.raises(AppointmentAlreadyTriggered):
        watcher.add_appointment(appointment, Cryptographer.sign(appointment.serialize(), user_sk))
コード例 #9
0
def test_get_appointment_not_registered_user(client):
    # Not registered users have no associated appointments, so this should fail
    tmp_sk, tmp_pk = generate_keypair()

    # The tower is designed so a not found appointment and a request from a non-registered user return the same error to
    # prevent probing.
    test_get_random_appointment_registered_user(client, tmp_sk)
コード例 #10
0
def test_add_appointment(watcher, generate_dummy_appointment, monkeypatch):
    # A registered user with no subscription issues should be able to add an appointment
    appointment = generate_dummy_appointment()

    # Mock a registered user
    expiry = 100
    user_info = UserInfo(MAX_APPOINTMENTS, expiry)
    monkeypatch.setattr(watcher.gatekeeper, "authenticate_user",
                        lambda x, y: user_id)
    monkeypatch.setattr(watcher.gatekeeper, "has_subscription_expired",
                        lambda x: (False, expiry))
    monkeypatch.setattr(watcher.responder, "has_tracker", lambda x: False)
    monkeypatch.setattr(watcher.gatekeeper, "add_update_appointment",
                        lambda x, y, z: MAX_APPOINTMENTS - 1)
    monkeypatch.setattr(watcher.gatekeeper, "get_user_info",
                        lambda x: user_info)

    response = watcher.add_appointment(appointment, appointment.user_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment.user_signature, response.get("start_block")),
                response.get("signature"),
            ))

    # Check that we can also add an already added appointment (same locator)
    response = watcher.add_appointment(appointment, appointment.user_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment.user_signature, response.get("start_block")),
                response.get("signature"),
            ))
    # One one copy is kept since the appointments were the same
    # (the slot count should have not been reduced, but that's something to be tested in the Gatekeeper)
    assert len(watcher.locator_uuid_map[appointment.locator]) == 1

    # If two appointments with the same locator come from different users, they are kept.
    another_user_sk, another_user_pk = generate_keypair()
    another_user_id = Cryptographer.get_compressed_pk(another_user_pk)
    monkeypatch.setattr(watcher.gatekeeper, "authenticate_user",
                        lambda x, y: another_user_id)

    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               another_user_sk)
    response = watcher.add_appointment(appointment, appointment_signature)
    assert response.get("locator") == appointment.locator
    assert Cryptographer.get_compressed_pk(
        watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
            Cryptographer.recover_pk(
                receipts.create_appointment_receipt(
                    appointment_signature, response.get("start_block")),
                response.get("signature"),
            ))
    assert len(watcher.locator_uuid_map[appointment.locator]) == 2
コード例 #11
0
def test_identify_user_non_registered(gatekeeper):
    # Non-registered user won't be identified
    sk, pk = generate_keypair()

    message = "Hey, it's me"
    signature = Cryptographer.sign(message.encode("utf-8"), sk)

    with pytest.raises(AuthenticationFailure):
        gatekeeper.authenticate_user(message.encode("utf-8"), signature)
コード例 #12
0
def test_add_appointment_non_registered(watcher):
    # Appointments from non-registered users should fail
    user_sk, user_pk = generate_keypair()

    appointment, dispute_tx = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)

    with pytest.raises(AuthenticationFailure, match="User not found"):
        watcher.add_appointment(appointment, appointment_signature)
コード例 #13
0
def test_add_appointment_not_registered(api, client, appointment):
    # Properly formatted appointment, user is not registered
    tmp_sk, tmp_pk = generate_keypair()
    tmp_compressed_pk = hexlify(tmp_pk.format(compressed=True)).decode("utf-8")

    appointment_signature = Cryptographer.sign(appointment.serialize(), tmp_sk)
    r = add_appointment(
        client, {"appointment": appointment.to_dict(), "signature": appointment_signature}, tmp_compressed_pk
    )
    assert r.status_code == HTTP_BAD_REQUEST
    assert errors.APPOINTMENT_INVALID_SIGNATURE_OR_INSUFFICIENT_SLOTS == r.json.get("error_code")
コード例 #14
0
def test_add_appointment_no_slots(watcher):
    # Appointments from register users with no available slots should aso fail
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(available_slots=0, subscription_expiry=10)

    appointment, dispute_tx = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)

    with pytest.raises(NotEnoughSlots):
        watcher.add_appointment(appointment, appointment_signature)
コード例 #15
0
def test_check_appointment_signature():
    # The inspector receives the public key as hex
    client_sk, client_pk = generate_keypair()
    client_pk_hex = client_pk.format().hex()

    dummy_appointment_data, _ = generate_dummy_appointment_data(
        real_height=False)
    assert Inspector.check_appointment_signature(
        dummy_appointment_data["appointment"],
        dummy_appointment_data["signature"],
        dummy_appointment_data["public_key"])

    fake_sk, _ = generate_keypair()

    # Create a bad signature to make sure inspector rejects it
    bad_signature = Cryptographer.sign(
        Appointment.from_dict(
            dummy_appointment_data["appointment"]).serialize(), fake_sk)
    assert (Inspector.check_appointment_signature(
        dummy_appointment_data["appointment"], bad_signature,
        client_pk_hex)[0] == APPOINTMENT_INVALID_SIGNATURE)
コード例 #16
0
def test_add_appointment_non_registered(internal_api, stub,
                                        generate_dummy_appointment):
    # If the user is not registered we should get UNAUTHENTICATED + the proper message
    another_user_sk, another_user_pk = generate_keypair()
    appointment, _ = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               another_user_sk)

    e = send_wrong_appointment(stub, appointment, appointment_signature)

    assert e.value.code() == grpc.StatusCode.UNAUTHENTICATED
    assert "Invalid signature or user does not have enough slots available" in e.value.details(
    )
コード例 #17
0
def test_identify_user(gatekeeper):
    # Identify user should return a user_pk for registered users. It raises
    # IdentificationFailure for invalid parameters or non-registered users.

    # Let's first register a user
    sk, pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(pk)
    gatekeeper.add_update_user(user_id)

    message = "Hey, it's me"
    signature = Cryptographer.sign(message.encode(), sk)

    assert gatekeeper.authenticate_user(message.encode(), signature) == user_id
コード例 #18
0
def test_add_appointment_not_registered(internal_api, client, appointment):
    # Properly formatted appointment, user is not registered
    tmp_sk, tmp_pk = generate_keypair()
    tmp_user_id = Cryptographer.get_compressed_pk(tmp_pk)

    appointment_signature = Cryptographer.sign(appointment.serialize(), tmp_sk)
    r = add_appointment(client, {
        "appointment": appointment.to_dict(),
        "signature": appointment_signature
    }, tmp_user_id)
    assert r.status_code == HTTP_BAD_REQUEST
    assert errors.APPOINTMENT_INVALID_SIGNATURE_OR_SUBSCRIPTION_ERROR == r.json.get(
        "error_code")
コード例 #19
0
def test_add_update_appointment(gatekeeper, generate_dummy_appointment):
    # add_update_appointment should decrease the slot count if a new appointment is added
    # let's add a new user
    sk, pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(pk)
    gatekeeper.add_update_user(user_id)

    # And now update add a new appointment
    appointment, _ = generate_dummy_appointment()
    appointment_uuid = get_random_value_hex(16)
    remaining_slots = gatekeeper.add_update_appointment(
        user_id, appointment_uuid, appointment)

    # This is a standard size appointment, so it should have reduced the slots by one
    assert appointment_uuid in gatekeeper.registered_users[
        user_id].appointments
    assert remaining_slots == config.get("SUBSCRIPTION_SLOTS") - 1

    # Updates can leave the count as is, decrease it, or increase it, depending on the appointment size (modulo
    # ENCRYPTED_BLOB_MAX_SIZE_HEX)

    # Appointments of the same size leave it as is
    appointment_same_size, _ = generate_dummy_appointment()
    remaining_slots = gatekeeper.add_update_appointment(
        user_id, appointment_uuid, appointment)
    assert appointment_uuid in gatekeeper.registered_users[
        user_id].appointments
    assert remaining_slots == config.get("SUBSCRIPTION_SLOTS") - 1

    # Bigger appointments decrease it
    appointment_x2_size = appointment_same_size
    appointment_x2_size.encrypted_blob = "A" * (ENCRYPTED_BLOB_MAX_SIZE_HEX +
                                                1)
    remaining_slots = gatekeeper.add_update_appointment(
        user_id, appointment_uuid, appointment_x2_size)
    assert appointment_uuid in gatekeeper.registered_users[
        user_id].appointments
    assert remaining_slots == config.get("SUBSCRIPTION_SLOTS") - 2

    # Smaller appointments increase it
    remaining_slots = gatekeeper.add_update_appointment(
        user_id, appointment_uuid, appointment)
    assert remaining_slots == config.get("SUBSCRIPTION_SLOTS") - 1

    # If the appointment needs more slots than there's free, it should fail
    gatekeeper.registered_users[user_id].available_slots = 1
    appointment_uuid = get_random_value_hex(16)
    with pytest.raises(NotEnoughSlots):
        gatekeeper.add_update_appointment(user_id, appointment_uuid,
                                          appointment_x2_size)
コード例 #20
0
def test_register_top_up(client, api):
    # Calling register more than once will give us SUBSCRIPTION_SLOTS * number_of_calls slots.
    # It will also refresh the expiry.
    temp_sk, tmp_pk = generate_keypair()
    tmp_user_id = hexlify(tmp_pk.format(compressed=True)).decode("utf-8")
    current_height = api.watcher.block_processor.get_block_count()

    data = {"public_key": tmp_user_id}

    for i in range(10):
        r = client.post(register_endpoint, json=data)
        assert r.status_code == HTTP_OK
        assert r.json.get("public_key") == tmp_user_id
        assert r.json.get("available_slots") == config.get("SUBSCRIPTION_SLOTS") * (i + 1)
        assert r.json.get("subscription_expiry") == current_height + config.get("SUBSCRIPTION_DURATION")
コード例 #21
0
def test_add_appointment_in_cache_invalid_blob(watcher):
    # Generate an appointment with an invalid transaction and add the dispute txid to the cache
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(
        available_slots=1,
        subscription_expiry=watcher.block_processor.get_block_count() + 1)

    # We need to create the appointment manually
    commitment_tx, commitment_txid, penalty_tx = create_txs()

    locator = compute_locator(commitment_tx)
    dummy_appointment_data = {
        "tx": penalty_tx,
        "tx_id": commitment_txid,
        "to_self_delay": 20
    }
    encrypted_blob = Cryptographer.encrypt(penalty_tx[::-1], commitment_txid)

    appointment_data = {
        "locator": locator,
        "to_self_delay": dummy_appointment_data.get("to_self_delay"),
        "encrypted_blob": encrypted_blob,
        "user_id": get_random_value_hex(16),
    }

    appointment = Appointment.from_dict(appointment_data)
    watcher.locator_cache.cache[appointment.locator] = commitment_txid

    # Try to add the appointment
    user_signature = Cryptographer.sign(appointment.serialize(), user_sk)
    response = watcher.add_appointment(appointment, user_signature)
    appointment_receipt = receipts.create_appointment_receipt(
        user_signature, response.get("start_block"))

    # The appointment is accepted but dropped (same as an invalid appointment that gets triggered)
    assert (response and response.get("locator") == appointment.locator
            and Cryptographer.get_compressed_pk(watcher.signing_key.public_key)
            == Cryptographer.get_compressed_pk(
                Cryptographer.recover_pk(appointment_receipt,
                                         response.get("signature"))))

    assert not watcher.locator_uuid_map.get(appointment.locator)
    assert appointment.locator not in [
        tracker.get("locator")
        for tracker in watcher.responder.trackers.values()
    ]
コード例 #22
0
def test_add_appointment_expired_subscription(watcher,
                                              generate_dummy_appointment):
    # Appointments from registered users with expired subscriptions fail as well
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)
    watcher.gatekeeper.registered_users[user_id] = UserInfo(
        available_slots=10,
        subscription_expiry=watcher.block_processor.get_block_count() -
        watcher.gatekeeper.expiry_delta - 1,
    )

    appointment, dispute_tx = generate_dummy_appointment()
    appointment_signature = Cryptographer.sign(appointment.serialize(),
                                               user_sk)

    with pytest.raises(SubscriptionExpired):
        watcher.add_appointment(appointment, appointment_signature)
コード例 #23
0
def api(db_manager, carrier, block_processor, gatekeeper, run_bitcoind):
    sk, pk = generate_keypair()

    responder = Responder(db_manager, gatekeeper, carrier, block_processor)
    watcher = Watcher(
        db_manager,
        gatekeeper,
        block_processor,
        responder,
        sk.to_der(),
        MAX_APPOINTMENTS,
        config.get("LOCATOR_CACHE_SIZE"),
    )
    inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY"))
    api = API(config.get("API_HOST"), config.get("API_PORT"), inspector, watcher)

    return api
コード例 #24
0
def ext_appointment_data():
    sk, pk = generate_keypair()
    locator = get_random_value_hex(LOCATOR_LEN_BYTES)
    encrypted_blob_data = get_random_value_hex(100)
    to_self_delay = 20
    user_id = Cryptographer.get_compressed_pk(pk)
    user_signature = Cryptographer.sign(encrypted_blob_data.encode("utf-8"),
                                        sk)
    start_block = 300

    return {
        "locator": locator,
        "to_self_delay": to_self_delay,
        "encrypted_blob": encrypted_blob_data,
        "user_id": user_id,
        "user_signature": user_signature,
        "start_block": start_block,
    }
コード例 #25
0
def test_identify_user_wrong(gatekeeper):
    # Wrong parameters shouldn't verify either
    sk, pk = generate_keypair()

    message = "Hey, it's me"
    signature = Cryptographer.sign(message.encode(), sk)

    # Non-byte message and str sig
    with pytest.raises(AuthenticationFailure):
        gatekeeper.authenticate_user(message, signature)

    # byte message and non-str sig
    with pytest.raises(AuthenticationFailure):
        gatekeeper.authenticate_user(message.encode(), signature.encode())

    # non-byte message and non-str sig
    with pytest.raises(AuthenticationFailure):
        gatekeeper.authenticate_user(message, signature.encode())
コード例 #26
0
def test_authenticate_user(gatekeeper, monkeypatch):
    # Authenticate user should return a user_pk for registered users. It raises IdentificationFailure for invalid
    # parameters or non-registered users.

    # Mock the required BlockProcessor calls from the Gatekeeper
    monkeypatch.setattr(gatekeeper.block_processor, "get_block_count",
                        lambda: 0)

    # Let's first register a user
    sk, pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(pk)
    # Mock the user registration
    monkeypatch.setitem(gatekeeper.registered_users, user_id, {})

    message = "Hey, it's me"
    signature = Cryptographer.sign(message.encode("utf-8"), sk)

    assert gatekeeper.authenticate_user(message.encode("utf-8"),
                                        signature) == user_id
コード例 #27
0
def test_add_appointment_multiple_times_different_users(api, client, appointment, n=MULTIPLE_APPOINTMENTS):
    # If the same appointment comes from different users, all are kept
    # Create user keys and appointment signatures
    user_keys = [generate_keypair() for _ in range(n)]
    signatures = [Cryptographer.sign(appointment.serialize(), key[0]) for key in user_keys]
    compressed_pks = [hexlify(pk.format(compressed=True)).decode("utf-8") for sk, pk in user_keys]

    # Add one slot per public key
    for pair in user_keys:
        tmp_compressed_pk = hexlify(pair[1].format(compressed=True)).decode("utf-8")
        api.watcher.gatekeeper.registered_users[tmp_compressed_pk] = UserInfo(available_slots=2, subscription_expiry=0)

    # Send the appointments
    for compressed_pk, signature in zip(compressed_pks, signatures):
        r = add_appointment(client, {"appointment": appointment.to_dict(), "signature": signature}, compressed_pk)
        assert r.status_code == HTTP_OK
        assert r.json.get("available_slots") == 1
        assert r.json.get("start_block") == api.watcher.last_known_block

    # Check that all the appointments have been added and that there are no duplicates
    assert len(set(api.watcher.locator_uuid_map[appointment.locator])) == n
コード例 #28
0
def test_get_subscription_info(block_processor, watcher,
                               generate_dummy_appointment,
                               generate_dummy_tracker):
    user_sk, user_pk = generate_keypair()
    user_id = Cryptographer.get_compressed_pk(user_pk)

    # Need to simulate registration for this user.
    available_slots = 1
    subscription_expiry = block_processor.get_block_count() + 1
    watcher.gatekeeper.registered_users[user_id] = UserInfo(
        available_slots, subscription_expiry)

    message = "get subscription info"
    signature = Cryptographer.sign(message.encode("utf-8"), user_sk)

    sub_info, locators = watcher.get_subscription_info(signature)

    assert len(locators) == 0
    assert sub_info.available_slots == available_slots
    assert sub_info.subscription_expiry == subscription_expiry

    uuid = get_random_value_hex(32)
    uuid2 = get_random_value_hex(32)

    appointment, _ = generate_dummy_appointment()
    tracker = generate_dummy_tracker()
    watcher.appointments = {uuid: appointment.get_summary()}
    watcher.responder.trackers = {uuid2: tracker.get_summary()}

    # The gatekeeper appointments dict format is of the form uuid:required_slots
    watcher.gatekeeper.registered_users[user_id].appointments[uuid] = {uuid: 1}
    watcher.gatekeeper.registered_users[user_id].appointments[uuid2] = {
        uuid2: 1
    }

    sub_info, locators = watcher.get_subscription_info(signature)

    assert set(locators) == set([appointment.locator, tracker.locator])
    assert sub_info.available_slots == available_slots
    assert sub_info.subscription_expiry == subscription_expiry
コード例 #29
0
def run_api(db_manager, carrier, block_processor):
    sk, pk = generate_keypair()

    responder = Responder(db_manager, carrier, block_processor)
    watcher = Watcher(db_manager, block_processor, responder, sk.to_der(),
                      config.get("MAX_APPOINTMENTS"),
                      config.get("EXPIRY_DELTA"))

    chain_monitor = ChainMonitor(watcher.block_queue,
                                 watcher.responder.block_queue,
                                 block_processor, bitcoind_feed_params)
    watcher.awake()
    chain_monitor.monitor_chain()

    api_thread = Thread(
        target=API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")),
                   watcher).start)
    api_thread.daemon = True
    api_thread.start()

    # It takes a little bit of time to start the API (otherwise the requests are sent too early and they fail)
    sleep(0.1)
コード例 #30
0
def test_update_states_empty_list(db_manager, gatekeeper, carrier,
                                  block_processor):
    w = Watcher(
        db_manager=db_manager,
        gatekeeper=gatekeeper,
        block_processor=block_processor,
        responder=Responder(db_manager, gatekeeper, carrier, block_processor),
        sk_der=generate_keypair()[0].to_der(),
        max_appointments=config.get("MAX_APPOINTMENTS"),
        blocks_in_cache=config.get("LOCATOR_CACHE_SIZE"),
    )

    missed_blocks_watcher = []
    missed_blocks_responder = [get_random_value_hex(32)]

    # Any combination of empty list must raise a ValueError
    with pytest.raises(ValueError):
        Builder.update_states(w, missed_blocks_watcher,
                              missed_blocks_responder)

    with pytest.raises(ValueError):
        Builder.update_states(w, missed_blocks_responder,
                              missed_blocks_watcher)