[tor-commits] [bridgedb/master] Deprecate b.Bridges.PluggableTransport for b.bridges.PluggableTransport.

isis at torproject.org isis at torproject.org
Sat Mar 21 02:02:57 UTC 2015


commit eeb5b7c9d72a4758f8c5dc70b67c8233548c91bf
Author: Isis Lovecruft <isis at torproject.org>
Date:   Sun Sep 7 00:04:17 2014 +0000

    Deprecate b.Bridges.PluggableTransport for b.bridges.PluggableTransport.
    
    This replaces the legacy `bridgedb.Bridges.PluggableTransport` class,
    which had several issues, including:
    
       - `assert` statements without catching errors
       - Cyclically referential data structures which contain __del__()
         methods. (Which means that these structures cannot be garbage
         collected!! see https://stackoverflow.com/a/10962484)
    
     * ADD new `bridgedb.bridges` module for replacing old code in
       `bridgedb.Bridges`.
    
     * MOVE legacy implementation `bridgedb.Bridges.PluggableTransport` to
       `bridgedb.test.deprecated` module for automated regression testing.
    
     * ADD new implementation, `bridgedb.bridges.PluggableTransport`, which
       is mostly backward-compatible with the old implementation, except
       that instead of taking an entire `bridgedb.Bridges.Bridge` class as
       its first argument, it takes just the uppercased, hexadecimal
       fingerprint of that bridge. This was done because the legacy `Bridge`
       and `PluggableTransport` classes posed a serialization problem due to
       infinitely self-referencing eachother, i.e. the
       `bridgedb.Bridges.Bridge.transports` attribute was a list of
       `bridgedb.Bridges.PluggableTransport`s, which in turn referenced
       their `bridgedb.Bridges.Bridge`, which referenced a list of
       bridgedb.Bridges.PluggableTransport`s... turtles all the way down,
       and they never get garbage collected, they just end up in Python's
       `gc.garbage` list for "the programmer to manually deal with".
    
     * FIXES part of #12505 https://bugs.torproject.org/12505
---
 lib/bridgedb/Bridges.py           |  104 -------------
 lib/bridgedb/Main.py              |   23 ++-
 lib/bridgedb/bridges.py           |  290 +++++++++++++++++++++++++++++++++++++
 lib/bridgedb/test/deprecated.py   |  112 ++++++++++++++
 lib/bridgedb/test/test_Bridges.py |    7 +-
 lib/bridgedb/test/test_Tests.py   |    2 +
 6 files changed, 424 insertions(+), 114 deletions(-)

diff --git a/lib/bridgedb/Bridges.py b/lib/bridgedb/Bridges.py
index fa718c0..dead9f2 100644
--- a/lib/bridgedb/Bridges.py
+++ b/lib/bridgedb/Bridges.py
@@ -451,110 +451,6 @@ re_ipv6 = re.compile("\[([a-fA-F0-9:]+)\]:(.*$)")
 re_ipv4 = re.compile("((?:\d{1,3}\.?){4}):(.*$)")
 
 
-class PluggableTransport(object):
-    """A PT with reference to the parent bridge on which it is running."""
-
-    def __init__(self, bridge, methodname, address, port, argdict=None):
-        """Create a ``PluggableTransport`` describing a PT running on a bridge.
-
-        Pluggable transports are described within a bridge's ``@type
-        bridge-extrainfo`` descriptor, see the ``Specifications: Client
-        behavior`` section and the ``TOR_PT_SERVER_TRANSPORT_OPTIONS``
-        description in pt-spec.txt_ for additional specification.
-
-        :type bridge: :class:`Bridge`
-        :param bridge: The parent bridge running this pluggable transport
-            instance, i.e. the main ORPort bridge whose
-            ``@type bridge-server-descriptor`` contains a hash digest for a
-            ``@type bridge-extrainfo-document``, the latter of which contains
-            the parameter of this pluggable transport in its ``transport``
-            line.
-
-        :param str methodname: The canonical "name" for this pluggable
-            transport, i.e. the one which would be specified in a torrc
-            file. For example, ``"obfs2"``, ``"obfs3"``, ``"scramblesuit"``
-            would all be pluggable transport method names.
-
-        :param str address: The IP address of the transport. Currently (as of
-            20 March 2014), there are no known, widely-deployed pluggable
-            transports which support IPv6. Ergo, this is very likely going to
-            be an IPv4 address.
-
-        :param int port: A integer specifying the port which this pluggable
-            transport is listening on. (This should likely be whatever port the
-            bridge specified in its ``ServerTransportPlugin`` torrc line,
-            unless the pluggable transport is running in "managed" mode.)
-
-        :param dict argdict: Some PTs can take additional arguments, which
-            must be distributed to the client out-of-band. These are present
-            in the ``@type bridge-extrainfo-document``, in the ``transport``
-            line like so::
-
-                METHOD SP ADDR ":" PORT SP [K=V[,K=V[,K=V[…]]]]
-
-            where K is the **argdict** key, and V is the value. For example,
-            in the case of ``scramblesuit``, for which the client must supply
-            a shared secret to the ``scramblesuit`` instance running on the
-            bridge, the **argdict** would be something like::
-
-                {'password': 'NEQGQYLUMUQGK5TFOJ4XI2DJNZTS4LRO'}
-
-        .. _pt-spec.txt:
-             https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt
-        """
-        #XXX: assert are disabled with python -O
-        assert isinstance(bridge, Bridge)
-        assert type(address) in (ipaddr.IPv4Address, ipaddr.IPv6Address)
-        assert type(port) is int
-        assert (0 < port < 65536)
-        assert type(methodname) is str
-
-        self.bridge = bridge
-        self.address = address
-        self.port = port
-        self.methodname = methodname
-        if type(argdict) is dict:
-            self.argdict = argdict
-        else: self.argdict = {}
-
-    def getTransportLine(self, includeFingerprint=False, bridgePrefix=False):
-        """Get a torrc line for this pluggable transport.
-
-        This method does not return lines which are prefixed with the word
-        'bridge', as they would be in a torrc file. Instead, lines returned
-        look like this:
-
-        obfs3 245.102.100.252:23619 59ca743e89b508e16b8c7c6d2290efdfd14eea98
-
-        :param bool includeFingerprints: If ``True``, include the digest of
-            this bridges public identity key in the torrc line.
-        :param bool bridgePrefix: If ``True``, add ``'Bridge '`` to the
-             beginning of each returned line (suitable for pasting directly
-             into a torrc file).
-        :rtype: str
-        :returns: A configuration line for adding this pluggable transport
-            into a torrc file.
-        """
-        sections = []
-
-        if bridgePrefix:
-            sections.append('Bridge')
-
-        if isinstance(self.address, ipaddr.IPv6Address):
-            host = "%s [%s]:%d" % (self.methodname, self.address, self.port)
-        else:
-            host = "%s %s:%d" % (self.methodname, self.address, self.port)
-        sections.append(host)
-
-        if includeFingerprint:
-            sections.append(self.bridge.fingerprint)
-
-        args = " ".join(["%s=%s" % (k, v) for k, v in self.argdict.items()])
-        sections.append(args)
-
-        line = ' '.join(sections)
-        return line
-
 def parseExtraInfoFile(f):
     """
     parses lines in Bridges extra-info documents.
diff --git a/lib/bridgedb/Main.py b/lib/bridgedb/Main.py
index ce3edc5..e1963f5 100644
--- a/lib/bridgedb/Main.py
+++ b/lib/bridgedb/Main.py
@@ -27,6 +27,9 @@ from bridgedb import proxy
 from bridgedb import safelog
 from bridgedb import schedule
 from bridgedb import util
+from bridgedb.bridges import InvalidPluggableTransportIP
+from bridgedb.bridges import MalformedPluggableTransport
+from bridgedb.bridges import PluggableTransport
 from bridgedb.configure import loadConfig
 from bridgedb.configure import Conf
 from bridgedb.parse import options
@@ -128,13 +131,19 @@ def load(state, splitter, clear=False):
                 if bridges[ID].running:
                     logging.info("Adding %s transport to running bridge"
                                  % method_name)
-                    bridgePT = Bridges.PluggableTransport(
-                        bridges[ID], method_name, address, port, argdict)
-                    bridges[ID].transports.append(bridgePT)
-                    if not bridgePT in bridges[ID].transports:
-                        logging.critical(
-                            "Added a transport, but it disappeared!",
-                            "\tTransport: %r" % bridgePT)
+                    try:
+                        bridgePT = PluggableTransport(Bridges.toHex(ID),
+                                                      method_name, address,
+                                                      port, argdict)
+                    except (InvalidPluggableTransportIP,
+                            MalformedPluggableTransport) as error:
+                        logging.warn(error)
+                    else:
+                        bridges[ID].transports.append(bridgePT)
+                        if not bridgePT in bridges[ID].transports:
+                            logging.critical(
+                                "Added a transport, but it disappeared!",
+                                "\tTransport: %r" % bridgePT)
             except KeyError as error:
                 logging.error("Could not find bridge with fingerprint '%s'."
                               % Bridges.toHex(ID))
diff --git a/lib/bridgedb/bridges.py b/lib/bridgedb/bridges.py
new file mode 100644
index 0000000..65d4d02
--- /dev/null
+++ b/lib/bridgedb/bridges.py
@@ -0,0 +1,290 @@
+# -*- coding: utf-8 ; test-case-name: bridgedb.test.test_bridges -*-
+#
+# This file is part of BridgeDB, a Tor bridge distribution system.
+#
+# :authors: please see the AUTHORS file for attributions
+# :copyright: (c) 2013-2014, Isis Lovecruft
+#             (c) 2007-2014, The Tor Project, Inc.
+# :license: see LICENSE for licensing information
+
+"""Classes for manipulating and storing Bridges and their attributes."""
+
+
+import ipaddr
+import logging
+import os
+
+from bridgedb.parse.addr import isValidIP
+from bridgedb.parse.fingerprint import isValidFingerprint
+
+
+class MalformedBridgeInfo(ValueError):
+    """Raised when some information about a bridge appears malformed."""
+
+
+class MalformedPluggableTransport(MalformedBridgeInfo):
+    """Raised when information used to initialise a :class:`PluggableTransport`
+    appears malformed.
+    """
+
+class InvalidPluggableTransportIP(MalformedBridgeInfo):
+    """Raised when a :class:`PluggableTransport` has an invalid address."""
+
+
+class PluggableTransport(object):
+    """A single instance of a Pluggable Transport (PT) offered by a
+    :class:`Bridge`.
+
+    Pluggable transports are described within a bridge's
+    ``@type bridge-extrainfo`` descriptor, see the
+    ``Specifications: Client behavior`` section and the
+    ``TOR_PT_SERVER_TRANSPORT_OPTIONS`` description in pt-spec.txt_ for
+    additional specification.
+
+    .. _pt-spec.txt:
+        https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt
+
+    :type fingerprint: str
+    :ivar fingerprint: The uppercased, hexadecimal fingerprint of the identity
+        key of the parent bridge running this pluggable transport instance,
+        i.e. the main ORPort bridge whose ``@type bridge-server-descriptor``
+        contains a hash digest for a ``@type bridge-extrainfo-document``, the
+        latter of which contains the parameter of this pluggable transport in
+        its ``transport`` line.
+
+    :type methodname: str
+    :ivar methodname: The canonical "name" for this pluggable transport,
+        i.e. the one which would be specified in a torrc file. For example,
+        ``"obfs2"``, ``"obfs3"``, ``"scramblesuit"`` would all be pluggable
+        transport method names.
+
+    :type address: ``ipaddr.IPv4Address`` or ``ipaddr.IPv6Address``
+    :ivar address: The IP address of the transport. Currently (as of 20 March
+        2014), there are no known, widely-deployed pluggable transports which
+        support IPv6. Ergo, this is very likely going to be an IPv4 address.
+
+    :type port: int
+    :ivar port: A integer specifying the port which this pluggable transport
+        is listening on. (This should likely be whatever port the bridge
+        specified in its ``ServerTransportPlugin`` torrc line, unless the
+        pluggable transport is running in "managed" mode.)
+
+    :type arguments: dict
+    :ivar arguments: Some PTs can take additional arguments, which must be
+        distributed to the client out-of-band. These are present in the
+        ``@type bridge-extrainfo-document``, in the ``transport`` line like
+        so::
+
+            METHOD SP ADDR ":" PORT SP [K=V[,K=V[,K=V[…]]]]
+
+        where K is the key in **arguments**, and V is the value. For example,
+        in the case of ``scramblesuit``, for which the client must supply a
+        shared secret to the ``scramblesuit`` instance running on the bridge,
+        the **arguments** would be something like::
+
+            {'password': 'NEQGQYLUMUQGK5TFOJ4XI2DJNZTS4LRO'}
+    """
+
+    def __init__(self, fingerprint=None, methodname=None,
+                 address=None, port=None, arguments=None):
+        """Create a ``PluggableTransport`` describing a PT running on a bridge.
+
+        :param str fingerprint: The uppercased, hexadecimal fingerprint of the
+            identity key of the parent bridge running this pluggable transport.
+        :param str methodname: The canonical "name" for this pluggable
+            transport. See :data:`methodname`.
+        :param str address: The IP address of the transport. See
+            :data:`address`.
+        :param int port: A integer specifying the port which this pluggable
+            transport is listening on.
+        :param dict arguments: Any additional arguments which the PT takes,
+            which must be distributed to the client out-of-band. See
+            :data:`arguments`.
+        """
+        self.fingerprint = fingerprint
+        self.address = address
+        self.port = port
+        self.methodname = methodname
+        self.arguments = arguments
+
+        # Because we can intitialise this class with the __init__()
+        # parameters, or use the ``updateFromStemTransport()`` method, we'll
+        # only use the ``_runChecks()`` method now if we were initialised with
+        # parameters:
+        if (self.fingerprint or self.address or self.port or
+            self.methodname or self.arguments):
+            self._runChecks()
+
+    def _parseArgumentsIntoDict(self, argumentList):
+        """Convert a list of Pluggable Transport arguments into a dictionary
+        suitable for :data:`arguments`.
+
+        :param list argumentList: A list of Pluggable Transport
+            arguments. There might be multiple, comma-separated ``K=V``
+            Pluggable Transport arguments in a single item in the
+            **argumentList**, or each item might be its own ``K=V``; we don't
+            care and we should be able to parse it either way.
+        :rtype: dict
+        :returns: A dictionary of all the ``K=V`` Pluggable Transport
+            arguments.
+        """
+        argDict = {}
+
+        # PT argumentss are comma-separated in the extrainfo
+        # descriptors. While there *shouldn't* be anything after them that was
+        # separated by a space (and hence would wind up being in a different
+        # item in `arguments`), if there was we'll join it to the rest of the
+        # PT arguments with a comma so that they are parsed as if they were PT
+        # arguments as well:
+        allArguments = ','.join(argumentList)
+
+        for arg in allArguments.split(','):
+            try:
+                key, value = arg.split('=')
+            except ValueError:
+                logging.warn("  Couldn't parse K=V from PT arg: %r" % arg)
+            else:
+                logging.debug("  Parsed PT Argument: %s: %s" % (key, value))
+                argDict[key] = value
+
+        return argDict
+
+    def _runChecks(self):
+        """Validate that we were initialised with acceptable parameters.
+
+        We currently check that:
+
+          1. The :data:`fingerprint` is valid, according to
+             :func:`~bridgedb.parse.fingerprint.isValidFingerprint`.
+
+          2. The :data:`address` is valid, according to
+             :func:`~bridgedb.parse.addr.isValidIP`.
+
+          3. The :data:`port` is an integer, and that it is between the values
+              of ``0`` and ``65535`` (inclusive).
+
+          4. The :data:`arguments` is a dictionary.
+
+        :raises MalformedPluggableTransport: if any of the above checks fails.
+        """
+        if not isValidFingerprint(self.fingerprint):
+            raise MalformedPluggableTransport(
+                ("Cannot create PluggableTransport with bad Bridge "
+                 "fingerprint: %r.") % self.fingerprint)
+
+        valid = isValidIP(self.address)
+        if not valid:
+            raise InvalidPluggableTransportIP(
+                ("Cannot create PluggableTransport with address '%s'. "
+                 "type(address)=%s.") % (self.address, type(self.address)))
+        self.address = ipaddr.IPAddress(self.address)
+
+        try:
+            # Coerce the port to be an integer:
+            self.port = int(self.port)
+        except TypeError:
+            raise MalformedPluggableTransport(
+                ("Cannot create PluggableTransport with port type: %s.")
+                % type(self.port))
+        else:
+            if not (0 <= self.port <= 65535):
+                raise MalformedPluggableTransport(
+                    ("Cannot create PluggableTransport with out-of-range port:"
+                     " %r.") % self.port)
+
+        if not isinstance(self.arguments, dict):
+            raise MalformedPluggableTransport(
+                ("Cannot create PluggableTransport with arguments type: %s")
+                % type(self.arguments))
+
+    def getTransportLine(self, includeFingerprint=True, bridgePrefix=False):
+        """Get a Bridge Line for this :class:`PluggableTransport`.
+
+        .. glossary::
+
+           Bridge Line
+             A "Bridge Line" is how BridgeDB refers to lines in a ``torrc``
+             file which should begin with the word ``"Bridge"``, and it is how
+             a client tells their Tor process that they would like to use a
+             particular bridge.
+
+        .. note:: If **bridgePrefix** is ``False``, this method does not
+            return lines which are prefixed with the word 'bridge', as they
+            would be in a torrc file. Instead, lines returned look like this::
+
+                obfs3 245.102.100.252:23619 59ca743e89b508e16b8c7c6d2290efdfd14eea98
+
+            This was made configurable to fix Vidalia being a brain-damaged
+            piece of shit (#5851_). TorLaucher replaced Vidalia soon after,
+            and TorLauncher is intelligent enough to understand
+            :term:`Bridge Line`s regardless of whether or not they are prefixed
+            with the word "Bridge".
+
+        .. _#5851: https://bugs.torproject.org/5851
+
+        :param bool includeFingerprints: If ``True``, include the digest of
+            this bridges public identity key in the torrc line.
+        :param bool bridgePrefix: If ``True``, add ``'Bridge '`` to the
+             beginning of each returned line (suitable for pasting directly
+             into a ``torrc`` file).
+        :rtype: str
+        :returns: A configuration line for adding this Pluggable Transport
+            into a ``torrc`` file.
+        """
+        sections = []
+
+        if bridgePrefix:
+            sections.append('Bridge')
+
+        if self.address.version == 6:
+            # If the address was IPv6, put brackets around it:
+            host = '%s [%s]:%d' % (self.methodname, self.address, self.port)
+        else:
+            host = '%s %s:%d' % (self.methodname, self.address, self.port)
+        sections.append(host)
+
+        if includeFingerprint:
+            sections.append(self.fingerprint)
+
+        for key, value in self.arguments.items():
+            sections.append('%s=%s' % (key, value))
+
+        line = ' '.join(sections)
+
+        return line
+
+    def updateFromStemTransport(self, fingerprint, methodname, kitchenSink):
+        """Update this :class:`PluggableTransport` from the data structure
+        which Stem uses.
+
+        Stem's
+        :api:`stem.descriptor.extrainfo_descriptor.BridgeExtraInfoDescriptor`
+        parses extrainfo ``transport`` lines into a dictionary with the
+        following structure::
+
+            {u'obfs2': (u'34.230.223.87', 37339, []),
+             u'obfs3': (u'34.230.223.87', 37338, []),
+             u'obfs4': (u'34.230.223.87', 37341, [
+                 (u'iat-mode=0,'
+                  u'node-id=2a79f14120945873482b7823caabe2fcde848722,'
+                  u'public-key=0a5b046d07f6f971b7776de682f57c5b9cdc8fa060db7ef59de82e721c8098f4')]),
+             u'scramblesuit': (u'34.230.223.87', 37340, [
+                 u'password=ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'])}
+
+        This method will initialise this class from the dictionary key
+        (**methodname**) and its tuple of values (**kitchenSink**).
+
+        :param str fingerprint: The uppercased, hexadecimal fingerprint of the
+            identity key of the parent bridge running this pluggable transport.
+        :param str methodname: The :data:`methodname` of this Pluggable
+            Transport.
+        :param tuple kitchenSink: Everything else that was on the
+            ``transport`` line in the bridge's extrainfo descriptor, which
+            Stem puts into the 3-tuples shown in the example above.
+        """
+        self.fingerprint = fingerprint
+        self.methodname = methodname
+        self.address = kitchenSink[0]
+        self.port = kitchenSink[1]
+        self.arguments = self._parseArgumentsIntoDict(kitchenSink[2])
+        self._runChecks()
diff --git a/lib/bridgedb/test/deprecated.py b/lib/bridgedb/test/deprecated.py
index a972a52..40cfe0a 100644
--- a/lib/bridgedb/test/deprecated.py
+++ b/lib/bridgedb/test/deprecated.py
@@ -123,6 +123,118 @@ class ParseORAddressError(Exception):
 
 
 @deprecate.deprecated(
+    Version('bridgedb', 0, 2, 4),
+    replacement='bridgedb.bridges.PluggableTransport')
+class PluggableTransport(object):
+    """A PT with reference to the parent bridge on which it is running.
+
+    Deprecated :class:`bridgedb.Bridges.PluggableTransport`, replaced in
+    bridgedb-0.2.4, by :class:`bridgedb.bridges.PluggableTransport`.
+    """
+
+    def __init__(self, bridge, methodname, address, port, argdict=None):
+        """Create a ``PluggableTransport`` describing a PT running on a bridge.
+
+        Pluggable transports are described within a bridge's ``@type
+        bridge-extrainfo`` descriptor, see the ``Specifications: Client
+        behavior`` section and the ``TOR_PT_SERVER_TRANSPORT_OPTIONS``
+        description in pt-spec.txt_ for additional specification.
+
+        :type bridge: :class:`Bridge`
+        :param bridge: The parent bridge running this pluggable transport
+            instance, i.e. the main ORPort bridge whose
+            ``@type bridge-server-descriptor`` contains a hash digest for a
+            ``@type bridge-extrainfo-document``, the latter of which contains
+            the parameter of this pluggable transport in its ``transport``
+            line.
+
+        :param str methodname: The canonical "name" for this pluggable
+            transport, i.e. the one which would be specified in a torrc
+            file. For example, ``"obfs2"``, ``"obfs3"``, ``"scramblesuit"``
+            would all be pluggable transport method names.
+
+        :param str address: The IP address of the transport. Currently (as of
+            20 March 2014), there are no known, widely-deployed pluggable
+            transports which support IPv6. Ergo, this is very likely going to
+            be an IPv4 address.
+
+        :param int port: A integer specifying the port which this pluggable
+            transport is listening on. (This should likely be whatever port the
+            bridge specified in its ``ServerTransportPlugin`` torrc line,
+            unless the pluggable transport is running in "managed" mode.)
+
+        :param dict argdict: Some PTs can take additional arguments, which
+            must be distributed to the client out-of-band. These are present
+            in the ``@type bridge-extrainfo-document``, in the ``transport``
+            line like so::
+
+                METHOD SP ADDR ":" PORT SP [K=V[,K=V[,K=V[…]]]]
+
+            where K is the **argdict** key, and V is the value. For example,
+            in the case of ``scramblesuit``, for which the client must supply
+            a shared secret to the ``scramblesuit`` instance running on the
+            bridge, the **argdict** would be something like::
+
+                {'password': 'NEQGQYLUMUQGK5TFOJ4XI2DJNZTS4LRO'}
+
+        .. _pt-spec.txt:
+             https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt
+        """
+        #XXX: assert are disabled with python -O
+        assert isinstance(bridge, Bridge)
+        assert type(address) in (ipaddr.IPv4Address, ipaddr.IPv6Address)
+        assert type(port) is int
+        assert (0 < port < 65536)
+        assert type(methodname) is str
+
+        self.bridge = bridge
+        self.address = address
+        self.port = port
+        self.methodname = methodname
+        if type(argdict) is dict:
+            self.argdict = argdict
+        else: self.argdict = {}
+
+    def getTransportLine(self, includeFingerprint=False, bridgePrefix=False):
+        """Get a torrc line for this pluggable transport.
+
+        This method does not return lines which are prefixed with the word
+        'bridge', as they would be in a torrc file. Instead, lines returned
+        look like this:
+
+        obfs3 245.102.100.252:23619 59ca743e89b508e16b8c7c6d2290efdfd14eea98
+
+        :param bool includeFingerprints: If ``True``, include the digest of
+            this bridges public identity key in the torrc line.
+        :param bool bridgePrefix: If ``True``, add ``'Bridge '`` to the
+             beginning of each returned line (suitable for pasting directly
+             into a torrc file).
+        :rtype: str
+        :returns: A configuration line for adding this pluggable transport
+            into a torrc file.
+        """
+        sections = []
+
+        if bridgePrefix:
+            sections.append('Bridge')
+
+        if isinstance(self.address, ipaddr.IPv6Address):
+            host = "%s [%s]:%d" % (self.methodname, self.address, self.port)
+        else:
+            host = "%s %s:%d" % (self.methodname, self.address, self.port)
+        sections.append(host)
+
+        if includeFingerprint:
+            sections.append(self.bridge.fingerprint)
+
+        args = " ".join(["%s=%s" % (k, v) for k, v in self.argdict.items()])
+        sections.append(args)
+
+        line = ' '.join(sections)
+        return line
+
+
+ at deprecate.deprecated(
     Version('bridgedb', 0, 0, 1),
     replacement='bridgedb.parse.addr.PortList')
 class PortList:
diff --git a/lib/bridgedb/test/test_Bridges.py b/lib/bridgedb/test/test_Bridges.py
index 93d6c10..2c7d09b 100644
--- a/lib/bridgedb/test/test_Bridges.py
+++ b/lib/bridgedb/test/test_Bridges.py
@@ -15,6 +15,7 @@ from binascii import a2b_hex
 from twisted.trial import unittest
 
 from bridgedb import Bridges
+from bridgedb.bridges import PluggableTransport
 from bridgedb.parse.addr import PortList
 
 import hashlib
@@ -125,9 +126,9 @@ class BridgeClassTest(unittest.TestCase):
                                 id_digest=self.id_digest,
                                 or_addresses=self.or_addresses)
         ptArgs = {'password': 'NEQGQYLUMUQGK5TFOJ4XI2DJNZTS4LRO'}
-        pt = Bridges.PluggableTransport(bridge, 'scramblesuit',
-                                        ipaddr.IPAddress('42.42.42.42'), 4242,
-                                        ptArgs)
+        pt = PluggableTransport(bridge.fingerprint, 'scramblesuit',
+                                ipaddr.IPAddress('42.42.42.42'), 4242,
+                                ptArgs)
         bridge.transports.append(pt)
         bridgeLine = bridge.getConfigLine(includeFingerprint=True,
                                           transport='scramblesuit')
diff --git a/lib/bridgedb/test/test_Tests.py b/lib/bridgedb/test/test_Tests.py
index 816cd40..e57f4a1 100644
--- a/lib/bridgedb/test/test_Tests.py
+++ b/lib/bridgedb/test/test_Tests.py
@@ -94,6 +94,8 @@ def monkeypatchTests():
     patcher.addPatch(Tests.bridgedb.Bridges, 'fromHex', binascii.a2b_hex)
     patcher.addPatch(Tests.bridgedb.Bridges, 'is_valid_fingerprint',
                      deprecated.is_valid_fingerprint)
+    patcher.addPatch(Tests.bridgedb.Bridges, 'PluggableTransport',
+                     deprecated.PluggableTransport)
     return patcher
 
 





More information about the tor-commits mailing list