run update
This commit is contained in:
parent
11af4540c5
commit
6806bebb7c
607 changed files with 52543 additions and 31832 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2015, Damian Johnson and The Tor Project
|
||||
# Copyright 2015-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
|
|
@ -6,13 +6,6 @@ Interactive interpreter for interacting with Tor directly. This adds usability
|
|||
features such as tab completion, history, and IRC-style functions (like /help).
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'arguments',
|
||||
'autocomplete',
|
||||
'commands',
|
||||
'help',
|
||||
]
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
|
@ -26,13 +19,20 @@ import stem.util.term
|
|||
|
||||
from stem.util.term import Attr, Color, format
|
||||
|
||||
__all__ = [
|
||||
'arguments',
|
||||
'autocomplete',
|
||||
'commands',
|
||||
'help',
|
||||
]
|
||||
|
||||
PROMPT = format('>>> ', Color.GREEN, Attr.BOLD, Attr.READLINE_ESCAPE)
|
||||
|
||||
STANDARD_OUTPUT = (Color.BLUE, )
|
||||
BOLD_OUTPUT = (Color.BLUE, Attr.BOLD)
|
||||
HEADER_OUTPUT = (Color.GREEN, )
|
||||
HEADER_BOLD_OUTPUT = (Color.GREEN, Attr.BOLD)
|
||||
ERROR_OUTPUT = (Attr.BOLD, Color.RED)
|
||||
STANDARD_OUTPUT = (Color.BLUE, Attr.LINES)
|
||||
BOLD_OUTPUT = (Color.BLUE, Attr.BOLD, Attr.LINES)
|
||||
HEADER_OUTPUT = (Color.GREEN, Attr.LINES)
|
||||
HEADER_BOLD_OUTPUT = (Color.GREEN, Attr.BOLD, Attr.LINES)
|
||||
ERROR_OUTPUT = (Attr.BOLD, Color.RED, Attr.LINES)
|
||||
|
||||
settings_path = os.path.join(os.path.dirname(__file__), 'settings.cfg')
|
||||
uses_settings = stem.util.conf.uses_settings('stem_interpreter', settings_path)
|
||||
|
|
@ -60,7 +60,7 @@ def main():
|
|||
print(stem.interpreter.arguments.get_help())
|
||||
sys.exit()
|
||||
|
||||
if args.disable_color:
|
||||
if args.disable_color or not sys.stdout.isatty():
|
||||
global PROMPT
|
||||
stem.util.term.DISABLE_COLOR_SUPPORT = True
|
||||
PROMPT = '>>> '
|
||||
|
|
@ -72,22 +72,30 @@ def main():
|
|||
is_tor_running = stem.util.system.is_running('tor') or stem.util.system.is_running('tor.real')
|
||||
|
||||
if not is_tor_running:
|
||||
if not stem.util.system.is_available('tor'):
|
||||
if args.tor_path == 'tor' and not stem.util.system.is_available('tor'):
|
||||
print(format(msg('msg.tor_unavailable'), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(format(msg('msg.starting_tor'), *HEADER_OUTPUT))
|
||||
if not args.run_cmd and not args.run_path:
|
||||
print(format(msg('msg.starting_tor'), *HEADER_OUTPUT))
|
||||
|
||||
stem.process.launch_tor_with_config(
|
||||
config = {
|
||||
'SocksPort': '0',
|
||||
'ControlPort': str(args.control_port),
|
||||
'CookieAuthentication': '1',
|
||||
'ExitPolicy': 'reject *:*',
|
||||
},
|
||||
completion_percent = 5,
|
||||
take_ownership = True,
|
||||
)
|
||||
control_port = '9051' if args.control_port == 'default' else str(args.control_port)
|
||||
|
||||
try:
|
||||
stem.process.launch_tor_with_config(
|
||||
config = {
|
||||
'SocksPort': '0',
|
||||
'ControlPort': control_port,
|
||||
'CookieAuthentication': '1',
|
||||
'ExitPolicy': 'reject *:*',
|
||||
},
|
||||
tor_cmd = args.tor_path,
|
||||
completion_percent = 5,
|
||||
take_ownership = True,
|
||||
)
|
||||
except OSError as exc:
|
||||
print(format(msg('msg.unable_to_start_tor', error = exc), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
|
||||
control_port = (args.control_address, args.control_port)
|
||||
control_socket = args.control_socket
|
||||
|
|
@ -115,27 +123,64 @@ def main():
|
|||
readline.set_completer(autocompleter.complete)
|
||||
readline.set_completer_delims('\n')
|
||||
|
||||
interpreter = stem.interpreter.commands.ControlInterpretor(controller)
|
||||
interpreter = stem.interpreter.commands.ControlInterpreter(controller)
|
||||
showed_close_confirmation = False
|
||||
|
||||
for line in msg('msg.startup_banner').splitlines():
|
||||
line_format = HEADER_BOLD_OUTPUT if line.startswith(' ') else HEADER_OUTPUT
|
||||
print(format(line, *line_format))
|
||||
if args.run_cmd:
|
||||
if args.run_cmd.upper().startswith('SETEVENTS '):
|
||||
# TODO: we can use a lambda here when dropping python 2.x support, but
|
||||
# until then print's status as a keyword prevents it from being used in
|
||||
# lambdas
|
||||
|
||||
print('')
|
||||
def handle_event(event_message):
|
||||
print(format(str(event_message), *STANDARD_OUTPUT))
|
||||
|
||||
while True:
|
||||
controller._handle_event = handle_event
|
||||
|
||||
if sys.stdout.isatty():
|
||||
events = args.run_cmd.upper().split(' ', 1)[1]
|
||||
print(format('Listening to %s events. Press any key to quit.\n' % events, *HEADER_BOLD_OUTPUT))
|
||||
|
||||
controller.msg(args.run_cmd)
|
||||
|
||||
try:
|
||||
raw_input()
|
||||
except (KeyboardInterrupt, stem.SocketClosed):
|
||||
pass
|
||||
else:
|
||||
interpreter.run_command(args.run_cmd, print_response = True)
|
||||
elif args.run_path:
|
||||
try:
|
||||
prompt = '... ' if interpreter.is_multiline_context else PROMPT
|
||||
for line in open(args.run_path).readlines():
|
||||
interpreter.run_command(line.strip(), print_response = True)
|
||||
except IOError as exc:
|
||||
print(format(msg('msg.unable_to_read_file', path = args.run_path, error = exc), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
|
||||
if stem.prereq.is_python_3():
|
||||
user_input = input(prompt)
|
||||
else:
|
||||
user_input = raw_input(prompt)
|
||||
else:
|
||||
for line in msg('msg.startup_banner').splitlines():
|
||||
line_format = HEADER_BOLD_OUTPUT if line.startswith(' ') else HEADER_OUTPUT
|
||||
print(format(line, *line_format))
|
||||
|
||||
response = interpreter.run_command(user_input)
|
||||
print('')
|
||||
|
||||
if response is not None:
|
||||
print(response)
|
||||
except (KeyboardInterrupt, EOFError, stem.SocketClosed) as exc:
|
||||
print('') # move cursor to the following line
|
||||
break
|
||||
while True:
|
||||
try:
|
||||
prompt = '... ' if interpreter.is_multiline_context else PROMPT
|
||||
user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
|
||||
interpreter.run_command(user_input, print_response = True)
|
||||
except stem.SocketClosed:
|
||||
if showed_close_confirmation:
|
||||
print(format('Unable to run tor commands. The control connection has been closed.', *ERROR_OUTPUT))
|
||||
else:
|
||||
prompt = format("Tor's control port has closed. Do you want to continue this interpreter? (y/n) ", *HEADER_BOLD_OUTPUT)
|
||||
user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
|
||||
print('') # blank line
|
||||
|
||||
if user_input.lower() in ('y', 'yes'):
|
||||
showed_close_confirmation = True
|
||||
else:
|
||||
break
|
||||
except (KeyboardInterrupt, EOFError, stem.SocketClosed):
|
||||
print('') # move cursor to the following line
|
||||
break
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2015, Damian Johnson and The Tor Project
|
||||
# Copyright 2015-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
|
|
@ -7,22 +7,26 @@ Commandline argument parsing for our interpreter prompt.
|
|||
|
||||
import collections
|
||||
import getopt
|
||||
import os
|
||||
|
||||
import stem.interpreter
|
||||
import stem.util.connection
|
||||
|
||||
DEFAULT_ARGS = {
|
||||
'control_address': '127.0.0.1',
|
||||
'control_port': 9051,
|
||||
'control_port': 'default',
|
||||
'user_provided_port': False,
|
||||
'control_socket': '/var/run/tor/control',
|
||||
'user_provided_socket': False,
|
||||
'tor_path': 'tor',
|
||||
'run_cmd': None,
|
||||
'run_path': None,
|
||||
'disable_color': False,
|
||||
'print_help': False,
|
||||
}
|
||||
|
||||
OPT = 'i:s:h'
|
||||
OPT_EXPANDED = ['interface=', 'socket=', 'no-color', 'help']
|
||||
OPT_EXPANDED = ['interface=', 'socket=', 'tor=', 'run=', 'no-color', 'help']
|
||||
|
||||
|
||||
def parse(argv):
|
||||
|
|
@ -50,7 +54,7 @@ def parse(argv):
|
|||
for opt, arg in recognized_args:
|
||||
if opt in ('-i', '--interface'):
|
||||
if ':' in arg:
|
||||
address, port = arg.split(':', 1)
|
||||
address, port = arg.rsplit(':', 1)
|
||||
else:
|
||||
address, port = None, arg
|
||||
|
||||
|
|
@ -68,6 +72,13 @@ def parse(argv):
|
|||
elif opt in ('-s', '--socket'):
|
||||
args['control_socket'] = arg
|
||||
args['user_provided_socket'] = True
|
||||
elif opt in ('--tor'):
|
||||
args['tor_path'] = arg
|
||||
elif opt in ('--run'):
|
||||
if os.path.exists(arg):
|
||||
args['run_path'] = arg
|
||||
else:
|
||||
args['run_cmd'] = arg
|
||||
elif opt == '--no-color':
|
||||
args['disable_color'] = True
|
||||
elif opt in ('-h', '--help'):
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
# Copyright 2014-2015, Damian Johnson and The Tor Project
|
||||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Tab completion for our interpreter prompt.
|
||||
"""
|
||||
|
||||
import stem.prereq
|
||||
|
||||
from stem.interpreter import uses_settings
|
||||
|
||||
try:
|
||||
# added in python 3.2
|
||||
if stem.prereq._is_lru_cache_available():
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
else:
|
||||
from stem.util.lru_cache import lru_cache
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2014-2015, Damian Johnson and The Tor Project
|
||||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
|
|
@ -6,7 +6,9 @@ Handles making requests and formatting the responses.
|
|||
"""
|
||||
|
||||
import code
|
||||
import contextlib
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import stem
|
||||
import stem.control
|
||||
|
|
@ -19,6 +21,13 @@ import stem.util.tor_tools
|
|||
from stem.interpreter import STANDARD_OUTPUT, BOLD_OUTPUT, ERROR_OUTPUT, uses_settings, msg
|
||||
from stem.util.term import format
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
MAX_EVENTS = 100
|
||||
|
||||
|
||||
def _get_fingerprint(arg, controller):
|
||||
"""
|
||||
|
|
@ -51,7 +60,7 @@ def _get_fingerprint(arg, controller):
|
|||
raise ValueError("Unable to find a relay with the nickname of '%s'" % arg)
|
||||
elif ':' in arg or stem.util.connection.is_valid_ipv4_address(arg):
|
||||
if ':' in arg:
|
||||
address, port = arg.split(':', 1)
|
||||
address, port = arg.rsplit(':', 1)
|
||||
|
||||
if not stem.util.connection.is_valid_ipv4_address(address):
|
||||
raise ValueError("'%s' isn't a valid IPv4 address" % address)
|
||||
|
|
@ -84,7 +93,18 @@ def _get_fingerprint(arg, controller):
|
|||
raise ValueError("'%s' isn't a fingerprint, nickname, or IP address" % arg)
|
||||
|
||||
|
||||
class ControlInterpretor(code.InteractiveConsole):
|
||||
@contextlib.contextmanager
|
||||
def redirect(stdout, stderr):
|
||||
original = sys.stdout, sys.stderr
|
||||
sys.stdout, sys.stderr = stdout, stderr
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sys.stdout, sys.stderr = original
|
||||
|
||||
|
||||
class ControlInterpreter(code.InteractiveConsole):
|
||||
"""
|
||||
Handles issuing requests and providing nicely formed responses, with support
|
||||
for special irc style subcommands.
|
||||
|
|
@ -115,7 +135,10 @@ class ControlInterpretor(code.InteractiveConsole):
|
|||
|
||||
def handle_event_wrapper(event_message):
|
||||
handle_event_real(event_message)
|
||||
self._received_events.append(event_message)
|
||||
self._received_events.insert(0, event_message)
|
||||
|
||||
if len(self._received_events) > MAX_EVENTS:
|
||||
self._received_events.pop()
|
||||
|
||||
self._controller._handle_event = handle_event_wrapper
|
||||
|
||||
|
|
@ -276,13 +299,14 @@ class ControlInterpretor(code.InteractiveConsole):
|
|||
return format(response, *STANDARD_OUTPUT)
|
||||
|
||||
@uses_settings
|
||||
def run_command(self, command, config):
|
||||
def run_command(self, command, config, print_response = False):
|
||||
"""
|
||||
Runs the given command. Requests starting with a '/' are special commands
|
||||
to the interpreter, and anything else is sent to the control port.
|
||||
|
||||
:param stem.control.Controller controller: tor control connection
|
||||
:param str command: command to be processed
|
||||
:param bool print_response: prints the response to stdout if true
|
||||
|
||||
:returns: **list** out output lines, each line being a list of
|
||||
(msg, format) tuples
|
||||
|
|
@ -290,12 +314,9 @@ class ControlInterpretor(code.InteractiveConsole):
|
|||
:raises: **stem.SocketClosed** if the control connection has been severed
|
||||
"""
|
||||
|
||||
if not self._controller.is_alive():
|
||||
raise stem.SocketClosed()
|
||||
|
||||
# Commands fall into three categories:
|
||||
#
|
||||
# * Interpretor commands. These start with a '/'.
|
||||
# * Interpreter commands. These start with a '/'.
|
||||
#
|
||||
# * Controller commands stem knows how to handle. We use our Controller's
|
||||
# methods for these to take advantage of caching and present nicer
|
||||
|
|
@ -338,17 +359,25 @@ class ControlInterpretor(code.InteractiveConsole):
|
|||
is_tor_command = cmd in config.get('help.usage', {}) and cmd.lower() != 'events'
|
||||
|
||||
if self._run_python_commands and not is_tor_command:
|
||||
self.is_multiline_context = code.InteractiveConsole.push(self, command)
|
||||
return
|
||||
console_output = StringIO()
|
||||
|
||||
with redirect(console_output, console_output):
|
||||
self.is_multiline_context = code.InteractiveConsole.push(self, command)
|
||||
|
||||
output = console_output.getvalue().strip()
|
||||
else:
|
||||
try:
|
||||
output = format(self._controller.msg(command).raw_content().strip(), *STANDARD_OUTPUT)
|
||||
except stem.ControllerError as exc:
|
||||
if isinstance(exc, stem.SocketClosed):
|
||||
raise exc
|
||||
raise
|
||||
else:
|
||||
output = format(str(exc), *ERROR_OUTPUT)
|
||||
|
||||
output += '\n' # give ourselves an extra line before the next prompt
|
||||
if output:
|
||||
output += '\n' # give ourselves an extra line before the next prompt
|
||||
|
||||
if print_response:
|
||||
print(output)
|
||||
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
# Copyright 2014-2015, Damian Johnson and The Tor Project
|
||||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Provides our /help responses.
|
||||
"""
|
||||
|
||||
import stem.prereq
|
||||
|
||||
from stem.interpreter import (
|
||||
STANDARD_OUTPUT,
|
||||
BOLD_OUTPUT,
|
||||
|
|
@ -15,10 +17,9 @@ from stem.interpreter import (
|
|||
|
||||
from stem.util.term import format
|
||||
|
||||
try:
|
||||
# added in python 3.2
|
||||
if stem.prereq._is_lru_cache_available():
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
else:
|
||||
from stem.util.lru_cache import lru_cache
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ msg.help
|
|||
| -i, --interface [ADDRESS:]PORT change control interface from {address}:{port}
|
||||
| -s, --socket SOCKET_PATH attach using unix domain socket if present,
|
||||
| SOCKET_PATH defaults to: {socket}
|
||||
| --tor PATH tor binary if tor isn't already running
|
||||
| --run executes the given command or file of commands
|
||||
| --no-color disables colorized output
|
||||
| -h, --help presents this help
|
||||
|
|
||||
|
|
@ -41,6 +43,8 @@ msg.startup_banner
|
|||
|
|
||||
|
||||
msg.tor_unavailable Tor isn't running and the command currently isn't in your PATH.
|
||||
msg.unable_to_start_tor Unable to start tor: {error}
|
||||
msg.unable_to_read_file Unable to read {path}: {error}
|
||||
|
||||
msg.starting_tor
|
||||
|Tor isn't running. Starting a temporary Tor instance for our interpreter to
|
||||
|
|
@ -57,7 +61,7 @@ msg.starting_tor
|
|||
# Response for the '/help' command without any arguments.
|
||||
|
||||
help.general
|
||||
|Interpretor commands include:
|
||||
|Interpreter commands include:
|
||||
| /help - provides information for interpreter and tor commands
|
||||
| /events - prints events that we've received
|
||||
| /info - general information for a relay
|
||||
|
|
@ -319,7 +323,9 @@ autocomplete AUTHCHALLENGE
|
|||
autocomplete DROPGUARDS
|
||||
autocomplete ADD_ONION NEW:BEST
|
||||
autocomplete ADD_ONION NEW:RSA1024
|
||||
autocomplete ADD_ONION NEW:ED25519-V3
|
||||
autocomplete ADD_ONION RSA1024:
|
||||
autocomplete ADD_ONION ED25519-V3:
|
||||
autocomplete DEL_ONION
|
||||
autocomplete HSFETCH
|
||||
autocomplete HSPOST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue