Skip to content
Snippets Groups Projects
strategies.py 26 KiB
Newer Older
# Copyright 2019 PrivateStorage.io, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Hypothesis strategies for property testing.
"""

Tom Prince's avatar
Tom Prince committed
from base64 import b64encode, urlsafe_b64encode
from datetime import datetime, timedelta
Tom Prince's avatar
Tom Prince committed
from urllib import quote
Tom Prince's avatar
Tom Prince committed
from allmydata.client import config_from_string
from allmydata.interfaces import HASH_SIZE, IDirectoryNode, IFilesystemNode
from hypothesis.strategies import (
Tom Prince's avatar
Tom Prince committed
    builds,
Tom Prince's avatar
Tom Prince committed
    datetimes,
    dictionaries,
Tom Prince's avatar
Tom Prince committed
    integers,
    just,
    lists,
    none,
    one_of,
Tom Prince's avatar
Tom Prince committed
    sampled_from,
    sets,
    text,
Tom Prince's avatar
Tom Prince committed
    tuples,
Tom Prince's avatar
Tom Prince committed
from twisted.internet.defer import succeed
from twisted.internet.task import Clock
from twisted.web.test.requesthelper import DummyRequest
from zope.interface import implementer
Tom Prince's avatar
Tom Prince committed
from ..configutil import config_string_from_sections
from ..lease_maintenance import LeaseMaintenanceConfig, lease_maintenance_config_to_dict
from ..model import (
Tom Prince's avatar
Tom Prince committed
    DoubleSpend,
    Error,
Tom Prince's avatar
Tom Prince committed
    Pending,
Tom Prince's avatar
Tom Prince committed
    Redeemed,
    Redeeming,
Tom Prince's avatar
Tom Prince committed
    Voucher,
# Sizes informed by
# https://github.com/brave-intl/challenge-bypass-ristretto/blob/2f98b057d7f353c12b2b12d0f5ae9ad115f1d0ba/src/oprf.rs#L18-L33

# The length of a `TokenPreimage`, in bytes.
_TOKEN_PREIMAGE_LENGTH = 64
# The length of a `Token`, in bytes.
_TOKEN_LENGTH = 96
# The length of a `UnblindedToken`, in bytes.
_UNBLINDED_TOKEN_LENGTH = 96
# The length of a `VerificationSignature`, in bytes.
_VERIFICATION_SIGNATURE_LENGTH = 64
Tom Prince's avatar
Tom Prince committed

def tahoe_config_texts(storage_client_plugins, shares):
    """
    Build the text of complete Tahoe-LAFS configurations for a node.

    :param storage_client_plugins: A dictionary with storage client plugin
        names as keys.

    :param shares: A strategy to build erasure encoding parameters.  These are
        built as a three-tuple giving (needed, total, happy).  Each element
        may be an integer or None to leave it unconfigured (and rely on the
        default).
Tom Prince's avatar
Tom Prince committed

    def merge_shares(shares, the_rest):
        for (k, v) in zip(("needed", "happy", "total"), shares):
            if v is not None:
                the_rest["shares." + k] = u"{}".format(v)
        return the_rest

    client_section = builds(
        merge_shares,
        shares,
        fixed_dictionaries(
            {
                "storage.plugins": just(
                    u",".join(storage_client_plugins.keys()),
                ),
            },
        ),
    )

        lambda *sections: config_string_from_sections(
            sections,
        ),
        fixed_dictionaries(
            {
                "storageclient.plugins.{}".format(name): configs
Tom Prince's avatar
Tom Prince committed
                for (name, configs) in storage_client_plugins.items()
            },
        ),
        fixed_dictionaries(
            {
                "node": fixed_dictionaries(
                    {
                        "nickname": node_nicknames(),
                    },
                ),
def minimal_tahoe_configs(storage_client_plugins=None, shares=just((None, None, None))):
    """
    Build complete Tahoe-LAFS configurations for a node.

    :param shares: See ``tahoe_config_texts``.

    :return SearchStrategy[unicode]: A strategy that builds unicode strings
        which are Tahoe-LAFS configuration file contents.
    """
    if storage_client_plugins is None:
        storage_client_plugins = {}
    return tahoe_config_texts(
        storage_client_plugins,
def node_nicknames():
    """
    Builds Tahoe-LAFS node nicknames.
    """
    return text(
        min_size=0,
        max_size=16,
        alphabet=characters(
            blacklist_categories={
                # Surrogates
                u"Cs",
                # Unnamed and control characters
                u"Cc",
            },
        ),
    )


def dummy_ristretto_keys():
    """
    Build string values which one could imagine might be Ristretto-flavored
    PrivacyPass signing or public keys.

    They're not really because they're entirely random rather than points on
    the curve.
    """
Tom Prince's avatar
Tom Prince committed
    return (
        binary(
            min_size=32,
            max_size=32,
        )
        .map(
            b64encode,
        )
        .map(
            lambda bs: bs.decode("ascii"),
        )
def server_configurations(signing_key_path):
    Build configuration values for the server-side plugin.

    :param unicode signing_key_path: A value to insert for the
        **ristretto-signing-key-path** item.
Tom Prince's avatar
Tom Prince committed
        fixed_dictionaries(
            {
                u"pass-value":
Loading
Loading full blame...