commit 5eb2155266cf4d50af23a9c0cd06d5ab05db9553
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jun 21 20:14:09 2011 -0700
Relay setup wizard role selection
This provides the first prompt of the relay setup wizard which has options for
the general role Tor will have. Options include:
- Internal Realy
- Exit Relay
- Bridge
- Client
- Cancel
Selection is currenty a no-op. Next thing to do are the sub-dialogs these
options go to...
---
README | 1 +
src/cli/__init__.py | 2 +-
src/cli/controller.py | 7 +++-
src/cli/menu/actions.py | 2 +
src/cli/menu/menu.py | 1 +
src/cli/wizard.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++
src/settings.cfg | 15 +++++++
src/util/uiTools.py | 11 +++++
8 files changed, 135 insertions(+), 2 deletions(-)
diff --git a/README b/README
index 44fabf1..835b02b 100644
--- a/README
+++ b/README
@@ -187,6 +187,7 @@ Layout:
headerPanel.py - top of all pages, providing general information
descriptorPopup.py - displays connection descriptor data
popups.py - toolkit providing display popups
+ wizard.py - provides the relay setup wizard
logPanel.py - (page 1) displays tor, arm, and torctl events
configPanel.py - (page 3) editor panel for the tor configuration
diff --git a/src/cli/__init__.py b/src/cli/__init__.py
index 1564f68..435883d 100644
--- a/src/cli/__init__.py
+++ b/src/cli/__init__.py
@@ -2,5 +2,5 @@
Panels, popups, and handlers comprising the arm user interface.
"""
-__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "popups", "torrcPanel"]
+__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "popups", "torrcPanel", "wizard"]
diff --git a/src/cli/controller.py b/src/cli/controller.py
index e20e023..e771a26 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -8,6 +8,7 @@ import curses
import threading
import cli.menu.menu
+import cli.wizard
import cli.popups
import cli.headerPanel
import cli.logPanel
@@ -455,6 +456,7 @@ def startTorMonitor(startTime):
cli.graphing.graphPanel.loadConfig(config)
cli.connections.connEntry.loadConfig(config)
+ cli.wizard.loadConfig(config)
# attempts to fetch the tor pid, warning if unsuccessful (this is needed for
# checking its resource usage, among other things)
@@ -536,7 +538,8 @@ def drawTorMonitor(stdscr, startTime):
# main draw loop
overrideKey = None # uses this rather than waiting on user input
isUnresponsive = False # flag for heartbeat responsiveness check
-
+ if not torTools.getConn().isAlive(): overrideKey = ord('w') # shows wizard
+
while not control.isDone():
displayPanels = control.getDisplayPanels()
isUnresponsive = heartbeatCheck(isUnresponsive)
@@ -593,6 +596,8 @@ def drawTorMonitor(stdscr, startTime):
log.log(log.ERR, "Error detected when reloading tor: %s" % sysTools.getFileErrorMsg(exc))
elif key == ord('h') or key == ord('H'):
overrideKey = cli.popups.showHelpPopup()
+ elif key == ord('w') or key == ord('W'):
+ cli.wizard.showWizard()
else:
for panelImpl in displayPanels:
isKeystrokeConsumed = panelImpl.handleKey(key)
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index c571bd8..3c90b10 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -5,6 +5,7 @@ Generates the menu for arm, binding options with their related actions.
import functools
import cli.popups
+import cli.wizard
import cli.controller
import cli.menu.item
import cli.graphing.graphPanel
@@ -53,6 +54,7 @@ def makeActionsMenu():
actionsMenu = cli.menu.item.Submenu("Actions")
actionsMenu.add(cli.menu.item.MenuItem("Close Menu", None))
actionsMenu.add(cli.menu.item.MenuItem("New Identity", headerPanel.sendNewnym))
+ actionsMenu.add(cli.menu.item.MenuItem("Setup Wizard", cli.wizard.showWizard))
if control.isPaused(): label, arg = "Unpause", False
else: label, arg = "Pause", True
diff --git a/src/cli/menu/menu.py b/src/cli/menu/menu.py
index 1dbbbd0..8302551 100644
--- a/src/cli/menu/menu.py
+++ b/src/cli/menu/menu.py
@@ -109,6 +109,7 @@ def showMenu():
popup.win.refresh()
+ curses.cbreak()
key = control.getScreen().getch()
cursor.handleKey(key)
diff --git a/src/cli/wizard.py b/src/cli/wizard.py
new file mode 100644
index 0000000..2b7cdf7
--- /dev/null
+++ b/src/cli/wizard.py
@@ -0,0 +1,98 @@
+"""
+Provides user prompts for setting up a new relay. This autogenerates a torrc
+that's used by arm to start its tor instance.
+"""
+
+import curses
+
+import cli.popups
+import cli.controller
+
+from util import enum, uiTools
+
+# basic configuration types we can run as
+RunType = enum.Enum("RELAY", "EXIT", "BRIDGE", "CLIENT")
+
+# other options provided in the prompts
+CANCEL, BACK = "Cancel", "Back"
+
+CONFIG = {"wizard.role.message": "",
+ "wizard.role.option.label": {},
+ "wizard.role.option.description": {}}
+
+def loadConfig(config):
+ config.update(CONFIG)
+
+def showWizard():
+ myRole = promptRunType()
+
+def promptRunType():
+ """
+ Provides a prompt for selecting the general role we'd like Tor to run with.
+ This returns a RunType enumeration for the selection, or None if the dialog
+ was canceled.
+ """
+
+ popup, _, _ = cli.popups.init(23, 58)
+ if not popup: return
+ control = cli.controller.getController()
+ key, selection = 0, 0
+
+ # constructs (enum, label, [description lines]) tuples for our options
+ options = []
+
+ for runType in RunType.values() + [CANCEL]:
+ label = CONFIG["wizard.role.option.label"].get(runType, "")
+ descRemainder = CONFIG["wizard.role.option.description"].get(runType, "")
+ descLines = []
+
+ while descRemainder:
+ descLine, descRemainder = uiTools.cropStr(descRemainder, 54, None, endType = None, getRemainder = True)
+ descLines.append(descLine.strip())
+
+ options.append((runType, label, descLines))
+
+ try:
+ popup.win.box()
+ curses.cbreak()
+ format = uiTools.getColor("green")
+ y, msgRemainder = 1, CONFIG["wizard.role.message"]
+
+ # provides the welcoming message
+ while msgRemainder:
+ msg, msgRemainder = uiTools.cropStr(msgRemainder, 54, None, endType = None, getRemainder = True)
+ popup.addstr(y, 2, msg.strip(), format | curses.A_BOLD)
+ y += 1
+
+ while not uiTools.isSelectionKey(key):
+ offset = 0
+
+ for i in range(len(options)):
+ _, label, lines = options[i]
+ optionFormat = format | curses.A_STANDOUT if i == selection else format
+
+ # Curses has a weird bug where there's a one-pixel alignment
+ # difference between bold and regular text, so it looks better
+ # to render the whitespace here as not being bold.
+
+ offset += 1
+ popup.addstr(y + offset, 2, label, optionFormat | curses.A_BOLD)
+ popup.addstr(y + offset, 2 + len(label), " " * (54 - len(label)), optionFormat)
+ offset += 1
+
+ for line in lines:
+ popup.addstr(y + offset, 2, uiTools.padStr(line, 54), optionFormat)
+ offset += 1
+
+ popup.win.refresh()
+ key = control.getScreen().getch()
+
+ if key == curses.KEY_UP: selection = max(0, selection - 1)
+ elif key == curses.KEY_DOWN: selection = min(len(options) - 1, selection + 1)
+ elif key == 27: selection, key = -1, curses.KEY_ENTER # esc - cancel
+ finally:
+ cli.popups.finalize()
+
+ selectedOption = options[selection][0]
+ return None if selectedOption == CANCEL else selectedOption
+
diff --git a/src/settings.cfg b/src/settings.cfg
index bced9a4..2ad2784 100644
--- a/src/settings.cfg
+++ b/src/settings.cfg
@@ -340,6 +340,21 @@ msg.ARM_DEBUG GETINFO traffic/written
msg.ARM_DEBUG GETCONF
msg.ARM_DEBUG Unable to query process resource usage from ps
+# descriptions used in the relay setup wizard
+wizard.role.message Welcome to the Tor network! This will step you through the configuration process for being a part of it. To start with, what role would you like to have?
+
+wizard.role.option.label Relay => Internal Relay
+wizard.role.option.label Exit => Exit Relay
+wizard.role.option.label Bridge => Bridge
+wizard.role.option.label Client => Client
+wizard.role.option.label Cancel => Cancel
+
+wizard.role.option.description Relay => Provides interconnections with other Tor relays. This is a safe and easy of making the network better.
+wizard.role.option.description Exit => Connects between Tor an the outside Internet. This is a vital role, but can lead to abuse complaints.
+wizard.role.option.description Bridge => Non-public relay specifically for helping censored users.
+wizard.role.option.description Client => Use the network without contributing to it.
+wizard.role.option.description Cancel => Close without starting Tor.
+
# some config options are fetched via special values
torrc.map HiddenServiceDir => HiddenServiceOptions
torrc.map HiddenServicePort => HiddenServiceOptions
diff --git a/src/util/uiTools.py b/src/util/uiTools.py
index 40a3087..52885de 100644
--- a/src/util/uiTools.py
+++ b/src/util/uiTools.py
@@ -282,6 +282,17 @@ def cropStr(msg, size, minWordLen = 4, minCrop = 0, endType = Ending.ELLIPSE, ge
if getRemainder: return (returnMsg, remainder)
else: return returnMsg
+def padStr(msg, size):
+ """
+ Provides the string padded with whitespace to the given length.
+
+ Arguments:
+ msg - string to be padded
+ size - length to be padded to
+ """
+
+ return ("%%-%is" % size) % msg
+
def camelCase(label, divider = "_", joiner = " "):
"""
Converts the given string to camel case, ie: