commit 1a31910080c81f01bf07aeccbaed8ff3d861ec49 Author: Damian Johnson atagar@torproject.org Date: Thu Jun 16 20:53:45 2011 -0700
Adding a "New Identity" option
Providing an option for sending newnym signals to tor. This is both provided via a menu option and a 'n' hotkey. There's also an indicator in the header panel if we're both on a wide screen and running as a non-relay. This was requested on 'https://trac.torproject.org/projects/tor/ticket/3394'. --- src/cli/headerPanel.py | 30 ++++++++++++++++++++++++++---- src/cli/menu/actions.py | 3 +++ src/util/torTools.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py index d367b98..b5b3826 100644 --- a/src/cli/headerPanel.py +++ b/src/cli/headerPanel.py @@ -113,10 +113,24 @@ class HeaderPanel(panel.Panel, threading.Thread): if self.vals["tor/orPort"]: return 4 if isWide else 6 else: return 3 if isWide else 4
+ def sendNewnym(self): + """ + Requests a new identity and provides a visual queue. + """ + + torTools.getConn().sendNewnym() + + # If we're wide then the newnym label in this panel will give an + # indication that the signal was sent. Otherwise use a msg. + isWide = self.getParent().getmaxyx()[1] >= MIN_DUAL_COL_WIDTH + if not isWide: cli.popups.showMsg("Requesting a new identity", 1) + def handleKey(self, key): isKeystrokeConsumed = True
- if key in (ord('r'), ord('R')) and not self._isTorConnected: + if key in (ord('n'), ord('N')) and torTools.getConn().isNewnymAvailable(): + self.sendNewnym() + elif key in (ord('r'), ord('R')) and not self._isTorConnected: try: ctlAddr, ctlPort = self._config["startup.interface.ipAddress"], self._config["startup.interface.port"] tmpConn, authType, authValue = TorCtl.TorCtl.connectionComp(ctlAddr, ctlPort) @@ -309,9 +323,17 @@ class HeaderPanel(panel.Panel, threading.Thread): self.addstr(2, x, ", ") x += 2 else: - # Client only - # TODO: not sure what information to provide here... - pass + # (Client only) Undisplayed / Line 2 Right (new identity option) + if isWide: + conn = torTools.getConn() + newnymWait = conn.getNewnymWait() + + msg = "press 'n' for a new identity" + if newnymWait > 0: + pluralLabel = "s" if newnymWait > 1 else "" + msg = "building circuits, available again in %i second%s" % (newnymWait, pluralLabel) + + self.addstr(1, leftWidth, msg)
self.valsLock.release()
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py index b8b59e1..c571bd8 100644 --- a/src/cli/menu/actions.py +++ b/src/cli/menu/actions.py @@ -42,14 +42,17 @@ def makeActionsMenu(): """ Submenu consisting of... Close Menu + New Identity Pause / Unpause Reset Tor Exit """
control = cli.controller.getController() + headerPanel = control.getPanel("header") 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))
if control.isPaused(): label, arg = "Unpause", False else: label, arg = "Pause", True diff --git a/src/util/torTools.py b/src/util/torTools.py index d0d658a..17c54f0 100644 --- a/src/util/torTools.py +++ b/src/util/torTools.py @@ -6,6 +6,7 @@ accessing TorCtl and notifications of state changes to subscribers. import os import pwd import time +import math import socket import thread import threading @@ -411,6 +412,9 @@ class Controller(TorCtl.PostEventListener): self._status = State.INIT self._statusTime = time.time()
+ # time that we sent our last newnym signal + self._lastNewnym = 0 + # notifies listeners that a new controller is available if not NO_SPAWN: self._notificationQueue.put(State.INIT) @@ -714,6 +718,36 @@ class Controller(TorCtl.PostEventListener):
if raisedExc: raise raisedExc
+ def sendNewnym(self): + """ + Sends a newnym request to Tor. These are rate limited so if it occures + more than once within a ten second window then the second is delayed. + """ + + self.connLock.acquire() + + if self.isAlive(): + self._lastNewnym = time.time() + self.conn.send_signal("NEWNYM") + + self.connLock.release() + + def isNewnymAvailable(self): + """ + True if Tor will immediately respect a newnym request, false otherwise. + """ + + return self.getNewnymWait() == 0 + + def getNewnymWait(self): + """ + Provides the number of seconds until a newnym signal would be respected. + """ + + # newnym signals can occure at the rate of one every ten seconds + # TODO: this can't take other controllers into account :( + return max(0, math.ceil(self._lastNewnym + 10 - time.time())) + def getCircuits(self, default = []): """ This provides a list with tuples of the form: