├── test ├── __init__.py ├── test_log.py ├── util.py ├── py3_test_controller.py ├── test_attacher.py ├── test_util_imports.py ├── py3_torstate.py ├── test_microdesc.py └── test_fsm.py ├── debian ├── compat ├── files ├── changelog ├── rules ├── control └── copyright ├── .coveragerc ├── docs ├── _static │ ├── logo.png │ └── avatar.png ├── _themes │ ├── alabaster │ │ ├── _version.py │ │ ├── navigation.html │ │ ├── donate.html │ │ ├── __init__.py │ │ ├── theme.conf │ │ ├── about.html │ │ ├── layout.html │ │ └── static │ │ │ └── pygments.css │ └── README ├── txtorcon-config.rst ├── txtorcon-util.rst ├── txtorcon-controller.rst ├── txtorcon-state.rst ├── txtorcon.rst ├── txtorcon-protocol.rst ├── txtorcon-endpoints.rst ├── txtorcon-interface.rst ├── interop_asyncio.rst ├── txtorcon-socks.rst ├── apilinks_sphinxext.py ├── txtorcon-onion.rst ├── hacking.rst └── index.rst ├── logo ├── txtorcon-logo-150px.png ├── txtorcon-logo-250px.png ├── txtorcon-logo-75px.png └── README ├── signatures ├── txtorcon-0.6.tar.gz.sig ├── txtorcon-0.7.tar.gz.sig ├── txtorcon-0.8.1.tar.gz.sig ├── txtorcon-0.10.0.tar.gz.asc ├── txtorcon-0.10.1.tar.gz.asc ├── txtorcon-0.11.0.tar.gz.asc ├── txtorcon-0.11.1.tar.gz.asc ├── txtorcon-0.12.0.tar.gz.asc ├── txtorcon-0.14.0.tar.gz.asc ├── txtorcon-0.15.0.tar.gz.asc ├── txtorcon-0.15.1.tar.gz.asc ├── txtorcon-0.16.1.tar.gz.asc ├── txtorcon-0.17.0.tar.gz.asc ├── txtorcon-0.18.0.tar.gz.asc ├── txtorcon-0.19.0.tar.gz.asc ├── txtorcon-0.19.3.tar.gz.asc ├── txtorcon-0.20.0.tar.gz.asc ├── txtorcon-0.8.2.tar.gz.asc ├── txtorcon-0.9.1.tar.gz.asc ├── txtorcon-0.9.2.tar.gz.asc ├── txtorcon-0.10.0-py2-none-any.whl.asc ├── txtorcon-0.10.1-py2-none-any.whl.asc ├── txtorcon-0.11.0-py2-none-any.whl.asc ├── txtorcon-0.11.1-py2-none-any.whl.asc ├── txtorcon-0.12.0-py2-none-any.whl.asc ├── txtorcon-0.14.0-py2-none-any.whl.asc ├── txtorcon-0.15.0-py2-none-any.whl.asc ├── txtorcon-0.15.1-py2-none-any.whl.asc ├── txtorcon-0.16.1-py2-none-any.whl.asc ├── txtorcon-0.17.0-py2-none-any.whl.asc ├── txtorcon-0.18.0-py2-none-any.whl.asc ├── txtorcon-0.9.1-py27-none-any.whl.asc ├── txtorcon-0.9.2-py2-none-any.whl.asc ├── txtorcon-0.19.0-py2.py3-none-any.whl.asc ├── txtorcon-0.19.3-py2.py3-none-any.whl.asc ├── txtorcon-0.20.0-py2.py3-none-any.whl.asc ├── txtorcon-18.0.0.tar.gz.asc ├── txtorcon-18.0.1.tar.gz.asc ├── txtorcon-18.0.2.tar.gz.asc ├── txtorcon-18.1.0.tar.gz.asc ├── txtorcon-18.2.0.tar.gz.asc ├── txtorcon-18.3.0.tar.gz.asc ├── txtorcon-19.0.0.tar.gz.asc ├── txtorcon-19.1.0.tar.gz.asc ├── txtorcon-20.0.0.tar.gz.asc ├── txtorcon-21.0.0.tar.gz.asc ├── txtorcon-21.1.0.tar.gz.asc ├── txtorcon-22.0.0.tar.gz.asc ├── txtorcon-23.5.0.tar.gz.asc ├── txtorcon-24.8.0.tar.gz.asc ├── txtorcon-23.5.0-py3-none-any.whl.asc ├── txtorcon-24.8.0-py3-none-any.whl.asc ├── txtorcon-18.0.0-py2.py3-none-any.whl.asc ├── txtorcon-18.0.1-py2.py3-none-any.whl.asc ├── txtorcon-18.0.2-py2.py3-none-any.whl.asc ├── txtorcon-18.1.0-py2.py3-none-any.whl.asc ├── txtorcon-18.2.0-py2.py3-none-any.whl.asc ├── txtorcon-18.3.0-py2.py3-none-any.whl.asc ├── txtorcon-19.0.0-py2.py3-none-any.whl.asc ├── txtorcon-19.1.0-py2.py3-none-any.whl.asc ├── txtorcon-20.0.0-py2.py3-none-any.whl.asc ├── txtorcon-21.0.0-py2.py3-none-any.whl.asc ├── txtorcon-21.1.0-py2.py3-none-any.whl.asc └── txtorcon-22.0.0-py2.py3-none-any.whl.asc ├── twisted └── plugins │ └── txtorcon_endpoint_parser.py ├── txtorcon ├── _metadata.py ├── log.py ├── controller_py3.py ├── attacher.py ├── testutil.py ├── addrmap.py ├── __init__.py ├── _microdesc_parser.py └── spaghetti.py ├── requirements.txt ├── integration ├── no_testcase ├── hidden_service_listen_ports │ ├── README │ ├── container_run │ └── host_run ├── timeout_tor_launch │ ├── README │ ├── container_run │ └── host_run ├── run.py └── README ├── dev-requirements.txt ├── .readthedocs.yaml ├── .gitignore ├── doc-requirements.txt ├── examples ├── minimal_endpoint.py ├── dns_lookups.py ├── connect.py ├── monitor.py ├── close_all_circuits.py ├── hidden_echo.py ├── web_client_treq.py ├── readme2.py ├── readme.py ├── launch_tor2web.py ├── launch_tor_endpoint2.py ├── web_client.py ├── web_onion_service_prop224.py ├── txtorcon.tac ├── web_onion_service_ephemeral_nonanon.py ├── web_onion_service_prop224_endpoints_file.py ├── web_client_authenticated.py ├── web_onion_service_ephemeral_unix.py ├── stem_relay_descriptor.py ├── launch_tor.py ├── launch_tor_unix_sockets.py ├── disallow_streams_by_port.py ├── web_onion_service_ephemeral_auth.py ├── web_onion_service_filesystem.py ├── stream_circuit_logger.py ├── tor_info.py ├── web_client_custom_circuit.py ├── web_onion_service_endpoints.py ├── launch_tor_endpoint.py ├── webui_server.py └── web_onion_service_aiohttp.py ├── docs-requirements.txt ├── scripts ├── test-release.sh └── download-release-onion.sh ├── .github └── workflows │ ├── flake8.yaml │ ├── readme_render.yaml │ └── python3.yaml ├── MANIFEST.in ├── Dockerfile ├── LICENSE ├── INSTALL ├── test3 └── test_controller.py ├── meejah.asc ├── tox.ini ├── setup.py └── Makefile /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/files: -------------------------------------------------------------------------------- 1 | python-txtorcon_0.5_all.deb python optional 2 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [paths] 2 | source = 3 | txtorcon 4 | 5 | [run] 6 | source = ./txtorcon -------------------------------------------------------------------------------- /docs/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/docs/_static/logo.png -------------------------------------------------------------------------------- /docs/_static/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/docs/_static/avatar.png -------------------------------------------------------------------------------- /logo/txtorcon-logo-150px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/logo/txtorcon-logo-150px.png -------------------------------------------------------------------------------- /logo/txtorcon-logo-250px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/logo/txtorcon-logo-250px.png -------------------------------------------------------------------------------- /logo/txtorcon-logo-75px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/logo/txtorcon-logo-75px.png -------------------------------------------------------------------------------- /docs/_themes/alabaster/_version.py: -------------------------------------------------------------------------------- 1 | __version_info__ = (0, 6, 0) 2 | __version__ = '.'.join(map(str, __version_info__)) 3 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.6.tar.gz.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/signatures/txtorcon-0.6.tar.gz.sig -------------------------------------------------------------------------------- /signatures/txtorcon-0.7.tar.gz.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/signatures/txtorcon-0.7.tar.gz.sig -------------------------------------------------------------------------------- /signatures/txtorcon-0.8.1.tar.gz.sig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meejah/txtorcon/HEAD/signatures/txtorcon-0.8.1.tar.gz.sig -------------------------------------------------------------------------------- /logo/README: -------------------------------------------------------------------------------- 1 | This is a rough combination of (most of) the Twisted logo with the Tor onion. 2 | Any trademarks belong to their respective organizations. 3 | 4 | -------------------------------------------------------------------------------- /docs/_themes/README: -------------------------------------------------------------------------------- 1 | This is the "alabaster" theme that I've hacked upon a little. All the HTML mistakes are mine :) 2 | 3 | See https://github.com/bitprophet/alabaster 4 | 5 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | txtorcon (0.5) UNRELEASED; urgency=low 2 | 3 | * Initial release. (Closes: #None) 4 | 5 | -- Michele Orrù Tue, 17 Jul 2012 18:39:46 +0200 6 | -------------------------------------------------------------------------------- /test/test_log.py: -------------------------------------------------------------------------------- 1 | from twisted.trial import unittest 2 | 3 | from txtorcon import log 4 | 5 | 6 | class LoggingTests(unittest.TestCase): 7 | def test_debug(self): 8 | log.debug_logging() 9 | -------------------------------------------------------------------------------- /twisted/plugins/txtorcon_endpoint_parser.py: -------------------------------------------------------------------------------- 1 | import txtorcon 2 | tcpHiddenServiceEndpointParser = txtorcon.TCPHiddenServiceEndpointParser() 3 | tcpTorClientEndpointParser = txtorcon.TorClientEndpointStringParser() 4 | -------------------------------------------------------------------------------- /txtorcon/_metadata.py: -------------------------------------------------------------------------------- 1 | __version__ = '24.8.0' 2 | __author__ = 'meejah' 3 | __contact__ = 'meejah@meejah.ca' 4 | __url__ = 'https://github.com/meejah/txtorcon' 5 | __license__ = 'MIT' 6 | __copyright__ = 'Copyright 2012-2024' 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ## see also dev-requirements.txt to build 2 | ## hmm, travis-ci doesn't like this since we need a GeoIP-dev package 3 | ##GeoIP>=1.2.9 4 | Twisted[tls]>=15.5.0 5 | zope.interface>=3.6.1 6 | automat 7 | cryptography 8 | -------------------------------------------------------------------------------- /integration/no_testcase: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## this is the default script to run from the container; run.py and 4 | ## the host_run commands run each test in the usual case 5 | 6 | echo "Please see integration/README in the txtorcon repo" 7 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | tox 2 | coverage<5.0 3 | cuvner 4 | setuptools>=0.8.0 5 | Sphinx 6 | repoze.sphinx.autointerface>=0.4 7 | coveralls 8 | codecov 9 | wheel 10 | twine 11 | pyflakes 12 | pycodestyle 13 | ipaddress>=1.0.16 14 | geoip 15 | readme_renderer 16 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | apt_packages: 8 | - libgeoip-dev 9 | 10 | sphinx: 11 | configuration: docs/conf.py 12 | 13 | python: 14 | install: 15 | - requirements: doc-requirements.txt 16 | -------------------------------------------------------------------------------- /docs/txtorcon-config.rst: -------------------------------------------------------------------------------- 1 | Reading and Writing Live Tor Configuration 2 | ========================================== 3 | 4 | 5 | TorConfig 6 | --------- 7 | .. autoclass:: txtorcon.TorConfig 8 | 9 | 10 | HiddenService 11 | ------------- 12 | .. autoclass:: txtorcon.HiddenService 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dockerbase-wheezy/ 2 | _trial_temp/ 3 | build/ 4 | dist/ 5 | txtorcon.egg-info/ 6 | *.pyo 7 | *.pyc 8 | *.swp 9 | *.swo 10 | *~ 11 | announcements/ 12 | annotated_coverage/ 13 | twisted/plugins/dropin.cache 14 | docs/_build 15 | .coverage 16 | .tox 17 | venv/ 18 | venv_tox_*/ 19 | PRIVATE* -------------------------------------------------------------------------------- /docs/_themes/alabaster/navigation.html: -------------------------------------------------------------------------------- 1 |

Navigation

2 | {{ toctree(includehidden=theme_sidebar_includehidden) }} 3 | {% if theme_extra_nav_links %} 4 |
5 | 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /doc-requirements.txt: -------------------------------------------------------------------------------- 1 | GeoIP>=1.2.9 2 | Twisted[tls]>=15.5.0 3 | zope.interface>=3.6.1 4 | automat 5 | cryptography 6 | tox 7 | coverage<5.0 8 | cuvner 9 | setuptools>=0.8.0 10 | Sphinx 11 | repoze.sphinx.autointerface>=0.4 12 | coveralls 13 | codecov 14 | wheel 15 | twine 16 | pyflakes 17 | pycodestyle 18 | ipaddress>=1.0.16 19 | geoip 20 | readme_renderer 21 | -------------------------------------------------------------------------------- /examples/minimal_endpoint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from twisted.internet import reactor 4 | from twisted.internet.endpoints import serverFromString 5 | from twisted.web import server, static 6 | 7 | serverFromString(reactor, "onion:80").listen( 8 | server.Site(static.Data("Hello, world!", "text/plain")) 9 | ).addCallback(print) 10 | reactor.run() 11 | -------------------------------------------------------------------------------- /docs-requirements.txt: -------------------------------------------------------------------------------- 1 | ## see also dev-requirements.txt to build 2 | ## hmm, travis-ci doesn't like this since we need a GeoIP-dev package 3 | ##GeoIP>=1.2.9 4 | Twisted[tls]>=11.1.0 5 | ipaddress>=1.0.16 6 | zope.interface>=3.6.1 7 | setuptools>=0.8.0 8 | Sphinx 9 | repoze.sphinx.autointerface>=0.4 10 | coveralls 11 | wheel 12 | twine 13 | pyflakes 14 | pep8 15 | automat 16 | -------------------------------------------------------------------------------- /docs/_themes/alabaster/donate.html: -------------------------------------------------------------------------------- 1 | {% if theme_gittip_user %} 2 |

Donate

3 |

4 | Consider supporting the authors on Gittip: 5 | 8 |

9 | {% endif %} 10 | -------------------------------------------------------------------------------- /docs/txtorcon-util.rst: -------------------------------------------------------------------------------- 1 | :mod:`txtorcon.util` Module 2 | =========================== 3 | 4 | util.NetLocation 5 | ---------------- 6 | .. autoclass:: txtorcon.util.NetLocation 7 | 8 | util.process_from_address 9 | ------------------------- 10 | .. automethod:: txtorcon.util.process_from_address 11 | 12 | util.delete_file_or_tree 13 | ------------------------ 14 | .. automethod:: txtorcon.util.delete_file_or_tree 15 | -------------------------------------------------------------------------------- /docs/txtorcon-controller.rst: -------------------------------------------------------------------------------- 1 | High Level API 2 | ============== 3 | 4 | This is the recommended API. See the :ref:`programming_guide` for 5 | "prose" documentation of these (and other) APIs. 6 | 7 | 8 | Tor 9 | --- 10 | .. autoclass:: txtorcon.Tor 11 | 12 | 13 | connect 14 | ------- 15 | 16 | .. automethod:: txtorcon.controller.connect 17 | 18 | 19 | launch 20 | ------ 21 | 22 | .. automethod:: txtorcon.controller.launch 23 | -------------------------------------------------------------------------------- /docs/txtorcon-state.rst: -------------------------------------------------------------------------------- 1 | Tracking and Changing Live Tor State 2 | ==================================== 3 | 4 | .. comment:: 5 | launch_tor is documented in txtorcon-launching.rst 6 | 7 | 8 | TorState 9 | -------- 10 | .. autoclass:: txtorcon.TorState 11 | 12 | 13 | Circuit 14 | ------- 15 | .. autoclass:: txtorcon.Circuit 16 | 17 | 18 | Stream 19 | ------ 20 | .. autoclass:: txtorcon.Stream 21 | 22 | 23 | Router 24 | ------ 25 | .. autoclass:: txtorcon.Router 26 | -------------------------------------------------------------------------------- /integration/hidden_service_listen_ports/README: -------------------------------------------------------------------------------- 1 | This test uses the standard txtorcon test container. 2 | 3 | This test confirms that a TCP4HiddenServiceEndpoint listens only on 4 | the loopback interface. Basically "container_run" uses launch_tor() 5 | and TCPHiddenServiceEndpoint to create a working hidden service. For 6 | bonus points, it runs "netstat -pltn" after the service is set up. 7 | 8 | "host_run" (from outside the container) uses nmap to confirm nothing 9 | is listening on the public interface. 10 | -------------------------------------------------------------------------------- /txtorcon/log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This module handles txtorcon debug messages. 5 | """ 6 | 7 | from twisted.python import log as twlog 8 | 9 | __all__ = ['txtorlog'] 10 | 11 | txtorlog = twlog.LogPublisher() 12 | 13 | 14 | def debug_logging(): 15 | stdobserver = twlog.PythonLoggingObserver('txtorcon') 16 | fileobserver = twlog.FileLogObserver(open('txtorcon.log', 'w')) 17 | 18 | txtorlog.addObserver(stdobserver.emit) 19 | txtorlog.addObserver(fileobserver.emit) 20 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.10.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTnTI9AAoJEMJgKAMSgGmn8+AH/1vqXvEFOPomq+Afqv+UGUuI 4 | hH3+bCv4QnY2HhSLZLuo+N2XlzPNT7JsICbgdll9DGw41nPJqRFjq1SNwoCO8XOj 5 | a7ILRC9JsZY1Ez/LnHSpRoQU5+rsXJf5ffET5nBVamRWhNJ1Mg8macgP+zehyU40 6 | LXFgiIIm0sNqVzuAHil/ISJslX4V7HO729ehAaEwR5si6Jyw+OQwXY0St8cM3D8H 7 | pSDd7WR0FUb+BV/Z6EWGWdGooIbAg9m76XUXaSqWOg5Kpf+88AqcWOsFKSw1LAkM 8 | Ll830ravGIad2KQgWa01hH6VWrmWTlOuZeMA9ItlUadYLLzZbk3c2d3nBUWzR/A= 9 | =Vcwh 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.10.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTzDhRAAoJEMJgKAMSgGmnVy4H/iKWRvwWQixsU6k2/j7GqCN3 4 | xpHQCZC+3pejNH5GO7hfx26UC7FGHc/CMW7Ul+Mb0uppp5UEOJYd4sK8dcdDXodA 5 | QDMkwxdgDckUxsY1p8mK/fFnf+nBkniY9Lpub9Pz+qiW43iBXgsESB6V8RXpxK+x 6 | QUbZt9Jw+vU0SfM06vCowLuO/2uu9WKJZAI6BxGXiDAxcG75fXALHSAVwQWvgfS/ 7 | UsrOve7f4TCvn9mAe9zyCUD4eB9f7phE8vt6jfqlp68iBhT40FKtlEeousuztdX5 8 | LMnkoPrwy7iGNyg1Uv32A97dwqrN/PQSNEoPPrKMMUu1+QpqAl7bEMEcrAir4eo= 9 | =1VBF 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.11.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJT7vZoAAoJEMJgKAMSgGmnmjUIAIFSOGt/oS2qqDbaqnwQHtXG 4 | LfT5pnrPGWdH7UekVBgWPibyQQRhNaB8qvsaqBuEsEDD7099SiNa2YJ7a8dwHedo 5 | BUcuFxh2lToBtD5iHjyRHMPu9F6rc39dtNrZsGFRzr6axOP9B6c1pWS7RkRnTyOQ 6 | mqJCLRVGAnAvc2+X54aUf0+e75U09/yFQIy6zmtoUfjOybus81J6bvXUeXCwH6ps 7 | diIqV7w4g1h+L/CqjALGjrdej/G7DitN0eyFXWce24Kc4VopY6SSzx/SUsE59nKz 8 | SgBUDfEPrlJZhgxUlGe+SHoBkULgxAGfS4fq19TJLmzkiJxGhGbhTkspKiX4Onk= 9 | =dOHs 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.11.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJV69UxAAoJEMJgKAMSgGmno5sH/iU1YcdGso972z1JrWAi9Q2H 4 | r2apOpMHChZWQhp+Wdkajz1MMnTreNa4jiWicFUw3rbYFaT9Bkip4ligLSVIrZoV 5 | LnFf3ADUs1dVL8hcq5GIVqP48n95LSDLTBDRULxR0PUIzk8HHnjpDbIFAkNXe7Gp 6 | PyLLtHSt8uI+LRcEMyWyby4+tMLNJE/Aymf+owpirHI6xLkRssPKTqPoMH0Dy/Bj 7 | JYzEdDDGycgIWfRnQQHoLqyBsY6bjXB1FvhCffE+o0/pXR/8a9hyHcUr7Rz78bOB 8 | dyiWSaT9Fp0gyTOZuv6HlpEeZHR1qtrVyWok7y00vqAJSjwWcRBxAyfsEkrpOxE= 9 | =SA4P 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.12.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJU0TImAAoJEMJgKAMSgGmnqccH/RkAUYO9IMlo+Cl7TFpLvypT 4 | TZBlGyoPnfKLEn+79Gv7FrahDv4CeFMCHZwX72sYRMuIjPHSsxYmJYpSshYO9T0v 5 | GrxwlAg7a3//KH2BJvzYEdBb2m8iKNUSSU4U+Om2DgoHZlhBKhEaK07lf10DPI5p 6 | yrTRgI0xnYFnBUaVU5o+ExdkWet5qu5nchhizhO7ynY25iJiCDd+/8UOG+fDWXPN 7 | XjmSHhtovdeSvTiwUsRxxiO/qd0JGcg5N96KUr3c4mOFAZEgE0pZ66Hd0OyYrDuS 8 | DhfncVo1H7C9Bw5ZKlxdHo6XgYQAaKGxD6ZHCfMxdwYMjJ+sv1XjSastWMFwhjc= 9 | =/2hQ 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.14.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJWB28VAAoJEMJgKAMSgGmnhm0H/1yKzhDHqobrH9larcw+Ss74 4 | 5uQiF7DJBuqrMvopI7aSPNE70y7HeUksFt8+/x01pll6uOLUTdf2INeus0GVu8Ek 5 | g2r7uHQI68kQbc8nXw80Itt220ttz2civK9I0HmyxRa8EIDf6vjdLCSKAaOgaf51 6 | EIKyQJBv9Gn6tmUQJ5DrFta/4ofQMr59Rq6K/InWyf07suCup+YwY1HanotRDjCw 7 | zK5qMFJKFMk6CZb+jnVIaP5XwF28AdrNTHb70pqQAX/pTi2KjJbF74/wqPbmzjTP 8 | dA5YCdrN8M0q1gfCebJEVlAoMJWJznjoNa7MdgpiTqTc2fqBRureL7psWnsGTpo= 9 | =Y6q2 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.15.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXl+nuAAoJEMJgKAMSgGmnCeEH/3xuGojNfjOBnsVWZxDEl1qH 4 | BYvRIUF/tcs8HgZeAcNuZWG20Bx3tOdn7TnC5BVjz8U4wG5XGSWe3iTaXlR5S61p 5 | koF283to2s25oJmEAM2rdUSRcSoBP6VnCfuC3f9jQIEcbM5Sq7zDMAc8G4bcGrY0 6 | xHfZ/fEwQWplpdm70D16RnaSNAe16ie05n3zs0kvyjeVX8zr/S8yExpU78OCngbb 7 | mkqpxnsei6w+/bBhHWFofjcQGb43mxRZ6FJO5V9zuaFM8iLXZe5vwyZq2JLzvOoH 8 | G4RFkF9jTASvkzRFlM5ZHhmU6hW1kvVDKoR+MnyMj9D6b6uc7+mAfjxvJIJKLcU= 9 | =VBhI 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.15.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXrPR0AAoJEMJgKAMSgGmnGsMH/iDw5W6KuMEAsN9DI3POWi7C 4 | FNNqsfoAJvjOzRWswQX+YBhTpzEzrwqK9nsvNhTw3UjAb/O+0G/bnG6gdL8wcOYd 5 | AHuVG/ltDCyIix2F4VW5jqzrxBneNko7iW5mgimRKMWQus6kXXodx0wHpgapGY6D 6 | hrW2kkduw/S+QfMFR2xQSCz8mk6Ol1xLaWQPuR35vlvsw90yr+Vow/waBE+xqQad 7 | 2BQE+DVm2Il97pYw21N0jLyrUdZbjisELwRrMRBIn4pBa+8hK8DSXMbQ0/rmVV7E 8 | KVqUDVwNAxNwFbpL2Ck8H2rSG7S6eaG4/jUo93VFKsvwyDFoklO3qyfHKycG+rg= 9 | =YOFf 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.16.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXx3PTAAoJEMJgKAMSgGmnr7sH/1ejb0p814V9k+skAVQhmcyL 4 | 4zaE/y6c8ZLGhoBkYNScm3FLx4Eku18EO2lGuw+q+Lwv1eKI5wf5V2YKAs6OFjbp 5 | Qu3peMLEHcDotQbyfesJ2EJIeZpBWnpOm56WRhIS0I8hWdKQq1wNVc4nEzeHqXpn 6 | ewgmU2UP7w6fUFnXXbYl+khlmEFnTQfodJUSuK+ygRFFNSrGGOUG6Z10t6BPgY7u 7 | oHp77RPsYK6gq3eydOpBmtQMRv7Y57BEzuDSd1c1+1rSW0+Vl1RNGiWjYl3Zn+C5 8 | ElaOG0DzjzX7kPX+qGh2INkqnhj86OHPM361tOq94MqB9OI4VGW4S+EyX7bKsko= 9 | =45a6 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.17.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJX9B0yAAoJEMJgKAMSgGmnUBwIAJ//ppHpBcCTDaewW1OThtHI 4 | k//igQ4xH0BvwcKGY8UDV7FGAvRl5ZSqlklydy/zY9B3bPiOVDgtFtM5u35+eq9g 5 | 1tajKq7kI+eBM92l0HNWYKrPb8SPtq2kCN1x+D7IAXhKgt85RufwRfHK4fK/SaRU 6 | mbV62ribfdhH3G7p/07ADtuCUf5kU3ukrDniFvX7u7JiMIR5f42fu8vu71wZC7oa 7 | uUJgmTFXdL/0jZhmSi5+NLN0ogh4UAl8L5G4Y7R8TIMMJtG7PXizjFN570kyWE56 8 | GWlrYNz7KQGXSV59NJrd2wt42OGDt+2m8D8gk+8sko2tVurSGsuPJ00nAjZjPAI= 9 | =dwWC 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.18.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJYdp2RAAoJEMJgKAMSgGmnSk4H/3pVvX6aB9VLrkDcGLZW2VfT 4 | HPQq3RCS5TKCnU2SgSXIlvL1jL8UZDYO+qoS6uA23o37MYDR6DNsqLC3owdk5rdo 5 | 3aMnLRABO/lwxccTag2/sSGW7aH4Xgfh+By/tXa/0qwlvPNHbY50Lk7M36u4gu+7 6 | 3spS80Lw2iGVCMjjrx9rsSTiD9+Vd14TRZg+knTA4Z3tYuC6jeUmLqFmp/aqyjig 7 | E0b34bJeW0Ls1bv13NdTORnm0PVDzxTTGbDbJTLuXbU4iBBZ4fzR8N1TA8HPsOkg 8 | TA66zKybWK0AA8BLRHVMch/1hM2UZ3BScN073aBmepTLA14BmCrxAJ+qGJikvmw= 9 | =GjTJ 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.19.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJY+ZBdAAoJEMJgKAMSgGmnJrQH/2QjOI9UqN1CFFkP8rmPDBDW 4 | kZjwTUe3YIu3nmVVSJz0OykBEqEV8mt5sPbowkg36ULVqdXauGHw7kCzqXuAqi8+ 5 | hlqGiTUY0N+dqRPJ9E/Rq0NMGoxF2QxBvxAa14iGvGauIZuhdyfERNVxlQA1d5gv 6 | ea8b9IAMvd1JQbp+WifXsCtSXywNzL7kPNNG/zjXvHNE53pN2RCvgsM+dg75J4jB 7 | IS9RwgMkX4ZPnftHp/3AjnwHXD8mic+38+LrcBTHGAqhz+Vd2D2AVXMVKHS5Xw7I 8 | jv/DfUVkoh/+F6vB7tbo0fPe+kpljZU0yQAUMn6das4wGAHViefYjQuV5XHjfDE= 9 | =DCuB 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.19.3.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJZJS04AAoJEMJgKAMSgGmnH+MIAIqWuuhFmRCd6FQ8agVIR3zW 4 | JauyAlepAf0FljQ/JGUc9aMzFXYjt8Pq41bYSPayw1fkguNNRDUyt2As9m7XRe2a 5 | V2xFgUlYWfZVFVHaPjU4tPWFeZ5SmdX7f9LNUOeowRBnUiguLHatuj8LPELxk1W3 6 | BB4GrjrHTVWha4MIUqCL0p2d4UhvyDQbBR4iFRA/WLYMGCgUcz++j+5z6ttMLYK3 7 | Jv7jjoOFsQaGmhzdfZLnqUzUeC0943WUhG85HManTOIUSPgcQhoMBbRADanVOOwW 8 | oSymyZhCUJTnGvVtS4s1ze/t+2BCy8Lbzsas6g5m0LcBsxV/85qnGJtFz/S8Yyc= 9 | =jhw5 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.20.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJajkI1AAoJEMJgKAMSgGmnpk8H/0Zuxl1ibK3jSPs1uK4o48nY 4 | 42owz3z8hoE3vlGyRJwHioSgPZdx4vVBs5O7sQ71sbHy4MJef4yZAhnRlTv0JdZC 5 | jCkvZtg1xbWfW7LOec+jLOdv7khEqjXjaamHhl5YGHT7DX1HaWNu9CR4kzmOXflf 6 | JO2jUFWlD81E+WTe8CQSuX0/5sT7jA5W1yNAFIsR+2ff4ISAyG4uIyDjAzKvIszD 7 | 1BK1eums/6E1VcC1u+PnAzW+swT4V6E4lGp2x6xRWh/zOZAk4s9s1ApQTstrquvE 8 | BE9nER84f2wXdoRJZfrtj51FIE/YcC4qBNvczGC2FtYF2zkb1/AQkKOQXol5Ess= 9 | =/mHU 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.8.2.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJSkEngAAoJEMJgKAMSgGmnuiUH/1AfaZhdVGmIZ8eBt8a6c2Nt 4 | wtxVzynU3ADF2BUC5Ekn1Ih7WWRTl/CEXKhyo5pDXHLbYAcIZvxhrhLiKa7Z3G1a 5 | FB7CT7eySEr7SHnYc2pQGijCsy1tXj5tXTYacLCviQ9OEuBgfHEmur/LvKHsBC6Z 6 | CQYh5Tfx10SdoYhZ1/bfXiji56AIMo/IbcDM+/TLNhqrq3wvWzTf3kZxO5GHvLtj 7 | oqE+Wq9W7u+D9xaW3K/OUcowb772YNXYB7E6u3TiUDggCzoCmPyB4/ys/kuAQ+wk 8 | Crl0Gk2LA7cJfNEbAmLJ2WN8j0sZe03A8GYe6TCGFpp38lI5HnkF+HOvG3Hy6tY= 9 | =gu/U 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.9.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJS3W1NAAoJEMJgKAMSgGmnU4MH/0e1xYzsMhhKiGRNTncFJuKF 4 | tkjVRwX/q9O2kQ6Mgu3vY/JybpU/PqIlTCFMQht59HnO6x0KmadTUVBNPbULkgsu 5 | Xj1ub1UoK09Oyp1IDwO1q2xF4WHv6zIOrRsHpTBsH0miGNN/hTjij4E245r96eL0 6 | 7fXxRumksAiFv+GIhvzgsg3pibYDfr2CI16yNWig229iEkQxujZaymZOSbNvm1T/ 7 | k7qKfSQCs9ouEIuIrnA5ZtsEytcWB/bXsbx6b6sVhVRgE+X3q0ESJD22ODUrT3Dc 8 | 5v7+g4hbURPf/groM4+4z7GZVMjJLk2SiTOvoLdlP23OejfLAO/ar/sdUXGu190= 9 | =pqYV 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.9.2.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTWVYtAAoJEMJgKAMSgGmn/kUH/1WXoKDMkuU0w+cK3Af+LipI 4 | rn5rJfTJaA4pY2+PC3DYv6/ACIw5wMzja0lX4q2VBpOzk1dBFHrr0Vv6te8V/sQe 5 | jUc8ONjlDwRLwebPg8aYHFHhTjVJiQmZtCQDSCMWJ4gC9rQWG7lvm96VHIVnH2oc 6 | 8PU6vdr8iyfkL47B90JKajTBZGekrCk7+IT41byAJSns6Y39LHm1xCADtB5T3ot3 7 | jWuxQIqtnDw9lY9KEcmowmWVBh4eKhogS9tvTM7xNCPrD8YufN205zGhKXlm2CZD 8 | lZc1Cs+f/6sNtuSPQZg8ODjImrsY03c43uSThwJai907gyLOvMZUBh4THuvdjoI= 9 | =NZEB 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.10.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTnTJJAAoJEMJgKAMSgGmnDN8H/2b31BgLjQCcRVkLANU+rFK+ 4 | pW2pLQRtAbxC18vzJjAJSSrj/pYt+s8MC3MHsUBRwPtZQwXfJJpq3P+Ki14UgmIl 5 | Dwft9wkzAe6SEguSPbvPlefRMqBgR5LsCrpTTJXXw5M656XGqWhopTeCJlxxcqo4 6 | VbXXx1cnP21a9gwnm13qf8QhmcK57Gh1/06vHMxGcEtdvKIkf5FC8KmnMMzK0y/S 7 | /TO246bCJfdjnss+QqY2O9Hjrjn9VJ5xJvDCumdoAwSuIyy3Ir1AMvtMsBGUkTl2 8 | Z3QM2Q4ujEJKb2ksX1uqZZtxq1WygOvL4Y5QYrgFJnwqTOC0vzyOl3Yughyq7sI= 9 | =hMVt 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.10.1-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTzDfRAAoJEMJgKAMSgGmnhBUIAN4FIhbn5vhudDOpkF0axs4z 4 | GF8Sm9JiJIrRljRJHcoN1Pe6fW77ExHjbkur4WXDedX4lqMc+9DeZkF6L94ARRCf 5 | Fj2UuJqq0wkFTd6An9sA3YHzHSEF0jBq8E4sJczwNj9d0MYVPkp/ZANr1Zc8mzfn 6 | yA6VJ9vsA81e5zUJYaStp7+TIAB4WlByV0gOMm3b2bDv0avmVszxQgOy/ObLnvEa 7 | cIMqZZiOGGBPc0K4dBnFUiXvNWw9A74OL9Ao9alrJivh8NPc2LfaW9FqtdI0ReTC 8 | VbAE+KFZH7O2jET3ZIXAOOp6dweoyOMzaWZi6RQdNw2WXEOLup//vNL+U0XuZrM= 9 | =eR+L 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.11.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJT7vZ5AAoJEMJgKAMSgGmnC98H/1F/ARG2KBXpjCVYZbNg+Lgq 4 | 9AH8N+PT+XxxBhTGUHQ+ne2Vx6Kxh/IEWRlTjPgKZy/OyzdHceGXYbwOzBCmxuve 5 | XbHJkh6SGds559Q/8IqHwi/BLiA6JAdOnv7OswKdRAHQ2tJYpKuN4ZoGJWw1r6Ku 6 | 8OOJhGsYKtelYrIHK3XvIlMJtd6HDgL/m5Kq/ufiM52eR3z6V7xfShLkzgEVLvvc 7 | RtjYfxCEx45PePbkaorUwE+D64KBFFxT24rl59a2UVj824a1QV4qfAs3N3cQvIdS 8 | kw460eqZYcIY/UltDBP9KFz2SZmaX8TcGBT3gJcrHuQiMO4Fs09R0gTE+H+A4do= 9 | =PfVO 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.11.1-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJV69UfAAoJEMJgKAMSgGmnB2AIAI9IV6hVkj+OxNrVI8JTnc4U 4 | 37zT/RcyPPL5iPI5chnsWJvI3/NEznxuE9MbeJE9n17TZ981Rv2LqC28psK99+Uq 5 | 7d2TbOo7xZx0yftQHT/4j0tLjzZPmAlymuDR5mrJWqD3xgyYTpau38sMHIColxAv 6 | TJcp3RP+2ML8vgAdfqVYaGPy8ma9hCorqu64t7CN41prYRBxlPLYDh8p0joQ4Hks 7 | vtbOdtHSckdPsWC5pKpFJj/9yZuf1r17nACWORRpqkFJkhnPMm50v914GhxkPGLW 8 | 06d4ESUkCZWgzqeN0VprRtyfpeLpgjOY09QGmtDl9Lnjly8cpH7wJoNfXs+qrKQ= 9 | =d/m9 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.12.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJU0TIdAAoJEMJgKAMSgGmnr44IAKI7ODRvIlfrPrm5moHPuc3M 4 | tR30y4MGVtnAOjnrUjM8I2OKvQ2I/Z9tU4VRreVHz8T7lZfrjED2bOhyf78gnJR3 5 | /4OWGO/1ZwVrv2uHpT1puc/BSG6MjfOLAefIf9LabisdZhKiDzL4xDAQHZf5Bes+ 6 | ihpC4xAHKjgj11LlZUf4oug76EC6GHiT5wgSZHTqInyb3ONP5/lLFnPycX3hg2jR 7 | JIG6crn6PrrlCawXkMcC9SxpMyb3Lgjy8MRQY+2RYe5ywIGNYbXA9ERnYGsfGunB 8 | mhzGcqJvaegJgbokUGjkUnDwqa0e0+C/CSolnZ/dY14UgASIms9A8QcQaUh1UXI= 9 | =NI6H 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.14.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJWB28dAAoJEMJgKAMSgGmns10IAIKTjR3JAg82RHxVT5+vK5+w 4 | Vklr1Kmsevk9sWwQynRn9RgGMfmUqIvKpm3wCdRTEMiwkPfGDYjJdzJZAJjWM5PU 5 | 6nioJpSz40EGMZ7hkQIArTa7eWBRkQJBR1Sspkbnw4/R6InFrnjjrcj7MJMSlgRK 6 | 0thiGATMJd2C/HIc630qklxdXTOyqyIdRBLSJ4nHscAzJyXro7Zfax9kKUF7BKcn 7 | 6qdIzJ/k6siXE171eyEGQiJeLcuXIIZnZLspvrkWpUHPiR5EoNhFAyJ4xw6yWnIw 8 | aOaTc34fqIAEjddHTv/VRNBZrE97ZxgZuNs7VBHTMXzaVphNwoF5W/PYt9nh5bU= 9 | =YymY 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.15.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXl+nWAAoJEMJgKAMSgGmnaMkH/0L31RT2Ur8MQQX0dIiIdjsV 4 | oRhzO2iQlE2T9w65tqBK2ot2txyqrgwdrjdny2nSfE66bY3b7q9gNY/Q2dmLUvMN 5 | DXTQswTH+vWnSloMU03NEJ7LYs601qDeHvhetrOHGoQdBlA39XmNipCR/2g8mflp 6 | d1ry5l9h21ggO43c6Xo+vmRQHNpw5CQ59+eAQpgikyu38860Z9dioEMWUhxnklml 7 | +KdItNVrVrH0fRpy2TbSm0BZgaInr0Wu4OTeE4HefN5GdHT6lJd+7WOPHTPLyLn4 8 | CQnT1kv3NQrreE3C7rpxYXP/4EVzXyuVm6sD2mux6RtVmcYh1fgS0696dQJCwQU= 9 | =Xa5R 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.15.1-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXrPRRAAoJEMJgKAMSgGmnzHwH/Rt/KcPAOFt3UZD5gNwYRClw 4 | 8vDAVSnhjRlXh1e5NsEHVGtmbWl53xK6OPplfpOzqzFlSlqOUgKKQW6QbtBFkXl2 5 | dy8Hp1QJNC51Z66CGH/ppAR11HP6H+vimztpc2nM/xTkCWWtLBI5eGS0Ue8GpQ39 6 | 9firvgHt5l85ASBNQEsvzca/XnLi7diCaWPofT+lWgYir2YBD1f8W/y3Ao+BPanZ 7 | yJXuWU5NqGpcnnRfELQP3YvZZftJQpBywHNPnWqnsUVNvqFGfeEfUgDMzj28oj1Z 8 | VcKVNFgjwx3LzWrEjx66SVy4JMj62FwPaDe+xGEHMPNQPMHDUARqLxEL7QT/KqM= 9 | =QEEP 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.16.1-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJXx3PGAAoJEMJgKAMSgGmn/fEH/Rnme+kIqN5IEo9qlbLpKxha 4 | uZr0ia3KYUjrhrHm9TFYcnTBANt9T1SKhzgZDUNntJJo89ekSxUDC9zrCXkU6KKj 5 | qFPl/8rinY5BXr7dqKPVmJZxFoTax0af9P53HaQTB6BmjUTBmQ62j1UbGtXLCV2a 6 | 0LaxR3XQ4vPioUpXy+E6zkcisPLISanS0ceTW5kuKb9TO7LseGwT1u88b7Tea55y 7 | 9BjuTT7mODDOZI9R3VRRlRBusJigmD6eED2Pf2PmfRmzttFY32m2CvfXmMa2sjIj 8 | 4ZxauZAEbydI/RtMXjuXf/capzVuZij4z8SapJRBRMegJsZ3PhOqRfKvKOFUnEE= 9 | =NCFL 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.17.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJX9B0iAAoJEMJgKAMSgGmnGPMH/1EfH65ROFDH5MrISDTmHEtx 4 | Aqn0LffbsXOleRXHZfX5kvg/MYo6/UK+CNAqCyAjGMxspS7BRCcvhFNX8zwsybML 5 | PdWMt4ZUwNiMLaDobfohwQU062OER/Jim511YkJLMt5PrToYiUAudaB1s1TdPhVV 6 | bsXTeZbuAzjbYDqpAXG5EKWn2uDkAGb5Qonx/plndp9c8RC8/Wgt1TtQE3xi+kRy 7 | FteOAkslU8v1hQCjyrzxd+424dZ3i4APaFujPtTUNZffJEiTrDdLjfGVSOXdwOv1 8 | Tz4Ecs80/sHUzDoQKterluyBQM010eiowWLUO6Tqq63ZHh/7H44L99Aj+fjH7b8= 9 | =4oTF 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.18.0-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJYdp2NAAoJEMJgKAMSgGmnKXIH/jS1Z56IkQ8QcMUpXuRvIpNN 4 | d7Zx1HMqTyG0YnBwUirPSjc2hikWNrsj2TkVz2wltFJBUv13h222RqFvhxMsA/Ib 5 | Bz/sFJ++EYvE6zoU6VBDeCPFdEDfeAbll91IMxYlaDBBMg7VJFcK24eTqfLDNC9V 6 | Dl/MwyMgOHiPJAsu2OxyxxWOUiknQCDJB4K6uyvhG6U6fL0F+jDkz0eI5AGhb/ZJ 7 | 7ag+6mwArXY+0RkLjmhgzF1RkcN+dN3kJkRw4O44TDTX+4Yumry0ILMHsgPXG/A1 8 | LzeAHlxDlV38VX5zwz9j7ekCjL7tDfjf5H7/fCe7PVDyJV38UlDbIXP65QCK1Zo= 9 | =NX0y 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.9.1-py27-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJS3W1GAAoJEMJgKAMSgGmn9kcIALfNOR0JKzkNQ8Nf9EYP4r0/ 4 | 0JHmmWGcvEELnHPnm6vadkfV2BBh/xLIEfDnmX8fJPlKT7ZSvJQq3D7xM8rakCTw 5 | vG1iwqI23zSlPVjurIKLUF0ZNcfK0JPyQZ0N4rsG3o0j2AYFu8YjZeaqUfvjuR1k 6 | mbDKua99/brfEEMTmK+gO1wPknXlM0tZjoqJARLfQoOSmwEZdKtuFk77Pz+mSDNP 7 | +BgxIqewJsus5mrS9OeyP0PBRB87wEMHjmi64ZOPVQoG1eivtyzRwMA+VaGxcXvE 8 | FfwuPgdlfQidwrEhv2el9Jsv31V607hshqQ2glnWtWSH6ohyPO53y84i7E1em5E= 9 | =FNoJ 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.9.2-py2-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJTWVYgAAoJEMJgKAMSgGmnxLIH/2pad2QCL1O98ZGQV1z2JjE6 4 | Bjnue75N4NeGwib61jliufgZdxZ8qaIUD975pf64upD1gKXlMwXesC4LSKasBLVt 5 | Voli5KV6IliI2LTp0GhuMGoZdGzC0XYa2jqagm8zKQZESFSRxYN2Y2TxrWO+M6xn 6 | WYIHU3ukWWj4UPKLGwZVk4jExJE3OngjWSr3tY2EKEbwtGI/EvljbUaUXjl7dsAT 7 | Pa/oYa06vHMGhnp0pRxaclRYTfv3ij6fd/C8gvcBsbsBU63VH0Nw8kA9cIVGLcDC 8 | WAfc5NePhmcVyOJ7AbfnuMM2ZmGQgZPrQueH/8kUhBzTK8Q75/c10REV0bKUiWw= 9 | =2Yhi 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.19.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJY+ZBWAAoJEMJgKAMSgGmnTgkH/jptwaaV2k2+cf6HrY18KjAU 4 | +BDY7tQuu/BVH+jHwWWDkrC7YXOs2VtA8RDIRgEQyOb+J/sKWJIModhQ2358ORyW 5 | CypOYcBH0X7mmWZOrgDzswrcnh9B+FiZj4+/MK/r62ayNBwvDmpunLfT4VE3p/Up 6 | lFsSBSP4bNBeibneg5W0hkYRajLdHzllFon0eFaUtkmacJd/0ib3hGT460z7XbEM 7 | j5tmVpdhe98kW9lFfUdrtgrHngjGC6Y+oBg7Gvp2uF6dggi+eR1iy34gODuAFDhS 8 | j87NlIOdHWfwmq2k2vPrD7cgBO032v6FZfZ35fWSc7FiEtKdcYjxnEgEeHA2cdE= 9 | =csf7 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.19.3-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJZJS0yAAoJEMJgKAMSgGmnQLkH/jZrRLCcKJlm7JfwHNNtrQCw 4 | fD1hlEGme1oDW4IwnbmQQIef/MqnhAVmn8+2tb3jKUQbfVAgHd1ozUZZm1uD0FOl 5 | GzTEUBcUsEKd1oHVH4EFFJ0R2NSdHjZ0e92z1HnuWDbK7fjQ5sD7+AkYVp0tPA0c 6 | cHDIguXcPVm1/4UfBhfOc/m4j5O08dDrE6V0eQezXLQKyg9A1K+Lwiu0ly/rGVLw 7 | 6oDTfG/Tbi9t27sun3/W0r9d8T+LeREr4qtpNdnCDngMD6/KZNNmLTyodVCbPFBt 8 | lZW3F65rNPmqECul79tK2yuLaP2/8SVkfgMjkhs+eh7W6hj+BTP93lNi8sAa18w= 9 | =ri9v 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /signatures/txtorcon-0.20.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQEcBAABAgAGBQJajkIwAAoJEMJgKAMSgGmn0v4H/j0necyvWcmU4LhwOWMlkC3w 4 | /xxj25E6RHvdAoKmpnWt5+yay5iYe+I/M24Dd69NE+Mk0+qa+NCPfyQuskJ3oZh+ 5 | 1UANa5RBZsfJ+mlpT0y/ypslWwbsyw/r0kwtMlfdZSJrEZOdEj/YKdrLacCpMEG0 6 | OJ00ELGdGyDQLp5Llzg9n/vDbLvsf4lGZFZ6NTC+GdlOKwzi5XiSsehvuy6YLoD5 7 | S22sMggj8+vRFkS9wN1sghF8BE9XE39Knuq+nVKbSfWQQ7zbrTLGPOaX3Ad8YXvJ 8 | 1clORxLrXMa0qVimwxmGDFw2BaUfx9qXK7rxr2N2QOmPRZo44HrclMoCOALYcSk= 9 | =Nfcc 10 | -----END PGP SIGNATURE----- 11 | -------------------------------------------------------------------------------- /test/util.py: -------------------------------------------------------------------------------- 1 | 2 | import tempfile 3 | import shutil 4 | 5 | 6 | class TempDir(object): 7 | ''' 8 | This is a simple context manager that handles creating and 9 | cleaning up a tempdir. 10 | 11 | See also: https://gist.github.com/meejah/6430613 12 | 13 | ''' 14 | 15 | def __enter__(self, *args): 16 | self.dir_name = tempfile.mkdtemp() 17 | return self 18 | 19 | def __exit__(self, *args): 20 | shutil.rmtree(self.dir_name) 21 | 22 | def __str__(self): 23 | return self.dir_name 24 | -------------------------------------------------------------------------------- /docs/_themes/alabaster/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from alabaster import _version as version 4 | 5 | 6 | def get_path(): 7 | """ 8 | Shortcut for users whose theme is next to their conf.py. 9 | """ 10 | # Theme directory is defined as our parent directory 11 | return os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 12 | 13 | 14 | def update_context(app, pagename, templatename, context, doctree): 15 | context['alabaster_version'] = version.__version__ 16 | 17 | def setup(app): 18 | app.connect('html-page-context', update_context) 19 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlsof8kRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac1qwf/RZ41YGe1DjcXxKeBNf9uR/YtZO2IiSJA 5 | 6t1yt6Ks1skpwOWrlZV46/2kHEv4QDf2G+8tDm816a62HEh5IFrIzqK4IsCQv7jg 6 | 9qv3zrK8ueoxVMfdc9mIpjrB3BmeH1e7tlJ1gk8y9NGGkv4rrk8lVRP8rQ+b1p70 7 | he2EyhK7J9DQxe0t3F4m+KovyUpLCXwMPwuTkjmg3QQIG/e94rjF3U/dRjGqmP0s 8 | t9uEzLNG5mxaZYmFOtAM2vriB8Va6OEyJ6oG+ClGsbnL1ysFAYJKvNrOxS8SpSzu 9 | FKoCo0DqgAy+L+iQuxD4eOBDJe4AZeFfMQP5pjT3bvO/GognmUKNNg== 10 | =lojd 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.1.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAls3DnYRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac++Qf/T+KfJe3DSQRqTdteFJtk4eWU/deLhQTD 5 | mVEhmEZLK1gFeKyizAKHZsrbBVs/SlOsr3iYhTu38pdiHP4H26ww2XMn+UPfIhhQ 6 | TRT80sgiOQ2Zrrs3Ea9u9eHMP8Mk02s6ND22IwtaiLhH9Zfey17SnYY6HkGxuhG8 7 | vfOD65xm6vPwR5wUs00wSwfV2gpOgKffe0qakrbRg2tJhW2wLptXA3EgW2fOg4eW 8 | eUCg+cDwJ/vmh0ILXWGhZyUjHRny2gA8LzQKqnOuuxlIIfD2BEThc7ARZunib72w 9 | HiHgLLWQiOIYP7NfD8yTDr5ZC3gpA4rfwzRMYXk0y/HVLbql75xPQA== 10 | =okVE 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.2.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAls6cPgRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaf8AQgA1kXBK820RiuSWQUHADgG20yu0iTRcqy1 5 | LgYKjywGqeLB/lS8X2o6ucJnl0GFqk20JVN6fUWgotz7fGVGJYKM1srKVC3ORmh0 6 | 17MtBnCHctTIAT0F0IP0DYCcQp6KPeBxFrRjC2snG2uo0kKC3FzXf+4WNjCRV3Lr 7 | ERHPFmiBoGSkYfmm6ecfPzR+BoO4f7VzlL9SkA3U+vLaaT9+/999X3MJC7jyQzqR 8 | p/9sWMQUWePWauV6IOtqljChOhWVOiYrFfW66ukFulAs/LmOg1RsBhSEurXuqDkM 9 | eKU3Zp2GR12F3/zD86v0G361I765BlryDA0M7sdqJeOxXzWHUxB5Xw== 10 | =5mlq 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.1.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlusMwIRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaf8Zwf7BCDeb7DBg1uYgVCvMpPgcTlKkEU5jqoy 5 | bth8OatVMVZUY93apjOvgwiaFK9Nuz7SjNxrFx0DTWLruMq42s3ry2FuZMgqYrHi 6 | 0TZ3w3bHQlFtFH6RUjDKf1r65Bp8aNRVtigChGI3WjZwHyZngSp6aoFGI5K/mVzF 7 | MzLuG5YkFnzCtZAHRiHeEnWKyJCDAJ5z5bCzgJ+qnU9dz0heyygRlBK4/sFF6Sj8 8 | oZHvWO2dNOoqJMUi6Y9kp/R48o3NfdTtyasHCkXN3Pp1uzblxEzthxwoz16TmEzr 9 | cMwKpBFhIxbRqDqbFShKjuAASKaonVoYu5ga/AMZpE5Q2JdOq74O5Q== 10 | =Kr4Q 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.2.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlu2qDYRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaacZpwf/RhggNwKDDGgMXcOVTGHLK32XcnmNKYdC 5 | NRRnZKrPyYe8dJBdCYnY4QKazkarq/95fi6utQDqu69u5CXpFJss31SIm5Av0uhU 6 | Kj5MhQB9Cim099FxnNiFo3996PLWtAbNweIhZBJrKdpFWnxxFHuECWwLMvM0ds8z 7 | xzbAkxi4aO43R8ohiW5jSPMuyG7UPVMPYEHSLaVQlHkZP7s726TV+PcfTUwkM5PS 8 | z33vq3TAwdrFmh4v0tbFKYBrxqV9kIHWpHER3JlYKGDphgm3fVRciNTnfieoQxdF 9 | 1Vata9XHwwCwfFUte4rtJQrje8ffwzwMqPzg9mGYTfPoQIdX7zOGdA== 10 | =kpx8 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.3.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlu37kURHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaeAnwf/RAlwGVrhmsAOb3lxV7GEAxIfwvCKvqM0 5 | fRenQ2n0xg1gP+/v36q5B/paTMyYlhtf71cAWuiLoJ7YeGkqpCimzOxtWzpyyOrI 6 | gbwL26fyehpubrARdLhtbF78/IeszqC+ZqwgQuoXPqFuy7yN1yJbUM3TvgeWv2Fs 7 | 8RY4Y6jS0l3KK+y6weRr7L2WjnhYpsWfTNlQ8itJw/dEaOjQPfQP7YmqvEsMkSK3 8 | hXa7nYkfCajseqdg2xr7GesD2ofen6X4CjUxQqEDoyx7Kb8ohab1EZT3pLLWOSdM 9 | xukKxXkPc9gSIbe0YPmeXQEhsoppL5OU6zRyushMbb0wAAvrSjmndg== 10 | =JbEB 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-19.0.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlw+vEsRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaafScwf/Q9qEzLofe3g2TbDBAoMsEvbpanCdugiT 5 | 00Li6qvBCyXe29QMnvrVIPIxqFwfjK+jAI9p1ui10dhGpo3OhwqYgHfkGl5nRAWq 6 | FdByeLvdLT5zG0bPViqYAT1u25OoZDAci6x7345zQzFiypx8F6Ka9YIKo95kbRmj 7 | tIogwZApjVh3qPwzRO9Yvk25Edazps586DShSyTLqR3KOzrs7ubFpSScTIFMVenu 8 | YhxjVu3GBYH0Hvyl66nlbb8w/q+WMDzt+K95dCrIGe14JEVnNfublfkQwM2UY3kw 9 | qGoV+nv0aLwuBOP9aMKlC2YV3Fa27OhG59hefnEHOpSXmexbiM4oEQ== 10 | =SC5x 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-19.1.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAl13R7kRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac8mwgA3+MvWquHB1cutsr5/gfY/R2v4yxxHj/C 5 | sjJDtceDVv7DJm0nB/8yjUwJrAbtaP0/rnAG6yzZxMXGtvRzYhcs961fAhELUfg1 6 | 6WymkMCHVPS4h78vUvedsosuIjnsc7G8zBw0uO1dM+yJkBI6Wb3/8Z0YV7xPRsxs 7 | JULXhLCQ0AHn0KplIJs6yeXGy/f3RS0NYhM8nEe3aCiwOkuwdbEaCrCoVcK0Q8J+ 8 | WGsW9RezyUQuQZHCGZQc4NwGtKlXOaqeA2cC28orIhQEHou1+oKbaimFVm3qlKEG 9 | yGPvu5j1PnWe2FO5cyBbUSY30u/ocwOM0NhWGdIsp/tDPeuPf0v0iw== 10 | =QVjP 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-20.0.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAl6EAuIRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaeesAf+ORuJ1403lDAMPx85atPJPQXp6Zj1M7nW 5 | aUEpS1JVbL0dXgHvZczbZpdfDPfKePjLkUYKqInAR24OVGBEgs5oAbHcB9J9RlkF 6 | FQIAN53ItnS0WBvlU4y0l74eXLlPtHpminYZgTRUZAuva3fWbhQ8WK/GGxYrq6Bc 7 | l0sW9SCKqPUw7AI9wAziHzTeu6gTWvyBwuHEGKuGfo4LuWCqIz5yv5fSbF/vLws2 8 | B3nHQ7kREka3Z90rrCnA5yk1HYYx8n+OUEYu9QyZGz3n3sye4CzP9wCMCqY1d1Ix 9 | TgdZACNzHw80Cds/BEf2YhymiG555OLj4UmqV9+9YRY43L30Q0Gv3Q== 10 | =4rvm 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-21.0.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmEOz+YRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaeOQwgAo3bJJU9YpggiU36c+JM6W2MZZDVghcyk 5 | XqapBm5QMEHKW0E4RYM1sV2mG3AoIzTlgpQcTmYdK91XI0TCCfAzR2/Hc2ljgP4j 6 | exgjiGAMPCoaVOmrk0LICRKGutuYiVN0VsdsltGzBD6KxPAJG8qOJ0x9DVkn5m9f 7 | y/vakz9cxRWq0hWoAGF8hULE1ITqE9MgMPoeJ4CuEoIXKbsx9fmUQh5prrF9mMqm 8 | kw6yFGwcxiLUn6nMDEgvdF7TixUcI1riXsP21+S/jNiZdvoU9JLwsfC40duCcXEM 9 | XS2NYOlPgBPdUe55tkYqe1VSjv7xZ+cqgr0IAIgKMiW43zes2mQE6A== 10 | =Fbxp 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-21.1.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmEa1DERHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaad5tAgAtt1c1jPV2p85zbjHrrNZLnbvSplzlN43 5 | 6pIAUw9g/MGJ05MrriR51jidO25RbngEhK/WfO0El5y/ldGo3C0xQ1jkTR0gkGxF 6 | eNaJPzCqjKSB/E/9MzY1/EtMvmekRs715L+FJeYhH0ZrPnGrcKFa/JERzvWk7MbM 7 | gdv1/GjuUrPSaun+n7zQhXh0dyz/2+knb9aOTigK4Vp9Qfv84mLrmMiwPzd1cipb 8 | rbw5ZjUIO2jXT1TjQKD3j0YhcHX/LTbOD7OQlSQd0vQcnuedLVLFynLYc6qs5Tp5 9 | SbCUIRChKKFEVIlMUw8fJR/Nt/EgG6GtrLNnfx/uk8eTOKvCipCUsw== 10 | =rw8N 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-22.0.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmIyVpURHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac8SwgAv1I7RHHGhCZFGkgKMkTfIOiqKiEB5Gh5 5 | T96taMD0AI8zDn+05Y2KZ8I9N8noy536BdZE6Xem0LFDeTWMqWy+MIGkGgzs9urC 6 | uv9jik4mS4ngVS+DBnpWuuFVPznEvpbyGNigGZADf2QpQ+TFnHpInWyU+b16rIIA 7 | DF9fVaC7jwrAeHHHOw6Syiiw8W4U5A1M0/nTL49L+z63pE2LnIVrLmR8yjdCQN2P 8 | Ftx1ILFeBKAu4W7fkVlKb3VPO3cYImK/aWys9jJkByZWdz1VeKcFRjModc/clByU 9 | iHCSiLy3XZ+6KzYIPGIGBpPQG8wDqqKVWDmKZdUaN7wSqYc2FA/UvQ== 10 | =l6TZ 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-23.5.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmRmzxsRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac8/gf/YUBGPsOVwWVyyWYUZ1mbl8WSBfxJYz0u 5 | H4z1bGBlipBlx+xcwV0bO3dJ91l1q3+vKwspbcktynYJtk8rzuu/4FXsoik/kFq9 6 | 2RpAzHeMldBAWTc5b8XSRDrUgX+e3R/uf+ofQXpGGlPnqjeFahpV+EFYYnLe9lNw 7 | oF9ju047u15Lk7ur2YRgZ4PySrp3atDnddLuFnTYViQQSB8r3BeqD90+h9BHqQGQ 8 | enkHqmZ057Xb62TYiIU1byYvbX3oxYlqC9V03poPztlvMCmde6Fz6YmSa6bh9PDw 9 | L+jRhCbxTWYW6+lhAvVUK7nW0S2q89emZo0ufwsmBVIv2Dh8ZQeDMg== 10 | =BSj/ 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-24.8.0.tar.gz.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmbE8D4RHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaenagf+M5WYgEHxN0vr2CEvozbS1Gz0kAoQMRZT 5 | 4Rm+mg4+HAOmH3RLv1tuZBek1ndekF4ug0zvIExRNdh4/RQ61IyYOLZyR+51qhlF 6 | cIrmR46dZO9EqFGfd9yV/8kAONZ1xR1bJK2wrY3MgIJ0l1K2YBB5ZutfWe7l29vX 7 | kzn7wSZRG66GW64PMlkzeYu+mQFxpcV9xlAWr8bY/EX2C08nvjhUEwgAEb22tzik 8 | UX5CXLZ8SJfsIKzTsQEiJ7r8g1pHPypD8Fl5m2QdgXg29wPo5iDhcD/HWdV1iXHW 9 | KYoZAfyLbx4RZwL54mra/iwfuAUkiwj5ByyoaSKHqQRJjXRn2wrwfg== 10 | =1RZa 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /docs/txtorcon.rst: -------------------------------------------------------------------------------- 1 | .. _api_documentation: 2 | 3 | API Documentation 4 | ================= 5 | 6 | 7 | These are the lowest-level documents, directly from the doc-strings in 8 | the code with some minimal organization; if you're just getting 9 | started with txtorcon **the** ":ref:`programming_guide`" **is a better 10 | place to start**. 11 | 12 | .. toctree:: 13 | txtorcon-controller 14 | txtorcon-state 15 | txtorcon-config 16 | txtorcon-endpoints 17 | txtorcon-onion 18 | txtorcon-protocol 19 | txtorcon-socks 20 | txtorcon-interface 21 | txtorcon-util 22 | -------------------------------------------------------------------------------- /scripts/test-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd /tmp 4 | tar zxvf ${1}/dist/txtorcon-${2}.tar.gz 5 | cd txtorcon-${2} 6 | make venv 7 | . venv/bin/activate 8 | pip install --editable . 9 | 10 | ## the actual "testing" part here 11 | echo "testing doc build" 12 | cd html 13 | make clean 14 | make html 15 | cd .. 16 | echo "testing endpoint plugins" 17 | twistd web --port onion:80 --path . 18 | sleep 5 19 | cat twistd.log 20 | echo " killing" 21 | kill `cat twistd.pid` 22 | sleep 1 23 | ls /tmp/tortmp* 24 | 25 | ## cleanup 26 | deactivate 27 | cd /tmp 28 | rm -rf txtorcon-${2} 29 | popd 30 | -------------------------------------------------------------------------------- /signatures/txtorcon-23.5.0-py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmRmzxoRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaacE5wgA1zEMILg9OAJ/6pfeeigmt8dvigIl71jm 5 | YUcVTVue3caNnxjVAwYG5CUZ+FtXdGBqnjd/m7nyL4qs7PhtknAYUG8V8foOXlsk 6 | J9LK+fE2DY7WjWTn2i7V3D1f+o1q6/2VyQBZPagPAaF0rgitvRtOOgcXPZE2YBjt 7 | GN6VLvIb54Z8xRtnmyiyG70dGQeaS6QfTx0e+98+cElLMTXgUCn3m3jIJff2WL/o 8 | 4UqSIa542qHi2a40kKUj6yW9/k35mecRQa9oBW8Olxg9fIEqfN/bBNv+E+5z0X6S 9 | 4OEz6yeVOR4C0EpYmhqoQVcmiwvmbW7yBNoqva4nFFZ0gErLTReUhQ== 10 | =ejSh 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-24.8.0-py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmbE8DcRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaafn/AgA5n2V7QL9GZpF/kuh6FYsyAdfDJzcTTtU 5 | HK1VwBgRk4YjdwcTiEte1+3Tt9RozGgCzcxdiRAtm3XjwB6dKpI2m8JoVtVPTeWh 6 | rlEwqnkzXdY7LTQq0Jt+hrQmO4BUCPbQsxdLNgTm4BHIdpkkjwFFYZUsjfAdbhkF 7 | Lb8CH7nNCrSWW7n5JA4I8kQHrDhB6oB2Ft39rgJTLhfqbWn8RaIIvMNe6j7SSgFp 8 | 5ZJHU354DIaS5/EibYvF4y2qT8SJFwaDvOe0erynm1+1wFLovHZQJGHTckpxvcp+ 9 | U4S0PddL7AyYp0epno1YdcVv6jHRTFwDlL/7jxr/oXyDTNMcGpRntQ== 10 | =qsUI 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlsof8gRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaciPwf7B0B4aO93pn0uYIBJUo1LGlMa2WAk9dbD 5 | tAxrPfxB153Xngbd1833+CZfoXLrtSg1u21cYqXdxjZmJN0JNG7yWnX2b6I036rV 6 | oyXAYq6MEOZk1lHPcQl0BdUgtdaoRO20buW+wU+0pAgBxSytlpCV0yP2YlU3XJUn 7 | xdWkn55zpH2DYzi2vS/I5ihZdEd7zs0dRE/OKZBHMA+oN6GGLbGJ3Wv4Xz8SSlXY 8 | 0gZsy3Vo601GuyQpCv8+fRvDtyE+Anwsb4QAbEVe6kpG2jlUmh4mPmVNHHT51pnQ 9 | ygzLWcwi7zIEv0WZG//aZHRkAxQtze+p6BJRJ84lSE1NNknMFclpqA== 10 | =kEIk 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.1-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAls3Dm0RHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaezxwgAqgwoHxQ3eXU8puNvQQ5CTYhISKRZhqFB 5 | owu4YWfpFMtVrXBIRKKkI5hMJ7YASwGLSLnV1jjxTTZaDW340v3vikl9EjFsDQKV 6 | HQVRI/fQymgoyPZutz1vecJFU1XvXieVm7oK4MmSja841LGR6szel1OjT4U0lEFc 7 | TPIdfb5Rq/Oo5PBKKhKk/3qkZcT5OHqcuSqgT2+L4X97oKuMSfxkC1VGG4dPFdgd 8 | F59TsYulq9b6WRTaWgIIliIB0bWJiiKaajt2MhEQ1Vg3eCo1NVfSfXOt+vKXxkol 9 | mQtFPiKRCp+hQmij5IoQzapZlm4rG93EGkyMP2p56YI93pDmclM2OA== 10 | =ZKYN 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.0.2-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAls6cPERHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaadSOQf+M7VCCl4a/JigW7w7rBlSq77JIth4T3qv 5 | qqvB7PGzMvG7bX1f2hJvZzEx+pUhanDZIWny8L/RwsIyvKmXkA6i/p9P7m338RG9 6 | CULfskEuR3tU2sfWpQVuRN+BDHP4GJgJyOtLK2dnbM64BVsYEfpGqXbV86RfeUt7 7 | XClqLliofIQpu/KIxqcMJOjFRQ4mOCACyd0YHVCEPNFEvqDJz9rtqQBQkdghCuiU 8 | DIjBF5HrIl2nywItPaz/eOoCQHXa50A9mNR9sTKdg9MqTL8kw0BEji0s+obqkJP0 9 | Ix00JVBfkn5akyn1yqFxK7q/Xsqa8iVGkbl5iChaoLlLM/2nKXHavA== 10 | =Wszb 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.1.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlusLogRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaafSJAf+KbQ15L64hV9QzAXMicv1My+0E8B9OpFr 5 | y1YLMYOMX+q6I3MLH2ssvylv5JKQjGpnhzUR6BbgQCKX1f+JT8PYkc8klNR0RpUT 6 | 9HRvu4ud58GVt2ouBTETYSrxVriKS6zzoR6BPjzarejMugPFgo4Bwzff1047W1Nc 7 | bgWb9/i40K09yrVV3huRTXyj6oAgLyuNkRzWDg1Vb0imoNIKpKk7wX3YGeRaLWv7 8 | 61VqlEWRpmSnaAfgDenWLuWi8DMIj0etkyoNPW3a5N0YiWW/OIoI5Fkchs+hCSWH 9 | C/jtafBg6ancMmS4dhguUXAK19b2m/uFURJ8rWjvnQrEfFCKa/j5wA== 10 | =pMFf 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.2.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlu2qC0RHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaadD2Qf8CuumPxrttHAcHGQmqQmLwMUynm4v/Lqq 5 | h2bBOtL+1MsSVkd79+J/brLST+Q+Lcug0XV+icOxEJPK8snYcgrLRyQLSE6CoRjB 6 | td6p/smfTpWpwgDnJsoY0JXi6tLQl5p+QNI7RJJCYGJMwdfargan2MVk/uGD8GPF 7 | PjbpgDN/Y0/VcOTCTCFLqCYD59E3jaSfz25OW2pzOu/u003sWV17bNnnEqwen4ts 8 | cAJ7kpIHudjF9pRjQVECpT3+dwowceO819CYdqvwoXpofwYHhBq3Obu9L/kHGpDy 9 | MBN6LWQSXOcn//F/kr5CWXXudVM01FOXLS7q8EmOHiudzs4BIUi6yQ== 10 | =zTOj 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-18.3.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlu37jsRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaadbeQf9HUyGflyVVMpKuQEAqHXkC4EdbF7F251D 5 | vu3F1ESKfp88U6zXMv3IawLFsN0YQQBx9q3sPVvj8GL6+YY+bMBPWjg8fKuapxbF 6 | TW6vq8vQ5RQfRp9bkc+G4ytezG0gvWA/WgJrOUU18MrMOjLT3Dw9fbxCMPpVVgba 7 | ObvZXI+1kSiBx7+0LgSebr6w3/pVclllXeHgrJicW1Vfg66/4sYIDDBJLsma9n6r 8 | 9cLuwfNhayVp/DTTbCws8fvtFQyNwQl7130ctzeTvnf6RUu5i1wvjWhqLWp3Ps/j 9 | LO0SKbgOjclfPe0PlvbM1opcc3XDEp4m9892rLTC/e4m+ExplCNnbg== 10 | =PIGn 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-19.0.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAlw+vEQRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaadz6Af+OCa2ggZqn2MR5nEI73egG9Lap51wJs2/ 5 | yTNSwcbW/+uQ6WaOWbzKKwmd1ZPmOwMe/rQeE9dA2eqrHIXXef/8zvRW8px2GK5m 6 | 7JyGPVkFApAtryhiYA52Xccv1QeWn3DtXbWPao5dG+9V3YsK1u7Imu+WuAHRLR4f 7 | OWH6e9mEDqY+zPvd4GIdknsMI0VI8KHKCMJwvcUDR4akDNIEkkusr4XDnL968vij 8 | mzygF6miRuvRp1iZaUIswLbVAw1GfasNZ7U3yiPhvgrEdIkiu1VU9v5++eETyM5j 9 | eXgtODtQ2hMEZ6JmzRCnKur1/cumPkdBQrwER/JBKuSabQ2lT8rdcg== 10 | =qN/j 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-19.1.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCAAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAl13R7gRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaadApggAs8GMteIM2t4wbUgTKeBUzvt23LeoL+s7 5 | nAUaIB3S6sPtzwyPmDWkcHD+hfC4MD/nYyyYPbNctipnL2FedI9DErJAYsvU5dTg 6 | f8CgZFWPI9DmnuYNz8AIu86YUIyMbWphYs3vZUuklcV3SKaxa09VBCWw/Mp/jajD 7 | b+euLCdhP7we0c2RjknrXcbZc9DY6TB1UNN02R1fULE9THgJjlqINgUNyLvBm0uR 8 | 21yftJ1L+4U5ygMBzld7Co0DgQg/6smuP67+oXk6j5t8Y/xO4URsIIjoRs5Avby3 9 | xzeJvQ8yBcXLNDSrnq31J6u8jCmJ/glijR9lpaiJ6FaNxijD/g/zuA== 10 | =LDeq 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-20.0.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAl6EAt0RHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaft2AgAyDP+VMJiEpIzS8bgTs4jUJ0oSiR5mbWv 5 | KQCLInFL5vkYww8AKDbOTP7U+GKETGvpI3mGY4yiMPgzwqmBr2N0+0zYhu4/a8QL 6 | BruNb1nwo/jjAJp+gNfc6/YVfeCntU2k5Dz3Hq1L2hcx4rg2Ps9efyLa6dMFF7lA 7 | shoQyro4SDKNCH41ipjblWpYqGZQuiBkzAbNHS8PrcBKLL02UVwDStx3QBLVFw5P 8 | WeJGAIIiyh0O6wFA9h+qBT3m15Xo60FUSejJtGIMm55oUX6mO9h2SSkst62AaIAO 9 | HEyW4mZgEYZAxurVL/JONFSSrDuAHHkawk6cmkPCcM/+zyAjPbd3SQ== 10 | =D4HV 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-21.0.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmEOz+ARHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaetLwf+LHmv5jNcDjc4mIKvh4CypIy14IzpqLs+ 5 | 1ovME1ede1ifftEcHLXohXwx3mbH6WuIhLy5V164aq+BqnxsN3eIBDAh4ljo6oGt 6 | hha6G+6QyKiISkBCK2Ot9oNK+UtSOiXlOZ/mp1lyWkk54L4GnmOOJFck2D2gnw37 7 | oqS1c3Bv5ZhswOOfQw8iHOLI+J9TktTWiIS9p86E6yZfjcATp4vmb+2TTHpzJyKt 8 | vY/CVmaYfTpcO3hDHHOD+3xE1Dxn7fnw5+gqAK47uYZQ9lL9qIJld0Nd6IKnzJpy 9 | h/i1n2Kb3gS6TqmjfCHm1DSrzn1V1SsIGf2BSV5drzaD8gNZ1IKTCw== 10 | =e7nP 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-21.1.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmEa1CsRHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaaeNLQf9HP9eI3LJKQjym0V29xBW1d++f3teLbS3 5 | kA+a+N0EztY/v9Iw6vo/TkjQwTalIBLpKWjD+nPrTom4hPQeJl/k4ZOBChOA7v2l 6 | r/L0S4MfxB/V5ZUpd7okgadpxacLg5SZcLPEFyp8jKHSfFfnEciUATJ2wyDWgP6z 7 | U44j0hgWO9Ag2H63xE4U0Kona7sT6jnd6cInLF8KmxaEgRyNjd6atdy8lM/ZZ4bb 8 | foAlECxaJDog3zhMstASaZnZ1GchHuFz4jKOoP51SS6GVh1I1bP9meus/kkceow3 9 | LTSYIBZI/JM0AytqOTf7pXvmzit59C6KWug483mbiA5amYLpc90b2A== 10 | =8qi7 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /signatures/txtorcon-22.0.0-py2.py3-none-any.whl.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQFFBAABCgAvFiEEnVor1WiOy4id680/wmAoAxKAaacFAmIyVo4RHG1lZWphaEBt 4 | ZWVqYWguY2EACgkQwmAoAxKAaac0JQf9Hi7go+0SP2q2p239PVBf4RUBC5b4+r22 5 | 7pJCECSAg2HdFG8taz8/1TXBDnAnVXLc3+sA9i5R5zAmZcKEtVdL/miBveQvLve9 6 | UMUEtUtlbWvXBuHRuEEAXU387aI8yJ61VSsZd/pJdBJ7XkohEIudbl+f9IBlXKpk 7 | wMilH3e1fQD8K0RQcVEwnHEADWxW3+xiU48ZM1I22uootRsFDHulEamHgXmAomXU 8 | +GxMRXZkY/s8BwbgeQmNPiYv+IXFbmBzEoBnFjcw670x5RMWVprxn0i2LVvDMJvY 9 | j6T6yIT3kRzo937WlzVmtzp/HDaAmdDZfICC/ZQO3y2NjC7zKoX/EA== 10 | =tAyz 11 | -----END PGP SIGNATURE----- 12 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # This file was automatically generated by stdeb 0.6.0 at 4 | # Sun, 17 Jun 2012 11:40:22 +0200 5 | 6 | # Unset the environment variables set by dpkg-buildpackage. (This is 7 | # necessary because distutils is brittle with compiler/linker flags 8 | # set. Specifically, packages using f2py will break without this.) 9 | unexport CPPFLAGS 10 | unexport CFLAGS 11 | unexport CXXFLAGS 12 | unexport FFLAGS 13 | unexport LDFLAGS 14 | 15 | #exports specified using stdeb Setup-Env-Vars: 16 | export DH_OPTIONS=--buildsystem=python_distutils 17 | 18 | 19 | %: 20 | dh $@ 21 | 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yaml: -------------------------------------------------------------------------------- 1 | name: flake8 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | testing: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Python 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: 3.9 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip tox tox-gh-actions 24 | 25 | - name: Test 26 | run: | 27 | python --version 28 | python -m tox -e flake8 29 | -------------------------------------------------------------------------------- /.github/workflows/readme_render.yaml: -------------------------------------------------------------------------------- 1 | name: README render 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | testing: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Python 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: 3.9 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip tox tox-gh-actions 24 | 25 | - name: Test 26 | run: | 27 | python --version 28 | python -m tox -e readme_render 29 | -------------------------------------------------------------------------------- /docs/txtorcon-protocol.rst: -------------------------------------------------------------------------------- 1 | .. _protocol: 2 | 3 | Low-Level Protocol Classes 4 | ========================== 5 | 6 | build_tor_connection 7 | -------------------- 8 | .. autofunction:: txtorcon.build_tor_connection 9 | 10 | 11 | build_local_tor_connection 12 | -------------------------- 13 | .. autofunction:: txtorcon.build_local_tor_connection 14 | 15 | 16 | TorControlProtocol 17 | ------------------ 18 | .. autoclass:: txtorcon.TorControlProtocol 19 | 20 | 21 | TorProtocolFactory 22 | ------------------ 23 | .. autoclass:: txtorcon.TorProtocolFactory 24 | 25 | 26 | TorProcessProtocol 27 | ------------------ 28 | .. autoclass:: txtorcon.TorProcessProtocol 29 | 30 | -------------------------------------------------------------------------------- /integration/timeout_tor_launch/README: -------------------------------------------------------------------------------- 1 | Tor Timeout Test 2 | ================ 3 | 4 | In issue #59 it is reported that killing a Tor process launched with 5 | launch_tor() can become wedged if we disconnect due to a timeout. 6 | 7 | That is, if you provide a timeout to launch_tor() and tor hasn't 8 | launched by the time that timeout fires then the underlying Tor isn't 9 | killed properly. 10 | 11 | This integration test confirms this: 12 | 13 | 1. the container_run script calls launch_tor() with a 1 second 14 | timeout, and then does nothing 15 | 16 | 2. the host_run script waits an additional 5 seconds and then 17 | confirms that there is no Tor process running. 18 | -------------------------------------------------------------------------------- /txtorcon/controller_py3.py: -------------------------------------------------------------------------------- 1 | 2 | class _AsyncOnionAuthContext(object): 3 | """ 4 | Internal helper. An async context manager that holds client-style 5 | onion authentication details and adds + removes them using 6 | underlying :class:`txtorcon.Tor` methods. 7 | """ 8 | def __init__(self, tor, onion_host, token): 9 | self._tor = tor 10 | self._host = onion_host 11 | self._token = token 12 | 13 | async def __aenter__(self): 14 | await self._tor.add_onion_authentication(self._host, self._token) 15 | return self 16 | 17 | async def __aexit__(self, exc_type, exc, tb): 18 | await self._tor.remove_onion_authentication(self._host) 19 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile 2 | include README.rst 3 | include INSTALL 4 | include TODO 5 | include LICENSE 6 | include meejah.asc 7 | include scripts/*.py 8 | include docs/Makefile 9 | include docs/apilinks_sphinxext.py 10 | include docs/conf.py 11 | include docs/*.rst 12 | include docs/_static/* 13 | exclude docs/_static/*~ 14 | include docs/_themes/* 15 | exclude docs/_themes/*~ 16 | include docs/_themes/alabaster/* 17 | exclude docs/_themes/alabaster/*~ 18 | exclude docs/_themes/alabaster/*.pyc 19 | include docs/_themes/alabaster/static/* 20 | exclude docs/_themes/alabaster/static/*~ 21 | include examples/* 22 | exclude examples/*~ 23 | include requirements.txt 24 | include dev-requirements.txt 25 | include test/*.py 26 | -------------------------------------------------------------------------------- /docs/txtorcon-endpoints.rst: -------------------------------------------------------------------------------- 1 | Endpoints and Related Classes 2 | ============================= 3 | 4 | TCPHiddenServiceEndpoint 5 | ------------------------ 6 | 7 | .. autoclass:: txtorcon.TCPHiddenServiceEndpoint 8 | 9 | 10 | .. autofunction:: txtorcon.get_global_tor 11 | 12 | 13 | TCPHiddenServiceEndpointParser 14 | ------------------------------ 15 | 16 | .. autoclass:: txtorcon.TCPHiddenServiceEndpointParser 17 | 18 | 19 | TorOnionAddress 20 | --------------- 21 | 22 | .. autoclass:: txtorcon.TorOnionAddress 23 | 24 | 25 | TorOnionListeningPort 26 | --------------------- 27 | 28 | .. autoclass:: txtorcon.TorOnionListeningPort 29 | 30 | 31 | IProgressProvider 32 | ----------------- 33 | 34 | .. autointerface:: txtorcon.IProgressProvider 35 | -------------------------------------------------------------------------------- /examples/dns_lookups.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.task import react 2 | from twisted.internet.defer import inlineCallbacks 3 | from twisted.internet.endpoints import clientFromString 4 | import txtorcon 5 | 6 | 7 | @react 8 | @inlineCallbacks 9 | def main(reactor): 10 | control_ep = clientFromString(reactor, "tcp:localhost:9051") 11 | tor = yield txtorcon.connect(reactor, control_ep) 12 | for domain in ['torproject.org', 'meejah.ca']: 13 | print("Looking up '{}' via Tor".format(domain)) 14 | ans = yield tor.dns_resolve(domain) 15 | print("...got answer: {}".format(ans)) 16 | print("Doing PTR on {}".format(ans)) 17 | ans = yield tor.dns_resolve_ptr(ans) 18 | print("...got answer: {}".format(ans)) 19 | -------------------------------------------------------------------------------- /examples/connect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from twisted.internet.task import react 4 | from twisted.internet.defer import inlineCallbacks 5 | from twisted.internet.endpoints import TCP4ClientEndpoint 6 | import txtorcon 7 | 8 | 9 | @react 10 | @inlineCallbacks 11 | def main(reactor): 12 | ep = TCP4ClientEndpoint(reactor, "localhost", 9051) 13 | # or (e.g. on Debian): 14 | # ep = UNIXClientEndpoint(reactor, "/var/run/tor/control") 15 | tor = yield txtorcon.connect(reactor, ep) 16 | print("Connected to Tor {version}".format(version=tor.protocol.version)) 17 | 18 | d = tor.protocol.when_disconnected() 19 | 20 | def its_gone(value): 21 | print("Connection gone") 22 | d.addCallback(its_gone) 23 | 24 | tor.protocol.transport.loseConnection() 25 | yield d 26 | -------------------------------------------------------------------------------- /integration/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## this runs all the integration tests under here, exiting right away 4 | ## if any one does. 5 | ## FIXME can't I [ab]use trial or unittest for this?? 6 | 7 | import os 8 | import sys 9 | import subprocess 10 | 11 | base_path = os.path.split(os.path.realpath(sys.argv[0]))[0] 12 | print("PATH", base_path) 13 | 14 | for d in os.listdir(base_path): 15 | path = os.path.join(base_path, d, 'host_run') 16 | if os.path.exists(path): 17 | print() 18 | print("Running Test:", d) 19 | print(path) 20 | print() 21 | ret = subprocess.check_call([path]) 22 | if ret: 23 | print() 24 | print("Test FAILED") 25 | sys.exit(ret) 26 | print() 27 | print("Test successful.") 28 | print() 29 | sys.exit(0) 30 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM dockerbase-jessie 2 | 3 | ADD docker-apt-tor /etc/apt/sources.list.d/tor.list 4 | ADD docker-backports /etc/apt/sources.list.d/backports.list 5 | ADD tor-deb-signing-key /root/tor-deb-signing-key 6 | 7 | ##RUN apt-get update 8 | ##RUN `awk '/BEGIN_INSTALL/,/END_INSTALL/' ./README.rst | /bin/grep apt-get | /bin/grep -v development` 9 | ## above fails when run via Docker 10 | 11 | RUN apt-key add /root/tor-deb-signing-key 12 | RUN apt-get update && apt-get install -y python-pip python-virtualenv python-dev tor 13 | RUN pip install twisted ipaddress service-identity 14 | 15 | # can we do this during build-time somehow? 16 | # RUN pip install --editable /txtorcon 17 | 18 | ## we make our code available via a "container volume" (-v option to run) 19 | ## at /txtorcon 20 | 21 | # this one just tells you to rtfm (use run.py) 22 | CMD ["/txtorcon/integration/no_testcase"] 23 | -------------------------------------------------------------------------------- /docs/txtorcon-interface.rst: -------------------------------------------------------------------------------- 1 | :mod:`txtorcon.interface` Module 2 | ================================ 3 | 4 | Note: the Onion interfaces are defined in :ref:`onion_api` 5 | 6 | interface.IStreamAttacher 7 | ------------------------- 8 | .. autointerface:: txtorcon.interface.IStreamAttacher 9 | 10 | interface.IStreamListener 11 | ------------------------- 12 | .. autointerface:: txtorcon.interface.IStreamListener 13 | 14 | interface.ICircuitListener 15 | -------------------------- 16 | .. autointerface:: txtorcon.interface.ICircuitListener 17 | 18 | interface.ICircuitContainer 19 | --------------------------- 20 | .. autointerface:: txtorcon.interface.ICircuitContainer 21 | 22 | interface.IRouterContainer 23 | -------------------------- 24 | .. autointerface:: txtorcon.interface.IRouterContainer 25 | 26 | interface.ITorControlProtocol 27 | ----------------------------- 28 | .. autointerface:: txtorcon.interface.ITorControlProtocol 29 | -------------------------------------------------------------------------------- /scripts/download-release-onion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # use this like: 4 | # download-release-onion.sh ${VERSION} 5 | # ...to test that the hidden service contains the correct release 6 | 7 | set -x 8 | pushd /tmp 9 | torsocks curl -O http://fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion/txtorcon-${1}.tar.gz || exit $? 10 | torsocks curl -O http://fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion/txtorcon-${1}.tar.gz.asc || exit $? 11 | gpg --verify txtorcon-${1}.tar.gz.asc || exit 1 12 | 13 | torsocks curl -O http://fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion/txtorcon-${1}-py2.py3-none-any.whl || exit $? 14 | torsocks curl -O http://fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion/txtorcon-${1}-py2.py3-none-any.whl.asc || exit $? 15 | gpg --verify txtorcon-${1}-py2.py3-none-any.whl.asc || exit 1 16 | 17 | echo "Both binaries check out for version" ${1} 18 | popd 19 | 20 | -------------------------------------------------------------------------------- /examples/monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Just listens for a few EVENTs from Tor (INFO NOTICE WARN ERR) and 4 | # prints out the contents, so functions like a log monitor. 5 | 6 | from twisted.internet import task, defer 7 | from twisted.internet.endpoints import UNIXClientEndpoint 8 | import txtorcon 9 | 10 | 11 | @task.react 12 | @defer.inlineCallbacks 13 | def main(reactor): 14 | ep = UNIXClientEndpoint(reactor, '/var/run/tor/control') 15 | tor = yield txtorcon.connect(reactor, ep) 16 | 17 | def log(msg): 18 | print(msg) 19 | print("Connected to a Tor version", tor.protocol.version) 20 | for event in ['INFO', 'NOTICE', 'WARN', 'ERR']: 21 | tor.protocol.add_event_listener(event, log) 22 | is_current = yield tor.protocol.get_info('status/version/current') 23 | version = yield tor.protocol.get_info('version') 24 | print("Version '{}', is_current={}".format(version, is_current['status/version/current'])) 25 | yield defer.Deferred() 26 | -------------------------------------------------------------------------------- /integration/timeout_tor_launch/container_run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode: python -*- 3 | 4 | ## see README 5 | ## this runs in the container, and sets up the testcase 6 | 7 | import os 8 | import sys 9 | 10 | import tempfile 11 | import functools 12 | 13 | from twisted.internet import reactor, defer, task 14 | from twisted.internet.endpoints import TCP4ServerEndpoint 15 | from twisted.web import server, resource 16 | from twisted.python import log 17 | 18 | sys.path.insert(0, '/txtorcon') 19 | import txtorcon 20 | 21 | 22 | log.startLogging(sys.stdout) 23 | 24 | def updates(prog, tag, summary): 25 | p = ('#' * int(10*(prog/100.0))) + ('.'*(10 - int(10*(prog/100.0)))) 26 | print("%s %s" % (p, summary)) 27 | 28 | @defer.inlineCallbacks 29 | def main(reactor): 30 | print("Launching Tor") 31 | tor = yield txtorcon.launch(reactor, progress_updates=updates) 32 | print("launch over:", proto) 33 | print('Running "ps afxu":') 34 | os.system("ps afxu") 35 | 36 | task.react(main) 37 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: txtorcon 2 | Maintainer: meejah 3 | Section: python 4 | Priority: optional 5 | Build-Depends: python-support (>=0.6) 6 | Standards-Version: 3.8.4 7 | XS-Python-Version: >= 2.6 8 | 9 | Package: python-txtorcon 10 | Architecture: all 11 | Homepage: http://github.com/meejah/txtorcon 12 | Description: Twisted-based asynchronous Tor control protocol implementation 13 | The main abstraction of this library is txtorcon.TorControlProtocol which presents 14 | an asynchronous API to speak the Tor client protocol in Python. txtorcon also 15 | provides abstractions to track and get updates about Tor's state (txtorcon.TorState) 16 | and current configuration (including writing it to Tor or disk) in txtorcon.TorConfig, 17 | along with helpers to asynchronously launch slave instances of Tor including Twisted endpoint support. 18 | Depends: ${misc:Depends}, ${python:Depends}, python-twisted (>= 11.1.0), python-geoip, python-ipaddr (>=2.1.10) 19 | XB-Python-Version: ${python:Versions} 20 | Provides: ${python:Provides} 21 | 22 | -------------------------------------------------------------------------------- /examples/close_all_circuits.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.task import react 2 | from twisted.internet.defer import inlineCallbacks 3 | from twisted.internet.endpoints import UNIXClientEndpoint 4 | 5 | import txtorcon 6 | 7 | 8 | @react 9 | @inlineCallbacks 10 | def main(reactor): 11 | """ 12 | Close all open streams and circuits in the Tor we connect to 13 | """ 14 | control_ep = UNIXClientEndpoint(reactor, '/var/run/tor/control') 15 | tor = yield txtorcon.connect(reactor, control_ep) 16 | state = yield tor.create_state() 17 | print("Closing all circuits:") 18 | for circuit in list(state.circuits.values()): 19 | path = '->'.join(map(lambda r: r.id_hex, circuit.path)) 20 | print("Circuit {} through {}".format(circuit.id, path)) 21 | for stream in circuit.streams: 22 | print(" Stream {} to {}".format(stream.id, stream.target_host)) 23 | yield stream.close() 24 | print(" closed") 25 | yield circuit.close() 26 | print("closed") 27 | yield tor.quit() 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, 2013 meejah 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.github/workflows/python3.yaml: -------------------------------------------------------------------------------- 1 | name: python3 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | testing: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: ["3.8", "3.9", "3.10"] 15 | twisted-version: [tx18, tx19, tx20, tx21, tx22, tx23, tx24] 16 | include: 17 | - python-version: "3.11" 18 | twisted-version: "tx24" 19 | - python-version: "3.12" 20 | twisted-version: "tx24" 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | 25 | - name: Set up Python 26 | uses: actions/setup-python@v2 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | 30 | - name: Install dependencies 31 | run: | 32 | python -m pip install --upgrade pip tox tox-gh-actions 33 | 34 | - name: Unit-Test 35 | run: | 36 | python -m tox -e py3-${{ matrix.twisted-version }} 37 | 38 | - name: Coveralls 39 | uses: coverallsapp/github-action@master 40 | with: 41 | github-token: ${{ secrets.GITHUB_TOKEN }} 42 | -------------------------------------------------------------------------------- /integration/timeout_tor_launch/host_run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## see README in this directory 4 | ## depends on "txtorcon-tester" docker.io container existing 5 | ## (run "make txtorcon-testing" at top-level to achieve this) 6 | 7 | import os 8 | import atexit 9 | import functools 10 | import subprocess 11 | import time 12 | import sys 13 | 14 | d = os.path.realpath(os.path.curdir) 15 | container = subprocess.check_output(['docker', 'run', '-v', d+':/txtorcon:ro', 16 | '-d', 'txtorcon-tester', '/txtorcon/integration/timeout_tor_launch/container_run'], 17 | text=True).strip() 18 | print('container:', container) 19 | def kill_container(container): 20 | print("killing", container) 21 | subprocess.check_output(['docker', 'kill', container]) 22 | atexit.register(functools.partial(kill_container, container)) 23 | 24 | print("waiting 15 seconds") 25 | time.sleep(15) 26 | 27 | print("gathering logs") 28 | logs = subprocess.check_output(['docker', 'logs', container], text=True) 29 | 30 | print(logs) 31 | if '/usr/sbin/tor' in logs: 32 | sys.exit(1) 33 | sys.exit(0) 34 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | See README for more information. 3 | 4 | To just install this as quickly as possible, using a Debian or Ubuntu 5 | system, run the following as root: 6 | 7 | apt-get install python-setuptools python-twisted python-ipaddress graphviz 8 | 9 | python setup.py install 10 | 11 | It's recommended to use a virtualenv (see below), but on OSX (and 12 | assuming homebrew is installed): 13 | 14 | brew install geoip 15 | pip install -r requirements.txt 16 | pip install -r dev-requirements.txt 17 | 18 | Or, instead of installing locally, simply: 19 | 20 | export PYTHONPATH=. 21 | 22 | 23 | If you want to take slightly more time, but only install temporarily, 24 | use virtualenv: 25 | 26 | apt-get install python-setuptools python-pip 27 | mkdir tmp 28 | virtualenv tmp/txtorcon_env 29 | cd tmp/txtorcon_env 30 | source bin/activate 31 | pip install --editable . # this will download from internets: 32 | 33 | (Or you can type "make virtualenv" which creates tmp/txtorcon_env, up 34 | to the "activate" step above) 35 | 36 | Now, this should work (where "work" means "prints nothing"): 37 | 38 | python -c "import txtorcon" 39 | -------------------------------------------------------------------------------- /test/py3_test_controller.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | 3 | from twisted.trial import unittest 4 | from twisted.internet.defer import ensureDeferred 5 | from zope.interface import directlyProvides 6 | 7 | from txtorcon import TorConfig 8 | from txtorcon.interface import ITorControlProtocol 9 | from txtorcon.controller import Tor 10 | 11 | 12 | class ClientOnionServiceAuthenticationTests3(unittest.TestCase): 13 | 14 | def setUp(self): 15 | reactor = Mock() 16 | proto = Mock() 17 | directlyProvides(proto, ITorControlProtocol) 18 | self.cfg = TorConfig() 19 | self.cfg.HidServAuth = ["existing.onion some_token"] 20 | self.tor = Tor(reactor, proto, _tor_config=self.cfg) 21 | 22 | def test_context(self): 23 | return ensureDeferred(self._context_test()) 24 | 25 | async def _context_test(self): 26 | async with self.tor.onion_authentication("some.onion", "token"): 27 | self.assertIn("some.onion token", self.cfg.HidServAuth) 28 | self.assertNotIn("some.onion token", self.cfg.HidServAuth) 29 | self.assertIn("existing.onion some_token", self.cfg.HidServAuth) 30 | -------------------------------------------------------------------------------- /examples/hidden_echo.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import protocol, reactor, endpoints 2 | 3 | # like the echo-server example on the front page of 4 | # https://twistedmatrix.com except this makes a Tor onion-service 5 | # that's an echo server. 6 | # 7 | # Note the *only* difference is the string we give to "serverFromString"! 8 | 9 | 10 | class Echo(protocol.Protocol): 11 | def connectionMade(self): 12 | print("Connection from {}".format(self.transport.getHost())) 13 | 14 | def dataReceived(self, data): 15 | print("echoing: '{}'".format(repr(data))) 16 | self.transport.write(data) 17 | 18 | 19 | class EchoFactory(protocol.Factory): 20 | def buildProtocol(self, addr): 21 | return Echo() 22 | 23 | 24 | print("Starting Tor, and onion service (can take a few minutes)") 25 | d = endpoints.serverFromString(reactor, "onion:1234").listen(EchoFactory()) 26 | 27 | 28 | def listening(port): 29 | # port is a Twisted IListeningPort 30 | print("Listening on: {} port 1234".format(port.getHost())) 31 | print("Try: torsocks telnet {} 1234".format(port.getHost().onion_uri)) 32 | 33 | 34 | d.addCallback(listening) 35 | reactor.run() 36 | -------------------------------------------------------------------------------- /docs/_themes/alabaster/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = alabaster.css 4 | pygments_style = alabaster.support.Alabaster 5 | 6 | [options] 7 | logo = 8 | logo_name = false 9 | logo_text_align = left 10 | description = 11 | github_user = 12 | github_repo = 13 | github_button = true 14 | github_banner = false 15 | github_type = watch 16 | github_count = true 17 | travis_button = false 18 | coveralls_button = false 19 | flattr_uri = 20 | gittip_user = 21 | analytics_id = 22 | touch_icon = 23 | extra_nav_links = 24 | sidebar_includehidden = true 25 | show_powered_by = true 26 | 27 | gray_1 = #444 28 | gray_2 = #EEE 29 | gray_3 = #AAA 30 | 31 | body_text = #3E4349 32 | footer_text = #888 33 | link = #004B6B 34 | link_hover = #6D4100 35 | sidebar_header = 36 | sidebar_text = #555 37 | sidebar_link = 38 | sidebar_link_underscore = #999 39 | sidebar_search_button = #CCC 40 | sidebar_list = #000 41 | sidebar_hr = 42 | anchor = #DDD 43 | anchor_hover_fg = 44 | anchor_hover_bg = #EAEAEA 45 | note_bg = 46 | note_border = #CCC 47 | footnote_bg = #FDFDFD 48 | footnote_border = 49 | pre_bg = 50 | narrow_sidebar_bg = #333 51 | narrow_sidebar_fg = #FFF 52 | narrow_sidebar_link = 53 | -------------------------------------------------------------------------------- /docs/interop_asyncio.rst: -------------------------------------------------------------------------------- 1 | .. _interop_asyncio: 2 | 3 | Using Asyncio Libraries with txtorcon 4 | ===================================== 5 | 6 | It is possible to use Twisted's `asyncioreactor 7 | `_ 8 | in order to use Twisted together with asyncio libraries. This comes 9 | with a couple caveats: 10 | 11 | * You need to install Twisted 12 | * Twisted "owns" the event-loop (i.e. you call :func:`reactor.run`); 13 | * You need to convert Futures/co-routines to Deferred sometimes 14 | (Twisted provides the required machinery) 15 | 16 | Here is an example using the `aiohttp 17 | `_ library as a Web server 18 | behind an Onion service that txtorcon has set up (in a newly-launched 19 | Tor process): 20 | 21 | **wanted**: I can't get this example to work properly with a Unix 22 | socket. 23 | 24 | .. _web_onion_service_aiohttp.py: 25 | 26 | ``web_onion_service_aiohttp.py`` 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | 29 | :download:`Download the example <../examples/web_onion_service_aiohttp.py>`. 30 | 31 | .. literalinclude:: ../examples/web_onion_service_aiohttp.py 32 | -------------------------------------------------------------------------------- /examples/web_client_treq.py: -------------------------------------------------------------------------------- 1 | # just copying over most of "carml checkpypi" because it's a good 2 | # example of "I want a stream over *this* circuit". 3 | 4 | from twisted.internet.defer import inlineCallbacks 5 | from twisted.internet.task import react 6 | from twisted.internet.endpoints import TCP4ClientEndpoint 7 | 8 | import txtorcon 9 | from txtorcon.util import default_control_port 10 | 11 | try: 12 | import treq 13 | except ImportError: 14 | print("To use this example, please install 'treq':") 15 | print("pip install treq") 16 | raise SystemExit(1) 17 | 18 | 19 | @react 20 | @inlineCallbacks 21 | def main(reactor): 22 | ep = TCP4ClientEndpoint(reactor, '127.0.0.1', default_control_port()) 23 | # ep = UNIXClientEndpoint(reactor, '/var/run/tor/control') 24 | tor = yield txtorcon.connect(reactor, ep) 25 | print("Connected:", tor) 26 | 27 | resp = yield treq.get( 28 | 'https://www.torproject.org:443', 29 | agent=tor.web_agent(), 30 | ) 31 | 32 | print("Retrieving {} bytes".format(resp.length)) 33 | data = yield resp.text() 34 | print("Got {} bytes:\n{}\n[...]{}".format( 35 | len(data), 36 | data[:120], 37 | data[-120:], 38 | )) 39 | -------------------------------------------------------------------------------- /test/test_attacher.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | from zope.interface import directlyProvides 3 | 4 | from twisted.trial import unittest 5 | 6 | from txtorcon.attacher import PriorityAttacher 7 | from txtorcon.interface import IStreamAttacher 8 | 9 | 10 | class PriorityAttacherTest(unittest.TestCase): 11 | 12 | def test_add_remove(self): 13 | a = PriorityAttacher() 14 | boom = Mock() 15 | directlyProvides(boom, IStreamAttacher) 16 | 17 | a.add_attacher(boom) 18 | a.remove_attacher(boom) 19 | with self.assertRaises(ValueError) as ctx: 20 | a.remove_attacher(boom) 21 | self.assertTrue('not found' in str(ctx.exception)) 22 | 23 | def test_stream_failure(self): 24 | a = PriorityAttacher() 25 | boom = Mock() 26 | directlyProvides(boom, IStreamAttacher) 27 | 28 | a.add_attacher(boom) 29 | a.attach_stream_failure(Mock(), Mock()) 30 | 31 | def test_attach_stream(self): 32 | a = PriorityAttacher() 33 | boom = Mock() 34 | directlyProvides(boom, IStreamAttacher) 35 | 36 | a.add_attacher(boom) 37 | a.attach_stream(Mock(), []) 38 | 39 | def test_attach_stream_nothing(self): 40 | a = PriorityAttacher() 41 | a.attach_stream(Mock(), []) 42 | -------------------------------------------------------------------------------- /test3/test_controller.py: -------------------------------------------------------------------------------- 1 | # this is for python3-only tests 2 | 3 | import unittest 4 | from unittest.mock import Mock, patch 5 | 6 | from zope.interface import directlyProvides 7 | 8 | from twisted.trial import unittest 9 | from twisted.internet.defer import ensureDeferred, succeed 10 | 11 | import txtorcon 12 | 13 | 14 | class Python3ControllerTests(unittest.TestCase): 15 | 16 | def setUp(self): 17 | reactor = Mock() 18 | proto = Mock() 19 | directlyProvides(proto, txtorcon.ITorControlProtocol) 20 | self.cfg = Mock() 21 | self.tor = txtorcon.Tor(reactor, proto, _tor_config=self.cfg) 22 | 23 | def test_authentication(self): 24 | return ensureDeferred(self.async_test_authentication()) 25 | 26 | async def async_test_authentication(self): 27 | add = patch.object(self.tor, "add_onion_authentication", return_value=succeed(None)) 28 | remove = patch.object(self.tor, "remove_onion_authentication", return_value=succeed(None)) 29 | with add as adder, remove as remover: 30 | async with self.tor.onion_authentication("fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion", "seekrit token"): 31 | self.assertTrue(adder.called) 32 | self.assertFalse(remover.called) 33 | self.assertTrue(remover.called) 34 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Michele Orrù 2 | on Mon, 16 Jul 2012 08:23:33 +0200, 3 | 4 | It was downloaded from http://github.com/meejah/txtorcon 5 | 6 | 7 | Copyright (c) 2012 meejah 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /examples/readme2.py: -------------------------------------------------------------------------------- 1 | # this is a Python2 version of the code in readme.py 2 | from twisted.internet.task import react 3 | from twisted.internet.defer import inlineCallbacks 4 | from twisted.internet.endpoints import UNIXClientEndpoint 5 | import treq 6 | import txtorcon 7 | 8 | 9 | @react 10 | @inlineCallbacks 11 | def main(reactor): 12 | tor = yield txtorcon.connect( 13 | reactor, 14 | UNIXClientEndpoint(reactor, "/var/run/tor/control") 15 | ) 16 | 17 | print("Connected to Tor version {}".format(tor.version)) 18 | 19 | url = 'https://www.torproject.org:443' 20 | print("Downloading {}".format(url)) 21 | resp = yield treq.get(url, agent=tor.web_agent()) 22 | 23 | print(" {} bytes".format(resp.length)) 24 | data = yield resp.text() 25 | print("Got {} bytes:\n{}\n[...]{}".format( 26 | len(data), 27 | data[:120], 28 | data[-120:], 29 | )) 30 | 31 | print("Creating a circuit") 32 | state = yield tor.create_state() 33 | circ = yield state.build_circuit() 34 | yield circ.when_built() 35 | print(" path: {}".format(" -> ".join([r.ip for r in circ.path]))) 36 | 37 | print("Downloading meejah's public key via above circuit...") 38 | resp = yield treq.get( 39 | 'https://meejah.ca/meejah.asc', 40 | agent=circ.web_agent(reactor, tor.config.socks_endpoint(reactor)), 41 | ) 42 | data = yield resp.text() 43 | print(data) 44 | -------------------------------------------------------------------------------- /integration/hidden_service_listen_ports/container_run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## see README 4 | ## this runs in the container, and sets up the testcase 5 | 6 | import os 7 | import sys 8 | 9 | import tempfile 10 | import functools 11 | 12 | from twisted.internet import reactor, defer, task 13 | from twisted.internet.endpoints import TCP4ServerEndpoint 14 | from twisted.web import server, resource 15 | from twisted.python import log 16 | 17 | log.startLogging(sys.stdout) 18 | 19 | print(sys.argv[0]) 20 | 21 | sys.path.insert(0, '/txtorcon') 22 | import txtorcon 23 | 24 | 25 | class Simple(resource.Resource): 26 | isLeaf = True 27 | 28 | def render_GET(self, request): 29 | return "Hello, world! I'm a hidden service!" 30 | 31 | 32 | def updates(prog, tag, summary): 33 | p = ('#' * int(10*(prog/100.0))) + ('.'*(10 - int(10*(prog/100.0)))) 34 | print("%s %s" % (p, summary)) 35 | 36 | 37 | @defer.inlineCallbacks 38 | def main(reactor): 39 | print("Launching Tor") 40 | tor = yield txtorcon.launch(reactor, socks_port=0, progress_updates=updates) 41 | 42 | hs_endpoint = tor.create_onion_endpoint(80) 43 | 44 | print("Starting site") 45 | site = server.Site(Simple()) 46 | port = yield hs_endpoint.listen(site) 47 | 48 | print(port.getHost().onion_uri, port.getHost().onion_port, port.local_address) 49 | print("liftoff") 50 | os.system("netstat -pltn") 51 | 52 | task.react(main) 53 | -------------------------------------------------------------------------------- /examples/readme.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.task import react 2 | from twisted.internet.defer import ensureDeferred 3 | from twisted.internet.endpoints import UNIXClientEndpoint 4 | 5 | import treq 6 | import txtorcon 7 | 8 | 9 | async def main(reactor): 10 | tor = await txtorcon.connect( 11 | reactor, 12 | UNIXClientEndpoint(reactor, "/var/run/tor/control") 13 | ) 14 | 15 | print("Connected to Tor version {}".format(tor.version)) 16 | 17 | url = u'https://www.torproject.org:443' 18 | print(u"Downloading {}".format(repr(url))) 19 | resp = await treq.get(url, agent=tor.web_agent()) 20 | 21 | print(u" {} bytes".format(resp.length)) 22 | data = await resp.text() 23 | print(u"Got {} bytes:\n{}\n[...]{}".format( 24 | len(data), 25 | data[:120], 26 | data[-120:], 27 | )) 28 | 29 | print(u"Creating a circuit") 30 | state = await tor.create_state() 31 | circ = await state.build_circuit() 32 | await circ.when_built() 33 | print(u" path: {}".format(" -> ".join([r.ip for r in circ.path]))) 34 | 35 | print(u"Downloading meejah's public key via above circuit...") 36 | config = await tor.get_config() 37 | resp = await treq.get( 38 | u'https://meejah.ca/meejah.asc', 39 | agent=circ.web_agent(reactor, config.socks_endpoint(reactor)), 40 | ) 41 | data = await resp.text() 42 | print(data) 43 | 44 | 45 | @react 46 | def _main(reactor): 47 | return ensureDeferred(main(reactor)) 48 | -------------------------------------------------------------------------------- /examples/launch_tor2web.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # launch a tor, and then connect a TorConfig object to it and 4 | # re-configure it. This allows us to determine what features the 5 | # running tor supports, *without* resorting to looking at version 6 | # numbers. 7 | 8 | import sys 9 | from twisted.internet.task import react 10 | from twisted.internet.defer import inlineCallbacks, Deferred 11 | import txtorcon 12 | 13 | 14 | @inlineCallbacks 15 | def main(reactor, tor_binary): 16 | config = txtorcon.TorConfig() 17 | config.ORPort = 0 18 | config.SOCKSPort = 0 19 | config.Tor2WebMode = 1 20 | # leaving ControlPort unset; launch_tor will choose one 21 | 22 | print("Launching tor...", tor_binary) 23 | try: 24 | yield txtorcon.launch_tor( 25 | config, 26 | reactor, 27 | tor_binary=tor_binary, 28 | stdout=sys.stdout 29 | ) 30 | print("success! We support Tor2Web mode") 31 | 32 | except RuntimeError as e: 33 | print("There was a problem:", str(e)) 34 | print("We do NOT support Tor2Web mode") 35 | return 36 | 37 | print("quitting in 5 seconds") 38 | reactor.callLater(5, lambda: reactor.stop()) 39 | yield Deferred() # wait forever because we never .callback() 40 | 41 | 42 | if __name__ == '__main__': 43 | tor_binary = None 44 | if len(sys.argv) > 1: 45 | tor_binary = sys.argv[1] 46 | # Twisted's newer task APIs are nice 47 | react(main, (tor_binary,)) 48 | -------------------------------------------------------------------------------- /test/test_util_imports.py: -------------------------------------------------------------------------------- 1 | from twisted.trial import unittest 2 | 3 | import sys 4 | import functools 5 | from unittest import skipUnless 6 | 7 | 8 | def fake_import(orig, name, *args, **kw): 9 | if name in ['GeoIP']: 10 | raise ImportError('testing!') 11 | return orig(*((name,) + args), **kw) 12 | 13 | 14 | class TestImports(unittest.TestCase): 15 | 16 | @skipUnless(False and 'pypy' not in sys.version.lower(), "Doesn't work in PYPY, Py3") 17 | def test_no_GeoIP(self): 18 | """ 19 | Make sure we don't explode if there's no GeoIP module 20 | """ 21 | 22 | orig = __import__ 23 | try: 24 | # attempt to ensure we've unimportted txtorcon.util 25 | try: 26 | del sys.modules['txtorcon.util'] 27 | except KeyError: 28 | pass 29 | import gc 30 | gc.collect() 31 | 32 | # replace global import with our test import, which will 33 | # throw on GeoIP import no matter what 34 | __builtins__['__import__'] = functools.partial(fake_import, orig) 35 | 36 | # now ensure we set up all the databases as "None" when we 37 | # import w/o the GeoIP thing available. 38 | import txtorcon.util 39 | loc = txtorcon.util.NetLocation('127.0.0.1') 40 | self.assertEqual(loc.city, None) 41 | self.assertEqual(loc.asn, None) 42 | self.assertEqual(loc.countrycode, '') 43 | 44 | finally: 45 | __builtins__['__import__'] = orig 46 | -------------------------------------------------------------------------------- /examples/launch_tor_endpoint2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Here we set up a Twisted Web server and then launch a slave tor 4 | # with a configured hidden service directed at the Web server we set 5 | # up. This uses serverFromString to translate the "onion" endpoint descriptor 6 | # into a TCPHiddenServiceEndpoint object... 7 | 8 | from twisted.internet import reactor 9 | from twisted.web import server, resource 10 | from twisted.internet.endpoints import serverFromString 11 | 12 | import txtorcon 13 | 14 | 15 | class Simple(resource.Resource): 16 | isLeaf = True 17 | 18 | def render_GET(self, request): 19 | return "Hello, world! I'm a hidden service!" 20 | 21 | 22 | site = server.Site(Simple()) 23 | 24 | 25 | def setup_failed(arg): 26 | print("SETUP FAILED", arg) 27 | 28 | 29 | def setup_complete(port): 30 | print("Hidden serivce:", port.getHost().onion_service) 31 | print(" locally at:", port.local_address) 32 | 33 | 34 | def progress(percent, tag, message): 35 | bar = int(percent / 10) 36 | print('[%s%s] %s' % ('#' * bar, '.' * (10 - bar), message)) 37 | 38 | 39 | hs_endpoint1 = serverFromString(reactor, "onion:80") 40 | hs_endpoint2 = serverFromString(reactor, "onion:80") 41 | 42 | txtorcon.IProgressProvider(hs_endpoint1).add_progress_listener(progress) 43 | txtorcon.IProgressProvider(hs_endpoint2).add_progress_listener(progress) 44 | 45 | d1 = hs_endpoint1.listen(site) 46 | d2 = hs_endpoint2.listen(site) 47 | 48 | d1.addCallback(setup_complete).addErrback(setup_failed) 49 | d2.addCallback(setup_complete).addErrback(setup_failed) 50 | 51 | reactor.run() 52 | -------------------------------------------------------------------------------- /docs/txtorcon-socks.rst: -------------------------------------------------------------------------------- 1 | .. _socks: 2 | 3 | :mod:`txtorcon.socks` Module 4 | ============================ 5 | 6 | SOCKS5 Errors 7 | ------------- 8 | 9 | SocksError 10 | ~~~~~~~~~~ 11 | .. autoclass:: txtorcon.socks.SocksError 12 | 13 | 14 | GeneralServerFailureError 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | .. autoclass:: txtorcon.socks.GeneralServerFailureError 17 | 18 | 19 | ConnectionNotAllowedError 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | .. autoclass:: txtorcon.socks.ConnectionNotAllowedError 22 | 23 | 24 | NetworkUnreachableError 25 | ~~~~~~~~~~~~~~~~~~~~~~~ 26 | .. autoclass:: txtorcon.socks.NetworkUnreachableError 27 | 28 | 29 | HostUnreachableError 30 | ~~~~~~~~~~~~~~~~~~~~ 31 | .. autoclass:: txtorcon.socks.HostUnreachableError 32 | 33 | 34 | ConnectionRefusedError 35 | ~~~~~~~~~~~~~~~~~~~~~~ 36 | .. autoclass:: txtorcon.socks.ConnectionRefusedError 37 | 38 | 39 | TtlExpiredError 40 | ~~~~~~~~~~~~~~~ 41 | .. autoclass:: txtorcon.socks.TtlExpiredError 42 | 43 | 44 | CommandNotSupportedError 45 | ~~~~~~~~~~~~~~~~~~~~~~~~ 46 | .. autoclass:: txtorcon.socks.CommandNotSupportedError 47 | 48 | 49 | AddressTypeNotSupportedError 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | .. autoclass:: txtorcon.socks.AddressTypeNotSupportedError 52 | 53 | 54 | .. note:: 55 | The following sections present low-level APIs. If you are able 56 | to work with :class:`txtorcon.Tor`'s corresponding high-level 57 | APIs, you should do so. 58 | 59 | 60 | resolve 61 | ------- 62 | .. autofunction:: txtorcon.socks.resolve 63 | 64 | 65 | resolve_ptr 66 | ----------- 67 | .. autofunction:: txtorcon.socks.resolve_ptr 68 | 69 | 70 | TorSocksEndpoint 71 | ---------------- 72 | .. autoclass:: txtorcon.socks.TorSocksEndpoint 73 | -------------------------------------------------------------------------------- /examples/web_client.py: -------------------------------------------------------------------------------- 1 | # this example shows how to use Twisted's web client with Tor via 2 | # txtorcon 3 | 4 | from twisted.internet.defer import inlineCallbacks 5 | from twisted.internet.task import react 6 | from twisted.internet.endpoints import TCP4ClientEndpoint 7 | from twisted.web.client import readBody 8 | 9 | import txtorcon 10 | from txtorcon.util import default_control_port 11 | 12 | 13 | @react 14 | @inlineCallbacks 15 | def main(reactor): 16 | # use port 9051 for system tor instances, or: 17 | # ep = UNIXClientEndpoint(reactor, '/var/run/tor/control') 18 | # ep = UNIXClientEndpoint(reactor, '/var/run/tor/control') 19 | ep = TCP4ClientEndpoint(reactor, '127.0.0.1', default_control_port()) 20 | tor = yield txtorcon.connect(reactor, ep) 21 | print("Connected to {tor} via localhost:{port}".format( 22 | tor=tor, 23 | port=default_control_port(), 24 | )) 25 | 26 | # create a web.Agent that will talk via Tor. If the socks port 27 | # given isn't yet configured, this will do so. It may also be 28 | # None, which means "the first configured SOCKSPort" 29 | # agent = tor.web_agent(u'9999') 30 | agent = tor.web_agent() 31 | uri = b'http://surely-this-has-not-been-registered-and-is-invalid.com' 32 | uri = b'https://www.torproject.org' 33 | uri = b'http://fjblvrw2jrxnhtg67qpbzi45r7ofojaoo3orzykesly2j3c2m3htapid.onion/' # txtorcon documentation 34 | print("Downloading {}".format(uri)) 35 | resp = yield agent.request(b'GET', uri) 36 | 37 | print("Response has {} bytes".format(resp.length)) 38 | body = yield readBody(resp) 39 | print("received body ({} bytes)".format(len(body))) 40 | print("{}\n[...]\n{}\n".format(body[:200], body[-200:])) 41 | -------------------------------------------------------------------------------- /meejah.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: SKS 1.1.0 3 | 4 | mQENBE86z3cBCADpSDuSTovhjXCzg/D4uw3ve9BIB+klOXxAXtpSwtMdfuTQrJ2aM5QkhkKK 5 | uWpmTravNM6Bg7U0qwjvjbrYKSfarDiRvCD8x7rfSnqn9EEOwtcQpVSmPqUaAF32FohHGyK1 6 | +M3ka8TdpLwqBr2v02usWWt8IKMSiMy0d3VO6Mj2HS/9ppuYMDpthD5lttToE2gksmCA4TOL 7 | G63IfXx2C/NuVrQo+vI4FGH/UI0R+zN8ibVq+j6gj9j9awSeUEiv2nQmUBZWSFncu/FXOFxD 8 | FLXdTDbFveYYEAQTYvDNp6k8sW6YmOKRCckhIV2NCDOUHgEiKuERAd0wuna9f3ylL8F1ABEB 9 | AAG0GW1lZWphaCA8bWVlamFoQG1lZWphaC5jYT6JATgEEwECACIFAk86z3cCGwMGCwkIBwMC 10 | BhUIAgkKCwQWAgMBAh4BAheAAAoJEMJgKAMSgGmneVwIAIM6/UQGGDCwtdnCVB3YmrtHxpsC 11 | DmgRNenB95e9GNNONr0FvwgfHz2vVD3JczYy2cnFxHASBoMcreCNHqkC5sg4XTtqwLju3HaA 12 | 4bagR0e/CvyBgREar2m00uCNGcmY9vWyZOBBYXnV4aIf1sC4XQEuehjg/pbmaBdYqjVy8hUx 13 | qW6hZ36In2UcGFdWS3aT6QmAXhoxM5Yt955X2ZT5EPV6yRqjdENyhOsOtPro6fEWFGYFr4ev 14 | 3oBBEZZQFJWtJfKBPWZK/xLka4fd5IppctmymXq7/BRcTcpQaKhSHlOLjjQA+fzmjizXK9hL 15 | KQ3bWml5zSlMxBvggrQYOR9yxHa5AQ0ETzrPdwEIAMqGB9+VB1yOK6xATYRd2crvKA2EASo2 16 | OMELsWgXnhWuZpsQj/w3IIDiK6n3M+z1AvxfU6YXZJta7obD3KZQrqAetZBHBoBT7Qgo7i5M 17 | 4/v5AVXGMlwgirlwPZ0N8KcFZn0QbyELF0acNYZ8xlUt1EQEHIKKxHThtGy8t7oJS7CMb83v 18 | NPo/E9NZ7AP1odQUD3+riADA7bPGGUksGRzKODRaOta93IhwEDNgcTRBU73/0RKS3mQTfY8f 19 | DXDUfNLtEtK8C1PtQqGcuC8zm0Kt7YK1+TPtSSbbseh36GmRTWkJ7/GYYoI4ZHjSAeJcsdkx 20 | OPs1dzEQkc+/q07WhimcRXkAEQEAAYkBHwQYAQIACQUCTzrPdwIbDAAKCRDCYCgDEoBpp+hc 21 | CACRh57atr3wUS7og3tL6NEsaa210CRUOGbU5vj1T6RJesmizG28JtfIY8oGpACAkQexOQIx 22 | BiIg9xP8tSiaJWlhrt1VVVk23O6FjBkLYraTl3h/yU+/hNFwn1zKrpRyXIiTfnO0PNe5jLeE 23 | aOuKy1E14fL8xN9c8dpJB1KxC95S1Ol+SDTEpfmY4NaRZdR8PViKxc3rJKE5sRBR6R320oEO 24 | o8DzQrkjnBRHXI6YgzvIQpLpJaMPk3826ImcCfLksID+RE73sMBEExaslGQGzUKTZEXEyk5/ 25 | 7ZAnWYZwB0CUU7QoU9NXBAtBb105fkqk+9k6p7ymANmPqwLFgwjzjArf 26 | =+73u 27 | -----END PGP PUBLIC KEY BLOCK----- 28 | -------------------------------------------------------------------------------- /examples/web_onion_service_prop224.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This shows how to leverage the endpoints API to get a new hidden 4 | # service up and running quickly. You can pass along this API to your 5 | # users by accepting endpoint strings as per Twisted recommendations. 6 | # 7 | # http://twistedmatrix.com/documents/current/core/howto/endpoints.html#maximizing-the-return-on-your-endpoint-investment 8 | # 9 | # note that only the progress-updates needs the "import txtorcon" -- 10 | # you do still need it installed so that Twisted finds the endpoint 11 | # parser plugin but code without knowledge of txtorcon can still 12 | # launch a Tor instance using it. cool! 13 | 14 | from twisted.internet import defer, task, endpoints 15 | from twisted.web import server, resource 16 | 17 | import txtorcon 18 | 19 | 20 | class Simple(resource.Resource): 21 | """ 22 | A really simple Web site. 23 | """ 24 | isLeaf = True 25 | 26 | def render_GET(self, request): 27 | return b"Hello, world! I'm a prop224 Onion Service!" 28 | 29 | 30 | @defer.inlineCallbacks 31 | def main(reactor): 32 | tor = yield txtorcon.connect( 33 | reactor, 34 | endpoints.TCP4ClientEndpoint(reactor, "localhost", 9251), 35 | ) 36 | print("{}".format(tor)) 37 | hs = yield tor.create_filesystem_onion_service( 38 | [(80, 8787)], 39 | "./prop224_hs", 40 | version=3, 41 | ) 42 | print("{}".format(hs)) 43 | print(dir(hs)) 44 | 45 | ep = endpoints.TCP4ServerEndpoint(reactor, 8787, interface="localhost") 46 | yield ep.listen(server.Site(Simple())) # returns 'port' 47 | print("Site listening: {}".format(hs.hostname)) 48 | print("Private key:\n{}".format(hs.private_key)) 49 | yield defer.Deferred() # wait forever 50 | 51 | 52 | task.react(main) 53 | -------------------------------------------------------------------------------- /examples/txtorcon.tac: -------------------------------------------------------------------------------- 1 | import functools 2 | from os.path import dirname 3 | import sys 4 | from tempfile import mkdtemp 5 | 6 | import txtorcon 7 | 8 | from twisted.application import service, internet 9 | from twisted.internet import reactor 10 | from twisted.internet.endpoints import TCP4ClientEndpoint 11 | from twisted.python import log 12 | from twisted.web import static, server 13 | from zope.interface import implements 14 | 15 | 16 | class TorService(service.Service): 17 | implements(service.IService) 18 | directory = dirname(__file__) 19 | port = 8080 20 | 21 | def __init__(self): 22 | self.torfactory = txtorcon.TorProtocolFactory() 23 | self.connection = TCP4ClientEndpoint(reactor, 'localhost', 9052) 24 | self.resource = server.Site(static.File(self.directory)) 25 | 26 | def startService(self): 27 | service.Service.startService(self) 28 | 29 | reactor.listenTCP(self.port, self.resource) 30 | self._bootstrap().addCallback(self._complete) 31 | 32 | def _bootstrap(self): 33 | self.config = txtorcon.TorConfig() 34 | self.config.HiddenServices = [ 35 | txtorcon.HiddenService(self.config, mkdtemp(), 36 | ['%d 127.0.0.1:%d' % (80, self.port)]) 37 | ] 38 | self.config.save() 39 | return txtorcon.launch_tor(self.config, reactor, 40 | progress_updates=self._updates, 41 | tor_binary='tor') 42 | 43 | def _updates(self, prog, tag, summary): 44 | log.msg('%d%%: %s' % (prog, summary)) 45 | 46 | def _complete(self, proto): 47 | log.msg(self.config.HiddenServices[0].hostname) 48 | 49 | application = service.Application("Txtorcon Application") 50 | torservice = TorService() 51 | torservice.setServiceParent(application) 52 | -------------------------------------------------------------------------------- /docs/apilinks_sphinxext.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Sphinx/docutils extension to create links to pyDoctor documentation using 3 | a RestructuredText interpreted text role that looks like this: 4 | 5 | :api:`python_object_to_link_to