def test_jsonrpc_trustee_request_decryption_authorization_for_free_keys(
        live_server):
    jsonrpc_url = jsonrpc_url = _get_trustee_jsonrpc_url(live_server)

    trustee_proxy = JsonRpcProxy(
        url=jsonrpc_url,
        response_error_handler=status_slugs_response_error_handler)

    keychain_uid_free = generate_uuid0()
    free_key_algo1 = "RSA_OAEP"
    free_key_algo2 = "ECC_DSS"
    free_key_algo3 = "DSA_DSS"

    all_requested_keypair_identifiers = [
        dict(keychain_uid=keychain_uid_free, key_algo=free_key_algo1),
        dict(keychain_uid=keychain_uid_free, key_algo=free_key_algo2),
    ]

    sql_keystore = SqlKeystore()

    with freeze_time(
    ) as frozen_datetime:  # TEST RELATION WITH FREE KEYS ATTACHMENT

        for i in range(3):  # Generate 1 free keypair per type
            has_generated = generate_free_keypair_for_least_provisioned_key_algo(
                keystore=sql_keystore,
                max_free_keys_per_algo=1,
                key_algos=[free_key_algo1, free_key_algo2, free_key_algo3])
            assert has_generated

        keys_generated_before_datetime = timezone.now()

        public_key_pem1 = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo1)
        assert public_key_pem1

        # This key will not have early-enough request for authorization
        public_key_pem3 = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo3)
        assert public_key_pem3

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=all_requested_keypair_identifiers,
            request_message="I want early decryption!",
        )
        assert result["success_count"] == 1
        assert result["too_old_count"] == 0
        assert result[
            "not_found_count"] == 1  # free_key_algo2 is not attached yet

        frozen_datetime.tick(delta=timedelta(minutes=6))

        public_key_pem2 = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo2)
        assert public_key_pem2

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=all_requested_keypair_identifiers,
            request_message="I want later decryption!",
        )
        assert result[
            "success_count"] == 1  # It's attachment time which counts!
        assert result["too_old_count"] == 1  # First key is too old now
        assert result["not_found_count"] == 0

        keypair_obj = TrusteeKeypair.objects.get(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo1)
        assert keypair_obj.created_at <= keys_generated_before_datetime
        assert keypair_obj.attached_at
        assert keypair_obj.decryption_authorized_at
        first_authorized_at = keypair_obj.decryption_authorized_at

        keypair_obj = TrusteeKeypair.objects.get(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo2)
        assert keypair_obj.created_at <= keys_generated_before_datetime
        assert keypair_obj.attached_at
        assert keypair_obj.decryption_authorized_at
        assert keypair_obj.decryption_authorized_at >= first_authorized_at + timedelta(
            minutes=5)

        keypair_obj = TrusteeKeypair.objects.get(
            keychain_uid=keychain_uid_free, key_algo=free_key_algo3)
        assert keypair_obj.created_at <= keys_generated_before_datetime
        assert keypair_obj.attached_at
        assert not keypair_obj.decryption_authorized_at  # Never requested
def test_jsonrpc_trustee_request_decryption_authorization_for_normal_keys(
        live_server):
    jsonrpc_url = jsonrpc_url = _get_trustee_jsonrpc_url(live_server)

    trustee_proxy = JsonRpcProxy(
        url=jsonrpc_url,
        response_error_handler=status_slugs_response_error_handler)

    key_cipher_algo = "RSA_OAEP"

    with freeze_time(
    ) as frozen_datetime:  # TEST AUTHORIZATION REQUEST HANDLING

        keychain_uid1 = generate_uuid0()
        keychain_uid2 = generate_uuid0()
        keychain_uid3 = generate_uuid0()
        keychain_uid4 = generate_uuid0()
        keychain_uid_unexisting = generate_uuid0()

        all_keypair_identifiers = [
            dict(keychain_uid=keychain_uid1, key_algo=key_cipher_algo),
            dict(keychain_uid=keychain_uid2, key_algo=key_cipher_algo),
            dict(keychain_uid=keychain_uid3, key_algo=key_cipher_algo),
            dict(keychain_uid=keychain_uid4, key_algo=key_cipher_algo),
            dict(keychain_uid=keychain_uid_unexisting,
                 key_algo=key_cipher_algo),
        ]

        public_key_pem = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid1, key_algo=key_cipher_algo)
        assert public_key_pem
        assert not _fetch_key_object_or_raise(
            keychain_uid=keychain_uid1,
            key_algo=key_cipher_algo).decryption_authorized_at

        # Non-pregenerated keys don't have that field set!
        assert not _fetch_key_object_or_raise(
            keychain_uid=keychain_uid1, key_algo=key_cipher_algo).attached_at

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=[], request_message="I want decryption!")
        assert result["success_count"] == 0
        assert result["too_old_count"] == 0
        assert result["not_found_count"] == 0

        frozen_datetime.tick(delta=timedelta(minutes=2))

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=all_keypair_identifiers,
            request_message="I want decryption!",
        )
        assert result["success_count"] == 1
        assert result["too_old_count"] == 0
        assert (result["not_found_count"] == 4
                )  # keychain_uid2 and keychain_uid3 not created yet

        old_decryption_authorized_at = _fetch_key_object_or_raise(
            keychain_uid=keychain_uid1,
            key_algo=key_cipher_algo).decryption_authorized_at
        assert old_decryption_authorized_at

        public_key_pem = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid2, key_algo=key_cipher_algo)
        assert public_key_pem
        public_key_pem = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid3, key_algo=key_cipher_algo)
        assert public_key_pem

        frozen_datetime.tick(delta=timedelta(minutes=4))

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=all_keypair_identifiers,
            request_message="I want decryption!",
        )
        assert result["success_count"] == 2
        assert result["too_old_count"] == 1
        assert result["not_found_count"] == 2

        assert (_fetch_key_object_or_raise(
            keychain_uid=keychain_uid1,
            key_algo=key_cipher_algo).decryption_authorized_at ==
                old_decryption_authorized_at)  # Unchanged
        assert _fetch_key_object_or_raise(
            keychain_uid=keychain_uid2,
            key_algo=key_cipher_algo).decryption_authorized_at
        assert _fetch_key_object_or_raise(
            keychain_uid=keychain_uid3,
            key_algo=key_cipher_algo).decryption_authorized_at

        with pytest.raises(KeyDoesNotExist, match="not found"):
            _fetch_key_object_or_raise(keychain_uid=keychain_uid_unexisting,
                                       key_algo=key_cipher_algo)

        public_key_pem = trustee_proxy.fetch_public_key(
            keychain_uid=keychain_uid4, key_algo=key_cipher_algo)
        assert public_key_pem

        frozen_datetime.tick(delta=timedelta(minutes=6))

        result = trustee_proxy.request_decryption_authorization(
            keypair_identifiers=all_keypair_identifiers,
            request_message="I want decryption!",
        )
        assert result["success_count"] == 0
        assert result["too_old_count"] == 4
        assert result["not_found_count"] == 1

        assert (_fetch_key_object_or_raise(
            keychain_uid=keychain_uid1,
            key_algo=key_cipher_algo).decryption_authorized_at ==
                old_decryption_authorized_at)  # Unchanged

    del all_keypair_identifiers