def new_desc_event(self, event): # updates self._titleStats with updated values conn = torTools.getConn() if not conn.isAlive(): return # keep old values myFingerprint = conn.getInfo("fingerprint", None) if not self._titleStats or not myFingerprint or (event and myFingerprint in event.idlist): stats = [] bwRate = conn.getMyBandwidthRate() bwBurst = conn.getMyBandwidthBurst() bwObserved = conn.getMyBandwidthObserved() bwMeasured = conn.getMyBandwidthMeasured() labelInBytes = self._config["features.graph.bw.transferInBytes"] if bwRate and bwBurst: bwRateLabel = uiTools.getSizeLabel(bwRate, 1, False, labelInBytes) bwBurstLabel = uiTools.getSizeLabel(bwBurst, 1, False, labelInBytes) # if both are using rounded values then strip off the ".0" decimal if ".0" in bwRateLabel and ".0" in bwBurstLabel: bwRateLabel = bwRateLabel.replace(".0", "") bwBurstLabel = bwBurstLabel.replace(".0", "") stats.append("limit: %s/s" % bwRateLabel) stats.append("burst: %s/s" % bwBurstLabel) # Provide the observed bandwidth either if the measured bandwidth isn't # available or if the measured bandwidth is the observed (this happens # if there isn't yet enough bandwidth measurements). if bwObserved and (not bwMeasured or bwMeasured == bwObserved): stats.append("observed: %s/s" % uiTools.getSizeLabel(bwObserved, 1, False, labelInBytes)) elif bwMeasured: stats.append("measured: %s/s" % uiTools.getSizeLabel(bwMeasured, 1, False, labelInBytes)) self._titleStats = stats
def bandwidth_event(self, event): self._process_event(event.read, event.written) msg = 'Download: %s/s' % uiTools.getSizeLabel(event.read, 2, isBytes=False) self.update_header('primary', msg) msg = 'Upload: %s/s' % uiTools.getSizeLabel(event.written, 2, isBytes=False) self.update_header('secondary', msg)
def bandwidth_event(self, event): self._process_event(event.read, event.written) msg = 'Download: %s/s' % uiTools.getSizeLabel( event.read, 2, isBytes=False) self.update_header('primary', msg) msg = 'Upload: %s/s' % uiTools.getSizeLabel( event.written, 2, isBytes=False) self.update_header('secondary', msg)
def getHeaderLabel(self, width, isPrimary): avg = (self.primaryTotal if isPrimary else self.secondaryTotal) / max(1, self.tick) lastAmount = self.lastPrimary if isPrimary else self.lastSecondary if isPrimary: return "CPU (%0.1f%%, avg: %0.1f%%):" % (lastAmount, avg) else: # memory sizes are converted from MB to B before generating labels usageLabel = uiTools.getSizeLabel(lastAmount * 1048576, 1) avgLabel = uiTools.getSizeLabel(avg * 1048576, 1) return "Memory (%s, avg: %s):" % (usageLabel, avgLabel)
def getHeaderLabel(self, width, isPrimary): avg = (self.primaryTotal if isPrimary else self.secondaryTotal) / max( 1, self.tick) lastAmount = self.lastPrimary if isPrimary else self.lastSecondary if isPrimary: return "CPU (%0.1f%%, avg: %0.1f%%):" % (lastAmount, avg) else: # memory sizes are converted from MB to B before generating labels usageLabel = uiTools.getSizeLabel(lastAmount * 1048576, 1) avgLabel = uiTools.getSizeLabel(avg * 1048576, 1) return "Memory (%s, avg: %s):" % (usageLabel, avgLabel)
def _updateAccountingInfo(self): """ Updates mapping used for accounting info. This includes the following keys: status, resetTime, read, written, readLimit, writtenLimit Any failed lookups result in a mapping to an empty string. """ conn = torTools.getConn() queried = dict([(arg, "") for arg in ACCOUNTING_ARGS]) queried["status"] = conn.getInfo("accounting/hibernating") # provides a nicely formatted reset time endInterval = conn.getInfo("accounting/interval-end") if endInterval: # converts from gmt to local with respect to DST if time.localtime()[8]: tz_offset = time.altzone else: tz_offset = time.timezone sec = time.mktime(time.strptime( endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset if self._config["features.graph.bw.accounting.isTimeLong"]: queried["resetTime"] = ", ".join( uiTools.getTimeLabels(sec, True)) else: days = sec / 86400 sec %= 86400 hours = sec / 3600 sec %= 3600 minutes = sec / 60 sec %= 60 queried["resetTime"] = "%i:%02i:%02i:%02i" % (days, hours, minutes, sec) # number of bytes used and in total for the accounting period used = conn.getInfo("accounting/bytes") left = conn.getInfo("accounting/bytes-left") if used and left: usedComp, leftComp = used.split(" "), left.split(" ") read, written = int(usedComp[0]), int(usedComp[1]) readLeft, writtenLeft = int(leftComp[0]), int(leftComp[1]) queried["read"] = uiTools.getSizeLabel(read) queried["written"] = uiTools.getSizeLabel(written) queried["readLimit"] = uiTools.getSizeLabel(read + readLeft) queried["writtenLimit"] = uiTools.getSizeLabel(written + writtenLeft) self.accountingInfo = queried self.accountingLastUpdated = time.time()
def update_labels(self, name): avg = 0 try: avg = self.total[name] / float(self.ticks[name]) except ZeroDivisionError: pass msg = "avg: %s/s, total: %s" % (uiTools.getSizeLabel(avg, 2, isBytes=False), uiTools.getSizeLabel(self.total[name], 2)) label = self.builder.get_object('label_graph_%s_bottom' % name) label.set_text(msg) return True
def getHeaderLabel(self, width, isPrimary): graphType = "Download" if isPrimary else "Upload" stats = [""] # if wide then avg and total are part of the header, otherwise they're on # the x-axis if width * 2 > COLLAPSE_WIDTH: stats = [""] * 3 stats[1] = "- %s" % self._getAvgLabel(isPrimary) stats[2] = ", %s" % self._getTotalLabel(isPrimary) stats[0] = "%-14s" % ("%s/sec" % uiTools.getSizeLabel( (self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"])) # drops label's components if there's not enough space labeling = graphType + " (" + "".join(stats).strip() + "):" while len(labeling) >= width: if len(stats) > 1: del stats[-1] labeling = graphType + " (" + "".join(stats).strip() + "):" else: labeling = graphType + ":" break return labeling
def _updateAccountingInfo(self): """ Updates mapping used for accounting info. This includes the following keys: status, resetTime, read, written, readLimit, writtenLimit Any failed lookups result in a mapping to an empty string. """ conn = torTools.getConn() queried = dict([(arg, "") for arg in ACCOUNTING_ARGS]) queried["status"] = conn.getInfo("accounting/hibernating", None) # provides a nicely formatted reset time endInterval = conn.getInfo("accounting/interval-end", None) if endInterval: # converts from gmt to local with respect to DST if time.localtime()[8]: tz_offset = time.altzone else: tz_offset = time.timezone sec = time.mktime(time.strptime(endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset if self._config["features.graph.bw.accounting.isTimeLong"]: queried["resetTime"] = ", ".join(uiTools.getTimeLabels(sec, True)) else: days = sec / 86400 sec %= 86400 hours = sec / 3600 sec %= 3600 minutes = sec / 60 sec %= 60 queried["resetTime"] = "%i:%02i:%02i:%02i" % (days, hours, minutes, sec) # number of bytes used and in total for the accounting period used = conn.getInfo("accounting/bytes", None) left = conn.getInfo("accounting/bytes-left", None) if used and left: usedComp, leftComp = used.split(" "), left.split(" ") read, written = int(usedComp[0]), int(usedComp[1]) readLeft, writtenLeft = int(leftComp[0]), int(leftComp[1]) queried["read"] = uiTools.getSizeLabel(read) queried["written"] = uiTools.getSizeLabel(written) queried["readLimit"] = uiTools.getSizeLabel(read + readLeft) queried["writtenLimit"] = uiTools.getSizeLabel(written + writtenLeft) self.accountingInfo = queried self.accountingLastUpdated = time.time()
def new_desc_event(self, event): conn = torTools.getConn() if not conn.isAlive(): return bwRate = conn.getMyBandwidthRate() bwBurst = conn.getMyBandwidthBurst() bwObserved = conn.getMyBandwidthObserved() bwMeasured = conn.getMyBandwidthMeasured() if bwRate and bwBurst: bwRateLabel = uiTools.getSizeLabel(bwRate, 1, False, isBytes=False) bwBurstLabel = uiTools.getSizeLabel(bwBurst, 1, False, isBytes=False) msg = "Limit: %s/s, Burst: %s/s" % (bwRateLabel, bwBurstLabel) label = self.builder.get_object('label_graph_top') label.set_text(msg)
def new_desc_event(self, event): # updates self._titleStats with updated values conn = torTools.getConn() if not conn.isAlive(): return # keep old values myFingerprint = conn.getInfo("fingerprint") if not self._titleStats or not myFingerprint or ( event and myFingerprint in event.idlist): stats = [] bwRate = conn.getMyBandwidthRate() bwBurst = conn.getMyBandwidthBurst() bwObserved = conn.getMyBandwidthObserved() bwMeasured = conn.getMyBandwidthMeasured() labelInBytes = self._config["features.graph.bw.transferInBytes"] if bwRate and bwBurst: bwRateLabel = uiTools.getSizeLabel(bwRate, 1, False, labelInBytes) bwBurstLabel = uiTools.getSizeLabel(bwBurst, 1, False, labelInBytes) # if both are using rounded values then strip off the ".0" decimal if ".0" in bwRateLabel and ".0" in bwBurstLabel: bwRateLabel = bwRateLabel.replace(".0", "") bwBurstLabel = bwBurstLabel.replace(".0", "") stats.append("limit: %s/s" % bwRateLabel) stats.append("burst: %s/s" % bwBurstLabel) # Provide the observed bandwidth either if the measured bandwidth isn't # available or if the measured bandwidth is the observed (this happens # if there isn't yet enough bandwidth measurements). if bwObserved and (not bwMeasured or bwMeasured == bwObserved): stats.append( "observed: %s/s" % uiTools.getSizeLabel(bwObserved, 1, False, labelInBytes)) elif bwMeasured: stats.append( "measured: %s/s" % uiTools.getSizeLabel(bwMeasured, 1, False, labelInBytes)) self._titleStats = stats
def getHeaderLabel(self, width, isPrimary): avg = (self.primaryTotal if isPrimary else self.secondaryTotal) / max(1, self.tick) lastAmount = self.lastPrimary if isPrimary else self.lastSecondary if isPrimary: statName = self._config["features.graph.ps.primaryStat"] else: statName = self._config["features.graph.ps.secondaryStat"] # provides nice labels for failures and common stats if not statName or self.failedCount >= FAILURE_THRESHOLD or not statName in self.queryParam: return "" elif statName == "%cpu": return "CPU (%s%%, avg: %0.1f%%):" % (lastAmount, avg) elif statName in ("rss", "size"): # memory sizes are converted from MB to B before generating labels statLabel = "Memory" if statName == "rss" else "Size" usageLabel = uiTools.getSizeLabel(lastAmount * 1048576, 1) avgLabel = uiTools.getSizeLabel(avg * 1048576, 1) return "%s (%s, avg: %s):" % (statLabel, usageLabel, avgLabel) else: # generic label (first letter of stat name is capitalized) statLabel = statName[0].upper() + statName[1:] return "%s (%s, avg: %s):" % (statLabel, lastAmount, avg)
def _getValue(self): """ Provides the current value of the configuration entry, taking advantage of the torTools caching to effectively query the accurate value. This uses the value's type to provide a user friendly representation if able. """ confValue = ", ".join(torTools.getConn().getOption(self.get(Field.OPTION), [], True)) # provides nicer values for recognized types if not confValue: confValue = "<none>" elif self.get(Field.TYPE) == "Boolean" and confValue in ("0", "1"): confValue = "False" if confValue == "0" else "True" elif self.get(Field.TYPE) == "DataSize" and confValue.isdigit(): confValue = uiTools.getSizeLabel(int(confValue)) elif self.get(Field.TYPE) == "TimeInterval" and confValue.isdigit(): confValue = uiTools.getTimeLabel(int(confValue), isLong = True) return confValue
def _getValue(self): """ Provides the current value of the configuration entry, taking advantage of the torTools caching to effectively query the accurate value. This uses the value's type to provide a user friendly representation if able. """ confValue = ", ".join(torTools.getConn().getOption( self.get(FIELD_OPTION), [], True)) # provides nicer values for recognized types if not confValue: confValue = "<none>" elif self.get(FIELD_TYPE) == "Boolean" and confValue in ("0", "1"): confValue = "False" if confValue == "0" else "True" elif self.get(FIELD_TYPE) == "DataSize" and confValue.isdigit(): confValue = uiTools.getSizeLabel(int(confValue)) elif self.get(FIELD_TYPE) == "TimeInterval" and confValue.isdigit(): confValue = uiTools.getTimeLabel(int(confValue), isLong=True) return confValue
def getHeaderLabel(self, width, isPrimary): graphType = "Download" if isPrimary else "Upload" stats = [""] # if wide then avg and total are part of the header, otherwise they're on # the x-axis if width * 2 > COLLAPSE_WIDTH: stats = [""] * 3 stats[1] = "- %s" % self._getAvgLabel(isPrimary) stats[2] = ", %s" % self._getTotalLabel(isPrimary) stats[0] = "%-14s" % ("%s/sec" % uiTools.getSizeLabel((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"])) # drops label's components if there's not enough space labeling = graphType + " (" + "".join(stats).strip() + "):" while len(labeling) >= width: if len(stats) > 1: del stats[-1] labeling = graphType + " (" + "".join(stats).strip() + "):" else: labeling = graphType + ":" break return labeling
def _fill_entries(self): self.valsLock.acquire() listStore = self.builder.get_object('liststore_general') theme = gtkTools.Theme() listStore.clear() key = "arm" value = "%s (%s %s)" % (self.vals['sys/hostname'], self.vals['sys/os'], self.vals['sys/version']) row = (key, value, theme.colors['active']) listStore.append(row) versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "black" key = "Tor" value = "%s (<span foreground=\"%s\">%s</span>)" % ( self.vals['tor/version'], versionColor, self.vals['tor/versionStatus']) row = (key, value, theme.colors['active']) listStore.append(row) includeControlPort = True key = "Relaying" if self.vals["tor/orPort"]: myAddress = "Unknown" if self.vals["tor/orListenAddr"]: myAddress = self.vals["tor/orListenAddr"] elif self.vals["tor/address"]: myAddress = self.vals["tor/address"] dirPortLabel = ", Dir Port: %s" % self.vals[ "tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" value = "%s%s%s%s" % (self.vals["tor/nickname"], " - " + myAddress, ":" + self.vals["tor/orPort"], dirPortLabel) else: if self._isTorConnected: value = "Disabled" else: statusTime = torTools.getConn().getStatus()[1] if statusTime: statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ", time.localtime(statusTime)) else: statusTimeLabel = "" value = "%s%s" % ("Tor Disconnected", statusTimeLabel) includeControlPort = False row = (key, value, theme.colors['active']) listStore.append(row) key = "Control Port" if includeControlPort: if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" authColor = "red" if authType == "open" else "green" value = "%s (<span foreground=\"%s\">%s</span>)" % ( self.vals['tor/controlPort'], authColor, authType) row = (key, value, theme.colors['active']) listStore.append(row) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"])) else: memoryLabel = "0" uptimeLabel = "N/A" if self.vals["tor/startTime"]: if self.isPaused() or not self._isTorConnected: uptimeLabel = uiTools.getShortTimeLabel( self.getPauseTime() - self.vals["tor/startTime"]) else: uptimeLabel = uiTools.getShortTimeLabel( time.time() - self.vals["tor/startTime"]) key = "CPU" value = "%s%% Tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"]) row = (key, value, theme.colors['active']) listStore.append(row) key = "Memory" value = "%s (%s%%)" % (memoryLabel, self.vals["stat/%mem"]) row = (key, value, theme.colors['active']) listStore.append(row) key = "PID" value = "%s" % (self.vals["tor/pid"] if self._isTorConnected else "") row = (key, value, theme.colors['active']) listStore.append(row) key = "Uptime" value = uptimeLabel row = (key, value, theme.colors['active']) listStore.append(row) self.valsLock.release()
def validate(contents = None): """ Performs validation on the given torrc contents, providing back a listing of (line number, issue, msg) tuples for issues found. If the issue occures on a multiline torrc entry then the line number is for the last line of the entry. Arguments: contents - torrc contents """ conn = torTools.getConn() customOptions = getCustomOptions() issuesFound, seenOptions = [], [] # Strips comments and collapses multiline multi-line entries, for more # information see: # https://trac.torproject.org/projects/tor/ticket/1929 strippedContents, multilineBuffer = [], "" for line in _stripComments(contents): if not line: strippedContents.append("") else: line = multilineBuffer + line multilineBuffer = "" if line.endswith("\\"): multilineBuffer = line[:-1] strippedContents.append("") else: strippedContents.append(line.strip()) for lineNumber in range(len(strippedContents) - 1, -1, -1): lineText = strippedContents[lineNumber] if not lineText: continue lineComp = lineText.split(None, 1) if len(lineComp) == 2: option, value = lineComp else: option, value = lineText, "" # if an aliased option then use its real name if option in CONFIG["torrc.alias"]: option = CONFIG["torrc.alias"][option] # most parameters are overwritten if defined multiple times if option in seenOptions and not option in getMultilineParameters(): issuesFound.append((lineNumber, VAL_DUPLICATE, option)) continue else: seenOptions.append(option) # checks if the value isn't necessary due to matching the defaults if not option in customOptions: issuesFound.append((lineNumber, VAL_IS_DEFAULT, option)) # replace aliases with their recognized representation if option in CONFIG["torrc.alias"]: option = CONFIG["torrc.alias"][option] # tor appears to replace tabs with a space, for instance: # "accept\t*:563" is read back as "accept *:563" value = value.replace("\t", " ") # parse value if it's a size or time, expanding the units value, valueType = _parseConfValue(value) # issues GETCONF to get the values tor's currently configured to use torValues = conn.getOption(option, [], True) # Some singleline entries are lists, in which case tor provides csv values # without spaces, such as: # lolcat1,lolcat2,cutebunny,extracutebunny,birthdaynode # so we need to strip spaces in comma separated values. if "," in value: value = ",".join([val.strip() for val in value.split(",")]) # multiline entries can be comma separated values (for both tor and conf) valueList = [value] if option in getMultilineParameters(): valueList = [val.strip() for val in value.split(",")] fetchedValues, torValues = torValues, [] for fetchedValue in fetchedValues: for fetchedEntry in fetchedValue.split(","): fetchedEntry = fetchedEntry.strip() if not fetchedEntry in torValues: torValues.append(fetchedEntry) for val in valueList: # checks if both the argument and tor's value are empty isBlankMatch = not val and not torValues if not isBlankMatch and not val in torValues: # converts corrections to reader friedly size values displayValues = torValues if valueType == SIZE_VALUE: displayValues = [uiTools.getSizeLabel(int(val)) for val in torValues] elif valueType == TIME_VALUE: displayValues = [uiTools.getTimeLabel(int(val)) for val in torValues] issuesFound.append((lineNumber, VAL_MISMATCH, ", ".join(displayValues))) # checks if any custom options are missing from the torrc for option in customOptions: if not option in seenOptions: issuesFound.append((None, VAL_MISSING, option)) return issuesFound
def _fill_entries(self): self.valsLock.acquire() listStore = self.builder.get_object('liststore_general') theme = gtkTools.Theme() listStore.clear() key = "arm" value = "%s (%s %s)" % (self.vals['sys/hostname'], self.vals['sys/os'], self.vals['sys/version']) row = (key, value, theme.colors['active']) listStore.append(row) versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "black" key = "Tor" value = "%s (<span foreground=\"%s\">%s</span>)" % (self.vals['tor/version'], versionColor, self.vals['tor/versionStatus']) row = (key, value, theme.colors['active']) listStore.append(row) includeControlPort = True key = "Relaying" if self.vals["tor/orPort"]: myAddress = "Unknown" if self.vals["tor/orListenAddr"]: myAddress = self.vals["tor/orListenAddr"] elif self.vals["tor/address"]: myAddress = self.vals["tor/address"] dirPortLabel = ", Dir Port: %s" % self.vals["tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" value = "%s%s%s%s" % (self.vals["tor/nickname"], " - " + myAddress, ":" + self.vals["tor/orPort"], dirPortLabel) else: if self._isTorConnected: value = "Disabled" else: statusTime = torTools.getConn().getStatus()[1] if statusTime: statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ", time.localtime(statusTime)) else: statusTimeLabel = "" value = "%s%s" % ("Tor Disconnected", statusTimeLabel) includeControlPort = False row = (key, value, theme.colors['active']) listStore.append(row) key = "Control Port" if includeControlPort: if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" authColor = "red" if authType == "open" else "green" value = "%s (<span foreground=\"%s\">%s</span>)" % (self.vals['tor/controlPort'], authColor, authType) row = (key, value, theme.colors['active']) listStore.append(row) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"])) else: memoryLabel = "0" uptimeLabel = "N/A" if self.vals["tor/startTime"]: if self.isPaused() or not self._isTorConnected: uptimeLabel = uiTools.getShortTimeLabel(self.getPauseTime() - self.vals["tor/startTime"]) else: uptimeLabel = uiTools.getShortTimeLabel(time.time() - self.vals["tor/startTime"]) key = "CPU" value = "%s%% Tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"]) row = (key, value, theme.colors['active']) listStore.append(row) key = "Memory" value = "%s (%s%%)" % (memoryLabel, self.vals["stat/%mem"]) row = (key, value, theme.colors['active']) listStore.append(row) key = "PID" value = "%s" % (self.vals["tor/pid"] if self._isTorConnected else "") row = (key, value, theme.colors['active']) listStore.append(row) key = "Uptime" value = uptimeLabel row = (key, value, theme.colors['active']) listStore.append(row) self.valsLock.release()
def draw(self, width, height): self.valsLock.acquire() isWide = width + 1 >= MIN_DUAL_COL_WIDTH # space available for content if isWide: leftWidth = max(width / 2, 77) rightWidth = width - leftWidth else: leftWidth = rightWidth = width # Line 1 / Line 1 Left (system and tor version information) sysNameLabel = "arm - %s" % self.vals["sys/hostname"] contentSpace = min(leftWidth, 40) if len(sysNameLabel) + 10 <= contentSpace: sysTypeLabel = "%s %s" % (self.vals["sys/os"], self.vals["sys/version"]) sysTypeLabel = uiTools.cropStr(sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4) self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel)) else: self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace)) contentSpace = leftWidth - 43 if 7 + len(self.vals["tor/version"]) + len(self.vals["tor/versionStatus"]) <= contentSpace: if self.vals["tor/version"] != "Unknown": versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white" labelPrefix = "Tor %s (" % self.vals["tor/version"] self.addstr(0, 43, labelPrefix) self.addstr(0, 43 + len(labelPrefix), self.vals["tor/versionStatus"], uiTools.getColor(versionColor)) self.addstr(0, 43 + len(labelPrefix) + len(self.vals["tor/versionStatus"]), ")") elif 11 <= contentSpace: self.addstr(0, 43, uiTools.cropStr("Tor %s" % self.vals["tor/version"], contentSpace, 4)) # Line 2 / Line 2 Left (tor ip/port information) x, includeControlPort = 0, True if self.vals["tor/orPort"]: myAddress = "Unknown" if self.vals["tor/orListenAddr"]: myAddress = self.vals["tor/orListenAddr"] elif self.vals["tor/address"]: myAddress = self.vals["tor/address"] # acting as a relay (we can assume certain parameters are set dirPortLabel = ", Dir Port: %s" % self.vals["tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" for label in (self.vals["tor/nickname"], " - " + myAddress, ":" + self.vals["tor/orPort"], dirPortLabel): if x + len(label) <= leftWidth: self.addstr(1, x, label) x += len(label) else: break else: # non-relay (client only) if self._isTorConnected: self.addstr(1, x, "Relaying Disabled", uiTools.getColor("cyan")) x += 17 else: statusTime = torTools.getConn().getStatus()[1] if statusTime: statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ", time.localtime(statusTime)) else: statusTimeLabel = "" # never connected to tor self.addstr(1, x, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red")) self.addstr(1, x + 16, " (%spress r to reconnect)" % statusTimeLabel) x += 39 + len(statusTimeLabel) includeControlPort = False if includeControlPort: if self.vals["tor/controlPort"] == "0": # connected via a control socket self.addstr(1, x, ", Control Socket: %s" % self.vals["tor/socketPath"]) else: if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" if x + 19 + len(self.vals["tor/controlPort"]) + len(authType) <= leftWidth: authColor = "red" if authType == "open" else "green" self.addstr(1, x, ", Control Port (") self.addstr(1, x + 16, authType, uiTools.getColor(authColor)) self.addstr(1, x + 16 + len(authType), "): %s" % self.vals["tor/controlPort"]) elif x + 16 + len(self.vals["tor/controlPort"]) <= leftWidth: self.addstr(1, 0, ", Control Port: %s" % self.vals["tor/controlPort"]) # Line 3 / Line 1 Right (system usage info) y, x = (0, leftWidth) if isWide else (2, 0) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"])) else: memoryLabel = "0" uptimeLabel = "" if self.vals["tor/startTime"]: if self.isPaused() or not self._isTorConnected: # freeze the uptime when paused or the tor process is stopped uptimeLabel = uiTools.getShortTimeLabel(self.getPauseTime() - self.vals["tor/startTime"]) else: uptimeLabel = uiTools.getShortTimeLabel(time.time() - self.vals["tor/startTime"]) sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])), (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])), (47, "pid: %s" % (self.vals["tor/pid"] if self._isTorConnected else "")), (59, "uptime: %s" % uptimeLabel)) for (start, label) in sysFields: if start + len(label) <= rightWidth: self.addstr(y, x + start, label) else: break if self.vals["tor/orPort"]: # Line 4 / Line 2 Right (fingerprint, and possibly file descriptor usage) y, x = (1, leftWidth) if isWide else (3, 0) fingerprintLabel = uiTools.cropStr("fingerprint: %s" % self.vals["tor/fingerprint"], width) self.addstr(y, x, fingerprintLabel) # if there's room and we're able to retrieve both the file descriptor # usage and limit then it might be presented if width - x - 59 >= 20 and self.vals["tor/fdUsed"] and self.vals["tor/fdLimit"]: # display file descriptor usage if we're either configured to do so or # running out fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals["tor/fdLimit"] if fdPercent >= 60 or self._config["features.showFdUsage"]: fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL if fdPercent >= 95: fdPercentFormat = curses.A_BOLD | uiTools.getColor("red") elif fdPercent >= 90: fdPercentFormat = uiTools.getColor("red") elif fdPercent >= 60: fdPercentFormat = uiTools.getColor("yellow") estimateChar = "?" if self.vals["tor/isFdLimitEstimate"] else "" baseLabel = "file desc: %i / %i%s (" % (self.vals["tor/fdUsed"], self.vals["tor/fdLimit"], estimateChar) self.addstr(y, x + 59, baseLabel) self.addstr(y, x + 59 + len(baseLabel), fdPercentLabel, fdPercentFormat) self.addstr(y, x + 59 + len(baseLabel) + len(fdPercentLabel), ")") # Line 5 / Line 3 Left (flags) if self._isTorConnected: y, x = (2 if isWide else 4, 0) self.addstr(y, x, "flags: ") x += 7 if len(self.vals["tor/flags"]) > 0: for i in range(len(self.vals["tor/flags"])): flag = self.vals["tor/flags"][i] flagColor = FLAG_COLORS[flag] if flag in FLAG_COLORS.keys() else "white" self.addstr(y, x, flag, curses.A_BOLD | uiTools.getColor(flagColor)) x += len(flag) if i < len(self.vals["tor/flags"]) - 1: self.addstr(y, x, ", ") x += 2 else: self.addstr(y, x, "none", curses.A_BOLD | uiTools.getColor("cyan")) else: y = 2 if isWide else 4 statusTime = torTools.getConn().getStatus()[1] statusTimeLabel = time.strftime("%H:%M %m/%d/%Y", time.localtime(statusTime)) self.addstr(y, 0, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red")) self.addstr(y, 16, " (%s) - press r to reconnect" % statusTimeLabel) # Undisplayed / Line 3 Right (exit policy) if isWide: exitPolicy = self.vals["tor/exitPolicy"] # adds note when default exit policy is appended if exitPolicy == "": exitPolicy = "<default>" elif not exitPolicy.endswith((" *:*", " *")): exitPolicy += ", <default>" self.addstr(2, leftWidth, "exit policy: ") x = leftWidth + 13 # color codes accepts to be green, rejects to be red, and default marker to be cyan isSimple = len(exitPolicy) > rightWidth - 13 policies = exitPolicy.split(", ") for i in range(len(policies)): policy = policies[i].strip() policyLabel = policy.replace("accept", "").replace("reject", "").strip() if isSimple else policy policyColor = "white" if policy.startswith("accept"): policyColor = "green" elif policy.startswith("reject"): policyColor = "red" elif policy.startswith("<default>"): policyColor = "cyan" self.addstr(2, x, policyLabel, curses.A_BOLD | uiTools.getColor(policyColor)) x += len(policyLabel) if i < len(policies) - 1: self.addstr(2, x, ", ") x += 2 else: # (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()
def _getAvgLabel(self, isPrimary): total = self.primaryTotal if isPrimary else self.secondaryTotal total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal return "avg: %s/sec" % uiTools.getSizeLabel( (total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"])
def _getTotalLabel(self, isPrimary): total = self.primaryTotal if isPrimary else self.secondaryTotal total += self.initialPrimaryTotal if isPrimary else self.initialSecondaryTotal return "total: %s" % uiTools.getSizeLabel(total * 1024, 1)
def _getAvgLabel(self, isPrimary): total = self.primaryTotal if isPrimary else self.secondaryTotal total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal return "avg: %s/sec" % uiTools.getSizeLabel((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"])
def draw(self, width, height): self.valsLock.acquire() isWide = width + 1 >= MIN_DUAL_COL_WIDTH # space available for content if isWide: leftWidth = max(width / 2, 77) rightWidth = width - leftWidth else: leftWidth = rightWidth = width # Line 1 / Line 1 Left (system and tor version information) sysNameLabel = "arm - %s" % self.vals["sys/hostname"] contentSpace = min(leftWidth, 40) if len(sysNameLabel) + 10 <= contentSpace: sysTypeLabel = "%s %s" % (self.vals["sys/os"], self.vals["sys/version"]) sysTypeLabel = uiTools.cropStr( sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4) self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel)) else: self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace)) contentSpace = leftWidth - 43 if 7 + len(self.vals["tor/version"]) + len( self.vals["tor/versionStatus"]) <= contentSpace: if self.vals["tor/version"] != "Unknown": versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white" labelPrefix = "Tor %s (" % self.vals["tor/version"] self.addstr(0, 43, labelPrefix) self.addstr(0, 43 + len(labelPrefix), self.vals["tor/versionStatus"], uiTools.getColor(versionColor)) self.addstr( 0, 43 + len(labelPrefix) + len(self.vals["tor/versionStatus"]), ")") elif 11 <= contentSpace: self.addstr( 0, 43, uiTools.cropStr("Tor %s" % self.vals["tor/version"], contentSpace, 4)) # Line 2 / Line 2 Left (tor ip/port information) x, includeControlPort = 0, True if self.vals["tor/orPort"]: myAddress = "Unknown" if self.vals["tor/orListenAddr"]: myAddress = self.vals["tor/orListenAddr"] elif self.vals["tor/address"]: myAddress = self.vals["tor/address"] # acting as a relay (we can assume certain parameters are set dirPortLabel = ", Dir Port: %s" % self.vals[ "tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" for label in (self.vals["tor/nickname"], " - " + myAddress, ":" + self.vals["tor/orPort"], dirPortLabel): if x + len(label) <= leftWidth: self.addstr(1, x, label) x += len(label) else: break else: # non-relay (client only) if self._isTorConnected: self.addstr(1, x, "Relaying Disabled", uiTools.getColor("cyan")) x += 17 else: statusTime = torTools.getConn().getStatus()[1] if statusTime: statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ", time.localtime(statusTime)) else: statusTimeLabel = "" # never connected to tor self.addstr(1, x, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red")) self.addstr(1, x + 16, " (%spress r to reconnect)" % statusTimeLabel) x += 39 + len(statusTimeLabel) includeControlPort = False if includeControlPort: if self.vals["tor/controlPort"] == "0": # connected via a control socket self.addstr( 1, x, ", Control Socket: %s" % self.vals["tor/socketPath"]) else: if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" if x + 19 + len(self.vals["tor/controlPort"]) + len( authType) <= leftWidth: authColor = "red" if authType == "open" else "green" self.addstr(1, x, ", Control Port (") self.addstr(1, x + 16, authType, uiTools.getColor(authColor)) self.addstr(1, x + 16 + len(authType), "): %s" % self.vals["tor/controlPort"]) elif x + 16 + len(self.vals["tor/controlPort"]) <= leftWidth: self.addstr( 1, 0, ", Control Port: %s" % self.vals["tor/controlPort"]) # Line 3 / Line 1 Right (system usage info) y, x = (0, leftWidth) if isWide else (2, 0) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"])) else: memoryLabel = "0" uptimeLabel = "" if self.vals["tor/startTime"]: if self.isPaused() or not self._isTorConnected: # freeze the uptime when paused or the tor process is stopped uptimeLabel = uiTools.getShortTimeLabel( self.getPauseTime() - self.vals["tor/startTime"]) else: uptimeLabel = uiTools.getShortTimeLabel( time.time() - self.vals["tor/startTime"]) sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])), (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])), (47, "pid: %s" % (self.vals["tor/pid"] if self._isTorConnected else "")), (59, "uptime: %s" % uptimeLabel)) for (start, label) in sysFields: if start + len(label) <= rightWidth: self.addstr(y, x + start, label) else: break if self.vals["tor/orPort"]: # Line 4 / Line 2 Right (fingerprint, and possibly file descriptor usage) y, x = (1, leftWidth) if isWide else (3, 0) fingerprintLabel = uiTools.cropStr( "fingerprint: %s" % self.vals["tor/fingerprint"], width) self.addstr(y, x, fingerprintLabel) # if there's room and we're able to retrieve both the file descriptor # usage and limit then it might be presented if width - x - 59 >= 20 and self.vals["tor/fdUsed"] and self.vals[ "tor/fdLimit"]: # display file descriptor usage if we're either configured to do so or # running out fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals[ "tor/fdLimit"] if fdPercent >= 60 or self._config["features.showFdUsage"]: fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL if fdPercent >= 95: fdPercentFormat = curses.A_BOLD | uiTools.getColor( "red") elif fdPercent >= 90: fdPercentFormat = uiTools.getColor("red") elif fdPercent >= 60: fdPercentFormat = uiTools.getColor("yellow") estimateChar = "?" if self.vals[ "tor/isFdLimitEstimate"] else "" baseLabel = "file desc: %i / %i%s (" % ( self.vals["tor/fdUsed"], self.vals["tor/fdLimit"], estimateChar) self.addstr(y, x + 59, baseLabel) self.addstr(y, x + 59 + len(baseLabel), fdPercentLabel, fdPercentFormat) self.addstr(y, x + 59 + len(baseLabel) + len(fdPercentLabel), ")") # Line 5 / Line 3 Left (flags) if self._isTorConnected: y, x = (2 if isWide else 4, 0) self.addstr(y, x, "flags: ") x += 7 if len(self.vals["tor/flags"]) > 0: for i in range(len(self.vals["tor/flags"])): flag = self.vals["tor/flags"][i] flagColor = FLAG_COLORS[ flag] if flag in FLAG_COLORS.keys() else "white" self.addstr( y, x, flag, curses.A_BOLD | uiTools.getColor(flagColor)) x += len(flag) if i < len(self.vals["tor/flags"]) - 1: self.addstr(y, x, ", ") x += 2 else: self.addstr(y, x, "none", curses.A_BOLD | uiTools.getColor("cyan")) else: y = 2 if isWide else 4 statusTime = torTools.getConn().getStatus()[1] statusTimeLabel = time.strftime("%H:%M %m/%d/%Y", time.localtime(statusTime)) self.addstr(y, 0, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red")) self.addstr(y, 16, " (%s) - press r to reconnect" % statusTimeLabel) # Undisplayed / Line 3 Right (exit policy) if isWide: exitPolicy = self.vals["tor/exitPolicy"] # adds note when default exit policy is appended if exitPolicy == "": exitPolicy = "<default>" elif not exitPolicy.endswith((" *:*", " *")): exitPolicy += ", <default>" self.addstr(2, leftWidth, "exit policy: ") x = leftWidth + 13 # color codes accepts to be green, rejects to be red, and default marker to be cyan isSimple = len(exitPolicy) > rightWidth - 13 policies = exitPolicy.split(", ") for i in range(len(policies)): policy = policies[i].strip() policyLabel = policy.replace("accept", "").replace( "reject", "").strip() if isSimple else policy policyColor = "white" if policy.startswith("accept"): policyColor = "green" elif policy.startswith("reject"): policyColor = "red" elif policy.startswith("<default>"): policyColor = "cyan" self.addstr(2, x, policyLabel, curses.A_BOLD | uiTools.getColor(policyColor)) x += len(policyLabel) if i < len(policies) - 1: self.addstr(2, x, ", ") x += 2 else: # (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()
def validate(contents = None): """ Performs validation on the given torrc contents, providing back a listing of (line number, issue, msg) tuples for issues found. If the issue occures on a multiline torrc entry then the line number is for the last line of the entry. Arguments: contents - torrc contents """ conn = torTools.getConn() customOptions = getCustomOptions() issuesFound, seenOptions = [], [] # Strips comments and collapses multiline multi-line entries, for more # information see: # https://trac.torproject.org/projects/tor/ticket/1929 strippedContents, multilineBuffer = [], "" for line in _stripComments(contents): if not line: strippedContents.append("") else: line = multilineBuffer + line multilineBuffer = "" if line.endswith("\\"): multilineBuffer = line[:-1] strippedContents.append("") else: strippedContents.append(line.strip()) for lineNumber in range(len(strippedContents) - 1, -1, -1): lineText = strippedContents[lineNumber] if not lineText: continue lineComp = lineText.split(None, 1) if len(lineComp) == 2: option, value = lineComp else: option, value = lineText, "" # Tor is case insensetive when parsing its torrc. This poses a bit of an # issue for us because we want all of our checks to be case insensetive # too but also want messages to match the normal camel-case conventions. # # Using the customOptions to account for this. It contains the tor reported # options (camel case) and is either a matching set or the following defaut # value check will fail. Hence using that hash to correct the case. # # TODO: when refactoring for stem make this less confusing... for customOpt in customOptions: if customOpt.lower() == option.lower(): option = customOpt break # if an aliased option then use its real name if option in CONFIG["torrc.alias"]: option = CONFIG["torrc.alias"][option] # most parameters are overwritten if defined multiple times if option in seenOptions and not option in getMultilineParameters(): issuesFound.append((lineNumber, ValidationError.DUPLICATE, option)) continue else: seenOptions.append(option) # checks if the value isn't necessary due to matching the defaults if not option in customOptions: issuesFound.append((lineNumber, ValidationError.IS_DEFAULT, option)) # replace aliases with their recognized representation if option in CONFIG["torrc.alias"]: option = CONFIG["torrc.alias"][option] # tor appears to replace tabs with a space, for instance: # "accept\t*:563" is read back as "accept *:563" value = value.replace("\t", " ") # parse value if it's a size or time, expanding the units value, valueType = _parseConfValue(value) # issues GETCONF to get the values tor's currently configured to use torValues = conn.getOption(option, [], True) # multiline entries can be comma separated values (for both tor and conf) valueList = [value] if option in getMultilineParameters(): valueList = [val.strip() for val in value.split(",")] fetchedValues, torValues = torValues, [] for fetchedValue in fetchedValues: for fetchedEntry in fetchedValue.split(","): fetchedEntry = fetchedEntry.strip() if not fetchedEntry in torValues: torValues.append(fetchedEntry) for val in valueList: # checks if both the argument and tor's value are empty isBlankMatch = not val and not torValues if not isBlankMatch and not val in torValues: # converts corrections to reader friedly size values displayValues = torValues if valueType == ValueType.SIZE: displayValues = [uiTools.getSizeLabel(int(val)) for val in torValues] elif valueType == ValueType.TIME: displayValues = [uiTools.getTimeLabel(int(val)) for val in torValues] issuesFound.append((lineNumber, ValidationError.MISMATCH, ", ".join(displayValues))) # checks if any custom options are missing from the torrc for option in customOptions: # In new versions the 'DirReqStatistics' option is true by default and # disabled on startup if geoip lookups are unavailable. If this option is # missing then that's most likely the reason. # # https://trac.torproject.org/projects/tor/ticket/4237 if option == "DirReqStatistics": continue if not option in seenOptions: issuesFound.append((None, ValidationError.MISSING, option)) return issuesFound
def draw(self, subwindow, width, height): self.valsLock.acquire() isWide = width + 1 >= MIN_DUAL_COL_WIDTH # space available for content if isWide: leftWidth = max(width / 2, 77) rightWidth = width - leftWidth else: leftWidth = rightWidth = width # Line 1 / Line 1 Left (system and tor version information) sysNameLabel = "arm - %s" % self.vals["sys/hostname"] contentSpace = min(leftWidth, 40) if len(sysNameLabel) + 10 <= contentSpace: sysTypeLabel = "%s %s" % (self.vals["sys/os"], self.vals["sys/version"]) sysTypeLabel = uiTools.cropStr(sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4) self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel)) else: self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace)) contentSpace = leftWidth - 43 if 7 + len(self.vals["tor/version"]) + len(self.vals["tor/versionStatus"]) <= contentSpace: versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white" versionStatusMsg = "<%s>%s</%s>" % (versionColor, self.vals["tor/versionStatus"], versionColor) self.addfstr(0, 43, "Tor %s (%s)" % (self.vals["tor/version"], versionStatusMsg)) elif 11 <= contentSpace: self.addstr(0, 43, uiTools.cropStr("Tor %s" % self.vals["tor/version"], contentSpace, 4)) # Line 2 / Line 2 Left (tor ip/port information) if self.vals["tor/orPort"]: # acting as a relay (we can assume certain parameters are set entry = "" dirPortLabel = ", Dir Port: %s" % self.vals["tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" for label in (self.vals["tor/nickname"], " - " + self.vals["tor/address"], ":" + self.vals["tor/orPort"], dirPortLabel): if len(entry) + len(label) <= leftWidth: entry += label else: break else: # non-relay (client only) # TODO: not sure what sort of stats to provide... entry = "<red><b>Relaying Disabled</b></red>" if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" if len(entry) + 19 + len(self.vals["tor/controlPort"]) + len(authType) <= leftWidth: authColor = "red" if authType == "open" else "green" authLabel = "<%s>%s</%s>" % (authColor, authType, authColor) self.addfstr(1, 0, "%s, Control Port (%s): %s" % (entry, authLabel, self.vals["tor/controlPort"])) elif len(entry) + 16 + len(self.vals["tor/controlPort"]) <= leftWidth: self.addstr(1, 0, "%s, Control Port: %s" % (entry, self.vals["tor/controlPort"])) else: self.addstr(1, 0, entry) # Line 3 / Line 1 Right (system usage info) y, x = (0, leftWidth) if isWide else (2, 0) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"]) * 1024) else: memoryLabel = "0" sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])), (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])), (47, "pid: %s" % (self.vals["stat/pid"] if self._isTorConnected else "")), (59, "uptime: %s" % self.vals["stat/etime"])) for (start, label) in sysFields: if start + len(label) <= rightWidth: self.addstr(y, x + start, label) else: break if self.vals["tor/orPort"]: # Line 4 / Line 2 Right (fingerprint) y, x = (1, leftWidth) if isWide else (3, 0) fingerprintLabel = uiTools.cropStr("fingerprint: %s" % self.vals["tor/fingerprint"], width) self.addstr(y, x, fingerprintLabel) # Line 5 / Line 3 Left (flags) if self._isTorConnected: flagLine = "flags: " for flag in self.vals["tor/flags"]: flagColor = FLAG_COLORS[flag] if flag in FLAG_COLORS.keys() else "white" flagLine += "<b><%s>%s</%s></b>, " % (flagColor, flag, flagColor) if len(self.vals["tor/flags"]) > 0: flagLine = flagLine[:-2] else: flagLine += "<b><cyan>none</cyan></b>" self.addfstr(2 if isWide else 4, 0, flagLine) else: statusTime = torTools.getConn().getStatus()[1] statusTimeLabel = time.strftime("%H:%M %m/%d/%Y", time.localtime(statusTime)) self.addfstr(2 if isWide else 4, 0, "<b><red>Tor Disconnected</red></b> (%s)" % statusTimeLabel) # Undisplayed / Line 3 Right (exit policy) if isWide: exitPolicy = self.vals["tor/exitPolicy"] # adds note when default exit policy is appended if exitPolicy == "": exitPolicy = "<default>" elif not exitPolicy.endswith((" *:*", " *")): exitPolicy += ", <default>" # color codes accepts to be green, rejects to be red, and default marker to be cyan isSimple = len(exitPolicy) > rightWidth - 13 policies = exitPolicy.split(", ") for i in range(len(policies)): policy = policies[i].strip() displayedPolicy = policy.replace("accept", "").replace("reject", "").strip() if isSimple else policy if policy.startswith("accept"): policy = "<green><b>%s</b></green>" % displayedPolicy elif policy.startswith("reject"): policy = "<red><b>%s</b></red>" % displayedPolicy elif policy.startswith("<default>"): policy = "<cyan><b>%s</b></cyan>" % displayedPolicy policies[i] = policy self.addfstr(2, leftWidth, "exit policy: %s" % ", ".join(policies)) else: # Client only # TODO: not sure what information to provide here... pass self._isLastDrawWide = isWide self._isChanged = False self.valsLock.release()
def draw(self, subwindow, width, height): self.valsLock.acquire() isWide = width + 1 >= MIN_DUAL_COL_WIDTH # space available for content if isWide: leftWidth = max(width / 2, 77) rightWidth = width - leftWidth else: leftWidth = rightWidth = width # Line 1 / Line 1 Left (system and tor version information) sysNameLabel = "arm - %s" % self.vals["sys/hostname"] contentSpace = min(leftWidth, 40) if len(sysNameLabel) + 10 <= contentSpace: sysTypeLabel = "%s %s" % (self.vals["sys/os"], self.vals["sys/version"]) sysTypeLabel = uiTools.cropStr( sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4) self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel)) else: self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace)) contentSpace = leftWidth - 43 if 7 + len(self.vals["tor/version"]) + len( self.vals["tor/versionStatus"]) <= contentSpace: versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \ self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white" versionStatusMsg = "<%s>%s</%s>" % ( versionColor, self.vals["tor/versionStatus"], versionColor) self.addfstr( 0, 43, "Tor %s (%s)" % (self.vals["tor/version"], versionStatusMsg)) elif 11 <= contentSpace: self.addstr( 0, 43, uiTools.cropStr("Tor %s" % self.vals["tor/version"], contentSpace, 4)) # Line 2 / Line 2 Left (tor ip/port information) if self.vals["tor/orPort"]: # acting as a relay (we can assume certain parameters are set entry = "" dirPortLabel = ", Dir Port: %s" % self.vals[ "tor/dirPort"] if self.vals["tor/dirPort"] != "0" else "" for label in (self.vals["tor/nickname"], " - " + self.vals["tor/address"], ":" + self.vals["tor/orPort"], dirPortLabel): if len(entry) + len(label) <= leftWidth: entry += label else: break else: # non-relay (client only) # TODO: not sure what sort of stats to provide... entry = "<red><b>Relaying Disabled</b></red>" if self.vals["tor/isAuthPassword"]: authType = "password" elif self.vals["tor/isAuthCookie"]: authType = "cookie" else: authType = "open" if len(entry) + 19 + len( self.vals["tor/controlPort"]) + len(authType) <= leftWidth: authColor = "red" if authType == "open" else "green" authLabel = "<%s>%s</%s>" % (authColor, authType, authColor) self.addfstr( 1, 0, "%s, Control Port (%s): %s" % (entry, authLabel, self.vals["tor/controlPort"])) elif len(entry) + 16 + len(self.vals["tor/controlPort"]) <= leftWidth: self.addstr( 1, 0, "%s, Control Port: %s" % (entry, self.vals["tor/controlPort"])) else: self.addstr(1, 0, entry) # Line 3 / Line 1 Right (system usage info) y, x = (0, leftWidth) if isWide else (2, 0) if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel( int(self.vals["stat/rss"]) * 1024) else: memoryLabel = "0" sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])), (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])), (47, "pid: %s" % (self.vals["stat/pid"] if self._isTorConnected else "")), (59, "uptime: %s" % self.vals["stat/etime"])) for (start, label) in sysFields: if start + len(label) <= rightWidth: self.addstr(y, x + start, label) else: break if self.vals["tor/orPort"]: # Line 4 / Line 2 Right (fingerprint) y, x = (1, leftWidth) if isWide else (3, 0) fingerprintLabel = uiTools.cropStr( "fingerprint: %s" % self.vals["tor/fingerprint"], width) self.addstr(y, x, fingerprintLabel) # Line 5 / Line 3 Left (flags) if self._isTorConnected: flagLine = "flags: " for flag in self.vals["tor/flags"]: flagColor = FLAG_COLORS[flag] if flag in FLAG_COLORS.keys( ) else "white" flagLine += "<b><%s>%s</%s></b>, " % (flagColor, flag, flagColor) if len(self.vals["tor/flags"]) > 0: flagLine = flagLine[:-2] else: flagLine += "<b><cyan>none</cyan></b>" self.addfstr(2 if isWide else 4, 0, flagLine) else: statusTime = torTools.getConn().getStatus()[1] statusTimeLabel = time.strftime("%H:%M %m/%d/%Y", time.localtime(statusTime)) self.addfstr( 2 if isWide else 4, 0, "<b><red>Tor Disconnected</red></b> (%s)" % statusTimeLabel) # Undisplayed / Line 3 Right (exit policy) if isWide: exitPolicy = self.vals["tor/exitPolicy"] # adds note when default exit policy is appended if exitPolicy == "": exitPolicy = "<default>" elif not exitPolicy.endswith((" *:*", " *")): exitPolicy += ", <default>" # color codes accepts to be green, rejects to be red, and default marker to be cyan isSimple = len(exitPolicy) > rightWidth - 13 policies = exitPolicy.split(", ") for i in range(len(policies)): policy = policies[i].strip() displayedPolicy = policy.replace("accept", "").replace( "reject", "").strip() if isSimple else policy if policy.startswith("accept"): policy = "<green><b>%s</b></green>" % displayedPolicy elif policy.startswith("reject"): policy = "<red><b>%s</b></red>" % displayedPolicy elif policy.startswith("<default>"): policy = "<cyan><b>%s</b></cyan>" % displayedPolicy policies[i] = policy self.addfstr(2, leftWidth, "exit policy: %s" % ", ".join(policies)) else: # Client only # TODO: not sure what information to provide here... pass self._isLastDrawWide = isWide self._isChanged = False self.valsLock.release()