
commit 95635c7db39274d1a6f7539e62d915bbe61ebf7f Author: Sambuddha Basu <sambuddhabasu1@gmail.com> Date: Mon May 25 07:19:30 2015 +0400 Added downloadable tutorials for tutorial To Russia With Love --- docs/_static/example/client_usage_using_pycurl.py | 54 ++++ .../_static/example/client_usage_using_socksipy.py | 25 ++ docs/_static/example/custom_path_selection.py | 79 ++++++ docs/_static/example/reading_twitter.py | 87 +++++++ docs/tutorials/to_russia_with_love.rst | 265 +------------------- 5 files changed, 257 insertions(+), 253 deletions(-) diff --git a/docs/_static/example/client_usage_using_pycurl.py b/docs/_static/example/client_usage_using_pycurl.py new file mode 100644 index 0000000..847c106 --- /dev/null +++ b/docs/_static/example/client_usage_using_pycurl.py @@ -0,0 +1,54 @@ +import pycurl +import StringIO + +import stem.process + +from stem.util import term + +SOCKS_PORT = 7000 + + +def query(url): + """ + Uses pycurl to fetch a site using the proxy on the SOCKS_PORT. + """ + + output = StringIO.StringIO() + + query = pycurl.Curl() + query.setopt(pycurl.URL, url) + query.setopt(pycurl.PROXY, 'localhost') + query.setopt(pycurl.PROXYPORT, SOCKS_PORT) + query.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME) + query.setopt(pycurl.WRITEFUNCTION, output.write) + + try: + query.perform() + return output.getvalue() + except pycurl.error as exc: + return "Unable to reach %s (%s)" % (url, exc) + + +# Start an instance of Tor configured to only exit through Russia. This prints +# Tor's bootstrap information as it starts. Note that this likely will not +# work if you have another Tor instance running. + +def print_bootstrap_lines(line): + if "Bootstrapped " in line: + print term.format(line, term.Color.BLUE) + + +print term.format("Starting Tor:\n", term.Attr.BOLD) + +tor_process = stem.process.launch_tor_with_config( + config = { + 'SocksPort': str(SOCKS_PORT), + 'ExitNodes': '{ru}', + }, + init_msg_handler = print_bootstrap_lines, +) + +print term.format("\nChecking our endpoint:\n", term.Attr.BOLD) +print term.format(query("https://www.atagar.com/echo.php"), term.Color.BLUE) + +tor_process.kill() # stops tor diff --git a/docs/_static/example/client_usage_using_socksipy.py b/docs/_static/example/client_usage_using_socksipy.py new file mode 100644 index 0000000..c480682 --- /dev/null +++ b/docs/_static/example/client_usage_using_socksipy.py @@ -0,0 +1,25 @@ +import socks # SocksiPy module +import socket +import urllib + +# Set socks proxy and wrap the urllib module + +socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', SOCKS_PORT) +socket.socket = socks.socksocket + +# Perform DNS resolution through the socket + +def getaddrinfo(*args): + return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] + +socket.getaddrinfo = getaddrinfo + +def query(url): + """ + Uses urllib to fetch a site using SocksiPy for Tor over the SOCKS_PORT. + """ + + try: + return urllib.urlopen(url).read() + except: + return "Unable to reach %s" % url diff --git a/docs/_static/example/custom_path_selection.py b/docs/_static/example/custom_path_selection.py new file mode 100644 index 0000000..48f6ee7 --- /dev/null +++ b/docs/_static/example/custom_path_selection.py @@ -0,0 +1,79 @@ +import StringIO +import time + +import pycurl + +import stem.control + +# Static exit for us to make 2-hop circuits through. Picking aurora, a +# particularly beefy one... +# +# https://atlas.torproject.org/#details/379FB450010D17078B3766C2273303C358C3A4... + +EXIT_FINGERPRINT = '379FB450010D17078B3766C2273303C358C3A442' + +SOCKS_PORT = 9050 +CONNECTION_TIMEOUT = 30 # timeout before we give up on a circuit + +def query(url): + """ + Uses pycurl to fetch a site using the proxy on the SOCKS_PORT. + """ + + output = StringIO.StringIO() + + query = pycurl.Curl() + query.setopt(pycurl.URL, url) + query.setopt(pycurl.PROXY, 'localhost') + query.setopt(pycurl.PROXYPORT, SOCKS_PORT) + query.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME) + query.setopt(pycurl.CONNECTTIMEOUT, CONNECTION_TIMEOUT) + query.setopt(pycurl.WRITEFUNCTION, output.write) + + try: + query.perform() + return output.getvalue() + except pycurl.error as exc: + raise ValueError("Unable to reach %s (%s)" % (url, exc)) + + +def scan(controller, path): + """ + Fetch check.torproject.org through the given path of relays, providing back + the time it took. + """ + + circuit_id = controller.new_circuit(path, await_build = True) + + def attach_stream(stream): + if stream.status == 'NEW': + controller.attach_stream(stream.id, circuit_id) + + controller.add_event_listener(attach_stream, stem.control.EventType.STREAM) + + try: + controller.set_conf('__LeaveStreamsUnattached', '1') # leave stream management to us + start_time = time.time() + + check_page = query('https://check.torproject.org/') + + if 'Congratulations. This browser is configured to use Tor.' not in check_page: + raise ValueError("Request didn't have the right content") + + return time.time() - start_time + finally: + controller.remove_event_listener(attach_stream) + controller.reset_conf('__LeaveStreamsUnattached') + + +with stem.control.Controller.from_port() as controller: + controller.authenticate() + + relay_fingerprints = [desc.fingerprint for desc in controller.get_network_statuses()] + + for fingerprint in relay_fingerprints: + try: + time_taken = scan(controller, [fingerprint, EXIT_FINGERPRINT]) + print '%s => %0.2f seconds' % (fingerprint, time_taken) + except Exception as exc: + print '%s => %s' % (fingerprint, exc) diff --git a/docs/_static/example/reading_twitter.py b/docs/_static/example/reading_twitter.py new file mode 100644 index 0000000..b5dc684 --- /dev/null +++ b/docs/_static/example/reading_twitter.py @@ -0,0 +1,87 @@ +import binascii +import hashlib +import hmac +import json +import socket +import time +import urllib +import urllib2 + +import socks # SockiPy module +import stem.process + +SOCKS_PORT = 7000 +TWITTER_API_URL = "https://api.twitter.com/1.1/statuses/user_timeline.json" +CONSUMER_KEY = "" +CONSUMER_SECRET = "" +ACCESS_TOKEN = "" +ACCESS_TOKEN_SECRET = "" + +HEADER_AUTH_KEYS = ['oauth_consumer_key', 'oauth_nonce', 'oauth_signature', + 'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'] + +socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', SOCKS_PORT) +socket.socket = socks.socksocket + +def oauth_signature(key_dict): + fin_key = "" + + for key in sorted(key_dict.keys()): + fin_key += key + "=" + key_dict[key] + "&" + + fin_key = fin_key[:-1] + fin_key = 'GET' + "&" + urllib.quote(TWITTER_API_URL, '') + "&" + urllib.quote(fin_key, '') + key = urllib.quote(CONSUMER_SECRET, '') + "&" + urllib.quote(ACCESS_TOKEN_SECRET, '') + hashed = hmac.new(key, fin_key, hashlib.sha1) + fin_key = binascii.b2a_base64(hashed.digest())[:-1] + return urllib.quote(fin_key, '') + +def poll_twitter_feed(user_id, tweet_count): + """ + Polls Twitter for the tweets from a given user. + """ + + key_dict = { + 'oauth_consumer_key': urllib.quote(CONSUMER_KEY, ''), + 'oauth_nonce': urllib.quote(hashlib.md5(str(time.time())).hexdigest(), ''), + 'oauth_signature_method': urllib.quote("HMAC-SHA1", ''), + 'oauth_timestamp': urllib.quote(str(int(time.time())), ''), + 'oauth_token': urllib.quote(ACCESS_TOKEN, ''), + 'oauth_version': urllib.quote('1.0', ''), + } + + url_values = {'screen_name': user_id, 'count': str(tweet_count), 'include_rts': '1'} + + for key, value in url_values.items(): + key_dict[key] = urllib.quote(value, '') + + key_dict['oauth_signature'] = oauth_signature(key_dict) + + header_auth = 'OAuth ' + ', '.join(['%s="%s"' % (key, key_dict[key]) for key in HEADER_AUTH_KEYS]) + + data = urllib.urlencode(url_values) + api_request = urllib2.Request(TWITTER_API_URL + "?" + data, headers = {'Authorization': header_auth}) + + try: + api_response = urllib2.urlopen(api_request).read() + except: + raise IOError("Unable to reach %s" % TWITTER_API_URL) + + return json.loads(api_response) + +tor_process = stem.process.launch_tor_with_config( + config = { + 'SocksPort': str(SOCKS_PORT), + 'ExitNodes': '{ru}', + }, +) + +try: + for index, tweet in enumerate(poll_twitter_feed('ioerror', 3)): + print "%i. %s" % (index + 1, tweet["created_at"]) + print tweet["text"] + print +except IOError, exc: + print exc +finally: + tor_process.kill() # stops tor diff --git a/docs/tutorials/to_russia_with_love.rst b/docs/tutorials/to_russia_with_love.rst index f8bedc6..fc1b4d2 100644 --- a/docs/tutorials/to_russia_with_love.rst +++ b/docs/tutorials/to_russia_with_love.rst @@ -51,62 +51,9 @@ be edge cases that expose your real IP. If you have a suggestion for how to improve this example then please `let me know <https://www.atagar.com/contact/>`_! -:: - - import pycurl - import StringIO - - import stem.process - - from stem.util import term - - SOCKS_PORT = 7000 - - - def query(url): - """ - Uses pycurl to fetch a site using the proxy on the SOCKS_PORT. - """ - - output = StringIO.StringIO() - - query = pycurl.Curl() - query.setopt(pycurl.URL, url) - query.setopt(pycurl.PROXY, 'localhost') - query.setopt(pycurl.PROXYPORT, SOCKS_PORT) - query.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME) - query.setopt(pycurl.WRITEFUNCTION, output.write) - - try: - query.perform() - return output.getvalue() - except pycurl.error as exc: - return "Unable to reach %s (%s)" % (url, exc) - - - # Start an instance of Tor configured to only exit through Russia. This prints - # Tor's bootstrap information as it starts. Note that this likely will not - # work if you have another Tor instance running. - - def print_bootstrap_lines(line): - if "Bootstrapped " in line: - print term.format(line, term.Color.BLUE) - - - print term.format("Starting Tor:\n", term.Attr.BOLD) - - tor_process = stem.process.launch_tor_with_config( - config = { - 'SocksPort': str(SOCKS_PORT), - 'ExitNodes': '{ru}', - }, - init_msg_handler = print_bootstrap_lines, - ) - - print term.format("\nChecking our endpoint:\n", term.Attr.BOLD) - print term.format(query("https://www.atagar.com/echo.php"), term.Color.BLUE) - - tor_process.kill() # stops tor +.. literalinclude:: /_static/example/client_usage_using_pycurl.py + :caption: `[Download] <../_static/example/client_usage_using_pycurl.py>`__ + :language: python .. image:: /_static/locale_selection_output.png @@ -121,33 +68,9 @@ connections through Tor, so this'll break our ability to connect to Tor's control port. To use this approach simply replace the query() function above with... -:: - - import socks # SocksiPy module - import socket - import urllib - - # Set socks proxy and wrap the urllib module - - socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', SOCKS_PORT) - socket.socket = socks.socksocket - - # Perform DNS resolution through the socket - - def getaddrinfo(*args): - return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] - - socket.getaddrinfo = getaddrinfo - - def query(url): - """ - Uses urllib to fetch a site using SocksiPy for Tor over the SOCKS_PORT. - """ - - try: - return urllib.urlopen(url).read() - except: - return "Unable to reach %s" % url +.. literalinclude:: /_static/example/client_usage_using_socksipy.py + :caption: `[Download] <../_static/example/client_usage_using_socksipy.py>`__ + :language: python .. _reading-twitter: @@ -160,95 +83,9 @@ Tor. This can be done `using their API authentication `see their instructions <https://dev.twitter.com/oauth/overview/application-owner-access-tokens>`_... -:: - - import binascii - import hashlib - import hmac - import json - import socket - import time - import urllib - import urllib2 - - import socks # SockiPy module - import stem.process - - SOCKS_PORT = 7000 - TWITTER_API_URL = "https://api.twitter.com/1.1/statuses/user_timeline.json" - CONSUMER_KEY = "" - CONSUMER_SECRET = "" - ACCESS_TOKEN = "" - ACCESS_TOKEN_SECRET = "" - - HEADER_AUTH_KEYS = ['oauth_consumer_key', 'oauth_nonce', 'oauth_signature', - 'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'] - - socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', SOCKS_PORT) - socket.socket = socks.socksocket - - def oauth_signature(key_dict): - fin_key = "" - - for key in sorted(key_dict.keys()): - fin_key += key + "=" + key_dict[key] + "&" - - fin_key = fin_key[:-1] - fin_key = 'GET' + "&" + urllib.quote(TWITTER_API_URL, '') + "&" + urllib.quote(fin_key, '') - key = urllib.quote(CONSUMER_SECRET, '') + "&" + urllib.quote(ACCESS_TOKEN_SECRET, '') - hashed = hmac.new(key, fin_key, hashlib.sha1) - fin_key = binascii.b2a_base64(hashed.digest())[:-1] - return urllib.quote(fin_key, '') - - def poll_twitter_feed(user_id, tweet_count): - """ - Polls Twitter for the tweets from a given user. - """ - - key_dict = { - 'oauth_consumer_key': urllib.quote(CONSUMER_KEY, ''), - 'oauth_nonce': urllib.quote(hashlib.md5(str(time.time())).hexdigest(), ''), - 'oauth_signature_method': urllib.quote("HMAC-SHA1", ''), - 'oauth_timestamp': urllib.quote(str(int(time.time())), ''), - 'oauth_token': urllib.quote(ACCESS_TOKEN, ''), - 'oauth_version': urllib.quote('1.0', ''), - } - - url_values = {'screen_name': user_id, 'count': str(tweet_count), 'include_rts': '1'} - - for key, value in url_values.items(): - key_dict[key] = urllib.quote(value, '') - - key_dict['oauth_signature'] = oauth_signature(key_dict) - - header_auth = 'OAuth ' + ', '.join(['%s="%s"' % (key, key_dict[key]) for key in HEADER_AUTH_KEYS]) - - data = urllib.urlencode(url_values) - api_request = urllib2.Request(TWITTER_API_URL + "?" + data, headers = {'Authorization': header_auth}) - - try: - api_response = urllib2.urlopen(api_request).read() - except: - raise IOError("Unable to reach %s" % TWITTER_API_URL) - - return json.loads(api_response) - - tor_process = stem.process.launch_tor_with_config( - config = { - 'SocksPort': str(SOCKS_PORT), - 'ExitNodes': '{ru}', - }, - ) - - try: - for index, tweet in enumerate(poll_twitter_feed('ioerror', 3)): - print "%i. %s" % (index + 1, tweet["created_at"]) - print tweet["text"] - print - except IOError, exc: - print exc - finally: - tor_process.kill() # stops tor +.. literalinclude:: /_static/example/reading_twitter.py + :caption: `[Download] <../_static/example/reading_twitter.py>`__ + :language: python .. image:: /_static/twitter_output.png @@ -277,87 +114,9 @@ For an example of this lets fetch a site over each relay to determine it's reachability and speed. **Naturally doing this causes quite a bit of load so please be careful not to leave this running!** -:: - - import StringIO - import time - - import pycurl - - import stem.control - - # Static exit for us to make 2-hop circuits through. Picking aurora, a - # particularly beefy one... - # - # https://atlas.torproject.org/#details/379FB450010D17078B3766C2273303C358C3A4... - - EXIT_FINGERPRINT = '379FB450010D17078B3766C2273303C358C3A442' - - SOCKS_PORT = 9050 - CONNECTION_TIMEOUT = 30 # timeout before we give up on a circuit - - def query(url): - """ - Uses pycurl to fetch a site using the proxy on the SOCKS_PORT. - """ - - output = StringIO.StringIO() - - query = pycurl.Curl() - query.setopt(pycurl.URL, url) - query.setopt(pycurl.PROXY, 'localhost') - query.setopt(pycurl.PROXYPORT, SOCKS_PORT) - query.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME) - query.setopt(pycurl.CONNECTTIMEOUT, CONNECTION_TIMEOUT) - query.setopt(pycurl.WRITEFUNCTION, output.write) - - try: - query.perform() - return output.getvalue() - except pycurl.error as exc: - raise ValueError("Unable to reach %s (%s)" % (url, exc)) - - - def scan(controller, path): - """ - Fetch check.torproject.org through the given path of relays, providing back - the time it took. - """ - - circuit_id = controller.new_circuit(path, await_build = True) - - def attach_stream(stream): - if stream.status == 'NEW': - controller.attach_stream(stream.id, circuit_id) - - controller.add_event_listener(attach_stream, stem.control.EventType.STREAM) - - try: - controller.set_conf('__LeaveStreamsUnattached', '1') # leave stream management to us - start_time = time.time() - - check_page = query('https://check.torproject.org/') - - if 'Congratulations. This browser is configured to use Tor.' not in check_page: - raise ValueError("Request didn't have the right content") - - return time.time() - start_time - finally: - controller.remove_event_listener(attach_stream) - controller.reset_conf('__LeaveStreamsUnattached') - - - with stem.control.Controller.from_port() as controller: - controller.authenticate() - - relay_fingerprints = [desc.fingerprint for desc in controller.get_network_statuses()] - - for fingerprint in relay_fingerprints: - try: - time_taken = scan(controller, [fingerprint, EXIT_FINGERPRINT]) - print '%s => %0.2f seconds' % (fingerprint, time_taken) - except Exception as exc: - print '%s => %s' % (fingerprint, exc) +.. literalinclude:: /_static/example/custom_path_selection.py + :caption: `[Download] <../_static/example/custom_path_selection.py>`__ + :language: python ::