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