commit a17ea0cb44fc5d9f969e716ad5ddf8b7c164c5c8 Author: Arturo Filastò arturo@filasto.net Date: Wed Oct 24 16:12:23 2012 +0000
Refactor reporter, config and onion * Stop using newstyle super method on oldstyle class --- ooni/reporter.py | 17 ++++------- ooni/utils/config.py | 68 ++++++++++++++++++++++++++++++++++++++++++++- ooni/utils/onion.py | 76 +++++++++++++++++++++++++------------------------- 3 files changed, 111 insertions(+), 50 deletions(-)
diff --git a/ooni/reporter.py b/ooni/reporter.py index fc5dde9..4d09729 100644 --- a/ooni/reporter.py +++ b/ooni/reporter.py @@ -191,9 +191,6 @@ class OONIReporter(OReporter): tbformat=tbformat, realtime=realtime, publisher=publisher)
self._tests = {} - self._publisher = publisher - if publisher is not None: - publisher.addObserver(self._observeWarnings)
def getTestIndex(self, test): try: @@ -261,8 +258,6 @@ class OONIReporter(OReporter): and L{_separator} are all implemented. """ log.debug("Test run concluded") - if self._publisher is not None: - self._publisher.removeObserver(self._observeWarnings) if self._startTime is not None: self.report['startTime'] = self._startTime self.report['runTime'] = time.time() - self._startTime @@ -274,11 +269,11 @@ class OONIReporter(OReporter): self.writeYamlLine(self.report)
def addSuccess(self, test): - super(OONIReporter, self).addSuccess(test) + OONIReporter.addSuccess(self, test) #self.report['result'] = {'value': 'success'}
def addError(self, test, exception): - super(OONIReporter, self).addError(test, exception) + OONIReporter.addError(self, test, exception) exc_type, exc_value, exc_traceback = exception log.err(exc_type) log.err(str(exc_value)) @@ -287,19 +282,19 @@ class OONIReporter(OReporter): log.err(line)
def addFailure(self, *args): - super(OONIReporter, self).addFailure(*args) + OONIReporter.addFailure(self, *args) log.warn(args)
def addSkip(self, *args): - super(OONIReporter, self).addSkip(*args) + OONIReporter.addSkip(self, *args) #self.report['result'] = {'value': 'skip', 'args': args}
def addExpectedFailure(self, *args): - super(OONIReporter, self).addExpectedFailure(*args) + OONIReporter.addExpectedFailure(self, *args) #self.report['result'] = {'value': 'expectedFailure', 'args': args}
def addUnexpectedSuccess(self, *args): - super(OONIReporter, self).addUnexpectedSuccess(*args) + OONIReporter.addUnexpectedSuccess(self, *args) #self.report['result'] = {'args': args, 'value': 'unexpectedSuccess'}
diff --git a/ooni/utils/config.py b/ooni/utils/config.py index a5b32f8..5a0782d 100644 --- a/ooni/utils/config.py +++ b/ooni/utils/config.py @@ -1,7 +1,7 @@ import ConfigParser import os
-from ooni.utils import Storage +from ooni.utils import Storage, log
class Config(Storage): """ @@ -53,3 +53,69 @@ class Config(Storage): self._cfgparser.write(cfgfile) finally: cfgfile.close() + +class ValueChecker(object): + """ + A class for general purpose value checks on commandline parameters + passed to subclasses of :class:`twisted.python.usage.Options`. + """ + def __init__(self, coerce_doc=None): + self.coerce_doc = coerce_doc + + def port_check(self, port, range_min=1024, range_max=65535): + """ + Check that given ports are in the allowed range for an unprivileged + user. + + :param port: + The port to check. + :param range_min: + The minimum allowable port number. + :param range_max: + The minimum allowable port number. + :param coerce_doc: + The documentation string to show in the optParameters menu, see + :class:`twisted.python.usage.Options`. + """ + if self.coerce_doc is not None: + coerceDoc = self.coerce_doc + + assert type(port) is int + if port not in range(range_min, range_max): + raise ValueError("Port out of range") + log.err() + + @staticmethod + def uid_check(error_message): + """ + Check that we're not root. If we are, setuid(1000) to normal user if + we're running on a posix-based system, and if we're on Windows just + tell the user that we can't be run as root with the specified options + and then exit. + + :param error_message: + The string to log as an error message when the uid check fails. + """ + uid, gid = os.getuid(), os.getgid() + if uid == 0 and gid == 0: + log.msg(error_message) + if os.name == 'posix': + log.msg("Dropping privileges to normal user...") + os.setgid(1000) + os.setuid(1000) + else: + sys.exit(0) + + @staticmethod + def dir_check(d): + """Check that the given directory exists.""" + if not os.path.isdir(d): + raise ValueError("%s doesn't exist, or has wrong permissions" + % d) + + @staticmethod + def file_check(f): + """Check that the given file exists.""" + if not os.path.isfile(f): + raise ValueError("%s does not exist, or has wrong permissions" + % f) diff --git a/ooni/utils/onion.py b/ooni/utils/onion.py index 3326c75..9c80f62 100644 --- a/ooni/utils/onion.py +++ b/ooni/utils/onion.py @@ -67,7 +67,7 @@ def write_torrc(conf, data_dir=None): """ Create a torrc in our data_dir. If we don't yet have a data_dir, create a temporary one. Any temporary files or folders are added to delete_list. - + :param conf: A :class:`ooni.lib.txtorcon.TorConfig` object, with all configuration values saved. @@ -82,12 +82,12 @@ def write_torrc(conf, data_dir=None): log.err(ie)
delete_list = [] - + if data_dir is None: data_dir = mkdtemp(prefix='bridget-tordata') delete_list.append(data_dir) conf.DataDirectory = data_dir - + (fd, torrc) = mkstemp(dir=data_dir) delete_list.append(torrc) write(fd, conf.create_torrc()) @@ -136,7 +136,7 @@ def remove_public_relays(state, bridges):
XXX FIXME: There is a problem in that Tor needs a Bridge line to already be configured in order to bootstrap. However, after bootstrapping, we grab the - microdescriptors of all the relays and check if any of our bridges are + microdescriptors of all the relays and check if any of our bridges are listed as public relays. Because of this, the first bridge does not get checked for being a relay. """ @@ -180,7 +180,7 @@ def state_complete(state): return state
def updates(_progress, _tag, _summary): - """Log updates on the Tor bootstrapping process.""" + """Log updates on the Tor bootstrapping process.""" log.msg("%d%%: %s" % (_progress, _summary))
def bootstrap(ctrl): @@ -193,7 +193,7 @@ def bootstrap(ctrl): log.msg("Tor process connected, bootstrapping ...")
def start_tor(reactor, config, control_port, tor_binary, data_dir, - report=None, progress=updates, + report=None, progress=updates, process_cb=None, process_eb=None): """ Use a txtorcon.TorConfig() instance, config, to write a torrc to a @@ -223,11 +223,11 @@ def start_tor(reactor, config, control_port, tor_binary, data_dir, A non-blocking function to handle bootstrapping updates, which takes three parameters: _progress, _tag, and _summary. :param process_cb: - The function to callback to after + The function to callback to after class:`ooni.lib.txtorcon.TorProcessProtocol` returns with the fully bootstrapped Tor process. :param process_eb: - The function to errback to if + The function to errback to if class:`ooni.lib.txtorcon.TorProcessProtocol` fails. :return: The result of the callback of a @@ -284,9 +284,9 @@ def start_tor(reactor, config, control_port, tor_binary, data_dir, def start_tor_filter_nodes(reactor, config, control_port, tor_binary, data_dir, bridges): """ - Bootstrap a Tor process and return a fully-setup + Bootstrap a Tor process and return a fully-setup :class:`ooni.lib.txtorcon.TorState`. Then search for our bridges - to test in the list of known public relays, + to test in the list of known public relays, :ivar:`ooni.lib.txtorcon.TorState.routers`, and remove any bridges which are known public relays.
@@ -296,7 +296,7 @@ def start_tor_filter_nodes(reactor, config, control_port, tor_binary, An instance of :class:`ooni.lib.txtorcon.TorConfig`. :param control_port: The port to use for Tor's ControlPort. If already configured in - the TorConfig instance, this can be given as + the TorConfig instance, this can be given as TorConfig.config.ControlPort. :param tor_binary: The full path to the Tor binary to execute. @@ -309,7 +309,7 @@ def start_tor_filter_nodes(reactor, config, control_port, tor_binary, :return: A fully initialized :class:`ooni.lib.txtorcon.TorState`. """ - setup = yield start_tor(reactor, config, control_port, + setup = yield start_tor(reactor, config, control_port, tor_binary, data_dir, process_cb=setup_done, process_eb=setup_fail) filter_nodes = yield remove_public_relays(setup, bridges) @@ -333,7 +333,7 @@ def start_tor_with_timer(reactor, config, control_port, tor_binary, data_dir, An instance of :class:`ooni.lib.txtorcon.TorConfig`. :param control_port: The port to use for Tor's ControlPort. If already configured in - the TorConfig instance, this can be given as + the TorConfig instance, this can be given as TorConfig.config.ControlPort. :param tor_binary: The full path to the Tor binary to execute. @@ -347,7 +347,7 @@ def start_tor_with_timer(reactor, config, control_port, tor_binary, data_dir, The number of seconds to attempt to bootstrap the Tor process before raising a :class:`ooni.utils.timer.TimeoutError`. :return: - If the timeout limit is not exceeded, return a fully initialized + If the timeout limit is not exceeded, return a fully initialized :class:`ooni.lib.txtorcon.TorState`, else return None. """ error_msg = "Bootstrapping has exceeded the timeout limit..." @@ -365,9 +365,9 @@ def start_tor_with_timer(reactor, config, control_port, tor_binary, data_dir, else: state = yield remove_public_relays(setup, bridges) defer.returnValue(state) - + @defer.inlineCallbacks -def start_tor_filter_nodes_with_timer(reactor, config, control_port, +def start_tor_filter_nodes_with_timer(reactor, config, control_port, tor_binary, data_dir, bridges, timeout): """ Start bootstrapping a Tor process wrapped with an instance of the class @@ -386,7 +386,7 @@ def start_tor_filter_nodes_with_timer(reactor, config, control_port, An instance of :class:`ooni.lib.txtorcon.TorConfig`. :param control_port: The port to use for Tor's ControlPort. If already configured in - the TorConfig instance, this can be given as + the TorConfig instance, this can be given as TorConfig.config.ControlPort. :param tor_binary: The full path to the Tor binary to execute. @@ -400,13 +400,13 @@ def start_tor_filter_nodes_with_timer(reactor, config, control_port, The number of seconds to attempt to bootstrap the Tor process before raising a :class:`ooni.utils.timer.TimeoutError`. :return: - If the timeout limit is not exceeded, return a fully initialized + If the timeout limit is not exceeded, return a fully initialized :class:`ooni.lib.txtorcon.TorState`, else return None. """ error_msg = "Bootstrapping has exceeded the timeout limit..." with_timeout = deferred_timeout(timeout, e=error_msg)(start_tor_filter_nodes) try: - state = yield with_timeout(reactor, config, control_port, + state = yield with_timeout(reactor, config, control_port, tor_binary, data_dir, bridges) except TimeoutError, te: log.err(te) @@ -416,16 +416,16 @@ def start_tor_filter_nodes_with_timer(reactor, config, control_port, # defer.returnValue(None) else: defer.returnValue(state) - + class CustomCircuit(CircuitListenerMixin): """ - Utility class for controlling circuit building. See + Utility class for controlling circuit building. See 'attach_streams_by_country.py' in the txtorcon documentation.
:param state: A fully bootstrapped instance of :class:`ooni.lib.txtorcon.TorState`. :param relays: - A dictionary containing a key 'all', which is a list of relays to + A dictionary containing a key 'all', which is a list of relays to test connecting to. :ivar waiting_circuits: The list of circuits which we are waiting to attach to. You shouldn't @@ -498,10 +498,10 @@ class CustomCircuit(CircuitListenerMixin):
def check_circuit_route(self, router): """ - Check if a relay is a hop in one of our already built circuits. + Check if a relay is a hop in one of our already built circuits.
:param router: - An item from the list + An item from the list :func:`ooni.lib.txtorcon.TorState.routers.values()`. """ for circ in self.state.circuits.values(): @@ -551,7 +551,7 @@ class CustomCircuit(CircuitListenerMixin): assert len(path) >= 3, \ "Circuit path must be at least three hops!"
- log.msg("Requesting a circuit: %s" + log.msg("Requesting a circuit: %s" % '->'.join(map(lambda node: node, path)))
class AppendWaiting: @@ -575,7 +575,7 @@ class CustomCircuit(CircuitListenerMixin): class TxtorconImportError(ImportError): """ Raised when ooni.lib.txtorcon cannot be imported from. Checks our current - working directory and the path given to see if txtorcon has been + working directory and the path given to see if txtorcon has been initialized via /ooni/lib/Makefile. """ from os import getcwd, path @@ -609,25 +609,25 @@ class PTNotFoundException(Exception): return sys.exit()
@defer.inlineCallbacks -def __start_tor_with_timer__(reactor, config, control_port, tor_binary, +def __start_tor_with_timer__(reactor, config, control_port, tor_binary, data_dir, bridges=None, relays=None, timeout=None, retry=None): """ A wrapper for :func:`start_tor` which wraps the bootstrapping of a Tor - process and its connection to a reactor with a - :class:`twisted.internet.defer.Deferred` class decorator utility, + process and its connection to a reactor with a + :class:`twisted.internet.defer.Deferred` class decorator utility, :func:`ooni.utils.timer.deferred_timeout`, and a mechanism for resets. - + ## XXX fill me in """ raise NotImplementedError - + class RetryException(Exception): - pass + pass
import sys from ooni.utils.timer import deferred_timeout, TimeoutError - + def __make_var__(old, default, _type): if old is not None: assert isinstance(old, _type) @@ -635,15 +635,15 @@ def __start_tor_with_timer__(reactor, config, control_port, tor_binary, else: new = default return new - + reactor = reactor timeout = __make_var__(timeout, 120, int) retry = __make_var__(retry, 1, int)
with_timeout = deferred_timeout(timeout)(start_tor) - + @defer.inlineCallbacks - def __start_tor__(rc=reactor, cf=config, cp=control_port, tb=tor_binary, + def __start_tor__(rc=reactor, cf=config, cp=control_port, tb=tor_binary, dd=data_dir, br=bridges, rl=relays, cb=setup_done, eb=setup_fail, af=remove_public_relays, retry=retry): try: @@ -658,13 +658,13 @@ def __start_tor_with_timer__(reactor, config, control_port, tor_binary, setup = yield eb(setup) else: setup = setup - + if br is not None: state = af(setup,br) else: state = setup defer.returnValue(state) - + @defer.inlineCallbacks def __try_until__(tries): result = yield __start_tor__()