[tor-commits] [arm/release] Adding a "New Identity" option

atagar at torproject.org atagar at torproject.org
Sun Jul 17 06:08:25 UTC 2011


commit 1a31910080c81f01bf07aeccbaed8ff3d861ec49
Author: Damian Johnson <atagar at 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:





More information about the tor-commits mailing list