def CreatePanel(self): self.list = SelectableListCtrl(self) self.list.InsertColumn(0, 'Torrent') self.list.setResizeColumn(0) self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) self.list.SetMinSize((1, 80)) return self.list
class NewTorrentPanel(HomePanel): def __init__(self, parent): HomePanel.__init__(self, parent, 'Newest Torrents', SEPARATOR_GREY, (0, 1)) self.Layout() session = parent.guiutility.utility.session self.torrentdb = session.open_dbhandler(NTFY_TORRENTS) session.add_observer(self.OnNotify, NTFY_TORRENTS, [NTFY_INSERT]) def CreatePanel(self): self.list = SelectableListCtrl(self) self.list.InsertColumn(0, 'Torrent') self.list.setResizeColumn(0) self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) self.list.SetMinSize((1, 80)) return self.list def OnNotify(self, subject, type, infohash): try: if self.IsShownOnScreen(): self.UpdateStats(infohash) except wx.PyDeadObjectError: pass def UpdateStats(self, infohash): def db_callback(): torrent = self.torrentdb.getTorrent(infohash, include_mypref=False) if torrent: self._UpdateStats(torrent) startWorker(None, db_callback, uId=u"NewTorrentPanel_UpdateStats", priority=GUI_PRI_DISPERSY) @forceWxThread def _UpdateStats(self, torrent): self.list.InsertStringItem(0, torrent['name']) size = self.list.GetItemCount() if size > 10: self.list.DeleteItem(size - 1) def OnDoubleClick(self, event): selected = self.list.GetFirstSelected() if selected != -1: selected_file = self.list.GetItemText(selected) self.guiutility.dosearch(selected_file)
def AddComponents(self): self.graph_panel = wx.Panel(self, -1) self.graph_panel.Bind(wx.EVT_MOTION, self.OnMouse) self.graph_panel.Bind(wx.EVT_LEFT_UP, self.OnMouse) self.graph_panel.Bind(wx.EVT_PAINT, self.OnPaint) self.graph_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.circuit_list = SelectableListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SIMPLE) self.circuit_list.InsertColumn(0, 'ID', wx.LIST_FORMAT_LEFT, 25) self.circuit_list.InsertColumn(1, 'Online', wx.LIST_FORMAT_RIGHT, 50) self.circuit_list.InsertColumn(2, 'Hops', wx.LIST_FORMAT_RIGHT, 45) self.circuit_list.InsertColumn(3, u'Bytes \u2191', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(4, u'Bytes \u2193', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(5, 'Uptime', wx.LIST_FORMAT_RIGHT, 54) self.circuit_list.setResizeColumn(0) self.circuit_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) self.circuit_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemSelected) self.circuit_to_listindex = {} if self.fullscreen: self.log_text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.BORDER_SIMPLE | wx.HSCROLL & wx.VSCROLL) self.log_text.SetEditable(False) self.log_text.Show(self.fullscreen) self.num_circuits_label = wx.StaticText( self, -1, "You have 0 circuit(s); 0 relay(s); \ 0 exit socket(s); 0 candidate(s)") self.vSizer = wx.BoxSizer(wx.VERTICAL) self.vSizer.Add(self.circuit_list, 1, wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 0) if self.fullscreen: self.vSizer.Add(self.log_text, 1, wx.EXPAND | wx.TOP, 10) self.vSizer.Add(self.num_circuits_label, 0, wx.EXPAND | wx.TOP, 10) self.main_sizer = wx.BoxSizer(wx.HORIZONTAL) self.main_sizer.Add(self.graph_panel, 3, wx.EXPAND | wx.LEFT | wx.TOP | wx.BOTTOM, 10) self.main_sizer.Add(self.vSizer, 2, wx.EXPAND | wx.ALL, 10) self.SetSizer(self.main_sizer)
def AddComponents(self): self.graph_panel = wx.Panel(self, -1) self.graph_panel.Bind(wx.EVT_MOTION, self.OnMouse) self.graph_panel.Bind(wx.EVT_LEFT_UP, self.OnMouse) self.graph_panel.Bind(wx.EVT_PAINT, self.OnPaint) self.graph_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.circuit_list = SelectableListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SIMPLE) self.circuit_list.InsertColumn(0, 'ID', wx.LIST_FORMAT_LEFT, 25) self.circuit_list.InsertColumn(1, 'Online', wx.LIST_FORMAT_RIGHT, 50) self.circuit_list.InsertColumn(2, 'Hops', wx.LIST_FORMAT_RIGHT, 45) self.circuit_list.InsertColumn(3, u'Bytes \u2191', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(4, u'Bytes \u2193', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(5, 'Uptime', wx.LIST_FORMAT_RIGHT, 54) self.circuit_list.setResizeColumn(0) self.circuit_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) self.circuit_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemSelected) self.circuit_to_listindex = {} if self.fullscreen: self.log_text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.BORDER_SIMPLE | wx.HSCROLL & wx.VSCROLL) self.log_text.SetEditable(False) self.log_text.Show(self.fullscreen) self.num_circuits_label = wx.StaticText(self, -1, "You have 0 circuit(s); 0 relay(s); \ 0 exit socket(s); 0 candidate(s)") self.vSizer = wx.BoxSizer(wx.VERTICAL) self.vSizer.Add(self.circuit_list, 1, wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 0) if self.fullscreen: self.vSizer.Add(self.log_text, 1, wx.EXPAND | wx.TOP, 10) self.vSizer.Add(self.num_circuits_label, 0, wx.EXPAND | wx.TOP, 10) self.main_sizer = wx.BoxSizer(wx.HORIZONTAL) self.main_sizer.Add(self.graph_panel, 3, wx.EXPAND | wx.LEFT | wx.TOP | wx.BOTTOM, 10) self.main_sizer.Add(self.vSizer, 2, wx.EXPAND | wx.ALL, 10) self.SetSizer(self.main_sizer)
class NetworkGraphPanel(wx.Panel): def __init__(self, parent, fullscreen=True): wx.Panel.__init__(self, parent, -1) self.SetBackgroundColour(wx.WHITE) self.guiutility = GUIUtility.getInstance() self.utility = self.guiutility.utility self.session = self.utility.session self.dispersy = self.utility.session.lm.dispersy self.swarm = GuiImageManager.getInstance().getImage(u"darknet.png") self.font_small = self.GetFont() self.font_large = self.GetFont() self.font_large.SetPointSize(self.font_large.GetPointSize() + 2) self.circuits = {} self.circuits_old = None self.hop_to_colour = {} self.colours = [ wx.RED, wx.Colour(156, 18, 18), wx.Colour(183, 83, 83), wx.Colour(254, 134, 134), wx.Colour(254, 190, 190) ] self.selected_circuit = None self.hop_hover_evt = None self.hop_hover = None self.hop_active_evt = None self.hop_active = None self.hops = -1 self.fullscreen = fullscreen self.radius = 20 if self.fullscreen else 12 self.line_width = 2 if self.fullscreen else 1 self.margin_x = self.margin_y = self.radius self.swarm_size = wx.Size(180, 60) self.AddComponents() self.tunnel_community = None self.try_community() def try_community(self): try: tunnel_community = ( c for c in self.dispersy.get_communities() if isinstance(c, HiddenTunnelCommunity)).next() self.found_community(tunnel_community) except: wx.CallLater(1000, self.try_community) def found_community(self, tunnel_community): self.tunnel_community = tunnel_community self.my_address = Hop(self.tunnel_community.my_member._ec.pub()) self.my_address.address = ('127.0.0.1', "SELF") self.circuit_timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.OnUpdateCircuits, self.circuit_timer) self.circuit_timer.Start(5000) if self.fullscreen: self.session.add_observer( self.OnExtended, NTFY_TUNNEL, [NTFY_CREATED, NTFY_EXTENDED, NTFY_BROKEN]) self.session.add_observer(self.OnSelect, NTFY_TUNNEL, [NTFY_SELECT]) self.session.add_observer(self.OnJoined, NTFY_TUNNEL, [NTFY_JOINED]) self.session.add_observer(self.OnExtendedFor, NTFY_TUNNEL, [NTFY_EXTENDED_FOR]) self.session.add_observer(self.OnIpRemoved, NTFY_TUNNEL, [NTFY_IP_REMOVED]) self.session.add_observer(self.OnRpRemoved, NTFY_TUNNEL, [NTFY_RP_REMOVED]) self.session.add_observer(self.OnIpRecreate, NTFY_TUNNEL, [NTFY_IP_RECREATE]) self.session.add_observer(self.OnDhtLookup, NTFY_TUNNEL, [NTFY_DHT_LOOKUP]) self.session.add_observer(self.OnKeyRequest, NTFY_TUNNEL, [NTFY_KEY_REQUEST]) self.session.add_observer(self.OnKeyRespond, NTFY_TUNNEL, [NTFY_KEY_RESPOND]) self.session.add_observer(self.OnKeyResponse, NTFY_TUNNEL, [NTFY_KEY_RESPONSE]) self.session.add_observer(self.OnCreateE2E, NTFY_TUNNEL, [NTFY_CREATE_E2E]) self.session.add_observer(self.OnCreatedE2E, NTFY_TUNNEL, [NTFY_ONCREATED_E2E]) self.session.add_observer(self.OnIpCreated, NTFY_TUNNEL, [NTFY_IP_CREATED]) self.session.add_observer(self.OnRpCreated, NTFY_TUNNEL, [NTFY_RP_CREATED]) def AddComponents(self): self.graph_panel = wx.Panel(self, -1) self.graph_panel.Bind(wx.EVT_MOTION, self.OnMouse) self.graph_panel.Bind(wx.EVT_LEFT_UP, self.OnMouse) self.graph_panel.Bind(wx.EVT_PAINT, self.OnPaint) self.graph_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.circuit_list = SelectableListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SIMPLE) self.circuit_list.InsertColumn(0, 'ID', wx.LIST_FORMAT_LEFT, 25) self.circuit_list.InsertColumn(1, 'Online', wx.LIST_FORMAT_RIGHT, 50) self.circuit_list.InsertColumn(2, 'Hops', wx.LIST_FORMAT_RIGHT, 45) self.circuit_list.InsertColumn(3, u'Bytes \u2191', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(4, u'Bytes \u2193', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(5, 'Uptime', wx.LIST_FORMAT_RIGHT, 54) self.circuit_list.setResizeColumn(0) self.circuit_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) self.circuit_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemSelected) self.circuit_to_listindex = {} if self.fullscreen: self.log_text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.BORDER_SIMPLE | wx.HSCROLL & wx.VSCROLL) self.log_text.SetEditable(False) self.log_text.Show(self.fullscreen) self.num_circuits_label = wx.StaticText( self, -1, "You have 0 circuit(s); 0 relay(s); \ 0 exit socket(s); 0 candidate(s)") self.vSizer = wx.BoxSizer(wx.VERTICAL) self.vSizer.Add(self.circuit_list, 1, wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 0) if self.fullscreen: self.vSizer.Add(self.log_text, 1, wx.EXPAND | wx.TOP, 10) self.vSizer.Add(self.num_circuits_label, 0, wx.EXPAND | wx.TOP, 10) self.main_sizer = wx.BoxSizer(wx.HORIZONTAL) self.main_sizer.Add(self.graph_panel, 3, wx.EXPAND | wx.LEFT | wx.TOP | wx.BOTTOM, 10) self.main_sizer.Add(self.vSizer, 2, wx.EXPAND | wx.ALL, 10) self.SetSizer(self.main_sizer) def ShowTunnels(self, hops): self.circuit_list.Show(hops != 0) self.hops = hops self.OnUpdateCircuits(None) def OnItemSelected(self, event): selected = [] item = self.circuit_list.GetFirstSelected() while item != -1: selected.append(item) item = self.circuit_list.GetNextSelected(item) self.selected_circuit = None for item in selected: for circuit_id, listindex in self.circuit_to_listindex.iteritems(): if listindex == item and circuit_id in self.circuits: self.selected_circuit = self.circuits[circuit_id] self.graph_panel.Refresh() def OnUpdateCircuits(self, event): if not self.tunnel_community: return if self.fullscreen: self.num_circuits_label.SetLabel( "You have %d circuit(s); %d relay(s); %d exit socket(s); %d candidate(s)" % (len(self.tunnel_community.circuits), len(self.tunnel_community.relay_from_to), len(self.tunnel_community.exit_sockets), sum(1 for _ in self.tunnel_community. dispersy_yield_verified_candidates()))) new_circuits = dict(self.tunnel_community.circuits) self.circuits = { k: v for k, v in new_circuits.iteritems() if v.goal_hops == self.hops or self.hops < 0 } # Add new circuits & update existing circuits for circuit_id, circuit in self.circuits.iteritems(): if circuit_id not in self.circuit_to_listindex: pos = self.circuit_list.InsertStringItem( sys.maxsize, str(circuit_id)) self.circuit_to_listindex[circuit_id] = pos else: pos = self.circuit_to_listindex[circuit_id] self.circuit_list.SetStringItem(pos, 1, str(circuit.state)) self.circuit_list.SetStringItem( pos, 2, str(len(circuit.hops)) + "/" + str(circuit.goal_hops)) bytes_uploaded = circuit.bytes_up bytes_downloaded = circuit.bytes_down self.circuit_list.SetStringItem(pos, 3, size_format(bytes_uploaded)) self.circuit_list.SetStringItem(pos, 4, size_format(bytes_downloaded)) self.circuit_list.SetStringItem( pos, 5, "%d" % (time() - circuit.creation_time)) # Remove old circuits old_circuits = [ circuit_id for circuit_id in self.circuit_to_listindex if circuit_id not in self.circuits ] for circuit_id in old_circuits: listindex = self.circuit_to_listindex[circuit_id] self.circuit_list.DeleteItem(listindex) self.circuit_to_listindex.pop(circuit_id) for k, v in self.circuit_to_listindex.items(): if v > listindex: self.circuit_to_listindex[k] = v - 1 self.graph_panel.Refresh() def AppendToLog(self, msg): if not self: return self.log_text.AppendText( '[%s]: %s' % (datetime.datetime.now().strftime("%H:%M:%S"), msg)) @forceWxThread def OnExtended(self, subject, changeType, circuit): if not self: return if changeType == NTFY_CREATED: self.AppendToLog("Created circuit %s\n" % (circuit.circuit_id)) if changeType == NTFY_EXTENDED: self.AppendToLog("Extended circuit %s\n" % (circuit.circuit_id)) if changeType == NTFY_BROKEN: self.AppendToLog("Circuit %d has been broken\n" % circuit) @forceWxThread def OnSelect(self, subject, changeType, circuit, address): if not self: return self.AppendToLog("Circuit %d has been selected for destination %s\n" % (circuit, address)) @forceWxThread def OnJoined(self, subject, changeType, address, circuit_id): if not self: return self.AppendToLog("Joined an external circuit %d with %s:%d\n" % (circuit_id, address[0], address[1])) @forceWxThread def OnExtendedFor(self, subject, changeType, extended_for, extended_with): if not self: return self.AppendToLog( "Extended an external circuit (%s:%d, %d) with (%s:%d, %d)\n" % (extended_for[0].sock_addr[0], extended_for[0].sock_addr[1], extended_for[1], extended_with[0].sock_addr[0], extended_with[0].sock_addr[1], extended_with[1])) @forceWxThread def OnIpRemoved(self, subject, changeType, circuit_id): if not self: return self.AppendToLog("Removed introduction circuit %d\n" % (circuit_id)) @forceWxThread def OnIpRecreate(self, subject, changeType, circuit_id, info_hash): if not self: return self.AppendToLog( "Recreate introduction circuit to replace circuit %d for info_hash %s\n" % (circuit_id, info_hash)) @forceWxThread def OnRpRemoved(self, subject, changeType, circuit_id): if not self: return self.AppendToLog("Removed rendezvous circuit %d\n" % (circuit_id)) @forceWxThread def OnDhtLookup(self, subject, changeType, info_hash, peers): if not self: return self.AppendToLog( "DHT lookup for info_hash %s resulted in peers: %s\n" % (info_hash, repr(peers))) @forceWxThread def OnKeyRequest(self, subject, changeType, info_hash, peer): if not self: return self.AppendToLog("Request key for info_hash %s from %s\n" % (info_hash, repr(peer))) @forceWxThread def OnKeyRespond(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Respond with key for info_hash %s to circuit %s\n" % (info_hash, circuit_id)) @forceWxThread def OnKeyResponse(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Respond with key for info_hash %s to circuit %s\n" % (info_hash, circuit_id)) @forceWxThread def OnCreateE2E(self, subject, changeType, info_hash): if not self: return self.AppendToLog("Create end-to-end for info_hash %s\n" % (info_hash)) @forceWxThread def OnCreatedE2E(self, subject, changeType, info_hash, rp_addr): if not self: return self.AppendToLog("Connect rendezvous %s for info_hash %s\n" % (repr(rp_addr[0]), info_hash)) @forceWxThread def OnIpCreated(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog( "Created introduction point %s for info_hash on circuit %d\n" % (info_hash, circuit_id)) @forceWxThread def OnRpCreated(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog( "Created rendezvous point %s for info_hash on circuit %d\n" % (info_hash, circuit_id)) def OnMouse(self, event): if event.Moving(): self.hop_hover_evt = event.GetPosition() self.graph_panel.Refresh() elif event.LeftUp(): self.hop_active_evt = event.GetPosition() self.graph_panel.Refresh() def OnSize(self, evt): size = min(*evt.GetEventObject().GetSize()) x = min(size + self.margin_x * 2 + self.swarm.GetSize().x, self.GetSize().x - self.circuit_list.GetSize().x) y = size + self.margin_y * 2 self.graph_panel.SetSize((x, y)) def OnEraseBackground(self, event): pass def OnPaint(self, event): eo = event.GetEventObject() dc = wx.BufferedPaintDC(eo) dc.SetFont(self.font_large) dc.Clear() gc = wx.GraphicsContext.Create(dc) swarm_size = self.swarm.GetSize() w = eo.GetSize().x - 2 * self.margin_x - 1 - swarm_size.x h = eo.GetSize().y - 2 * self.margin_y - 1 swarm_pos = (eo.GetSize().x - swarm_size.x - 11, h / 2 - swarm_size.y / 2 + 11) swarm_center = (eo.GetSize().x - swarm_size.x / 2, h / 2 + self.margin_y) circuit_points = {} if self.hops != 0: num_circuits = len(self.circuits) for c_index, circuit in enumerate( sorted(self.circuits.values(), key=lambda c: c.circuit_id)): circuit_points[circuit] = [(self.margin_x, h / 2 + self.margin_y)] for h_index, hop in enumerate(circuit.hops): circuit_points[circuit].append( (w * (float(h_index + 1) / (circuit.goal_hops + 1)) + self.margin_x, h * (float(c_index + 0.5) / num_circuits) + self.margin_y)) else: circuit_points[None] = [(self.margin_x, h / 2 + self.margin_y)] gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) # Draw edges for circuit, points in circuit_points.iteritems(): for point1, point2 in zip(points[0::1], points[1::1]): if circuit == self.selected_circuit: gc.SetPen(wx.Pen(wx.BLUE, self.line_width)) else: gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) gc.DrawLines([point1, point2]) # If exit node, draw edge to bittorrent swarm if not circuit or circuit.goal_hops == len(circuit.hops): gc.DrawLines([points[-1], swarm_center]) # Draw vertices gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) for circuit, points in circuit_points.iteritems(): for index, point in enumerate(points): hop = (circuit, index) colour = self.hop_to_colour.get(hop, None) if not colour: self.hop_to_colour[hop] = colour = random.choice( self.colours[1:]) if index > 0 else self.colours[0] x, y = point gc.SetBrush(wx.Brush(colour)) gc.DrawEllipse(x - self.radius / 2, y - self.radius / 2, self.radius, self.radius) # Draw swarm and darknet gc.DrawBitmap(self.swarm, swarm_pos[0], swarm_pos[1], *swarm_size) self.DrawHoverAndInfo(gc, dc, circuit_points) def DrawHoverAndInfo(self, gc, dc, circuit_points): gc.SetBrush(wx.TRANSPARENT_BRUSH) if self.hop_hover_evt: self.hop_hover = self.PositionToCircuit(self.hop_hover_evt, circuit_points) self.hop_hover_evt = None if self.hop_hover and self.hop_hover[0] in circuit_points: circuit, hop_index = self.hop_hover x, y = circuit_points[circuit][hop_index] pen = wx.Pen(wx.Colour(229, 229, 229), 1, wx.USER_DASH) pen.SetDashes([8, 4]) gc.SetPen(pen) gc.DrawEllipse(x - self.radius, y - self.radius, self.radius * 2, self.radius * 2) if self.hop_active_evt: self.hop_active = self.PositionToCircuit(self.hop_active_evt, circuit_points) self.hop_active_evt = None if self.hop_active and self.hop_active[0] in circuit_points and \ (not self.hop_active[0] or self.hop_active[1] <= len(self.hop_active[0].hops)): circuit, hop_index = self.hop_active hop = circuit.hops[hop_index - 1] if hop_index and circuit else None x, y = circuit_points[circuit][hop_index] # Draw cicle around node pen = wx.Pen(self.hop_to_colour.get(self.hop_active, wx.BLACK), 1, wx.USER_DASH) pen.SetDashes([8, 4]) gc.SetPen(pen) gc.DrawEllipse(x - self.radius, y - self.radius, self.radius * 2, self.radius * 2) # Determine text dc.SetFont(self.font_small) if not hop: text = 'You\nPERMID ' + bin2str( self.tunnel_community.my_member.public_key)[:10] else: text = 'PERMID ' + bin2str( self.dispersy.crypto.key_to_hash(hop.public_key))[:10] if 'UNKNOWN HOST' not in hop.host: text = 'IP %s:%s\n' % (hop.host, hop.port) + text # Draw info box + text box_width, box_height = self.GetTextExtent(dc, text) box_width += 10 box_height += 10 x = x - box_width - 1.1 * self.radius if x > self.graph_panel.GetSize( )[0] / 2 else x + 1.1 * self.radius y = y - box_height - 1.1 * self.radius if y > self.graph_panel.GetSize( )[1] / 2 else y + 1.1 * self.radius gc.SetBrush(wx.Brush(wx.Colour(216, 237, 255, 50))) gc.SetPen(wx.Pen(LIST_BLUE)) gc.DrawRectangle(x, y, box_width, box_height) self.DrawText(dc, text, x + 5, y + 5) def GetTextExtent(self, dc, text): w_list, h_list = zip( *[dc.GetTextExtent(line) for line in text.split('\n')]) return max(w_list), sum(h_list) def DrawText(self, dc, text, x, y): # For wxPython 2.8, newline separated text does not always work with gc.DrawText y_cur = y for line in text.split('\n'): dc.DrawText(line, x, y_cur) _, h = dc.GetTextExtent(line) y_cur += h def PositionToCircuit(self, position, circuit_points): for circuit, points in circuit_points.iteritems(): for index, point in enumerate(points): if (position[0] - point[0])**2 + ( position[1] - point[1])**2 < self.radius**2: return (circuit, index) return None def ResetSearchBox(self): pass
class NetworkGraphPanel(wx.Panel): def __init__(self, parent, fullscreen=True): wx.Panel.__init__(self, parent, -1) self.SetBackgroundColour(wx.WHITE) self.guiutility = GUIUtility.getInstance() self.utility = self.guiutility.utility self.session = self.utility.session self.dispersy = self.utility.session.lm.dispersy self.swarm = GuiImageManager.getInstance().getImage(u"darknet.png") self.font_small = self.GetFont() self.font_large = self.GetFont() self.font_large.SetPointSize(self.font_large.GetPointSize() + 2) self.circuits = {} self.circuits_old = None self.hop_to_colour = {} self.colours = [wx.RED, wx.Colour(156, 18, 18), wx.Colour(183, 83, 83), wx.Colour(254, 134, 134), wx.Colour(254, 190, 190)] self.selected_circuit = None self.hop_hover_evt = None self.hop_hover = None self.hop_active_evt = None self.hop_active = None self.hops = -1 self.fullscreen = fullscreen self.radius = 20 if self.fullscreen else 12 self.line_width = 2 if self.fullscreen else 1 self.margin_x = self.margin_y = self.radius self.swarm_size = wx.Size(180, 60) self.AddComponents() self.tunnel_community = None self.try_community() def try_community(self): try: tunnel_community = ( c for c in self.dispersy.get_communities( ) if isinstance( c, HiddenTunnelCommunity)).next( ) self.found_community(tunnel_community) except: wx.CallLater(1000, self.try_community) def found_community(self, tunnel_community): self.tunnel_community = tunnel_community self.my_address = Hop(self.tunnel_community.my_member._ec.pub()) self.my_address.address = ('127.0.0.1', "SELF") self.circuit_timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.OnUpdateCircuits, self.circuit_timer) self.circuit_timer.Start(5000) if self.fullscreen: self.session.add_observer(self.OnExtended, NTFY_TUNNEL, [NTFY_CREATED, NTFY_EXTENDED, NTFY_BROKEN]) self.session.add_observer(self.OnSelect, NTFY_TUNNEL, [NTFY_SELECT]) self.session.add_observer(self.OnJoined, NTFY_TUNNEL, [NTFY_JOINED]) self.session.add_observer(self.OnExtendedFor, NTFY_TUNNEL, [NTFY_EXTENDED_FOR]) self.session.add_observer(self.OnIpRemoved, NTFY_TUNNEL, [NTFY_IP_REMOVED]) self.session.add_observer(self.OnRpRemoved, NTFY_TUNNEL, [NTFY_RP_REMOVED]) self.session.add_observer(self.OnIpRecreate, NTFY_TUNNEL, [NTFY_IP_RECREATE]) self.session.add_observer(self.OnDhtLookup, NTFY_TUNNEL, [NTFY_DHT_LOOKUP]) self.session.add_observer(self.OnKeyRequest, NTFY_TUNNEL, [NTFY_KEY_REQUEST]) self.session.add_observer(self.OnKeyRespond, NTFY_TUNNEL, [NTFY_KEY_RESPOND]) self.session.add_observer(self.OnKeyResponse, NTFY_TUNNEL, [NTFY_KEY_RESPONSE]) self.session.add_observer(self.OnCreateE2E, NTFY_TUNNEL, [NTFY_CREATE_E2E]) self.session.add_observer(self.OnCreatedE2E, NTFY_TUNNEL, [NTFY_ONCREATED_E2E]) self.session.add_observer(self.OnIpCreated, NTFY_TUNNEL, [NTFY_IP_CREATED]) self.session.add_observer(self.OnRpCreated, NTFY_TUNNEL, [NTFY_RP_CREATED]) def AddComponents(self): self.graph_panel = wx.Panel(self, -1) self.graph_panel.Bind(wx.EVT_MOTION, self.OnMouse) self.graph_panel.Bind(wx.EVT_LEFT_UP, self.OnMouse) self.graph_panel.Bind(wx.EVT_PAINT, self.OnPaint) self.graph_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.circuit_list = SelectableListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SIMPLE) self.circuit_list.InsertColumn(0, 'ID', wx.LIST_FORMAT_LEFT, 25) self.circuit_list.InsertColumn(1, 'Online', wx.LIST_FORMAT_RIGHT, 50) self.circuit_list.InsertColumn(2, 'Hops', wx.LIST_FORMAT_RIGHT, 45) self.circuit_list.InsertColumn(3, u'Bytes \u2191', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(4, u'Bytes \u2193', wx.LIST_FORMAT_RIGHT, 83) self.circuit_list.InsertColumn(5, 'Uptime', wx.LIST_FORMAT_RIGHT, 54) self.circuit_list.setResizeColumn(0) self.circuit_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) self.circuit_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemSelected) self.circuit_to_listindex = {} if self.fullscreen: self.log_text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.BORDER_SIMPLE | wx.HSCROLL & wx.VSCROLL) self.log_text.SetEditable(False) self.log_text.Show(self.fullscreen) self.num_circuits_label = wx.StaticText(self, -1, "You have 0 circuit(s); 0 relay(s); \ 0 exit socket(s); 0 candidate(s)") self.vSizer = wx.BoxSizer(wx.VERTICAL) self.vSizer.Add(self.circuit_list, 1, wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 0) if self.fullscreen: self.vSizer.Add(self.log_text, 1, wx.EXPAND | wx.TOP, 10) self.vSizer.Add(self.num_circuits_label, 0, wx.EXPAND | wx.TOP, 10) self.main_sizer = wx.BoxSizer(wx.HORIZONTAL) self.main_sizer.Add(self.graph_panel, 3, wx.EXPAND | wx.LEFT | wx.TOP | wx.BOTTOM, 10) self.main_sizer.Add(self.vSizer, 2, wx.EXPAND | wx.ALL, 10) self.SetSizer(self.main_sizer) def ShowTunnels(self, hops): self.circuit_list.Show(hops != 0) self.hops = hops self.OnUpdateCircuits(None) def OnItemSelected(self, event): selected = [] item = self.circuit_list.GetFirstSelected() while item != -1: selected.append(item) item = self.circuit_list.GetNextSelected(item) self.selected_circuit = None for item in selected: for circuit_id, listindex in self.circuit_to_listindex.iteritems(): if listindex == item and circuit_id in self.circuits: self.selected_circuit = self.circuits[circuit_id] self.graph_panel.Refresh() def OnUpdateCircuits(self, event): if not self.tunnel_community: return if self.fullscreen: self.num_circuits_label.SetLabel("You have %d circuit(s); %d relay(s); %d exit socket(s); %d candidate(s)" % (len(self.tunnel_community.circuits), len(self.tunnel_community.relay_from_to), len(self.tunnel_community.exit_sockets), sum(1 for _ in self.tunnel_community.dispersy_yield_verified_candidates()))) new_circuits = dict(self.tunnel_community.circuits) self.circuits = {k: v for k, v in new_circuits.iteritems() if v.goal_hops == self.hops or self.hops < 0} # Add new circuits & update existing circuits for circuit_id, circuit in self.circuits.iteritems(): if circuit_id not in self.circuit_to_listindex: pos = self.circuit_list.InsertStringItem(sys.maxsize, str(circuit_id)) self.circuit_to_listindex[circuit_id] = pos else: pos = self.circuit_to_listindex[circuit_id] self.circuit_list.SetStringItem(pos, 1, str(circuit.state)) self.circuit_list.SetStringItem(pos, 2, str(len(circuit.hops)) + "/" + str(circuit.goal_hops)) bytes_uploaded = circuit.bytes_up bytes_downloaded = circuit.bytes_down self.circuit_list.SetStringItem(pos, 3, size_format(bytes_uploaded)) self.circuit_list.SetStringItem(pos, 4, size_format(bytes_downloaded)) self.circuit_list.SetStringItem(pos, 5, "%d" % (time() - circuit.creation_time)) # Remove old circuits old_circuits = [circuit_id for circuit_id in self.circuit_to_listindex if circuit_id not in self.circuits] for circuit_id in old_circuits: listindex = self.circuit_to_listindex[circuit_id] self.circuit_list.DeleteItem(listindex) self.circuit_to_listindex.pop(circuit_id) for k, v in self.circuit_to_listindex.items(): if v > listindex: self.circuit_to_listindex[k] = v - 1 self.graph_panel.Refresh() def AppendToLog(self, msg): if not self: return self.log_text.AppendText('[%s]: %s' % (datetime.datetime.now().strftime("%H:%M:%S"), msg)) @forceWxThread def OnExtended(self, subject, changeType, circuit): if not self: return if changeType == NTFY_CREATED: self.AppendToLog("Created circuit %s\n" % (circuit.circuit_id)) if changeType == NTFY_EXTENDED: self.AppendToLog("Extended circuit %s\n" % (circuit.circuit_id)) if changeType == NTFY_BROKEN: self.AppendToLog("Circuit %d has been broken\n" % circuit) @forceWxThread def OnSelect(self, subject, changeType, circuit, address): if not self: return self.AppendToLog("Circuit %d has been selected for destination %s\n" % (circuit, address)) @forceWxThread def OnJoined(self, subject, changeType, address, circuit_id): if not self: return self.AppendToLog("Joined an external circuit %d with %s:%d\n" % (circuit_id, address[0], address[1])) @forceWxThread def OnExtendedFor(self, subject, changeType, extended_for, extended_with): if not self: return self.AppendToLog("Extended an external circuit (%s:%d, %d) with (%s:%d, %d)\n" % ( extended_for[0].sock_addr[0], extended_for[0].sock_addr[1], extended_for[1], extended_with[0].sock_addr[0], extended_with[0].sock_addr[1], extended_with[1])) @forceWxThread def OnIpRemoved(self, subject, changeType, circuit_id): if not self: return self.AppendToLog("Removed introduction circuit %d\n" % (circuit_id)) @forceWxThread def OnIpRecreate(self, subject, changeType, circuit_id, info_hash): if not self: return self.AppendToLog("Recreate introduction circuit to replace circuit %d for info_hash %s\n" % (circuit_id, info_hash)) @forceWxThread def OnRpRemoved(self, subject, changeType, circuit_id): if not self: return self.AppendToLog("Removed rendezvous circuit %d\n" % (circuit_id)) @forceWxThread def OnDhtLookup(self, subject, changeType, info_hash, peers): if not self: return self.AppendToLog("DHT lookup for info_hash %s resulted in peers: %s\n" % (info_hash, repr(peers))) @forceWxThread def OnKeyRequest(self, subject, changeType, info_hash, peer): if not self: return self.AppendToLog("Request key for info_hash %s from %s\n" % (info_hash, repr(peer))) @forceWxThread def OnKeyRespond(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Respond with key for info_hash %s to circuit %s\n" % (info_hash, circuit_id)) @forceWxThread def OnKeyResponse(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Respond with key for info_hash %s to circuit %s\n" % (info_hash, circuit_id)) @forceWxThread def OnCreateE2E(self, subject, changeType, info_hash): if not self: return self.AppendToLog("Create end-to-end for info_hash %s\n" % (info_hash)) @forceWxThread def OnCreatedE2E(self, subject, changeType, info_hash, rp_addr): if not self: return self.AppendToLog("Connect rendezvous %s for info_hash %s\n" % (repr(rp_addr[0]), info_hash)) @forceWxThread def OnIpCreated(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Created introduction point %s for info_hash on circuit %d\n" % (info_hash, circuit_id)) @forceWxThread def OnRpCreated(self, subject, changeType, info_hash, circuit_id): if not self: return self.AppendToLog("Created rendezvous point %s for info_hash on circuit %d\n" % (info_hash, circuit_id)) def OnMouse(self, event): if event.Moving(): self.hop_hover_evt = event.GetPosition() self.graph_panel.Refresh() elif event.LeftUp(): self.hop_active_evt = event.GetPosition() self.graph_panel.Refresh() def OnSize(self, evt): size = min(*evt.GetEventObject().GetSize()) x = min(size + self.margin_x * 2 + self.swarm.GetSize().x, self.GetSize().x - self.circuit_list.GetSize().x) y = size + self.margin_y * 2 self.graph_panel.SetSize((x, y)) def OnEraseBackground(self, event): pass def OnPaint(self, event): eo = event.GetEventObject() dc = wx.BufferedPaintDC(eo) dc.SetFont(self.font_large) dc.Clear() gc = wx.GraphicsContext.Create(dc) swarm_size = self.swarm.GetSize() w = eo.GetSize().x - 2 * self.margin_x - 1 - swarm_size.x h = eo.GetSize().y - 2 * self.margin_y - 1 swarm_pos = (eo.GetSize().x - swarm_size.x - 11, h / 2 - swarm_size.y / 2 + 11) swarm_center = (eo.GetSize().x - swarm_size.x / 2, h / 2 + self.margin_y) circuit_points = {} if self.hops != 0: num_circuits = len(self.circuits) for c_index, circuit in enumerate(sorted(self.circuits.values(), key=lambda c: c.circuit_id)): circuit_points[circuit] = [(self.margin_x, h / 2 + self.margin_y)] for h_index, hop in enumerate(circuit.hops): circuit_points[circuit].append((w * (float(h_index + 1) / (circuit.goal_hops + 1)) + self.margin_x, h * (float(c_index + 0.5) / num_circuits) + self.margin_y)) else: circuit_points[None] = [(self.margin_x, h / 2 + self.margin_y)] gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) # Draw edges for circuit, points in circuit_points.iteritems(): for point1, point2 in zip(points[0::1], points[1::1]): if circuit == self.selected_circuit: gc.SetPen(wx.Pen(wx.BLUE, self.line_width)) else: gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) gc.DrawLines([point1, point2]) # If exit node, draw edge to bittorrent swarm if not circuit or circuit.goal_hops == len(circuit.hops): gc.DrawLines([points[-1], swarm_center]) # Draw vertices gc.SetPen(wx.Pen(wx.Colour(229, 229, 229), self.line_width)) for circuit, points in circuit_points.iteritems(): for index, point in enumerate(points): hop = (circuit, index) colour = self.hop_to_colour.get(hop, None) if not colour: self.hop_to_colour[hop] = colour = random.choice(self.colours[1:]) if index > 0 else self.colours[0] x, y = point gc.SetBrush(wx.Brush(colour)) gc.DrawEllipse(x - self.radius / 2, y - self.radius / 2, self.radius, self.radius) # Draw swarm and darknet gc.DrawBitmap(self.swarm, swarm_pos[0], swarm_pos[1], *swarm_size) self.DrawHoverAndInfo(gc, dc, circuit_points) def DrawHoverAndInfo(self, gc, dc, circuit_points): gc.SetBrush(wx.TRANSPARENT_BRUSH) if self.hop_hover_evt: self.hop_hover = self.PositionToCircuit(self.hop_hover_evt, circuit_points) self.hop_hover_evt = None if self.hop_hover and self.hop_hover[0] in circuit_points: circuit, hop_index = self.hop_hover x, y = circuit_points[circuit][hop_index] pen = wx.Pen(wx.Colour(229, 229, 229), 1, wx.USER_DASH) pen.SetDashes([8, 4]) gc.SetPen(pen) gc.DrawEllipse(x - self.radius, y - self.radius, self.radius * 2, self.radius * 2) if self.hop_active_evt: self.hop_active = self.PositionToCircuit(self.hop_active_evt, circuit_points) self.hop_active_evt = None if self.hop_active and self.hop_active[0] in circuit_points and \ (not self.hop_active[0] or self.hop_active[1] <= len(self.hop_active[0].hops)): circuit, hop_index = self.hop_active hop = circuit.hops[hop_index - 1] if hop_index and circuit else None x, y = circuit_points[circuit][hop_index] # Draw cicle around node pen = wx.Pen(self.hop_to_colour.get(self.hop_active, wx.BLACK), 1, wx.USER_DASH) pen.SetDashes([8, 4]) gc.SetPen(pen) gc.DrawEllipse(x - self.radius, y - self.radius, self.radius * 2, self.radius * 2) # Determine text dc.SetFont(self.font_small) if not hop: text = 'You\nPERMID ' + bin2str(self.tunnel_community.my_member.public_key)[:10] else: text = 'PERMID ' + bin2str(self.dispersy.crypto.key_to_hash(hop.public_key))[:10] if 'UNKNOWN HOST' not in hop.host: text = 'IP %s:%s\n' % (hop.host, hop.port) + text # Draw info box + text box_width, box_height = self.GetTextExtent(dc, text) box_width += 10 box_height += 10 x = x - box_width - 1.1 * self.radius if x > self.graph_panel.GetSize()[0] / 2 else x + 1.1 * self.radius y = y - box_height - 1.1 * self.radius if y > self.graph_panel.GetSize()[1] / 2 else y + 1.1 * self.radius gc.SetBrush(wx.Brush(wx.Colour(216, 237, 255, 50))) gc.SetPen(wx.Pen(LIST_BLUE)) gc.DrawRectangle(x, y, box_width, box_height) self.DrawText(dc, text, x + 5, y + 5) def GetTextExtent(self, dc, text): w_list, h_list = zip(*[dc.GetTextExtent(line) for line in text.split('\n')]) return max(w_list), sum(h_list) def DrawText(self, dc, text, x, y): # For wxPython 2.8, newline separated text does not always work with gc.DrawText y_cur = y for line in text.split('\n'): dc.DrawText(line, x, y_cur) _, h = dc.GetTextExtent(line) y_cur += h def PositionToCircuit(self, position, circuit_points): for circuit, points in circuit_points.iteritems(): for index, point in enumerate(points): if (position[0] - point[0]) ** 2 + (position[1] - point[1]) ** 2 < self.radius ** 2: return (circuit, index) return None def ResetSearchBox(self): pass