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