source: trunk/src/allmydata/test/matchers.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 3.6 KB
Line 
1"""
2Testtools-style matchers useful to the Tahoe-LAFS test suite.
3
4Ported to Python 3.
5"""
6
7import attr
8from hyperlink import DecodedURL
9
10from testtools.matchers import (
11    Mismatch,
12    AfterPreprocessing,
13    MatchesStructure,
14    MatchesDict,
15    MatchesListwise,
16    Always,
17    Equals,
18)
19
20from foolscap.furl import (
21    decode_furl,
22)
23
24from allmydata.util import (
25    base32,
26)
27from allmydata.node import (
28    read_config,
29)
30from allmydata.crypto import (
31    ed25519,
32    error,
33)
34
35@attr.s
36class MatchesNodePublicKey(object):
37    """
38    Match an object representing the node's private key.
39
40    To verify, the private key is loaded from the node's private config
41    directory at the time the match is checked.
42    """
43    basedir = attr.ib()
44
45    def match(self, other):
46        """
47        Match a private key which is the same as the private key in the node at
48        ``self.basedir``.
49
50        :param other: A signing key (aka "private key") from
51            ``allmydata.crypto.ed25519``.  This is the key to check against
52            the node's key.
53
54        :return Mismatch: If the keys don't match.
55        """
56        config = read_config(self.basedir, u"tub.port")
57        privkey_bytes = config.get_private_config("node.privkey").encode("utf-8")
58        private_key = ed25519.signing_keypair_from_string(privkey_bytes)[0]
59        signature = ed25519.sign_data(private_key, b"")
60        other_public_key = ed25519.verifying_key_from_signing_key(other)
61        try:
62            ed25519.verify_signature(other_public_key, signature, b"")
63        except error.BadSignature:
64            return Mismatch("The signature did not verify.")
65
66
67def matches_storage_announcement(basedir, anonymous=True, options=None):
68    """
69    Match a storage announcement.
70
71    :param bytes basedir: The path to the node base directory which is
72        expected to emit the announcement.  This is used to determine the key
73        which is meant to sign the announcement.
74
75    :param bool anonymous: If True, matches a storage announcement containing
76        an anonymous access fURL.  Otherwise, fails to match such an
77        announcement.
78
79    :param list[matcher]|NoneType options: If a list, matches a storage
80        announcement containing a list of storage plugin options matching the
81        elements of the list.  If None, fails to match an announcement with
82        storage plugin options.
83
84    :return: A matcher with the requested behavior.
85    """
86    announcement = {
87        u"permutation-seed-base32": matches_base32(),
88    }
89    if anonymous:
90        announcement[u"anonymous-storage-FURL"] = matches_furl()
91        announcement[u"anonymous-storage-NURLs"] = matches_nurls()
92    if options:
93        announcement[u"storage-options"] = MatchesListwise(options)
94    return MatchesStructure(
95        # Has each of these keys with associated values that match
96        service_name=Equals(u"storage"),
97        ann=MatchesDict(announcement),
98        signing_key=MatchesNodePublicKey(basedir),
99    )
100
101
102def matches_furl():
103    """
104    Match any Foolscap fURL byte string.
105    """
106    return AfterPreprocessing(decode_furl, Always())
107
108
109def matches_nurls():
110    """
111    Matches a sequence of NURLs.
112    """
113    return AfterPreprocessing(
114        lambda nurls: [DecodedURL.from_text(u) for u in nurls],
115        Always()
116    )
117
118
119def matches_base32():
120    """
121    Match any base32 encoded byte string.
122    """
123    return AfterPreprocessing(base32.a2b, Always())
124
125
126
127class MatchesSameElements(object):
128    """
129    Match if the two-tuple value given contains two elements that are equal to
130    each other.
131    """
132    def match(self, value):
133        left, right = value
134        return Equals(left).match(right)
Note: See TracBrowser for help on using the repository browser.