Hello community,
here is the log from the commit of package python-txtorcon for openSUSE:Factory
checked in at 2019-09-27 14:48:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-txtorcon (Old)
and /work/SRC/openSUSE:Factory/.python-txtorcon.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-txtorcon"
Fri Sep 27 14:48:38 2019 rev:5 rq:731285 version:19.1.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-txtorcon/python-txtorcon.changes
2019-07-31 14:28:06.638167724 +0200
+++
/work/SRC/openSUSE:Factory/.python-txtorcon.new.2352/python-txtorcon.changes
2019-09-27 14:48:43.744720977 +0200
@@ -1,0 +2,16 @@
+Mon Sep 16 13:02:45 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 19.1.0:
+ * TorControlProtocol.on_disconnect is deprecated in favour of
+ TorControlProtocol.when_disconnected
+ * introduce non_anonymous_mode= kwarg in txtorcon.launch()
+ enabling Tor options making Onion Services non-anonymous for the
+ server (but they use a single hop instead of three to the
+ Introduction Point so they're slightly faster).
+ * add an API to listen to individual circuit and stream events
+ (without subclassing anything). Can be used as decorators too.
+ See e.g. TorState.on_circuit_new()
+- Drop merged patch:
+ * python-txtorcon-methods-are-bytes.patch
+
+-------------------------------------------------------------------
Old:
----
python-txtorcon-methods-are-bytes.patch
txtorcon-19.0.0.tar.gz
New:
----
txtorcon-19.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-txtorcon.spec ++++++
--- /var/tmp/diff_new_pack.TDYmXN/_old 2019-09-27 14:48:44.356719386 +0200
+++ /var/tmp/diff_new_pack.TDYmXN/_new 2019-09-27 14:48:44.356719386 +0200
@@ -18,15 +18,13 @@
%{?!python_module:%define python_module() python-%{**}
%{!?skip_python3:python3-%{**}}}
Name: python-txtorcon
-Version: 19.0.0
+Version: 19.1.0
Release: 0
Summary: Twisted-based asynchronous Tor control protocol implementation
License: MIT
Group: Development/Languages/Python
URL: https://txtorcon.readthedocs.org
Source:
https://files.pythonhosted.org/packages/source/t/txtorcon/txtorcon-%{version}.tar.gz
-#
https://github.com/meejah/txtorcon/commit/5d7ebea5086f361efe7f14aea58e512a04b401f3
-Patch0: python-txtorcon-methods-are-bytes.patch
BuildRequires: %{python_module setuptools >= 36.2}
BuildRequires: fdupes
BuildRequires: python-ipaddress
@@ -56,7 +54,6 @@
%prep
%setup -q -n txtorcon-%{version}
-%patch0 -p1
sed -i '/data_files/,/\]\,/s/^/#/' setup.py
++++++ txtorcon-19.0.0.tar.gz -> txtorcon-19.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/Makefile new/txtorcon-19.1.0/Makefile
--- old/txtorcon-19.0.0/Makefile 2019-01-16 06:04:26.000000000 +0100
+++ new/txtorcon-19.1.0/Makefile 2019-09-10 08:50:29.000000000 +0200
@@ -1,6 +1,6 @@
-.PHONY: test html counts coverage sdist clean install doc integration diagrams
+.PHONY: test html counts coverage sdist clean install doc integration diagrams
dist-hs
default: test
-VERSION = 19.0.0
+VERSION = 19.1.0
test:
PYTHONPATH=. trial --reporter=text test
@@ -103,6 +103,20 @@
dist-sigs: dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc
dist/txtorcon-${VERSION}.tar.gz.asc
+dist-hs:
+ cp dist/txtorcon-${VERSION}-py2.py3-none-any.whl
~/tools/dist/txtorcon3/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc
~/tools/dist/txtorcon3/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}-py2.py3-none-any.whl
~/tools/dist/txtorcon/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc
~/tools/dist/txtorcon/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}.tar.gz
~/tools/dist/txtorcon3/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}.tar.gz.asc
~/tools/dist/txtorcon3/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}.tar.gz
~/tools/dist/txtorcon/git/docs/_build/html/
+ cp dist/txtorcon-${VERSION}.tar.gz.asc
~/tools/dist/txtorcon/git/docs/_build/html/
+
+check-sigs:
+ gpg --verify dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc
+ gpg --verify dist/txtorcon-${VERSION}.tar.gz.asc
+
sdist: setup.py
python setup.py check
python setup.py sdist
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/PKG-INFO new/txtorcon-19.1.0/PKG-INFO
--- old/txtorcon-19.0.0/PKG-INFO 2019-01-16 06:08:27.000000000 +0100
+++ new/txtorcon-19.1.0/PKG-INFO 2019-09-10 08:50:32.000000000 +0200
@@ -1,12 +1,7 @@
Metadata-Version: 2.1
Name: txtorcon
-Version: 19.0.0
-Summary:
- Twisted-based Tor controller client, with state-tracking and
- configuration abstractions.
- https://txtorcon.readthedocs.org
- https://github.com/meejah/txtorcon
-
+Version: 19.1.0
+Summary: Twisted-based Tor controller client, with state-tracking and
configuration abstractions. https://txtorcon.readthedocs.org
https://github.com/meejah/txtorcon
Home-page: https://github.com/meejah/txtorcon
Author: meejah
Author-email: [email protected]
@@ -62,12 +57,6 @@
`Automat <https://github.com/glyph/automat>`_,
(and the `ipaddress <https://pypi.python.org/pypi/ipaddress>`_
backport for non Python 3)
- .. caution::
-
- Several large, new features have landed on master. If you're working
- directly from master, note that some of these APIs may change before
- the next release.
-
Ten Thousand Feet
-----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/README.rst
new/txtorcon-19.1.0/README.rst
--- old/txtorcon-19.0.0/README.rst 2018-12-11 17:15:06.000000000 +0100
+++ new/txtorcon-19.1.0/README.rst 2019-09-10 08:49:17.000000000 +0200
@@ -49,12 +49,6 @@
`Automat <https://github.com/glyph/automat>`_,
(and the `ipaddress <https://pypi.python.org/pypi/ipaddress>`_ backport for
non Python 3)
-.. caution::
-
- Several large, new features have landed on master. If you're working
- directly from master, note that some of these APIs may change before
- the next release.
-
Ten Thousand Feet
-----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/docs/guide.rst
new/txtorcon-19.1.0/docs/guide.rst
--- old/txtorcon-19.0.0/docs/guide.rst 2018-12-11 17:15:06.000000000 +0100
+++ new/txtorcon-19.1.0/docs/guide.rst 2019-09-10 08:13:40.000000000 +0200
@@ -127,7 +127,7 @@
Setting ``data_directory`` gives your Tor instance a place to cache
its state information which includes the current "consensus"
-document. If you don't set it, txtorcon creates a temporary directly
+document. If you don't set it, txtorcon creates a temporary directory
(which is deleted when this Tor instance exits). Startup time is
drammatically improved if Tor already has a recent consensus, so when
integrating with Tor by launching your own client it's highly
@@ -285,6 +285,10 @@
interested in a single circuit, you can call
:meth:`.Circuit.listen` directly on a ``Circuit`` instance.
+You can instead use methods (which also function as decorators) such
+as :meth:`.TorState.on_circuit_launched` or
+:meth:`.TorState.on_stream_closed` to add listeners for single events.
+
The Tor relays are abstracted with :class:`.Router`
instances. Again, these have read-only attributes for interesting
information, e.g.: ``id_hex``, ``ip``, ``flags`` (a list of strings),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/docs/release-checklist.rst
new/txtorcon-19.1.0/docs/release-checklist.rst
--- old/txtorcon-19.0.0/docs/release-checklist.rst 2019-01-16
06:07:19.000000000 +0100
+++ new/txtorcon-19.1.0/docs/release-checklist.rst 2019-09-10
08:50:29.000000000 +0200
@@ -23,13 +23,13 @@
* update heading, date
* on both signing-machine and build-machine shells:
- * export VERSION=19.0.0
+ * export VERSION=19.1.0
* (if on signing machine) "make dist" and "make dist-sigs"
* creates:
dist/txtorcon-${VERSION}.tar.gz.asc
dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc
- * add the signatures to "signatues/"
+ * add the signatures to "signatures/"
cp dist/txtorcon-${VERSION}.tar.gz.asc
dist/txtorcon-${VERSION}-py2.py3-none-any.whl.asc signatures/
* add ALL FOUR files to dist/ (OR fix twine commands)
@@ -103,6 +103,9 @@
* copy dist/* files + signatures to hidden-service machine
* copy them to the HTML build directory! (docs/_build/html/)
+ * make dist-hs
+ * make check-sigs
+
* git pull and build docs there
* FIXME: why aren't all the dist files copied as part of doc build (only
.tar.gz)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/docs/releases.rst
new/txtorcon-19.1.0/docs/releases.rst
--- old/txtorcon-19.0.0/docs/releases.rst 2019-01-16 06:07:08.000000000
+0100
+++ new/txtorcon-19.1.0/docs/releases.rst 2019-09-10 08:50:22.000000000
+0200
@@ -18,7 +18,26 @@
unreleased
----------
-`git master <https://github.com/meejah/txtorcon>`_ *will likely become v19.1.0*
+`git master <https://github.com/meejah/txtorcon>`_ *will likely become v19.2.0*
+
+
+v19.1.0
+-------
+
+September 10, 2019
+
+ * `txtorcon-19.1.0.tar.gz
<http://timaq4ygg2iegci7.onion/txtorcon-19.1.0.tar.gz>`_ (`PyPI
<https://pypi.python.org/pypi/txtorcon/19.1.0>`_ (:download:`local-sig
</../signatues/txtorcon-19.1.0.tar.gz.asc>` or `github-sig
<https://github.com/meejah/txtorcon/blob/master/signatues/txtorcon-19.1.0.tar.gz.asc?raw=true>`_)
(`source <https://github.com/meejah/txtorcon/archive/v19.1.0.tar.gz>`_)
+
+ * `TorControlProtocol.on_disconnect` is deprecated in favour of
+ :func:`TorControlProtocol.when_disconnected`
+ * introduce `non_anonymous_mode=` kwarg in :func:`txtorcon.launch`
+ enabling Tor options making Onion Services non-anonymous for the
+ server (but they use a single hop instead of three to the
+ Introduction Point so they're slightly faster).
+ * add an API to listen to individual circuit and stream events
+ (without subclassing anything). Can be used as decorators too.
+ See e.g. :func:`TorState.on_circuit_new`
+ * fixes to the CI setup to properly test Twisted versions
v19.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/examples/monitor_compose.py
new/txtorcon-19.1.0/examples/monitor_compose.py
--- old/txtorcon-19.0.0/examples/monitor_compose.py 1970-01-01
01:00:00.000000000 +0100
+++ new/txtorcon-19.1.0/examples/monitor_compose.py 2019-04-23
06:53:35.000000000 +0200
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Just listens for a few EVENTs from Tor (INFO NOTICE WARN ERR) and
+# prints out the contents, so functions like a log monitor.
+
+from __future__ import print_function
+
+from twisted.internet import task, defer
+from twisted.internet.endpoints import UNIXClientEndpoint
+import txtorcon
+
+
[email protected]
[email protected]
+def main(reactor):
+ ep = UNIXClientEndpoint(reactor, '/var/run/tor/control')
+ tor = yield txtorcon.connect(reactor, ep)
+
+ def log(msg):
+ print(msg)
+ print("Connected to a Tor version", tor.protocol.version)
+
+ state = yield tor.create_state()
+
+ print(dir(state))
+ @state.on_stream_new
+ def _(circ):
+ print("new stream: {}".format(circ))
+
+ yield defer.Deferred()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/txtorcon-19.0.0/examples/web_onion_service_nonanonymous.py
new/txtorcon-19.1.0/examples/web_onion_service_nonanonymous.py
--- old/txtorcon-19.0.0/examples/web_onion_service_nonanonymous.py
1970-01-01 01:00:00.000000000 +0100
+++ new/txtorcon-19.1.0/examples/web_onion_service_nonanonymous.py
2019-03-04 03:57:43.000000000 +0100
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+# This shows how to leverage the endpoints API to get a new hidden
+# service up and running quickly. You can pass along this API to your
+# users by accepting endpoint strings as per Twisted recommendations.
+#
+#
http://twistedmatrix.com/documents/current/core/howto/endpoints.html#maximizing-the-return-on-your-endpoint-investment
+#
+# note that only the progress-updates needs the "import txtorcon" --
+# you do still need it installed so that Twisted finds the endpoint
+# parser plugin but code without knowledge of txtorcon can still
+# launch a Tor instance using it. cool!
+
+from __future__ import print_function
+from twisted.internet import defer, task, endpoints
+from twisted.web import server, resource
+
+import txtorcon
+from txtorcon.util import default_control_port
+
+
+class Simple(resource.Resource):
+ """
+ A really simple Web site.
+ """
+ isLeaf = True
+
+ def render_GET(self, request):
+ print("serving request")
+ return b"<html>Hello, world! I'm a single-hop Onion Service!</html>"
+
+
[email protected]
+def main(reactor):
+ tor = yield txtorcon.launch(
+ reactor,
+ progress_updates=print,
+ non_anonymous_mode=True,
+ data_directory="./tor_data",
+ )
+ print("{}".format(tor))
+ hs = yield tor.create_filesystem_onion_service(
+ [(80, 8787)],
+ "./prop224_hs",
+ version=3,
+ )
+ print("{}".format(hs))
+
+ ep = endpoints.TCP4ServerEndpoint(reactor, 8787, interface="localhost")
+ port = yield ep.listen(server.Site(Simple()))
+ print("Site listening: {}".format(hs.hostname))
+ print("Private key:\n{}".format(hs.private_key))
+ yield defer.Deferred() # wait forever
+
+
+task.react(main)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/requirements.txt
new/txtorcon-19.1.0/requirements.txt
--- old/txtorcon-19.0.0/requirements.txt 2018-02-27 05:59:40.000000000
+0100
+++ new/txtorcon-19.1.0/requirements.txt 2019-09-10 06:54:13.000000000
+0200
@@ -6,3 +6,4 @@
zope.interface>=3.6.1
incremental
automat
+cryptography
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/setup.cfg
new/txtorcon-19.1.0/setup.cfg
--- old/txtorcon-19.0.0/setup.cfg 2019-01-16 06:08:27.000000000 +0100
+++ new/txtorcon-19.1.0/setup.cfg 2019-09-10 08:50:32.000000000 +0200
@@ -1,6 +1,3 @@
-[bdist_wheel]
-universal = 1
-
[egg_info]
tag_build =
tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/setup.py new/txtorcon-19.1.0/setup.py
--- old/txtorcon-19.0.0/setup.py 2018-09-06 08:57:21.000000000 +0200
+++ new/txtorcon-19.1.0/setup.py 2019-09-10 08:50:22.000000000 +0200
@@ -25,6 +25,12 @@
https://txtorcon.readthedocs.org
https://github.com/meejah/txtorcon
'''
+# if there are any newlines in the short-description, there's no error
+# .. but setuptools / pip / readme_renderere "or something" causes the
+# 'descript' to be all the meta-data after 'summary', which fails to
+# render.
+# see: https://github.com/pypa/setuptools/issues/1390
+description = description.replace('\n', ' ')
sphinx_rst_files = [x for x in listdir('docs') if x[-3:] == 'rst']
sphinx_docs = [join('docs', x) for x in sphinx_rst_files]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/test/test_controller.py
new/txtorcon-19.1.0/test/test_controller.py
--- old/txtorcon-19.0.0/test/test_controller.py 2018-12-11 17:15:06.000000000
+0100
+++ new/txtorcon-19.1.0/test/test_controller.py 2019-09-10 06:54:13.000000000
+0200
@@ -236,6 +236,20 @@
)
self.assertTrue("must exist" in str(ctx.exception))
+ @defer.inlineCallbacks
+ def test_launch_tor_non_anonymous_and_socks(self):
+ reactor = FakeReactor(self, Mock(), None, [9050])
+ with self.assertRaises(ValueError) as ctx:
+ yield launch(
+ reactor,
+ non_anonymous_mode=True,
+ socks_port=1234,
+ tor_binary="/bin/echo",
+ stdout=Mock(),
+ stderr=Mock(),
+ )
+ self.assertIn("Cannot use SOCKS", str(ctx.exception))
+
@patch('txtorcon.controller.find_tor_binary', return_value='/bin/echo')
@defer.inlineCallbacks
def test_launch_fails(self, ftb):
@@ -290,6 +304,35 @@
tor = yield launch(reactor, _tor_config=config)
self.assertTrue(isinstance(tor, Tor))
+ @patch('txtorcon.controller.find_tor_binary', return_value='/bin/echo')
+ @patch('txtorcon.controller.TorProcessProtocol')
+ @defer.inlineCallbacks
+ def test_successful_launch_non_anonymous(self, tpp, ftb):
+ trans = FakeProcessTransport()
+ reactor = FakeReactor(self, trans, lambda p: None, [1, 2, 3])
+ config = TorConfig()
+
+ def boot(arg=None):
+ config.post_bootstrap.callback(config)
+ config.__dict__['bootstrap'] = Mock(side_effect=boot)
+ config.__dict__['attach_protocol'] =
Mock(return_value=defer.succeed(None))
+
+ def foo(*args, **kw):
+ rtn = Mock()
+ rtn.post_bootstrap = defer.succeed(None)
+ rtn.when_connected = Mock(return_value=defer.succeed(rtn))
+ return rtn
+ tpp.side_effect = foo
+
+ tor = yield launch(reactor, _tor_config=config,
non_anonymous_mode=True)
+ self.assertTrue(isinstance(tor, Tor))
+ self.assertTrue(config.HiddenServiceNonAnonymousMode)
+
+ with self.assertRaises(Exception):
+ yield tor.web_agent()
+ with self.assertRaises(Exception):
+ yield tor.dns_resolve('meejah.ca')
+
@defer.inlineCallbacks
def test_quit(self):
tor = Tor(Mock(), Mock())
@@ -1017,7 +1060,7 @@
print("Skipping; appears we don't have web support")
return
- resp = yield agent.request('GET', b'meejah.ca')
+ resp = yield agent.request(b'GET', b'meejah.ca')
self.assertEqual(self.expected_response, resp)
@defer.inlineCallbacks
@@ -1031,7 +1074,7 @@
tor = Tor(reactor, proto, _tor_config=cfg)
agent = tor.web_agent(pool=self.pool, socks_endpoint=socks_d)
- resp = yield agent.request('GET', b'meejah.ca')
+ resp = yield agent.request(b'GET', b'meejah.ca')
self.assertEqual(self.expected_response, resp)
@defer.inlineCallbacks
@@ -1046,7 +1089,7 @@
tor = Tor(reactor, proto, _tor_config=cfg)
agent = tor.web_agent(pool=self.pool, socks_endpoint=socks)
- resp = yield agent.request('GET', b'meejah.ca')
+ resp = yield agent.request(b'GET', b'meejah.ca')
self.assertEqual(self.expected_response, resp)
@defer.inlineCallbacks
@@ -1059,7 +1102,7 @@
tor = Tor(reactor, proto, _tor_config=cfg)
with self.assertRaises(ValueError) as ctx:
agent = tor.web_agent(pool=self.pool, socks_endpoint=object())
- yield agent.request('GET', b'meejah.ca')
+ yield agent.request(B'GET', b'meejah.ca')
self.assertTrue("'socks_endpoint' should be" in str(ctx.exception))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/test/test_torconfig.py
new/txtorcon-19.1.0/test/test_torconfig.py
--- old/txtorcon-19.0.0/test/test_torconfig.py 2018-07-18 07:53:09.000000000
+0200
+++ new/txtorcon-19.1.0/test/test_torconfig.py 2019-03-04 03:38:01.000000000
+0100
@@ -270,9 +270,9 @@
self.protocol.answers.append({'baz': 'auto'})
conf = TorConfig(self.protocol)
- self.assertTrue(conf.foo is 0)
- self.assertTrue(conf.bar is 1)
- self.assertTrue(conf.baz is -1)
+ self.assertEqual(conf.foo, 0)
+ self.assertEqual(conf.bar, 1)
+ self.assertEqual(conf.baz, -1)
def test_save_boolean_auto(self):
self.protocol.answers.append(
@@ -295,10 +295,10 @@
('bar', 0),
('baz', 1),
('qux', 'auto')]))
- self.assertTrue(conf.foo is 1)
- self.assertTrue(conf.bar is 0)
- self.assertTrue(conf.baz is 1)
- self.assertTrue(conf.qux is -1)
+ self.assertEqual(conf.foo, 1)
+ self.assertEqual(conf.bar, 0)
+ self.assertEqual(conf.baz, 1)
+ self.assertEqual(conf.qux, -1)
def test_save_invalid_boolean_auto(self):
self.protocol.answers.append(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/test/test_torstate.py
new/txtorcon-19.1.0/test/test_torstate.py
--- old/txtorcon-19.0.0/test/test_torstate.py 2019-01-13 10:02:00.000000000
+0100
+++ new/txtorcon-19.1.0/test/test_torstate.py 2019-06-15 08:32:36.000000000
+0200
@@ -1534,3 +1534,146 @@
d.addErrback(check_reason)
return d
+
+
+class ComposibleListenerTests(unittest.TestCase):
+
+ def setUp(self):
+ self.protocol = TorControlProtocol()
+ self.state = TorState(self.protocol)
+
+ def test_circuit_new(self):
+ listener_calls = []
+
+ @self.state.on_circuit_new
+ def _(circ):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+
+ self.assertEqual(len(listener_calls), 1)
+ self.assertEqual(listener_calls[0].id, 42)
+
+ def test_circuit_launched(self):
+ listener_calls = []
+
+ @self.state.on_circuit_launched
+ def _(circ):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+
+ self.assertEqual(len(listener_calls), 1)
+ self.assertEqual(listener_calls[0].id, 42)
+
+ def test_circuit_extend(self):
+ listener_calls = []
+
+ @self.state.on_circuit_extend
+ def _(circ, router):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+ c.update(["42", "BUILDING", "$deadbeef,$1ee7"])
+
+ # we get two calls because we've now extended to 2 relays
+ self.assertEqual(len(listener_calls), 2)
+ self.assertEqual(listener_calls[0].id, 42)
+ self.assertEqual(listener_calls[1].id, 42)
+
+ def test_circuit_built(self):
+ listener_calls = []
+
+ @self.state.on_circuit_built
+ def _(circ):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+ c.update(["42", "BUILT"])
+
+ self.assertEqual(len(listener_calls), 1)
+ self.assertEqual(listener_calls[0].id, 42)
+
+ def test_circuit_closed(self):
+ listener_calls = []
+
+ @self.state.on_circuit_closed
+ def _(circ):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+ c.update(["42", "CLOSED"])
+
+ self.assertEqual(len(listener_calls), 1)
+ self.assertEqual(listener_calls[0].id, 42)
+
+ def test_circuit_failed(self):
+ listener_calls = []
+
+ @self.state.on_circuit_failed
+ def _(circ):
+ listener_calls.append(circ)
+
+ c = self.state._maybe_create_circuit("42")
+ c.update(["42", "LAUNCHED"])
+ c.update(["42", "FAILED"])
+
+ self.assertEqual(len(listener_calls), 1)
+ self.assertEqual(listener_calls[0].id, 42)
+
+ def test_stream_events(self):
+ """
+ one for the philosophers: is this 'one, but big' test better /
+ easier to read than the N circuit tests above?
+ """
+ listener_calls = [] # list of 2-tuples
+
+ @self.state.on_stream_new
+ def _(stream):
+ listener_calls.append(("new", stream.id))
+
+ @self.state.on_stream_succeeded
+ def _(stream):
+ listener_calls.append(("succeeded", stream.id))
+
+ @self.state.on_stream_attach
+ def _(stream, circ):
+ listener_calls.append(("attach", stream.id))
+
+ @self.state.on_stream_detach
+ def _(stream):
+ listener_calls.append(("detach", stream.id))
+
+ @self.state.on_stream_closed
+ def _(stream):
+ listener_calls.append(("closed", stream.id))
+
+ @self.state.on_stream_failed
+ def _(stream):
+ listener_calls.append(("failed", stream.id))
+
+ circ = self.state._maybe_create_circuit("42")
+ circ.update(["42", "LAUNCHED"])
+
+ self.state._stream_update("1234 NEW 0 meejah.ca:80")
+ self.state._stream_update("1234 SUCCEEDED 42")
+ self.state._stream_update("1234 DETACHED 0")
+ self.state._stream_update("1234 CLOSED 0")
+ self.state._stream_update("1234 FAILED 0")
+
+ self.assertEqual(
+ listener_calls,
+ [
+ ("new", 1234),
+ ("succeeded", 1234),
+ ("attach", 1234),
+ ("detach", 1234),
+ ("closed", 1234),
+ ("failed", 1234),
+ ]
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/test/test_util.py
new/txtorcon-19.1.0/test/test_util.py
--- old/txtorcon-19.0.0/test/test_util.py 2018-07-17 21:02:42.000000000
+0200
+++ new/txtorcon-19.1.0/test/test_util.py 2019-03-04 03:38:01.000000000
+0100
@@ -14,7 +14,6 @@
from txtorcon.util import process_from_address
from txtorcon.util import delete_file_or_tree
from txtorcon.util import find_keywords
-from txtorcon.util import ip_from_int
from txtorcon.util import find_tor_binary
from txtorcon.util import maybe_ip_addr
from txtorcon.util import unescape_quoted_string
@@ -44,12 +43,6 @@
return None
-class TestIPFromInt(unittest.TestCase):
-
- def test_cast(self):
- self.assertEqual(ip_from_int(0x7f000001), '127.0.0.1')
-
-
class TestGeoIpDatabaseLoading(unittest.TestCase):
def test_bad_geoip_path(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/_metadata.py
new/txtorcon-19.1.0/txtorcon/_metadata.py
--- old/txtorcon-19.0.0/txtorcon/_metadata.py 2019-01-16 06:04:37.000000000
+0100
+++ new/txtorcon-19.1.0/txtorcon/_metadata.py 2019-09-10 08:50:22.000000000
+0200
@@ -1,4 +1,4 @@
-__version__ = '19.0.0'
+__version__ = '19.1.0'
__author__ = 'meejah'
__contact__ = '[email protected]'
__url__ = 'https://github.com/meejah/txtorcon'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/circuit.py
new/txtorcon-19.1.0/txtorcon/circuit.py
--- old/txtorcon-19.0.0/txtorcon/circuit.py 2018-09-27 03:34:37.000000000
+0200
+++ new/txtorcon-19.1.0/txtorcon/circuit.py 2019-06-15 08:32:36.000000000
+0200
@@ -494,7 +494,7 @@
rendevouz point not in the current consensus.
"""
- oldpath = self.path
+ oldpath_len = len(self.path)
self.path = []
for p in path:
if p[0] != '$':
@@ -506,10 +506,10 @@
self.path.append(router)
# if the path grew, notify listeners
- if len(self.path) > len(oldpath):
+ if len(self.path) > oldpath_len:
for x in self.listeners:
x.circuit_extend(self, router)
- oldpath = self.path
+ oldpath_len = len(self.path)
def __str__(self):
path = ' '.join([x.ip for x in self.path])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/controller.py
new/txtorcon-19.1.0/txtorcon/controller.py
--- old/txtorcon-19.0.0/txtorcon/controller.py 2018-12-11 17:15:06.000000000
+0100
+++ new/txtorcon-19.1.0/txtorcon/controller.py 2019-03-11 01:37:39.000000000
+0100
@@ -55,6 +55,7 @@
control_port=None,
data_directory=None,
socks_port=None,
+ non_anonymous_mode=None,
stdout=None,
stderr=None,
timeout=None,
@@ -110,6 +111,16 @@
faster. If ``None`` (the default), we create a tempdir for this
**and delete it on exit**. It is recommended you pass something here.
+ :param non_anonymous_mode: sets the Tor options
+ `HiddenServiceSingleHopMode` and
+ `HiddenServiceNonAnonymousMode` to 1 and un-sets any
+ `SOCKSPort` config, thus putting this Tor client into
+ "non-anonymous mode" which allows starting so-called Single
+ Onion services -- which use single-hop circuits to rendezvous
+ points. See WARNINGs in Tor manual! Also you need Tor
+ `0.3.4.1` or later (e.g. any `0.3.5.*` or newer) for this to
+ work properly.
+
:param stdout: a file-like object to which we write anything that
Tor prints on stdout (just needs to support write()).
@@ -221,9 +232,18 @@
except KeyError:
socks_port = None
- if socks_port is None:
- socks_port = yield available_tcp_port(reactor)
- config.SOCKSPort = socks_port
+ if non_anonymous_mode:
+ if socks_port is not None:
+ raise ValueError(
+ "Cannot use SOCKS options with non_anonymous_mode=True"
+ )
+ config.HiddenServiceNonAnonymousMode = 1
+ config.HiddenServiceSingleHopMode = 1
+ config.SOCKSPort = 0
+ else:
+ if socks_port is None:
+ socks_port = yield available_tcp_port(reactor)
+ config.SOCKSPort = socks_port
try:
our_user = user or config.User
@@ -350,6 +370,7 @@
config.protocol,
_tor_config=config,
_process_proto=process_protocol,
+ _non_anonymous=True if non_anonymous_mode else False,
)
)
@@ -474,7 +495,7 @@
print(port.getHost())
"""
- def __init__(self, reactor, control_protocol, _tor_config=None,
_process_proto=None):
+ def __init__(self, reactor, control_protocol, _tor_config=None,
_process_proto=None, _non_anonymous=None):
"""
don't instantiate this class yourself -- instead use the factory
methods :func:`txtorcon.launch` or :func:`txtorcon.connect`
@@ -487,6 +508,8 @@
# cache our preferred socks port (please use
# self._default_socks_endpoint() to get one)
self._socks_endpoint = None
+ # True if we've turned on non-anonymous mode / Onion services
+ self._non_anonymous = _non_anonymous
@inlineCallbacks
def quit(self):
@@ -552,6 +575,10 @@
:param pool: passed on to the Agent (as ``pool=``)
"""
+ if self._non_anonymous:
+ raise Exception(
+ "Cannot use web_agent when in non_anonymous mode"
+ )
# local import since not all platforms have this
from txtorcon import web
@@ -932,6 +959,10 @@
(which might mean setting one up in our attacked Tor if it
doesn't have one)
"""
+ if self._non_anonymous:
+ raise Exception(
+ "Cannot use SOCKS when in non_anonymous mode"
+ )
if self._socks_endpoint is None:
self._socks_endpoint = yield _create_socks_endpoint(self._reactor,
self._protocol)
returnValue(self._socks_endpoint)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/onion.py
new/txtorcon-19.1.0/txtorcon/onion.py
--- old/txtorcon-19.0.0/txtorcon/onion.py 2018-12-11 17:15:06.000000000
+0100
+++ new/txtorcon-19.1.0/txtorcon/onion.py 2019-03-11 01:37:39.000000000
+0100
@@ -170,7 +170,11 @@
@staticmethod
@defer.inlineCallbacks
- def create(reactor, config, hsdir, ports, version=3, group_readable=False,
progress=None, await_all_uploads=None):
+ def create(reactor, config, hsdir, ports,
+ version=3,
+ group_readable=False,
+ progress=None,
+ await_all_uploads=None):
"""
returns a new FilesystemOnionService after adding it to the
provided config and ensuring at least one of its descriptors
@@ -1076,7 +1080,12 @@
@staticmethod
@defer.inlineCallbacks
- def create(reactor, config, hsdir, ports, auth=None, version=3,
group_readable=False, progress=None, await_all_uploads=None):
+ def create(reactor, config, hsdir, ports,
+ auth=None,
+ version=3,
+ group_readable=False,
+ progress=None,
+ await_all_uploads=None):
"""
returns a new FilesystemAuthenticatedOnionService after adding it
to the provided config and ensureing at least one of its
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/torcontrolprotocol.py
new/txtorcon-19.1.0/txtorcon/torcontrolprotocol.py
--- old/txtorcon-19.0.0/txtorcon/torcontrolprotocol.py 2019-01-13
10:02:00.000000000 +0100
+++ new/txtorcon-19.1.0/txtorcon/torcontrolprotocol.py 2019-03-04
03:38:01.000000000 +0100
@@ -8,6 +8,7 @@
import re
import base64
from binascii import b2a_hex, hexlify
+from warnings import warn
from twisted.python import log
from twisted.internet import defer
@@ -23,7 +24,8 @@
from txtorcon.interface import ITorControlProtocol
from .spaghetti import FSM, State, Transition
-from .util import maybe_coroutine, SingleObserver
+from .util import maybe_coroutine
+from .util import SingleObserver
DEFAULT_VALUE = 'DEFAULT'
@@ -263,12 +265,18 @@
self.valid_signals = []
"""A list of all valid signals we accept from Tor"""
- # XXX bad practice; this should be like an on_disconnct()
- # method that returns a new Deferred each time...
+ # NOTE: bad practice (and now deprecated) -- use
+ # when_disconnected() instead
self.on_disconnect = defer.Deferred()
"""
- This Deferred is triggered when the connection is closed. If
- there was an error, the errback is called instead.
+ This Deferred is triggered when the connection is closed. If there
+ was an error, the errback is called instead. (Deprecated: use
+ :func:`when_disconnected` instead)
+ """
+
+ self._when_disconnected = SingleObserver()
+ """
+ Internal use. A :class:`SingleObserver` for when_disconnected()
"""
self._when_disconnected = SingleObserver()
@@ -694,13 +702,17 @@
# 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 self.on_disconnect and not self.on_disconnect.called and
self.on_disconnect.callbacks:
+ warn(
+ 'TorControlProtocol.on_disconnect is deprecated; use
.when_disconnected() instead',
+ DeprecationWarning,
+ )
if reason.check(ConnectionDone):
self.on_disconnect.callback(self)
else:
self.on_disconnect.errback(reason)
self.on_disconnect = None
+ self._when_disconnected.fire(self)
outstanding = [self.command] + self.commands if self.command else
self.commands
for d, cmd, cmd_arg in outstanding:
if not d.called:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/torstate.py
new/txtorcon-19.1.0/txtorcon/torstate.py
--- old/txtorcon-19.0.0/txtorcon/torstate.py 2019-01-16 06:03:06.000000000
+0100
+++ new/txtorcon-19.1.0/txtorcon/torstate.py 2019-06-15 08:32:36.000000000
+0200
@@ -32,6 +32,8 @@
from txtorcon.interface import ICircuitContainer
from txtorcon.interface import IStreamListener
from txtorcon.interface import IStreamAttacher
+from txtorcon.interface import StreamListenerMixin
+from txtorcon.interface import CircuitListenerMixin
from ._microdesc_parser import MicrodescriptorParser
from .router import hexIdFromHash
from .util import maybe_coroutine
@@ -516,6 +518,66 @@
'CLOSECIRCUIT %s%s' % (circid, flags)
)
+ def on_circuit_new(self, callback):
+ """
+ :param callback: will be called (with 'circuit' instance) when a
+ CIRC NEW event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_new = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_circuit_launched(self, callback):
+ """
+ :param callback: will be called (with 'circuit' instance) when a
+ CIRC LAUNCHED event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_launched = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_circuit_extend(self, callback):
+ """
+ :param callback: will be called (with 'circuit' and 'router'
+ instances) when a CIRC EXTENDED event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_extend = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_circuit_built(self, callback):
+ """
+ :param callback: will be called (with 'circuit' instance) when a
+ CIRC BUILT event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_built = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_circuit_closed(self, callback):
+ """
+ :param callback: will be called (with 'circuit' instance, and
+ arbitrary kwargs) when a CIRC CLOSED event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_closed = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_circuit_failed(self, callback):
+ """
+ :param callback: will be called (with 'circuit' instance, and
+ arbitrary kwargs) when a CIRC FAILED event happens
+ """
+ listener = CircuitListenerMixin()
+ listener.circuit_failed = callback
+ self.add_circuit_listener(listener)
+ return callback # so we can be used as a listener
+
def add_circuit_listener(self, icircuitlistener):
"""
Adds a new instance of :class:`txtorcon.interface.ICircuitListener`
which
@@ -526,6 +588,66 @@
circ.listen(listen)
self.circuit_listeners.append(listen)
+ def on_stream_new(self, callback):
+ """
+ :param callback: will be called (with 'stream' instance) when a
+ STREAM NEW event happens.
+ """
+ listener = StreamListenerMixin()
+ listener.stream_new = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_stream_succeeded(self, callback):
+ """
+ :param callback: will be called (with 'stream' instance) when a
+ STREAM SUCCEEDED event happens.
+ """
+ listener = StreamListenerMixin()
+ listener.stream_succeeded = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_stream_attach(self, callback):
+ """
+ :param callback: will be called (with 'stream' and 'circuit'
+ instances) when a stream is attached to a circuit
+ """
+ listener = StreamListenerMixin()
+ listener.stream_attach = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_stream_detach(self, callback):
+ """
+ :param callback: will be called (with 'stream' instance and
+ arbitrary kwargs) when a STREAM DETACHED happens
+ """
+ listener = StreamListenerMixin()
+ listener.stream_detach = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_stream_closed(self, callback):
+ """
+ :param callback: will be called (with 'stream' instance and
+ arbitrary kwargs) when a STREAM CLOSED event happens.
+ """
+ listener = StreamListenerMixin()
+ listener.stream_closed = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
+ def on_stream_failed(self, callback):
+ """
+ :param callback: will be called (with 'stream' instance and
+ arbitrary kwargs) when a STREAM FAILED event happens.
+ """
+ listener = StreamListenerMixin()
+ listener.stream_failed = callback
+ self.add_stream_listener(listener)
+ return callback # so we can be used as a listener
+
def add_stream_listener(self, istreamlistener):
"""
Adds a new instance of :class:`txtorcon.interface.IStreamListener`
which
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon/util.py
new/txtorcon-19.1.0/txtorcon/util.py
--- old/txtorcon-19.0.0/txtorcon/util.py 2018-10-25 17:47:35.000000000
+0200
+++ new/txtorcon-19.1.0/txtorcon/util.py 2019-03-04 03:38:01.000000000
+0100
@@ -9,10 +9,8 @@
import hmac
import hashlib
import shutil
-import socket
import subprocess
import ipaddress
-import struct
import re
import six
@@ -192,11 +190,6 @@
shutil.rmtree(f, ignore_errors=True)
-def ip_from_int(ip):
- """ Convert long int back to dotted quad string """
- return socket.inet_ntoa(struct.pack('>I', ip))
-
-
def process_from_address(addr, port, torstate=None):
"""
Determines the PID from the address/port provided by using lsof
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon.egg-info/PKG-INFO
new/txtorcon-19.1.0/txtorcon.egg-info/PKG-INFO
--- old/txtorcon-19.0.0/txtorcon.egg-info/PKG-INFO 2019-01-16
06:08:27.000000000 +0100
+++ new/txtorcon-19.1.0/txtorcon.egg-info/PKG-INFO 2019-09-10
08:50:32.000000000 +0200
@@ -1,12 +1,7 @@
Metadata-Version: 2.1
Name: txtorcon
-Version: 19.0.0
-Summary:
- Twisted-based Tor controller client, with state-tracking and
- configuration abstractions.
- https://txtorcon.readthedocs.org
- https://github.com/meejah/txtorcon
-
+Version: 19.1.0
+Summary: Twisted-based Tor controller client, with state-tracking and
configuration abstractions. https://txtorcon.readthedocs.org
https://github.com/meejah/txtorcon
Home-page: https://github.com/meejah/txtorcon
Author: meejah
Author-email: [email protected]
@@ -62,12 +57,6 @@
`Automat <https://github.com/glyph/automat>`_,
(and the `ipaddress <https://pypi.python.org/pypi/ipaddress>`_
backport for non Python 3)
- .. caution::
-
- Several large, new features have landed on master. If you're working
- directly from master, note that some of these APIs may change before
- the next release.
-
Ten Thousand Feet
-----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon.egg-info/SOURCES.txt
new/txtorcon-19.1.0/txtorcon.egg-info/SOURCES.txt
--- old/txtorcon-19.0.0/txtorcon.egg-info/SOURCES.txt 2019-01-16
06:08:27.000000000 +0100
+++ new/txtorcon-19.1.0/txtorcon.egg-info/SOURCES.txt 2019-09-10
08:50:32.000000000 +0200
@@ -7,7 +7,6 @@
dev-requirements.txt
meejah.asc
requirements.txt
-setup.cfg
setup.py
docs/Makefile
docs/apilinks_sphinxext.py
@@ -60,6 +59,7 @@
examples/launch_tor_with_simplehttpd.py
examples/minimal_endpoint.py
examples/monitor.py
+examples/monitor_compose.py
examples/readme.py
examples/readme3.py
examples/stem_relay_descriptor.py
@@ -80,6 +80,7 @@
examples/web_onion_service_ephemeral_nonanon.py
examples/web_onion_service_ephemeral_unix.py
examples/web_onion_service_filesystem.py
+examples/web_onion_service_nonanonymous.py
examples/web_onion_service_prop224.py
examples/web_onion_service_prop224_endpoints.py
examples/web_onion_service_prop224_endpoints_ephemeral.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/txtorcon-19.0.0/txtorcon.egg-info/requires.txt
new/txtorcon-19.1.0/txtorcon.egg-info/requires.txt
--- old/txtorcon-19.0.0/txtorcon.egg-info/requires.txt 2019-01-16
06:08:27.000000000 +0100
+++ new/txtorcon-19.1.0/txtorcon.egg-info/requires.txt 2019-09-10
08:50:32.000000000 +0200
@@ -2,6 +2,7 @@
zope.interface>=3.6.1
incremental
automat
+cryptography
[:python_version < "3"]
ipaddress>=1.0.16