diff -Nru txtorcon-18.3.0/debian/changelog txtorcon-19.0.0/debian/changelog --- txtorcon-18.3.0/debian/changelog 2019-01-07 12:09:47.000000000 +0000 +++ txtorcon-19.0.0/debian/changelog 2019-07-16 16:49:24.000000000 +0000 @@ -1,3 +1,17 @@ +txtorcon (19.0.0-2) unstable; urgency=medium + + * Upload to unstable + + -- Iain R. Learmonth Tue, 16 Jul 2019 17:49:24 +0100 + +txtorcon (19.0.0-1) experimental; urgency=medium + + * New upstream version 19.0.0 + * d/patches: + - Refreshed remove-privacy-infringing-buttons.patch + + -- Iain R. Learmonth Thu, 13 Jun 2019 22:23:49 +0100 + txtorcon (18.3.0-1) unstable; urgency=medium * New upstream version 18.3.0 diff -Nru txtorcon-18.3.0/debian/patches/remove-privacy-infringing-buttons.patch txtorcon-19.0.0/debian/patches/remove-privacy-infringing-buttons.patch --- txtorcon-18.3.0/debian/patches/remove-privacy-infringing-buttons.patch 2019-01-07 12:05:02.000000000 +0000 +++ txtorcon-19.0.0/debian/patches/remove-privacy-infringing-buttons.patch 2019-07-16 16:49:24.000000000 +0000 @@ -11,7 +11,7 @@ --- a/README.rst +++ b/README.rst -@@ -11,35 +11,6 @@ +@@ -11,31 +11,6 @@ @@ -35,10 +35,6 @@ - :target: https://txtorcon.readthedocs.io/en/latest - :alt: ReadTheDocs - --.. image:: http://api.flattr.com/button/flattr-badge-large.png -- :target: http://flattr.com/thing/1689502/meejahtxtorcon-on-GitHub -- :alt: flattr -- -.. image:: https://landscape.io/github/meejah/txtorcon/master/landscape.svg?style=flat - :target: https://landscape.io/github/meejah/txtorcon/master - :alt: Code Health diff -Nru txtorcon-18.3.0/docs/release-checklist.rst txtorcon-19.0.0/docs/release-checklist.rst --- txtorcon-18.3.0/docs/release-checklist.rst 2018-10-05 00:27:55.000000000 +0000 +++ txtorcon-19.0.0/docs/release-checklist.rst 2019-01-16 05:07:19.000000000 +0000 @@ -23,7 +23,7 @@ * update heading, date * on both signing-machine and build-machine shells: - * export VERSION=18.0.0 + * export VERSION=19.0.0 * (if on signing machine) "make dist" and "make dist-sigs" * creates: diff -Nru txtorcon-18.3.0/docs/releases.rst txtorcon-19.0.0/docs/releases.rst --- txtorcon-18.3.0/docs/releases.rst 2018-10-05 23:02:38.000000000 +0000 +++ txtorcon-19.0.0/docs/releases.rst 2019-01-16 05:07:08.000000000 +0000 @@ -15,11 +15,22 @@ See also :ref:`api_stability`. - unreleased ---------- -`git master `_ *will likely become v19.0.0* +`git master `_ *will likely become v19.1.0* + + +v19.0.0 +------- + +January 15, 2019 + + * `txtorcon-19.0.0.tar.gz `_ (`PyPI `_ (:download:`local-sig ` or `github-sig `_) (`source `_) + * add :func:`TorControlProtocol.when_disconnected` (will replace `.on_disconnect`) + * add `detach=` kwarg to :func:`Tor.create_onion_service` + * add `purpose=` kwarg to :func:`TorState.build_circuit` + v18.3.0 ------- diff -Nru txtorcon-18.3.0/examples/connect.py txtorcon-19.0.0/examples/connect.py --- txtorcon-18.3.0/examples/connect.py 2017-10-06 05:58:29.000000000 +0000 +++ txtorcon-19.0.0/examples/connect.py 2019-01-13 09:02:00.000000000 +0000 @@ -16,9 +16,11 @@ tor = yield txtorcon.connect(reactor, ep) print("Connected to Tor {version}".format(version=tor.protocol.version)) - state = yield tor.create_state() - # or: - # state = yield txtorcon.TorState.from_protocol(tor.protocol) - print("Tor state created. Circuits:") - for circuit in state.circuits.values(): - print(" {circuit.id}: {circuit.path}".format(circuit=circuit)) + d = tor.protocol.when_disconnected() + + def its_gone(value): + print("Connection gone") + d.addCallback(its_gone) + + tor.protocol.transport.loseConnection() + yield d diff -Nru txtorcon-18.3.0/Makefile txtorcon-19.0.0/Makefile --- txtorcon-18.3.0/Makefile 2018-10-05 23:02:53.000000000 +0000 +++ txtorcon-19.0.0/Makefile 2019-01-16 05:04:26.000000000 +0000 @@ -1,6 +1,6 @@ .PHONY: test html counts coverage sdist clean install doc integration diagrams default: test -VERSION = 18.3.0 +VERSION = 19.0.0 test: PYTHONPATH=. trial --reporter=text test diff -Nru txtorcon-18.3.0/PKG-INFO txtorcon-19.0.0/PKG-INFO --- txtorcon-18.3.0/PKG-INFO 2018-10-05 23:05:41.000000000 +0000 +++ txtorcon-19.0.0/PKG-INFO 2019-01-16 05:08:27.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: txtorcon -Version: 18.3.0 +Version: 19.0.0 Summary: Twisted-based Tor controller client, with state-tracking and configuration abstractions. @@ -44,10 +44,6 @@ :target: https://txtorcon.readthedocs.io/en/latest :alt: ReadTheDocs - .. image:: http://api.flattr.com/button/flattr-badge-large.png - :target: http://flattr.com/thing/1689502/meejahtxtorcon-on-GitHub - :alt: flattr - .. image:: https://landscape.io/github/meejah/txtorcon/master/landscape.svg?style=flat :target: https://landscape.io/github/meejah/txtorcon/master :alt: Code Health diff -Nru txtorcon-18.3.0/README.rst txtorcon-19.0.0/README.rst --- txtorcon-18.3.0/README.rst 2018-04-29 18:42:10.000000000 +0000 +++ txtorcon-19.0.0/README.rst 2018-12-11 16:15:06.000000000 +0000 @@ -31,10 +31,6 @@ :target: https://txtorcon.readthedocs.io/en/latest :alt: ReadTheDocs -.. image:: http://api.flattr.com/button/flattr-badge-large.png - :target: http://flattr.com/thing/1689502/meejahtxtorcon-on-GitHub - :alt: flattr - .. image:: https://landscape.io/github/meejah/txtorcon/master/landscape.svg?style=flat :target: https://landscape.io/github/meejah/txtorcon/master :alt: Code Health diff -Nru txtorcon-18.3.0/test/test_controller.py txtorcon-19.0.0/test/test_controller.py --- txtorcon-18.3.0/test/test_controller.py 2018-10-05 18:07:56.000000000 +0000 +++ txtorcon-19.0.0/test/test_controller.py 2018-12-11 16:15:06.000000000 +0000 @@ -3,7 +3,7 @@ import functools from os.path import join from mock import Mock, patch -from six.moves import StringIO +from io import BytesIO from twisted.internet.interfaces import IReactorCore from twisted.internet.interfaces import IListeningPort @@ -51,7 +51,7 @@ ) def closeStdin(self): - self.process_protocol.outReceived(b"Bootstrap") + self.process_protocol.outReceived(b"Opening Control listener") return @@ -570,12 +570,12 @@ return proto.post_bootstrap def on_protocol(proto): - proto.errReceived('Something went horribly wrong!\n') + proto.errReceived(b'Something went horribly wrong!\n') trans = FakeProcessTransport() trans.protocol = Mock() - fakeout = StringIO() - fakeerr = StringIO() + fakeout = BytesIO() + fakeerr = BytesIO() creator = functools.partial(connector, Mock(), Mock()) try: yield launch( @@ -587,8 +587,8 @@ ) self.fail() # should't get callback except RuntimeError as e: - self.assertEqual('', fakeout.getvalue()) - self.assertEqual('Something went horribly wrong!\n', fakeerr.getvalue()) + self.assertEqual(b'', fakeout.getvalue()) + self.assertEqual(b'Something went horribly wrong!\n', fakeerr.getvalue()) self.assertTrue( 'Something went horribly wrong!' in str(e) ) @@ -599,7 +599,7 @@ trans = FakeProcessTransport() def on_protocol(proto): - proto.outReceived(b'Bootstrapped 100%\n') + proto.outReceived(b'Opening Control listener\n') reactor = FakeReactor(self, trans, on_protocol, [1, 2, 3]) fails = ['one'] diff -Nru txtorcon-18.3.0/test/test_torcontrolprotocol.py txtorcon-19.0.0/test/test_torcontrolprotocol.py --- txtorcon-18.3.0/test/test_torcontrolprotocol.py 2018-07-18 05:53:09.000000000 +0000 +++ txtorcon-19.0.0/test/test_torcontrolprotocol.py 2018-12-11 16:15:06.000000000 +0000 @@ -215,6 +215,38 @@ self.protocol.connectionLost(f) self.assertTrue(it_was_called.yes) + def test_when_disconnect(self): + """ + see that we get our callback for when_disconnected if the + transport goes away + """ + def it_was_called(arg): + it_was_called.yes = True + return None + it_was_called.yes = False + + d = self.protocol.when_disconnected() + d.addCallback(it_was_called) + f = failure.Failure(error.ConnectionDone("It's all over")) + self.protocol.connectionLost(f) + self.assertTrue(it_was_called.yes) + + def test_when_disconnect_error(self): + """ + see that we get our errback for when_disconnected if the + transport goes away + """ + def it_was_called(arg): + it_was_called.yes = True + return None + it_was_called.yes = False + + d = self.protocol.when_disconnected() + d.addErrback(it_was_called) + f = failure.Failure(RuntimeError("sadness")) + self.protocol.connectionLost(f) + self.assertTrue(it_was_called.yes) + def test_disconnect_errback(self): """ see that we get our callback on_disconnect if the transport diff -Nru txtorcon-18.3.0/test/test_torstate.py txtorcon-19.0.0/test/test_torstate.py --- txtorcon-18.3.0/test/test_torstate.py 2018-07-28 07:05:52.000000000 +0000 +++ txtorcon-19.0.0/test/test_torstate.py 2019-01-13 09:02:00.000000000 +0000 @@ -1399,7 +1399,6 @@ circ = FakeCircuit() def _build(*args, **kw): - print("DING {} {}".format(args, kw)) return defer.succeed(circ) self.state.build_circuit = _build @@ -1411,7 +1410,6 @@ # be closed d = build_timeout_circuit(self.state, clock, path, timeout, using_guards=False) clock.advance(1) - print("DING {}".format(self.state)) d.cancel() with self.assertRaises(CircuitBuildTimedOutError): @@ -1501,6 +1499,33 @@ self.send(b"250 EXTENDED 1234") # we can't just .send(b'650 CIRC 1234 BUILT') this because we # didn't fully hook up the protocol to the state, e.g. via + # post_bootstrap etc. + self.state.circuits[1234].update(['1234', 'FAILED', 'REASON=TIMEOUT']) + + def check_reason(fail): + self.assertEqual(fail.value.reason, 'TIMEOUT') + d.addErrback(check_reason) + + return d + + def test_build_circuit_with_purpose(self): + class FakeRouter: + def __init__(self, i): + self.id_hex = i + self.flags = [] + + path = [] + for x in range(3): + path.append(FakeRouter("$%040d" % x)) + path[0].flags = ['guard'] + + d = self.state.build_circuit(path, using_guards=True, purpose="general") + d.addCallback(self.circuit_callback) + + self.assertEqual(self.transport.value(), b'EXTENDCIRCUIT 0 0000000000000000000000000000000000000000,0000000000000000000000000000000000000001,0000000000000000000000000000000000000002 purpose=general\r\n') + self.send(b"250 EXTENDED 1234") + # we can't just .send(b'650 CIRC 1234 BUILT') this because we + # didn't fully hook up the protocol to the state, e.g. via # post_bootstrap etc. self.state.circuits[1234].update(['1234', 'FAILED', 'REASON=TIMEOUT']) diff -Nru txtorcon-18.3.0/txtorcon/controller.py txtorcon-19.0.0/txtorcon/controller.py --- txtorcon-18.3.0/txtorcon/controller.py 2018-10-05 18:07:56.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/controller.py 2018-12-11 16:15:06.000000000 +0000 @@ -945,7 +945,9 @@ # method names are kind of long (not-ideal) @inlineCallbacks - def create_onion_service(self, ports, private_key=None, version=3, progress=None, await_all_uploads=False, single_hop=None): + def create_onion_service(self, ports, private_key=None, version=3, + progress=None, await_all_uploads=False, + single_hop=None, detach=None): """ Create a new Onion service @@ -986,6 +988,12 @@ that Tor options `HiddenServiceSingleHopMode`, `HiddenServiceNonAnonymousMode` must be set to `1` and there must be no `SOCKSPort` configured for this to actually work. + + :param detach: if True, the created service won't be tied to + this control connection and will still be active when this + control-connection goes away (this means the service will + appear in `GETINFO onions/detached` to all other + controllers) """ if version not in (2, 3): raise ValueError( @@ -1005,6 +1013,7 @@ progress=progress, await_all_uploads=await_all_uploads, single_hop=single_hop, + detach=detach, ) returnValue(service) @@ -1234,7 +1243,7 @@ # tor_connection_failed) txtorlog.msg(data) if not self.attempted_connect and self.connection_creator \ - and b'Bootstrap' in data: + and b'Opening Control listener' in data: self.attempted_connect = True # hmmm, we don't "do" anything with this Deferred? # (should it be connected to the when_connected @@ -1273,7 +1282,8 @@ if self.kill_on_stderr: self.transport.loseConnection() raise RuntimeError( - "Received stderr output from slave Tor process: " + data) + "Received stderr output from slave Tor process: " + data.decode('utf8') + ) def cleanup(self): """ diff -Nru txtorcon-18.3.0/txtorcon/_metadata.py txtorcon-19.0.0/txtorcon/_metadata.py --- txtorcon-18.3.0/txtorcon/_metadata.py 2018-10-05 23:02:59.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/_metadata.py 2019-01-16 05:04:37.000000000 +0000 @@ -1,6 +1,6 @@ -__version__ = '18.3.0' +__version__ = '19.0.0' __author__ = 'meejah' __contact__ = 'meejah@meejah.ca' __url__ = 'https://github.com/meejah/txtorcon' __license__ = 'MIT' -__copyright__ = 'Copyright 2012-2018' +__copyright__ = 'Copyright 2012-2019' diff -Nru txtorcon-18.3.0/txtorcon/onion.py txtorcon-19.0.0/txtorcon/onion.py --- txtorcon-18.3.0/txtorcon/onion.py 2018-10-05 18:07:56.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/onion.py 2018-12-11 16:15:06.000000000 +0000 @@ -1118,7 +1118,6 @@ config.HiddenServices.append(fhs) def translate_progress(pct, tag, description): - print("OHAI {} {}".format(pct, tag)) # XXX fixme actually translate.. if progress: progress(pct, tag, description) diff -Nru txtorcon-18.3.0/txtorcon/torconfig.py txtorcon-19.0.0/txtorcon/torconfig.py --- txtorcon-18.3.0/txtorcon/torconfig.py 2018-09-27 01:34:37.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/torconfig.py 2018-12-11 16:15:06.000000000 +0000 @@ -1104,7 +1104,7 @@ # then...?) try: ephemeral = yield self.protocol.get_info('onions/current') - except Exception as e: + except Exception: self.config['EphemeralOnionServices'] = [] else: onions = [] diff -Nru txtorcon-18.3.0/txtorcon/torcontrolprotocol.py txtorcon-19.0.0/txtorcon/torcontrolprotocol.py --- txtorcon-18.3.0/txtorcon/torcontrolprotocol.py 2018-09-27 01:34:37.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/torcontrolprotocol.py 2019-01-13 09:02:00.000000000 +0000 @@ -23,7 +23,7 @@ from txtorcon.interface import ITorControlProtocol from .spaghetti import FSM, State, Transition -from .util import maybe_coroutine +from .util import maybe_coroutine, SingleObserver DEFAULT_VALUE = 'DEFAULT' @@ -271,6 +271,11 @@ there was an error, the errback is called instead. """ + self._when_disconnected = SingleObserver() + """ + Private. See :func:`.when_disconnected` + """ + self.post_bootstrap = defer.Deferred() """ This Deferred is triggered when we're done setting up @@ -648,6 +653,13 @@ self._maybe_issue_command() return d + def when_disconnected(self): + """ + :returns: a Deferred that fires when (if) we disconnect from our + Tor process. + """ + return self._when_disconnected.when_fired() + # the remaining methods are internal API implementations, # callbacks and state-tracking methods -- you shouldn't have any # need to call them. @@ -672,11 +684,17 @@ def connectionLost(self, reason): "Protocol API" txtorlog.msg('connection terminated: ' + str(reason)) + if reason.check(ConnectionDone): + self._when_disconnected.fire(self) + else: + self._when_disconnected.fire(reason) + # ...and this is why we don't do on_disconnect = Deferred() :( # and instead should have had on_disconnect() method that # returned a new Deferred to each caller..(we're checking if # this Deferred has any callbacks because if it doesn't we'll # generate an "Unhandled error in Deferred") + # XXX (deprecate this) if not self.on_disconnect.called and self.on_disconnect.callbacks: if reason.check(ConnectionDone): self.on_disconnect.callback(self) diff -Nru txtorcon-18.3.0/txtorcon/torstate.py txtorcon-19.0.0/txtorcon/torstate.py --- txtorcon-18.3.0/txtorcon/torstate.py 2018-09-27 01:34:37.000000000 +0000 +++ txtorcon-19.0.0/txtorcon/torstate.py 2019-01-16 05:03:06.000000000 +0000 @@ -545,7 +545,7 @@ circ.update([str(circ_id), 'EXTENDED']) return circ - def build_circuit(self, routers=None, using_guards=True): + def build_circuit(self, routers=None, using_guards=True, purpose=None): """ Builds a circuit consisting of exactly the routers specified, in order. This issues an EXTENDCIRCUIT call to Tor with all @@ -586,6 +586,9 @@ cmd += router.decode('utf8') else: cmd += router.id_hex[1:] + + if purpose is not None: + cmd += " purpose={}".format(purpose) d = self.protocol.queue_command(cmd) d.addCallback(self._find_circuit_after_extend) return d diff -Nru txtorcon-18.3.0/txtorcon.egg-info/PKG-INFO txtorcon-19.0.0/txtorcon.egg-info/PKG-INFO --- txtorcon-18.3.0/txtorcon.egg-info/PKG-INFO 2018-10-05 23:05:41.000000000 +0000 +++ txtorcon-19.0.0/txtorcon.egg-info/PKG-INFO 2019-01-16 05:08:27.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: txtorcon -Version: 18.3.0 +Version: 19.0.0 Summary: Twisted-based Tor controller client, with state-tracking and configuration abstractions. @@ -44,10 +44,6 @@ :target: https://txtorcon.readthedocs.io/en/latest :alt: ReadTheDocs - .. image:: http://api.flattr.com/button/flattr-badge-large.png - :target: http://flattr.com/thing/1689502/meejahtxtorcon-on-GitHub - :alt: flattr - .. image:: https://landscape.io/github/meejah/txtorcon/master/landscape.svg?style=flat :target: https://landscape.io/github/meejah/txtorcon/master :alt: Code Health