| 1 | """ |
|---|
| 2 | Ported to Python 3. |
|---|
| 3 | """ |
|---|
| 4 | |
|---|
| 5 | from twisted.trial import unittest |
|---|
| 6 | from twisted.internet import reactor |
|---|
| 7 | |
|---|
| 8 | from foolscap.connections import tcp |
|---|
| 9 | |
|---|
| 10 | from testtools.matchers import ( |
|---|
| 11 | MatchesDict, |
|---|
| 12 | IsInstance, |
|---|
| 13 | Equals, |
|---|
| 14 | ) |
|---|
| 15 | |
|---|
| 16 | from ..node import PrivacyError, config_from_string |
|---|
| 17 | from ..node import create_connection_handlers |
|---|
| 18 | from ..node import create_main_tub |
|---|
| 19 | from ..util.i2p_provider import create as create_i2p_provider |
|---|
| 20 | from ..util.tor_provider import create as create_tor_provider |
|---|
| 21 | |
|---|
| 22 | from .common import ( |
|---|
| 23 | SyncTestCase, |
|---|
| 24 | ConstantAddresses, |
|---|
| 25 | ) |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | BASECONFIG = "" |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | class CreateConnectionHandlersTests(SyncTestCase): |
|---|
| 32 | """ |
|---|
| 33 | Tests for the Foolscap connection handlers return by |
|---|
| 34 | ``create_connection_handlers``. |
|---|
| 35 | """ |
|---|
| 36 | def test_foolscap_handlers(self): |
|---|
| 37 | """ |
|---|
| 38 | ``create_connection_handlers`` returns a Foolscap connection handlers |
|---|
| 39 | dictionary mapping ``"tcp"`` to |
|---|
| 40 | ``foolscap.connections.tcp.DefaultTCP``, ``"tor"`` to the supplied Tor |
|---|
| 41 | provider's handler, and ``"i2p"`` to the supplied I2P provider's |
|---|
| 42 | handler. |
|---|
| 43 | """ |
|---|
| 44 | config = config_from_string( |
|---|
| 45 | "fake.port", |
|---|
| 46 | "no-basedir", |
|---|
| 47 | BASECONFIG, |
|---|
| 48 | ) |
|---|
| 49 | tor_endpoint = object() |
|---|
| 50 | tor = ConstantAddresses(handler=tor_endpoint) |
|---|
| 51 | i2p_endpoint = object() |
|---|
| 52 | i2p = ConstantAddresses(handler=i2p_endpoint) |
|---|
| 53 | _, foolscap_handlers = create_connection_handlers( |
|---|
| 54 | config, |
|---|
| 55 | i2p, |
|---|
| 56 | tor, |
|---|
| 57 | ) |
|---|
| 58 | self.assertThat( |
|---|
| 59 | foolscap_handlers, |
|---|
| 60 | MatchesDict({ |
|---|
| 61 | "tcp": IsInstance(tcp.DefaultTCP), |
|---|
| 62 | "i2p": Equals(i2p_endpoint), |
|---|
| 63 | "tor": Equals(tor_endpoint), |
|---|
| 64 | }), |
|---|
| 65 | ) |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | class Tor(unittest.TestCase): |
|---|
| 69 | |
|---|
| 70 | def test_socksport_bad_endpoint(self): |
|---|
| 71 | config = config_from_string( |
|---|
| 72 | "fake.port", |
|---|
| 73 | "no-basedir", |
|---|
| 74 | BASECONFIG + "[tor]\nsocks.port = meow:unsupported\n", |
|---|
| 75 | ) |
|---|
| 76 | with self.assertRaises(ValueError) as ctx: |
|---|
| 77 | tor_provider = create_tor_provider(reactor, config) |
|---|
| 78 | tor_provider.get_tor_handler() |
|---|
| 79 | self.assertIn( |
|---|
| 80 | "Unknown endpoint type: 'meow'", |
|---|
| 81 | str(ctx.exception) |
|---|
| 82 | ) |
|---|
| 83 | |
|---|
| 84 | def test_socksport_not_integer(self): |
|---|
| 85 | config = config_from_string( |
|---|
| 86 | "fake.port", |
|---|
| 87 | "no-basedir", |
|---|
| 88 | BASECONFIG + "[tor]\nsocks.port = tcp:localhost:kumquat\n", |
|---|
| 89 | ) |
|---|
| 90 | with self.assertRaises(ValueError) as ctx: |
|---|
| 91 | tor_provider = create_tor_provider(reactor, config) |
|---|
| 92 | tor_provider.get_tor_handler() |
|---|
| 93 | self.assertIn( |
|---|
| 94 | "invalid literal for int()", |
|---|
| 95 | str(ctx.exception) |
|---|
| 96 | ) |
|---|
| 97 | self.assertIn( |
|---|
| 98 | "kumquat", |
|---|
| 99 | str(ctx.exception) |
|---|
| 100 | ) |
|---|
| 101 | |
|---|
| 102 | class I2P(unittest.TestCase): |
|---|
| 103 | |
|---|
| 104 | def test_samport_and_launch(self): |
|---|
| 105 | config = config_from_string( |
|---|
| 106 | "no-basedir", |
|---|
| 107 | "fake.port", |
|---|
| 108 | BASECONFIG + "[i2p]\n" + |
|---|
| 109 | "sam.port = tcp:localhost:1234\n" + "launch = true\n", |
|---|
| 110 | ) |
|---|
| 111 | with self.assertRaises(ValueError) as ctx: |
|---|
| 112 | i2p_provider = create_i2p_provider(reactor, config) |
|---|
| 113 | i2p_provider.get_i2p_handler() |
|---|
| 114 | self.assertIn( |
|---|
| 115 | "must not set both sam.port and launch", |
|---|
| 116 | str(ctx.exception) |
|---|
| 117 | ) |
|---|
| 118 | |
|---|
| 119 | class Connections(unittest.TestCase): |
|---|
| 120 | |
|---|
| 121 | def setUp(self): |
|---|
| 122 | self.basedir = 'BASEDIR' |
|---|
| 123 | self.config = config_from_string("fake.port", self.basedir, BASECONFIG) |
|---|
| 124 | |
|---|
| 125 | def test_default(self): |
|---|
| 126 | default_connection_handlers, _ = create_connection_handlers( |
|---|
| 127 | self.config, |
|---|
| 128 | ConstantAddresses(handler=object()), |
|---|
| 129 | ConstantAddresses(handler=object()), |
|---|
| 130 | ) |
|---|
| 131 | self.assertEqual(default_connection_handlers["tcp"], "tcp") |
|---|
| 132 | self.assertEqual(default_connection_handlers["tor"], "tor") |
|---|
| 133 | self.assertEqual(default_connection_handlers["i2p"], "i2p") |
|---|
| 134 | |
|---|
| 135 | def test_tor(self): |
|---|
| 136 | config = config_from_string( |
|---|
| 137 | "fake.port", |
|---|
| 138 | "no-basedir", |
|---|
| 139 | BASECONFIG + "[connections]\ntcp = tor\n", |
|---|
| 140 | ) |
|---|
| 141 | default_connection_handlers, _ = create_connection_handlers( |
|---|
| 142 | config, |
|---|
| 143 | ConstantAddresses(handler=object()), |
|---|
| 144 | ConstantAddresses(handler=object()), |
|---|
| 145 | ) |
|---|
| 146 | |
|---|
| 147 | self.assertEqual(default_connection_handlers["tcp"], "tor") |
|---|
| 148 | self.assertEqual(default_connection_handlers["tor"], "tor") |
|---|
| 149 | self.assertEqual(default_connection_handlers["i2p"], "i2p") |
|---|
| 150 | |
|---|
| 151 | def test_tor_unimportable(self): |
|---|
| 152 | """ |
|---|
| 153 | If the configuration calls for substituting Tor for TCP and |
|---|
| 154 | ``foolscap.connections.tor`` is not importable then |
|---|
| 155 | ``create_connection_handlers`` raises ``ValueError`` with a message |
|---|
| 156 | explaining this makes Tor unusable. |
|---|
| 157 | """ |
|---|
| 158 | self.config = config_from_string( |
|---|
| 159 | "fake.port", |
|---|
| 160 | "no-basedir", |
|---|
| 161 | BASECONFIG + "[connections]\ntcp = tor\n", |
|---|
| 162 | ) |
|---|
| 163 | tor_provider = create_tor_provider( |
|---|
| 164 | reactor, |
|---|
| 165 | self.config, |
|---|
| 166 | import_tor=lambda: None, |
|---|
| 167 | ) |
|---|
| 168 | with self.assertRaises(ValueError) as ctx: |
|---|
| 169 | default_connection_handlers, _ = create_connection_handlers( |
|---|
| 170 | self.config, |
|---|
| 171 | i2p_provider=ConstantAddresses(handler=object()), |
|---|
| 172 | tor_provider=tor_provider, |
|---|
| 173 | ) |
|---|
| 174 | self.assertEqual( |
|---|
| 175 | str(ctx.exception), |
|---|
| 176 | "'tahoe.cfg [connections] tcp='" |
|---|
| 177 | " uses unavailable/unimportable handler type 'tor'." |
|---|
| 178 | " Please pip install tahoe-lafs[tor] to fix.", |
|---|
| 179 | ) |
|---|
| 180 | |
|---|
| 181 | def test_unknown(self): |
|---|
| 182 | config = config_from_string( |
|---|
| 183 | "fake.port", |
|---|
| 184 | "no-basedir", |
|---|
| 185 | BASECONFIG + "[connections]\ntcp = unknown\n", |
|---|
| 186 | ) |
|---|
| 187 | with self.assertRaises(ValueError) as ctx: |
|---|
| 188 | create_connection_handlers( |
|---|
| 189 | config, |
|---|
| 190 | ConstantAddresses(handler=object()), |
|---|
| 191 | ConstantAddresses(handler=object()), |
|---|
| 192 | ) |
|---|
| 193 | self.assertIn("'tahoe.cfg [connections] tcp='", str(ctx.exception)) |
|---|
| 194 | self.assertIn("uses unknown handler type 'unknown'", str(ctx.exception)) |
|---|
| 195 | |
|---|
| 196 | def test_tcp_disabled(self): |
|---|
| 197 | config = config_from_string( |
|---|
| 198 | "fake.port", |
|---|
| 199 | "no-basedir", |
|---|
| 200 | BASECONFIG + "[connections]\ntcp = disabled\n", |
|---|
| 201 | ) |
|---|
| 202 | default_connection_handlers, _ = create_connection_handlers( |
|---|
| 203 | config, |
|---|
| 204 | ConstantAddresses(handler=object()), |
|---|
| 205 | ConstantAddresses(handler=object()), |
|---|
| 206 | ) |
|---|
| 207 | self.assertEqual(default_connection_handlers["tcp"], None) |
|---|
| 208 | self.assertEqual(default_connection_handlers["tor"], "tor") |
|---|
| 209 | self.assertEqual(default_connection_handlers["i2p"], "i2p") |
|---|
| 210 | |
|---|
| 211 | class Privacy(unittest.TestCase): |
|---|
| 212 | |
|---|
| 213 | def test_connections(self): |
|---|
| 214 | config = config_from_string( |
|---|
| 215 | "fake.port", |
|---|
| 216 | "no-basedir", |
|---|
| 217 | BASECONFIG + "[node]\nreveal-IP-address = false\n", |
|---|
| 218 | ) |
|---|
| 219 | |
|---|
| 220 | with self.assertRaises(PrivacyError) as ctx: |
|---|
| 221 | create_connection_handlers( |
|---|
| 222 | config, |
|---|
| 223 | ConstantAddresses(handler=object()), |
|---|
| 224 | ConstantAddresses(handler=object()), |
|---|
| 225 | ) |
|---|
| 226 | |
|---|
| 227 | self.assertEqual( |
|---|
| 228 | str(ctx.exception), |
|---|
| 229 | "Privacy requested with `reveal-IP-address = false` " |
|---|
| 230 | "but `tcp = tcp` conflicts with this.", |
|---|
| 231 | ) |
|---|
| 232 | |
|---|
| 233 | def test_connections_tcp_disabled(self): |
|---|
| 234 | config = config_from_string( |
|---|
| 235 | "no-basedir", |
|---|
| 236 | "fake.port", |
|---|
| 237 | BASECONFIG + "[connections]\ntcp = disabled\n" + |
|---|
| 238 | "[node]\nreveal-IP-address = false\n", |
|---|
| 239 | ) |
|---|
| 240 | default_connection_handlers, _ = create_connection_handlers( |
|---|
| 241 | config, |
|---|
| 242 | ConstantAddresses(handler=object()), |
|---|
| 243 | ConstantAddresses(handler=object()), |
|---|
| 244 | ) |
|---|
| 245 | self.assertEqual(default_connection_handlers["tcp"], None) |
|---|
| 246 | |
|---|
| 247 | def test_tub_location_auto(self): |
|---|
| 248 | config = config_from_string( |
|---|
| 249 | "fake.port", |
|---|
| 250 | "no-basedir", |
|---|
| 251 | BASECONFIG + "[node]\nreveal-IP-address = false\n", |
|---|
| 252 | ) |
|---|
| 253 | |
|---|
| 254 | with self.assertRaises(PrivacyError) as ctx: |
|---|
| 255 | create_main_tub( |
|---|
| 256 | config, |
|---|
| 257 | tub_options={}, |
|---|
| 258 | default_connection_handlers={}, |
|---|
| 259 | foolscap_connection_handlers={}, |
|---|
| 260 | i2p_provider=ConstantAddresses(), |
|---|
| 261 | tor_provider=ConstantAddresses(), |
|---|
| 262 | ) |
|---|
| 263 | self.assertEqual( |
|---|
| 264 | str(ctx.exception), |
|---|
| 265 | "tub.location uses AUTO", |
|---|
| 266 | ) |
|---|