Skip to content
This repository has been archived by the owner on May 4, 2021. It is now read-only.

Bug28715 01 #318

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 48 additions & 47 deletions sbws/util/stem.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,52 @@ def _init_controller_socket(socket):
return c


def parse_user_torrc_config(torrc, torrc_text):
"""Parse the user configuration torrc text call `extra_lines`
to a dictionary suitable to use with stem and return a new torrc
dictionary that merges that dictionary with the existing torrc.
Example:
[tor]
extra_lines =
Log debug file /tmp/tor-debug.log
NumCPUs 1
"""
torrc_dict = torrc.copy()
for line in torrc_text.split('\n'):
# Remove leading and trailing whitespace, if any
line = line.strip()
# Ignore blank lines
if len(line) < 1:
continue
# Some torrc options are only a key, some are a key value pair.
kv = line.split(None, 1)
if len(kv) > 1:
key, value = kv
else:
key = kv[0]
value = None
# It's really easy to add to the torrc if the key doesn't exist
if key not in torrc:
torrc_dict.update({key: value})
# But if it does, we have to make a list of values. For example, say
# the user wants to add a SocksPort and we already have
# 'SocksPort auto' in the torrc. We'll go from
# torrc['SocksPort'] == 'auto'
# to
# torrc['SocksPort'] == ['auto', '9050']
else:
existing_val = torrc[key]
if isinstance(existing_val, str):
torrc_dict.update({key: [existing_val, value]})
else:
assert isinstance(existing_val, list)
existing_val.append(value)
torrc_dict.update({key: existing_val})
log.debug('Adding "%s %s" to torrc with which we are launching Tor',
key, value)
return torrc_dict


def launch_tor(conf):
assert isinstance(conf, ConfigParser)
os.makedirs(conf.getpath('tor', 'datadir'), mode=0o700, exist_ok=True)
Expand All @@ -139,53 +185,8 @@ def launch_tor(conf):
'LearnCircuitBuildTimeout': '0',
'CircuitBuildTimeout': conf['general']['circuit_timeout'],
})
# This block of code reads additional torrc lines from the user's
# config.ini so they can add arbitrary additional options.
#
# The user can't replace our options, only add to them. For example,
# there's no way to remove 'SocksPort auto' (if it is still in
# TORRC_STARTING_POINT). If you add a SocksPort in your config.ini, you'll
# open two socks ports.
#
# As an example, maybe the user hates their HDD and wants to fill it with
# debug logs, and wants to tell Tor to use only 1 CPU core.
#
# [tor]
# extra_lines =
# Log debug file /tmp/tor-debug.log
# NumCPUs 1
for line in conf['tor']['extra_lines'].split('\n'):
# Remove leading and trailing whitespace, if any
line = line.strip()
# Ignore blank lines
if len(line) < 1:
continue
# The way stem handles configuring Tor with a dictionary is the first
# word is a key and the remaining words are the value.
kv = line.split(None, 1)
if len(kv) < 2:
fail_hard('All torrc lines must have 2 or more words. "%s" has '
'fewer', line)
key, value = kv
log.info('Adding "%s %s" to torrc with which we are launching Tor',
key, value)
# It's really easy to add to the torrc if the key doesn't exist
if key not in torrc:
torrc.update({key: value})
# But if it does, we have to make a list of values. For example, say
# the user wants to add a SocksPort and we already have
# 'SocksPort auto' in the torrc. We'll go from
# torrc['SocksPort'] == 'auto'
# to
# torrc['SocksPort'] == ['auto', '9050']
else:
existing_val = torrc[key]
if isinstance(existing_val, str):
torrc.update({key: [existing_val, value]})
else:
assert isinstance(existing_val, list)
existing_val.append(value)
torrc.update({key: existing_val})

torrc = parse_user_torrc_config(torrc, conf['tor']['extra_lines'])
# Finally launch Tor
try:
stem.process.launch_tor_with_config(
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/util/test_stem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Unit tests for stem.py"""

from sbws.util.stem import parse_user_torrc_config


def test_parse_user_torrc_config_new_keyvalue_options_success():
config_torrc_extra_lines = """
Log debug file /tmp/tor-debug.log
NumCPUs 1
"""
torrc_dict = parse_user_torrc_config({}, config_torrc_extra_lines)
assert torrc_dict == \
{'Log': 'debug file /tmp/tor-debug.log', 'NumCPUs': '1'}


def test_parse_user_torrc_config_existing_keyvalue_options_fail(caplog):
torrc_dict = {'SocksPort': 'auto'}
config_torrc_extra_lines = """
SocksPort 9050
"""
torrc_dict_new = parse_user_torrc_config(
torrc_dict, config_torrc_extra_lines)
# the new dictionary contains the existing key option and a list with both
# the existing value and the new value
assert torrc_dict_new != torrc_dict
assert torrc_dict_new == {'SocksPort': ['auto', '9050']}


def test_parse_user_torrc_config_new_key_option_success():
config_torrc_extra_lines = """
LongLivedPorts
"""
torrc_dict = parse_user_torrc_config({}, config_torrc_extra_lines)
assert torrc_dict == {'LongLivedPorts': None}