Helpviewer/Passwords/PasswordManager.py

changeset 3002
6ffc581f00f1
parent 2403
e3d7a861547c
child 3020
542e97d4ecb3
child 3057
10516539f238
equal deleted inserted replaced
3001:3674ff5fa8f8 3002:6ffc581f00f1
7 Module implementing the password manager. 7 Module implementing the password manager.
8 """ 8 """
9 9
10 import os 10 import os
11 11
12 from PyQt4.QtCore import pyqtSignal, QObject, QByteArray, QUrl, QCoreApplication, \ 12 from PyQt4.QtCore import pyqtSignal, QObject, QByteArray, QUrl, \
13 QXmlStreamReader 13 QCoreApplication, QXmlStreamReader
14 from PyQt4.QtGui import QProgressDialog, QApplication 14 from PyQt4.QtGui import QProgressDialog, QApplication
15 from PyQt4.QtNetwork import QNetworkRequest 15 from PyQt4.QtNetwork import QNetworkRequest
16 from PyQt4.QtWebKit import QWebSettings, QWebPage 16 from PyQt4.QtWebKit import QWebSettings, QWebPage
17 17
18 from E5Gui import E5MessageBox 18 from E5Gui import E5MessageBox
97 """ 97 """
98 if not self.__loaded: 98 if not self.__loaded:
99 self.__load() 99 self.__load()
100 100
101 key = self.__createKey(url, realm) 101 key = self.__createKey(url, realm)
102 self.__logins[key] = (username, Utilities.crypto.pwConvert(password, encode=True)) 102 self.__logins[key] = (
103 username,
104 Utilities.crypto.pwConvert(password, encode=True)
105 )
103 self.changed.emit() 106 self.changed.emit()
104 107
105 def __createKey(self, url, realm): 108 def __createKey(self, url, realm):
106 """ 109 """
107 Private method to create the key string for the login credentials. 110 Private method to create the key string for the login credentials.
109 @param url URL to get the credentials for (QUrl) 112 @param url URL to get the credentials for (QUrl)
110 @param realm realm to get the credentials for (string) 113 @param realm realm to get the credentials for (string)
111 @return key string (string) 114 @return key string (string)
112 """ 115 """
113 if realm: 116 if realm:
114 key = "{0}://{1} ({2})".format(url.scheme(), url.authority(), realm) 117 key = "{0}://{1} ({2})".format(
118 url.scheme(), url.authority(), realm)
115 else: 119 else:
116 key = "{0}://{1}".format(url.scheme(), url.authority()) 120 key = "{0}://{1}".format(url.scheme(), url.authority())
117 return key 121 return key
118 122
119 def getFileName(self): 123 def getFileName(self):
132 return 136 return
133 137
134 from .PasswordWriter import PasswordWriter 138 from .PasswordWriter import PasswordWriter
135 loginFile = self.getFileName() 139 loginFile = self.getFileName()
136 writer = PasswordWriter() 140 writer = PasswordWriter()
137 if not writer.write(loginFile, self.__logins, self.__loginForms, self.__never): 141 if not writer.write(
142 loginFile, self.__logins, self.__loginForms, self.__never):
138 E5MessageBox.critical(None, 143 E5MessageBox.critical(None,
139 self.trUtf8("Saving login data"), 144 self.trUtf8("Saving login data"),
140 self.trUtf8("""<p>Login data could not be saved to <b>{0}</b></p>""" 145 self.trUtf8(
141 ).format(loginFile)) 146 """<p>Login data could not be saved to <b>{0}</b></p>"""
147 ).format(loginFile))
142 else: 148 else:
143 self.passwordsSaved.emit() 149 self.passwordsSaved.emit()
144 150
145 def __load(self): 151 def __load(self):
146 """ 152 """
150 if not os.path.exists(loginFile): 156 if not os.path.exists(loginFile):
151 self.__loadNonXml(os.path.splitext(loginFile)[0]) 157 self.__loadNonXml(os.path.splitext(loginFile)[0])
152 else: 158 else:
153 from .PasswordReader import PasswordReader 159 from .PasswordReader import PasswordReader
154 reader = PasswordReader() 160 reader = PasswordReader()
155 self.__logins, self.__loginForms, self.__never = reader.read(loginFile) 161 self.__logins, self.__loginForms, self.__never = \
162 reader.read(loginFile)
156 if reader.error() != QXmlStreamReader.NoError: 163 if reader.error() != QXmlStreamReader.NoError:
157 E5MessageBox.warning(None, 164 E5MessageBox.warning(None,
158 self.trUtf8("Loading login data"), 165 self.trUtf8("Loading login data"),
159 self.trUtf8("""Error when loading login data on""" 166 self.trUtf8("""Error when loading login data on"""
160 """ line {0}, column {1}:\n{2}""")\ 167 """ line {0}, column {1}:\n{2}""")\
186 """<p>Reason: {1}</p>""")\ 193 """<p>Reason: {1}</p>""")\
187 .format(loginFile, str(err))) 194 .format(loginFile, str(err)))
188 return 195 return
189 196
190 data = [] 197 data = []
191 section = 0 # 0 = login data, 1 = forms data, 2 = never store info 198 section = 0 # 0 = login data, 1 = forms data,
199 # 2 = never store info
192 for line in lines.splitlines(): 200 for line in lines.splitlines():
193 if line == self.FORMS: 201 if line == self.FORMS:
194 section = 1 202 section = 1
195 continue 203 continue
196 elif line == self.NEVER: 204 elif line == self.NEVER:
202 data.append(line) 210 data.append(line)
203 else: 211 else:
204 if len(data) != 3: 212 if len(data) != 3:
205 E5MessageBox.critical(None, 213 E5MessageBox.critical(None,
206 self.trUtf8("Loading login data"), 214 self.trUtf8("Loading login data"),
207 self.trUtf8("""<p>Login data could not be loaded """ 215 self.trUtf8(
208 """from <b>{0}</b></p>""" 216 """<p>Login data could not be loaded """
209 """<p>Reason: Wrong input format</p>""")\ 217 """from <b>{0}</b></p>"""
218 """<p>Reason: Wrong input format</p>""")\
210 .format(loginFile)) 219 .format(loginFile))
211 return 220 return
212 self.__logins[data[0]] = (data[1], data[2]) 221 self.__logins[data[0]] = (data[1], data[2])
213 data = [] 222 data = []
214 223
371 mb = E5MessageBox.E5MessageBox(E5MessageBox.Question, 380 mb = E5MessageBox.E5MessageBox(E5MessageBox.Question,
372 self.trUtf8("Save password"), 381 self.trUtf8("Save password"),
373 self.trUtf8( 382 self.trUtf8(
374 """<b>Would you like to save this password?</b><br/>""" 383 """<b>Would you like to save this password?</b><br/>"""
375 """To review passwords you have saved and remove them, """ 384 """To review passwords you have saved and remove them, """
376 """use the password management dialog of the Settings menu."""), 385 """use the password management dialog of the Settings"""
386 """ menu."""),
377 modal=True) 387 modal=True)
378 neverButton = mb.addButton( 388 neverButton = mb.addButton(
379 self.trUtf8("Never for this site"), E5MessageBox.DestructiveRole) 389 self.trUtf8("Never for this site"),
380 noButton = mb.addButton(self.trUtf8("Not now"), E5MessageBox.RejectRole) 390 E5MessageBox.DestructiveRole)
391 noButton = mb.addButton(
392 self.trUtf8("Not now"), E5MessageBox.RejectRole)
381 mb.addButton(E5MessageBox.Yes) 393 mb.addButton(E5MessageBox.Yes)
382 mb.exec_() 394 mb.exec_()
383 if mb.clickedButton() == neverButton: 395 if mb.clickedButton() == neverButton:
384 self.__never.append(url.toString()) 396 self.__never.append(url.toString())
385 return 397 return
398 elif password == "" and \ 410 elif password == "" and \
399 type_ == "password": 411 type_ == "password":
400 password = element[1] 412 password = element[1]
401 form.elements[index] = (element[0], "--PASSWORD--") 413 form.elements[index] = (element[0], "--PASSWORD--")
402 if user and password: 414 if user and password:
403 self.__logins[key] = (user, Utilities.crypto.pwConvert(password, encode=True)) 415 self.__logins[key] = \
416 (user, Utilities.crypto.pwConvert(password, encode=True))
404 self.__loginForms[key] = form 417 self.__loginForms[key] = form
405 self.changed.emit() 418 self.changed.emit()
406 419
407 def __stripUrl(self, url): 420 def __stripUrl(self, url):
408 """ 421 """
421 """ 434 """
422 Private method to find the form used for logging in. 435 Private method to find the form used for logging in.
423 436
424 @param webPage reference to the web page (QWebPage) 437 @param webPage reference to the web page (QWebPage)
425 @param data data to be sent (QByteArray) 438 @param data data to be sent (QByteArray)
426 @keyparam boundary boundary string (QByteArray) for multipart encoded data, 439 @keyparam boundary boundary string (QByteArray) for multipart
427 None for urlencoded data 440 encoded data, None for urlencoded data
428 @return parsed form (LoginForm) 441 @return parsed form (LoginForm)
429 """ 442 """
430 from .LoginForm import LoginForm 443 from .LoginForm import LoginForm
431 form = LoginForm() 444 form = LoginForm()
432 if boundary is not None: 445 if boundary is not None:
544 for element in form.elements: 557 for element in form.elements:
545 name = element[0] 558 name = element[0]
546 value = element[1] 559 value = element[1]
547 560
548 disabled = page.mainFrame().evaluateJavaScript( 561 disabled = page.mainFrame().evaluateJavaScript(
549 'document.forms[{0}].elements["{1}"].disabled'.format(formName, name)) 562 'document.forms[{0}].elements["{1}"].disabled'.format(
563 formName, name))
550 if disabled: 564 if disabled:
551 continue 565 continue
552 566
553 readOnly = page.mainFrame().evaluateJavaScript( 567 readOnly = page.mainFrame().evaluateJavaScript(
554 'document.forms[{0}].elements["{1}"].readOnly'.format(formName, name)) 568 'document.forms[{0}].elements["{1}"].readOnly'.format(
569 formName, name))
555 if readOnly: 570 if readOnly:
556 continue 571 continue
557 572
558 type_ = page.mainFrame().evaluateJavaScript( 573 type_ = page.mainFrame().evaluateJavaScript(
559 'document.forms[{0}].elements["{1}"].type'.format(formName, name)) 574 'document.forms[{0}].elements["{1}"].type'.format(
575 formName, name))
560 if type_ == "" or \ 576 if type_ == "" or \
561 type_ in ["hidden", "reset", "submit"]: 577 type_ in ["hidden", "reset", "submit"]:
562 continue 578 continue
563 if type_ == "password": 579 if type_ == "password":
564 value = Utilities.crypto.pwConvert(self.__logins[key][1], encode=False) 580 value = Utilities.crypto.pwConvert(
581 self.__logins[key][1], encode=False)
565 setType = type_ == "checkbox" and "checked" or "value" 582 setType = type_ == "checkbox" and "checked" or "value"
566 value = value.replace("\\", "\\\\") 583 value = value.replace("\\", "\\\\")
567 value = value.replace('"', '\\"') 584 value = value.replace('"', '\\"')
568 javascript = 'document.forms[{0}].elements["{1}"].{2}="{3}";'.format( 585 javascript = \
569 formName, name, setType, value) 586 'document.forms[{0}].elements["{1}"].{2}="{3}";'.format(
587 formName, name, setType, value)
570 page.mainFrame().evaluateJavaScript(javascript) 588 page.mainFrame().evaluateJavaScript(javascript)
571 589
572 def masterPasswordChanged(self, oldPassword, newPassword): 590 def masterPasswordChanged(self, oldPassword, newPassword):
573 """ 591 """
574 Public slot to handle the change of the master password. 592 Public slot to handle the change of the master password.
577 @param newPassword new master password (string) 595 @param newPassword new master password (string)
578 """ 596 """
579 if not self.__loaded: 597 if not self.__loaded:
580 self.__load() 598 self.__load()
581 599
582 progress = QProgressDialog(self.trUtf8("Re-encoding saved passwords..."), 600 progress = QProgressDialog(
601 self.trUtf8("Re-encoding saved passwords..."),
583 None, 0, len(self.__logins), QApplication.activeModalWidget()) 602 None, 0, len(self.__logins), QApplication.activeModalWidget())
584 progress.setMinimumDuration(0) 603 progress.setMinimumDuration(0)
585 count = 0 604 count = 0
586 605
587 for key in self.__logins: 606 for key in self.__logins:

eric ide

mercurial