Package Gnumed :: Package wxpython :: Module gmCryptoText
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmCryptoText

  1  #!/usr/bin/python 
  2  ############################################################################# 
  3  # 
  4  # gmCryptoText - implements a "crypto" aware text widget 
  5  # --------------------------------------------------------------------------- 
  6  # This text widget allows arbitrary text to be entered via keyboard, 
  7  # cut'n paste via clipboard, or text files via drag'n drop 
  8  # Right clicking pops up a menu that allows to encrypt or decrypt 
  9  # the selected text segment. 
 10  # 
 11  # @author: Dr. Horst Herb 
 12  # @copyright: author 
 13  # @license: GPL v2 or later (details at http://www.gnu.org) 
 14  # @dependencies: wxPython (>= version 2.3.1) 
 15  # @change log: 
 16  #       30.06.2001 hherb initial implementation, untested 
 17  #       25.10.2001 commenting of source, module test enabled, debug log inserts removed 
 18  # 
 19  # @TODO: 
 20  #       - all runtime error checking / exception handling 
 21  #       - plug in structure for ciphers, rich popup menu selection of crypto methods 
 22  #       - use Python OpenSSL wrappers or GnuPG wrapper! 
 23  #       - tagging of the used cipher and the user within the encrypted text 
 24  #       - timer that expires pas phrase after arbitrary time intervals 
 25  #       - implement a "rich text" widget 
 26  ############################################################################ 
 27   
 28   
 29  """This module implements a ""crypto"" aware text widget 
 30   
 31  This text widget allows arbitrary text to be entered via keyboard, 
 32  cut'n paste via clipboard, or text files via drag'n drop 
 33  Right clicking pops up a menu that allows to encrypt or decrypt 
 34  the selected text segment. 
 35  """ 
 36   
 37  import wx 
 38   
 39  import string, rotor, binascii 
 40   
 41  ID_POP_ENCRYPT = wx.NewId() 
 42  ID_POP_DECRYPT = wx.NewId() 
 43  ID_POP_PASSPHRASE = wx.NewId() 
 44   
45 -class gmTextctrlFileDropTarget(wx.FileDropTarget):
46 """ a generic text control widget that accepts dropped files """ 47
48 - def __init__(self, textwindow):
49 wx.FileDropTarget.__init__(self) 50 self.textwindow=textwindow
51
52 - def OnDropFiles(self, x, y, filenames):
53 """inserts the dropped file(s) content(s) at the cursor position""" 54 for file in filenames: 55 self.textwindow.WriteText(string.join(open(file, 'r').readlines()))
56 57
58 -class gmCryptoText(wx.TextCtrl):
59 """A special text widget that supports cryptography 60 61 A right mouse click pops up a manu that allows to encrypt 62 or decrypt selected text segments. 63 You can drag and drop any number of text files into the text 64 widget, and that text will be inserted at the current cursor 65 position 66 """ 67
68 - def __init__(self, parent, id, size=wx.DefaultSize, style=wx.TE_MULTILINE|wx.TE_RICH, defaulttext=None):
69 #initialize parent class 70 wx.TextCtrl.__init__(self, parent, id, size=size, style=style) 71 self.SetDefaultStyle(wx.TextAttr(wx.RED)) 72 73 #will search for text tags within fuzzymargin characters 74 self.fuzzymargin = 25 75 self.passphrase = None 76 #time in seconds until passphrase expires 77 self. passphrase_expiry = 120 78 #the text selected for encryption/decryption 79 self.textselection = None 80 self. selectionStart = 0 81 self.selectionEnd = 0 82 83 if defaulttext is not None: 84 self.WriteText(defaulttext) 85 86 #a reserved ID for events related to this widget 87 self.aID = wx.NewId() 88 89 #make this text widget a drop target for drag&dropped text files 90 dt = gmTextctrlFileDropTarget(self) 91 self.SetDropTarget(dt) 92 93 #bugger... this one for wxGTK 94 wx.EVT_RIGHT_UP(self,self.OnRightClick) 95 wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
96 97 #...and this one for wxMSW (hope this inconsistency is fixed soon 98 #wx.EVT_COMMAND_RIGHT_CLICK(self, self.aID, self.OnRightClick) 99
100 - def OnRightClick(self, event):
101 "A right mouse click triggers a popup menu for cryptographic functionality" 102 103 self.selectionStart, self.selectionEnd = self.GetSelection() 104 105 #create a popup menu 106 menu = wx.Menu() 107 menu.Append(ID_POP_ENCRYPT, _("Encrypt")) 108 menu.Append(ID_POP_DECRYPT, _("Decrypt")) 109 menu.Append(ID_POP_PASSPHRASE, _("Set pass phrase")) 110 111 #connect the events to event handler functions 112 wx.EVT_MENU(self, ID_POP_ENCRYPT, self.OnEncrypt) 113 wx.EVT_MENU(self, ID_POP_DECRYPT, self.OnDecrypt) 114 wx.EVT_MENU(self, ID_POP_PASSPHRASE, self.OnSetPassphrase) 115 116 #show the menu 117 self.PopupMenu(menu, wxPoint(event.GetX(), event.GetY())) 118 119 #free resources 120 menu.Destroy() 121 122 #anybody else needs to intercept right click events? 123 event.Skip() 124 125 126 def OnContextMenu(self, event): 127 pass
128 129
130 - def OnEncrypt(self, event):
131 """triggered by popup contect menu event""" 132 133 #get the selected text if any 134 self.textselection = self.GetValue()[self.selectionStart:self.selectionEnd] 135 #anything to do? 136 if len(self.textselection)<1: 137 return 138 139 #we can't crypt without passphrase, so ask for it if needed! 140 if self.passphrase is None: 141 self.passphrase = self.AskForPassphrase() 142 if self.passphrase == None: 143 return 144 #In order to be displayed, binary crypt output has to be 'hexlified' 145 #encrypted text is tagged with <! ... !> 146 #future versions will embed a algorithm tag here 147 self.Replace(self.selectionStart, self.selectionEnd, \ 148 '<!' + self.GetIdentTag() + binascii.hexlify(self.Encrypt(self.textselection, self.passphrase)) + '!>')
149 150
151 - def OnDecrypt(self, event):
152 153 if self.passphrase is None: 154 self.passphrase = self.AskForPassphrase() 155 if self.passphrase == None: 156 return 157 158 textselection, self.selectionStart, self.selectionEnd = \ 159 self.FuzzyScanSelection(self.selectionStart, self.selectionEnd, self.fuzzymargin) 160 #is the selection tagged as encrypted ? 161 if textselection[:2] != '<!' or textselection[-2:] != '!>': 162 wx.MessageBox(_("This is not correctly encrypted text!")) 163 return 164 #get rid of the tags 165 textselection = textselection[2:-2] 166 identtag, textselection = self.StripIdentTag(textselection) 167 #self.textselection = self.textselection[len(identtag):] 168 #and don't forget to unhexlify the ciphertext before you feed it to the crypt 169 decoded = self.Decrypt(binascii.unhexlify(textselection), self.passphrase, identtag) 170 self.Replace(self.selectionStart, self.selectionEnd, decoded)
171 172
173 - def OnSetPassphrase(self, event):
174 self.passphrase = self.AskForPassphrase()
175 176
177 - def OnRightDown(self, event):
178 """dummy function; if this event was not intercepted, GTK would 179 clear the text selection the very moment the mouse button is clicked""" 180 pass
181
182 - def AskForPassphrase(self):
183 """asks for a pass phrase and returns it""" 184 dlg = wxTextEntryDialog(self, _("Please enter your pass phrase:"), _("Pass phrase expired"), style=wxOK|wxCANCEL|wx.CENTRE|wx.TE_PASSWORD) 185 if dlg.ShowModal() == wx.ID_OK: 186 retval = dlg.GetValue() 187 else: 188 retval = None 189 dlg.Destroy() 190 return retval
191 192
193 - def Encrypt(self, cleartext, key):
194 """override this function for your own crypto funcs""" 195 rt = rotor.newrotor(key, 12) 196 return rt.encrypt(cleartext)
197 198
199 - def Decrypt(self, ciphertext, key, identtag):
200 """override this function for your own crypto funcs""" 201 rt = rotor.newrotor(key, 12) 202 return rt.decrypt(ciphertext)
203 204
205 - def StripIdentTag(self, text):
206 """Remove the 'ident tag' from text and return both tag and test""" 207 if text[0] != '[': 208 "No ident tag ?" 209 return '', text 210 try: 211 endtag = string.index(text, ']')+1 212 except ValueError: 213 return '', text 214 return text[:endtag], text[endtag:]
215 216
217 - def GetIdentTag(self):
218 """This is a 'virtual' function which should be overridden to provide your own meaningful tag""" 219 return '[rotor]'
220 221
222 - def SetFuzzyMargin(self, margin):
223 """The fuzzy margin is the number of characters on each side of the text selection 224 the decryption algorithm will search for correct delimiters. It should be at least as long as 225 the IdentTag is plus an extra 3 characters to allow for the crypto tag""" 226 self.fuzzymargin = margin
227 228
229 - def FuzzyScanSelection(self, frompos, topos, margin):
230 fulltext = self.GetValue() 231 #search left margin 232 start = frompos - margin 233 if start < 0: start = 0 234 if frompos == 0: frompos = 1 235 #search right margin 236 finish = topos + margin 237 if finish > len(fulltext): finish = len(fulltext) 238 if topos > len(fulltext)-2: topos = len (fulltext)-2 239 try: 240 left = string.rindex(fulltext, '<', start, frompos) 241 right = string.index(fulltext, '>', topos, finish)+1 242 except ValueError: 243 wx.LogMessage("FuzzyScan went wrong") 244 return '' 245 return fulltext[left:right], left,right
246 247 ############################################################################# 248 # test function for this module: simply run the module as "main" 249 # a text entry window will pop up. Write something, select arbitrary 250 # segmnts of text with the mouse, and then right click the selection 251 # for options like encryption, decryption, and setting of passphrase 252 ############################################################################# 253 if __name__ == '__main__': 254 _ = lambda x:x 255 app = wxPyWidgetTester(size = (400, 400)) 256 #show the login panel in a main window 257 app.SetWidget(gmCryptoText, -1) 258 app.MainLoop() 259