class TestEncryption(DCSATestCase): def test_group_creator_should_be_able_to_enable_encryption_on_group_creation(self): self.c = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.c.start() self._registerStartedChatSession(self.c) self.c.createGroup() self.c.turnOnEncryption() def test_should_create_cert_and_key_files(self): self.test_group_creator_should_be_able_to_enable_encryption_on_group_creation() def test_should_be_able_to_send_commands_to_other_peers_by_encryption_if_encryption_flag_enabled(self): self.test_group_creator_should_be_able_to_enable_encryption_on_group_creation() self.c2 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.c2.start() self.c2.turnOnEncryption() self._registerStartedChatSession(self.c2) self.c.addUser(self.c2.getListenAddress()) time.sleep(0.2) self.c2_total_msgs = len(self.c2.getChannel().getMessages()) self.c.sendMessage('hi') def test_should_be_able_to_receive_and_decode_commands_from_other_peers_by_encryption_if_encryption_flag_enabled(self): self.test_should_be_able_to_send_commands_to_other_peers_by_encryption_if_encryption_flag_enabled() time.sleep(0.1) self.assertEqual(self.c2_total_msgs + 1, len(self.c2.getChannel().getMessages()))
class MainWindow(wx.Frame): def __init__(self, parent, id, title): self.chat = None wx.Frame.__init__(self, parent, id, title, size=(800,600)) font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT) font.SetPointSize(12) # MENUS filemenu = wx.Menu() fileAbout = filemenu.Append(wx.ID_ANY, "&About DSCA"," Information about this program") filemenu.AppendSeparator() fileExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program") managemenu = wx.Menu() createGroup = managemenu.Append(wx.ID_ANY, "Create Group", "Create a new group if not already in a group") leaveGroup = managemenu.Append(wx.ID_ANY, "Leave Group", "Leave the group") addUser = managemenu.Append(wx.ID_ANY, "Add User", "Add user to group") managemenu.AppendSeparator() channelInfo = managemenu.Append(wx.ID_ANY, "Channel Info", "Get channels and channel membership info") channelMembership = managemenu.Append(wx.ID_ANY, "Join/Leave Channel", "Join or leave a channel") channelLog = managemenu.Append(wx.ID_ANY, "Channel Log History", "Get message history of a channel") menubar = wx.MenuBar() menubar.Append(filemenu, "&File") menubar.Append(managemenu, "Manage") self.SetMenuBar(menubar) # Set events. self.Bind(wx.EVT_MENU, self.OnAbout, fileAbout) self.Bind(wx.EVT_MENU, self.OnExit, fileExit) self.Bind(wx.EVT_MENU, self.OnCreateGroup, createGroup) self.Bind(wx.EVT_MENU, self.OnLeaveGroup, leaveGroup) self.Bind(wx.EVT_MENU, self.OnAddUser, addUser) self.Bind(wx.EVT_MENU, self.OnChannelInfo, channelInfo) self.Bind(wx.EVT_MENU, self.OnChannelMembership, channelMembership) self.Bind(wx.EVT_MENU, self.OnLogHistory, channelLog) mainPanel = wx.Panel(self, wx.ID_ANY) # Beginning of main window vbox = wx.BoxSizer(wx.VERTICAL) # Top button bar hbox0 = wx.BoxSizer(wx.HORIZONTAL) stxt = wx.StaticText(mainPanel, wx.ID_ANY, "IP Address: ") stxt.SetFont(font) hbox0.Add(stxt, 0, wx.ALL, 5) self.ip = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox0.Add(self.ip, 2, wx.EXPAND | wx.ALL, 5) stxt1 = wx.StaticText(mainPanel, wx.ID_ANY, "Port: ") stxt1.SetFont(font) hbox0.Add(stxt1, 0, wx.ALL, 5) self.port = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox0.Add(self.port, 1, wx.EXPAND | wx.ALL, 5) startButton = wx.Button(mainPanel, wx.ID_ANY, label="start") hbox0.Add(startButton, 0, wx.EXPAND | wx.ALL, 5) startButton.Bind(wx.EVT_BUTTON, self.OnStart) stopButton = wx.Button(mainPanel, wx.ID_ANY, label="stop") hbox0.Add(stopButton, 0, wx.EXPAND | wx.ALL, 5) stopButton.Bind(wx.EVT_BUTTON, self.OnStop) logoutButton = wx.Button(mainPanel, wx.ID_ANY, label="logout") hbox0.Add(logoutButton, 0, wx.EXPAND | wx.ALL, 5) logoutButton.Bind(wx.EVT_BUTTON, self.OnLogout) vbox.Add(hbox0, 0, wx.EXPAND) hbox02 = wx.BoxSizer(wx.HORIZONTAL) vbox02 = wx.BoxSizer(wx.VERTICAL) self.curNick = wx.StaticText(mainPanel, wx.ID_ANY, "No Nick") self.curNick.SetFont(font) self.curNick.SetForegroundColour('BLUE') vbox02.Add(self.curNick, 0, wx.LEFT | wx.RIGHT, 20) self.curAddr = wx.StaticText(mainPanel, wx.ID_ANY, "No Address") self.curAddr.SetFont(font) self.curAddr.SetForegroundColour('BLUE') vbox02.Add(self.curAddr, 0, wx.LEFT | wx.RIGHT, 20) hbox02.Add(vbox02, 2, wx.EXPAND) self.newNick = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox02.Add(self.newNick, 1, wx.EXPAND | wx.LEFT, 50) nickButton = wx.Button(mainPanel, wx.ID_ANY, label="Change Nick") hbox02.Add(nickButton, 0, wx.EXPAND | wx.ALL, 5) nickButton.Bind(wx.EVT_BUTTON, self.OnNickChange) vbox.Add(hbox02, 0, wx.EXPAND) # main section of window (chat/group view) mainHbox = wx.BoxSizer(wx.HORIZONTAL) panel1 = wx.Panel(mainPanel, -1) panel1.SetBackgroundColour(wx.LIGHT_GREY) mainHbox.Add(panel1, 7, wx.EXPAND | wx.ALL, 5) vbox1 = wx.BoxSizer(wx.VERTICAL) # chat tabs, 1 tab per channel + a network tab for debugging info self.nb = wx.Notebook(panel1) # initially only lobby and network tabs exist self.lobby = wx.TextCtrl(self.nb, -1, style= wx.TE_MULTILINE | wx.TE_READONLY) self.network = wx.TextCtrl(self.nb, -1, style= wx.TE_MULTILINE | wx.TE_READONLY) # initialize tab dictionary self.channelTabs = {} self.nb.AddPage(self.lobby, 'lobby') self.nb.AddPage(self.network, 'network') vbox1.Add(self.nb, 1, wx.EXPAND) # MESSAGE SENDING INTERFACE panel11 = wx.Panel(panel1, -1) hbox1 = wx.BoxSizer(wx.HORIZONTAL) # channel selection control self.channelSel = wx.Choice(panel11) hbox1.Add(self.channelSel, 0, wx.LEFT | wx.TOP, 5) # message to send box self.msg = wx.TextCtrl(panel11, -1) hbox1.Add(self.msg, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10) # send button send = wx.Button(panel11, wx.ID_ANY, label='send') hbox1.Add(send, 0, wx.TOP | wx.RIGHT, 5) send.Bind(wx.EVT_BUTTON, self.OnSendMsg) panel11.SetSizer(hbox1) vbox1.Add(panel11, 0, wx.EXPAND | wx.BOTTOM, 5) panel1.SetSizer(vbox1) # group view (online and offline users) groupVbox = wx.BoxSizer(wx.VERTICAL) headerPanel1 = wx.Panel(mainPanel, -1) headerHbox1 = wx.BoxSizer(wx.HORIZONTAL) onlineHeader = wx.StaticText(headerPanel1, -1, "ONLINE") onlineHeader.SetFont(font) headerHbox1.Add(onlineHeader, 0, wx.EXPAND | wx.ALL, 5) headerPanel1.SetBackgroundColour('GREEN') onlineHeader.SetForegroundColour('WHITE') headerPanel1.SetSizer(headerHbox1) groupVbox.Add(headerPanel1, 0, wx.EXPAND) self.onlineList = wx.ListBox(mainPanel, wx.ID_ANY, style=wx.LB_SINGLE) groupVbox.Add(self.onlineList, 1, wx.EXPAND) headerPanel2 = wx.Panel(mainPanel, -1) headerHbox2 = wx.BoxSizer(wx.HORIZONTAL) offlineHeader = wx.StaticText(headerPanel2, -1, "OFFLINE") offlineHeader.SetFont(font) headerHbox2.Add(offlineHeader, 0, wx.EXPAND | wx.ALL, 5) headerPanel2.SetBackgroundColour('RED') offlineHeader.SetForegroundColour('WHITE') headerPanel2.SetSizer(headerHbox2) groupVbox.Add(headerPanel2, 0, wx.EXPAND) self.offlineList = wx.ListBox(mainPanel, wx.ID_ANY, style=wx.LB_SINGLE) groupVbox.Add(self.offlineList, 1, wx.EXPAND) mainHbox.Add(groupVbox, 2, wx.EXPAND | wx.ALL, 5) vbox.Add(mainHbox, 3, wx.EXPAND | wx.ALL, 5) # FILE TRANSFER INTERFACE filePanel = wx.Panel(mainPanel, -1) fileVbox = wx.BoxSizer(wx.VERTICAL) # Change download directory controls fhbox0 = wx.BoxSizer(wx.HORIZONTAL) st0 = wx.StaticText(filePanel, -1, "Download Directory: ") st0.SetFont(font) fhbox0.Add(st0, 0, wx.ALL, 5) self.dldir = wx.TextCtrl(filePanel, wx.ID_ANY, style=wx.TE_READONLY) fhbox0.Add(self.dldir, 1, wx.EXPAND | wx.ALL, 5) st = wx.StaticText(filePanel, -1, "New Directory: ") st.SetFont(font) fhbox0.Add(st, 0, wx.ALL, 5) self.newdir = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox0.Add(self.newdir, 1, wx.EXPAND | wx.ALL, 5) changeDir = wx.Button(filePanel, wx.ID_ANY, label="Change") fhbox0.Add(changeDir, 0, wx.RIGHT | wx.TOP, 5) changeDir.Bind(wx.EVT_BUTTON, self.OnChangeDir) fileVbox.Add(fhbox0, 0, wx.EXPAND) # "Offered Files" label fhbox1 = wx.BoxSizer(wx.HORIZONTAL) st1 = wx.StaticText(filePanel, -1, "Offered Files") st1.SetFont(font) fhbox1.Add(st1, 0) fileVbox.Add(fhbox1, 0, wx.LEFT | wx.TOP, 5) # List of offered files and accept button fhbox2 = wx.BoxSizer(wx.HORIZONTAL) self.offeredList = wx.ListBox(filePanel, wx.ID_ANY, style=wx.LB_SINGLE) fhbox2.Add(self.offeredList, 1, wx.LEFT | wx.EXPAND) acceptButton = wx.Button(filePanel, wx.ID_ANY, label="Accept File") fhbox2.Add(acceptButton, 0, wx.TOP | wx.BOTTOM | wx.RIGHT, 5) acceptButton.Bind(wx.EVT_BUTTON, self.OnAcceptFile) fileVbox.Add(fhbox2, 1, wx.LEFT | wx.RIGHT | wx.EXPAND) # File sending controls fhbox3 = wx.BoxSizer(wx.HORIZONTAL) # File field st2 = wx.StaticText(filePanel, -1, "File: ") st2.SetFont(font) fhbox3.Add(st2, 0, wx.TOP | wx.LEFT, 5) self.file = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox3.Add(self.file, 2, wx.EXPAND | wx.ALL, 5) # To field st3 = wx.StaticText(filePanel, -1, "To: ") st3.SetFont(font) fhbox3.Add(st3, 0, wx.TOP | wx.LEFT, 5) self.fileTo = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox3.Add(self.fileTo, 1, wx.EXPAND | wx.ALL, 5) # send button offerFile = wx.Button(filePanel, wx.ID_ANY, label="Offer File") fhbox3.Add(offerFile, 0, wx.RIGHT | wx.TOP, 5) offerFile.Bind(wx.EVT_BUTTON, self.OnOfferFile) fileVbox.Add(fhbox3, 0, wx.LEFT | wx.RIGHT | wx.EXPAND) filePanel.SetSizer(fileVbox) vbox.Add(filePanel, 1, wx.EXPAND) mainPanel.SetSizer(vbox) self.Centre() self.Show(True) pub.subscribe(self.__OnLog, 'log') pub.subscribe(self.__OnMessage, 'message') pub.subscribe(self.__OnUpdate, 'update') pub.subscribe(self.__OnLeave, 'group.leave') def OnAbout(self, e): dlg = wx.MessageDialog(self, "Distributed Secure Chat Application", "About DSCA", wx.OK) dlg.ShowModal() dlg.Destroy() def OnExit(self, e): self.Close(True) def OnCreateGroup(self, e): self.chat.createGroup() def OnLeaveGroup(self, e): self.chat.leaveGroup() def OnAddUser(self, e): if self.chat: dlg = AddUser(self, wx.ID_ANY, "Add User", self.chat) dlg.ShowModal() dlg.Destroy() def OnChannelInfo(self, e): if self.chat: dlg = ChannelInfo(self, wx.ID_ANY, 'Channel Info', self.chat) dlg.ShowModal() dlg.Destroy() def OnChannelMembership(self, e): if self.chat: dlg = ChannelMembership(self, wx.ID_ANY, 'Channel Membership', self.chat) dlg.ShowModal() dlg.Destroy() self.UpdateChannels() def OnLogHistory(self, e): if self.chat: dlg = ChannelLog(self, wx.ID_ANY, 'Channel Log History', self.chat) dlg.ShowModal() dlg.Destroy() def UpdateChannels(self): channels = self.chat.getChannels() items = channels.keys() items.append('lobby') self.channelSel.SetItems(items) tabs = self.channelTabs.keys() for chan in items: if (chan not in tabs) and (chan != 'lobby'): index = self.nb.GetPageCount() - 1 self.channelTabs[chan] = ChannelPage(self.nb, index) self.UpdateChannel(chan) self.nb.InsertPage(index, self.channelTabs[chan], chan) for tab in tabs: if tab not in items: page = self.channelTabs[tab] self.nb.SetSelection(0) index = page.index self.nb.DeletePage(index) del self.channelTabs[tab] for i in range(index, (self.nb.GetPageCount() - 1)): page2 = self.nb.GetPage(i) page2.index = i def OnStart(self, e): '''Starts a chat session. Not necessary to specifically enable output to the GUI. Output is dependent upon subscribing to events published by Chat.''' atexit.register(self.quiet_stop) if not self.chat: if (not self.ip.IsEmpty()) and (not self.port.IsEmpty()): ipString = str(self.ip.GetLineText(0)) ipString = ipString.strip() portString = str(self.port.GetLineText(0)) portString = portString.strip() listen_address = (str(ipString), int(portString)) self.chat = Chat(listen_address) else: self.chat = Chat() self.ip.Clear() self.port.Clear() self.curAddr.SetLabel(str(self.chat.getListenAddress())) self.dldir.Clear() self.dldir.AppendText(os.path.abspath(self.chat.getDownloadDir())) elif (not self.ip.IsEmpty()) and (not self.port.IsEmpty()): dlg = wx.MessageDialog(self, 'Start failed.\nChat already started.', "WARNING", wx.OK) dlg.ShowModal() dlg.Destroy() return try: self.chat.start() except: self.chat = None raise def quiet_stop(self): try: self.chat.stop() self.chat = None except: pass def OnStop(self, e): if self.chat: self.chat.stop() self.chat = None def OnLogout(self, e): self.chat.logout() def OnSendMsg(self, e): channel = self.channelSel.GetStringSelection() if not channel: channel = 'lobby' self.chat.sendMessage(self.msg.GetLineText(0), channel) self.msg.Clear() def OnChangeDir(self, e): if not self.newdir.IsEmpty(): self.chat.setDownloadDir(self.newdir.GetLineText(0)) self.newdir.Clear() self.dldir.Clear() self.dldir.AppendText(os.path.abspath(self.chat.getDownloadDir())) def OnAcceptFile(self, e): selection = str(self.offeredList.GetStringSelection()) cookie = (selection.split(':'))[1] cookie = cookie.lstrip() self.network.AppendText("I made you a cookie... %s" % cookie) try: self.chat.acceptFileOffer(cookie) except InvalidFileCookieException: dlg = wx.MessageDialog(self, "File Accept Failed", "FAIL", wx.OK) dlg.ShowModal() dlg.Destroy() def OnOfferFile(self, e): fpath = os.path.abspath(self.file.GetLineText(0)) nick = str(self.fileTo.GetLineText(0)) self.file.Clear() self.fileTo.Clear() try: target_addr = self.chat.getAddressOfNick(nick) except NickNotFoundException: dlg = wx.MessageDialog(self, "'%s' is not a valid user" % nick, "ERROR", wx.OK) dlg.ShowModal() dlg.Destroy() else: try: self.chat.offerFile(fpath, target_addr) except FileNotFoundException: dlg = wx.MessageDialog(self, "File '%s' does not exist" % fpath, "ERROR", wx.OK) dlg.ShowModal() dlg.Destroy() def OnNickChange(self, e): if not self.newNick.IsEmpty(): newNick = str(self.newNick.GetLineText(0)) newNick = newNick.strip() if newNick != '': self.newNick.Clear() self.chat.changeNick(newNick) def __OnLog(self, message): channel = message.data['channel'] msg = message.data['msg'] if 'time' in message.data: sec = message.data['time'] tstring = time.strftime("%H:%M:%S ", time.localtime(sec)) msg = tstring + msg wx.CallAfter(self.AfterLog, channel, msg) def AfterLog(self, channel, msg): if channel == 'lobby': self.lobby.AppendText(msg + '\n') elif channel in self.channelTabs: tab = self.channelTabs[channel] tab.text.AppendText(msg + '\n') self.network.AppendText(msg + '\n') def __OnMessage(self, message): channel = message.data['channel'] msg = message.data['msg'] if 'time' in message.data: sec = message.data['time'] tstring = time.strftime("%H:%M:%S ", time.localtime(sec)) msg = tstring + msg wx.CallAfter(self.AfterMessage, channel, msg) def AfterMessage(self, channel, msg): if channel == 'lobby': self.lobby.AppendText(msg + '\n') elif channel in self.channelTabs: tab = self.channelTabs[channel] tab.text.AppendText(msg + '\n') def __OnUpdate(self, message): field = message.data['field'] if 'value' in message.data: value = message.data['value'] if field == 'myNick': wx.CallAfter(self.UpdateMyNick, value) elif field == 'nick': wx.CallAfter(self.UpdateNick, value) elif field == 'channel': wx.CallAfter(self.UpdateChannel, value) elif field == 'group': wx.CallAfter(self.UpdateGroup) elif field == 'fileOffers': wx.CallAfter(self.UpdateOfferedFiles) def UpdateMyNick(self, nick): try: self.curNick.SetLabel(nick) except: pass self.UpdateNick(self.chat.getListenAddress()) def UpdateNick(self, sender): for channelName in self.chat.channels: channel = self.chat.getChannel(channelName) if sender in channel.getUserAddresses(): self.UpdateChannel(channelName) self.UpdateGroup() def UpdateChannel(self, channelName): if channelName in self.channelTabs: tab = self.channelTabs[channelName] chan = self.chat.getChannel(channelName) tab.users.SetItems(chan.getUsers()) def UpdateGroup(self): if self.chat: online = self.chat.getOnlineUsers() offline = self.chat.getOfflineUsers() onlineNicks = [] for addr in online: nick = self.chat.getNickOfAddress(addr) onlineNicks.append(nick) offlineNicks = [] for addr in offline: nick = self.chat.getNickOfAddress(addr) offlineNicks.append(nick) self.onlineList.SetItems(onlineNicks) self.offlineList.SetItems(offlineNicks) else: self.onlineList.Clear() self.offlineList.Clear() def UpdateOfferedFiles(self): foss = self.chat.getFileOffers() now = time.time() files = [] for cookie in foss: fof = foss[cookie] if fof['expires_on'] < now: continue files.append("%s: %s" % (os.path.basename(fof['filename']), cookie)) self.offeredList.SetItems(files) def __OnLeave(self, message=None): wx.CallAfter(self.Leave) def Leave(self): self.curNick.SetLabel("No Nick") self.curAddr.SetLabel("No Address") for i in range(1, (self.nb.GetPageCount() -1)): self.nb.DeletePage(1) self.lobby.Clear() self.network.Clear() self.onlineList.Clear() self.offlineList.Clear() self.chat = None