diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/WebBrowser/Passwords/PasswordManager.py --- a/src/eric7/WebBrowser/Passwords/PasswordManager.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/WebBrowser/Passwords/PasswordManager.py Wed Jul 13 14:55:47 2022 +0200 @@ -10,7 +10,12 @@ import os from PyQt6.QtCore import ( - pyqtSignal, QObject, QByteArray, QUrl, QCoreApplication, QXmlStreamReader + pyqtSignal, + QObject, + QByteArray, + QUrl, + QCoreApplication, + QXmlStreamReader, ) from PyQt6.QtWidgets import QApplication from PyQt6.QtWebEngineCore import QWebEngineScript @@ -31,21 +36,22 @@ class PasswordManager(QObject): """ Class implementing the password manager. - + @signal changed() emitted to indicate a change @signal passwordsSaved() emitted after the passwords were saved """ + changed = pyqtSignal() passwordsSaved = pyqtSignal() - + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent object (QObject) """ super().__init__(parent) - + # setup userscript to monitor forms script = QWebEngineScript() script.setName("_eric_passwordmonitor") @@ -55,52 +61,53 @@ script.setSourceCode(Scripts.setupFormObserver()) profile = WebBrowser.WebBrowserWindow.WebBrowserWindow.webProfile() profile.scripts().insert(script) - + self.__logins = {} self.__loginForms = {} self.__never = [] self.__loaded = False self.__saveTimer = AutoSaver(self, self.save) - + self.changed.connect(self.__saveTimer.changeOccurred) - + def clear(self): """ Public slot to clear the saved passwords. """ if not self.__loaded: self.__load() - + self.__logins = {} self.__loginForms = {} self.__never = [] self.__saveTimer.changeOccurred() self.__saveTimer.saveIfNeccessary() - + self.changed.emit() - + def getLogin(self, url, realm): """ Public method to get the login credentials. - + @param url URL to get the credentials for (QUrl) @param realm realm to get the credentials for (string) @return tuple containing the user name (string) and password (string) """ if not self.__loaded: self.__load() - + key = self.__createKey(url, realm) try: return self.__logins[key][0], Utilities.crypto.pwConvert( - self.__logins[key][1], encode=False) + self.__logins[key][1], encode=False + ) except KeyError: return "", "" - + def setLogin(self, url, realm, username, password): """ Public method to set the login credentials. - + @param url URL to set the credentials for (QUrl) @param realm realm to set the credentials for (string) @param username username for the login (string) @@ -108,18 +115,18 @@ """ if not self.__loaded: self.__load() - + key = self.__createKey(url, realm) self.__logins[key] = ( username, - Utilities.crypto.pwConvert(password, encode=True) + Utilities.crypto.pwConvert(password, encode=True), ) self.changed.emit() - + def __createKey(self, url, realm): """ Private method to create the key string for the login credentials. - + @param url URL to get the credentials for (QUrl) @param realm realm to get the credentials for (string) @return key string (string) @@ -129,89 +136,93 @@ authority = authority[1:] key = ( "{0}://{1} ({2})".format(url.scheme(), authority, realm) - if realm else - "{0}://{1}".format(url.scheme(), authority) + if realm + else "{0}://{1}".format(url.scheme(), authority) ) return key - + def getFileName(self): """ Public method to get the file name of the passwords file. - + @return name of the passwords file (string) """ - return os.path.join(Utilities.getConfigDir(), - "web_browser", "logins.xml") - + return os.path.join(Utilities.getConfigDir(), "web_browser", "logins.xml") + def save(self): """ Public slot to save the login entries to disk. """ if not self.__loaded: return - + from WebBrowser.WebBrowserWindow import WebBrowserWindow + if not WebBrowserWindow.isPrivate(): from .PasswordWriter import PasswordWriter + loginFile = self.getFileName() writer = PasswordWriter() if not writer.write( - loginFile, self.__logins, self.__loginForms, self.__never): + loginFile, self.__logins, self.__loginForms, self.__never + ): EricMessageBox.critical( None, self.tr("Saving login data"), self.tr( - """<p>Login data could not be saved to""" - """ <b>{0}</b></p>""" - ).format(loginFile)) + """<p>Login data could not be saved to""" """ <b>{0}</b></p>""" + ).format(loginFile), + ) else: self.passwordsSaved.emit() - + def __load(self): """ Private method to load the saved login credentials. """ if self.__loaded: return - + loginFile = self.getFileName() if os.path.exists(loginFile): from .PasswordReader import PasswordReader + reader = PasswordReader() - self.__logins, self.__loginForms, self.__never = reader.read( - loginFile) + self.__logins, self.__loginForms, self.__never = reader.read(loginFile) if reader.error() != QXmlStreamReader.Error.NoError: EricMessageBox.warning( None, self.tr("Loading login data"), - self.tr("""Error when loading login data on""" - """ line {0}, column {1}:\n{2}""") - .format(reader.lineNumber(), - reader.columnNumber(), - reader.errorString())) - + self.tr( + """Error when loading login data on""" + """ line {0}, column {1}:\n{2}""" + ).format( + reader.lineNumber(), reader.columnNumber(), reader.errorString() + ), + ) + self.__loaded = True - + def reload(self): """ Public method to reload the login data. """ if not self.__loaded: return - + self.__loaded = False self.__load() - + def close(self): """ Public method to close the passwords manager. """ self.__saveTimer.saveIfNeccessary() - + def removePassword(self, site): """ Public method to remove a password entry. - + @param site web site name (string) """ if site in self.__logins: @@ -219,49 +230,50 @@ if site in self.__loginForms: del self.__loginForms[site] self.changed.emit() - + def allSiteNames(self): """ Public method to get a list of all site names. - + @return sorted list of all site names (list of strings) """ if not self.__loaded: self.__load() - + return sorted(self.__logins.keys()) - + def sitesCount(self): """ Public method to get the number of available sites. - + @return number of sites (integer) """ if not self.__loaded: self.__load() - + return len(self.__logins) - + def siteInfo(self, site): """ Public method to get a reference to the named site. - + @param site web site name (string) @return tuple containing the user name (string) and password (string) """ if not self.__loaded: self.__load() - + if site not in self.__logins: return None - + return self.__logins[site][0], Utilities.crypto.pwConvert( - self.__logins[site][1], encode=False) - + self.__logins[site][1], encode=False + ) + def formSubmitted(self, urlStr, userName, password, data, page): """ Public method to record login data. - + @param urlStr form submission URL @type str @param userName name of the user @@ -276,16 +288,16 @@ # shall passwords be saved? if not Preferences.getUser("SavePasswords"): return - + if WebBrowser.WebBrowserWindow.WebBrowserWindow.isPrivate(): return - + if not self.__loaded: self.__load() - + if urlStr in self.__never: return - + if userName and password: url = QUrl(urlStr) url = self.__stripUrl(url) @@ -298,13 +310,15 @@ """<b>Would you like to save this password?</b><br/>""" """To review passwords you have saved and remove""" """ them, use the password management dialog of the""" - """ Settings menu."""), - modal=True, parent=page.view()) + """ Settings menu.""" + ), + modal=True, + parent=page.view(), + ) neverButton = mb.addButton( - self.tr("Never for this site"), - EricMessageBox.DestructiveRole) - noButton = mb.addButton( - self.tr("Not now"), EricMessageBox.RejectRole) + self.tr("Never for this site"), EricMessageBox.DestructiveRole + ) + noButton = mb.addButton(self.tr("Not now"), EricMessageBox.RejectRole) mb.addButton(EricMessageBox.Yes) mb.exec() if mb.clickedButton() == neverButton: @@ -312,111 +326,114 @@ return elif mb.clickedButton() == noButton: return - + self.__logins[key] = ( userName, - Utilities.crypto.pwConvert(password, encode=True) + Utilities.crypto.pwConvert(password, encode=True), ) from .LoginForm import LoginForm + form = LoginForm() form.url = url form.name = userName form.postData = Utilities.crypto.pwConvert( - bytes(data).decode("utf-8"), encode=True) + bytes(data).decode("utf-8"), encode=True + ) self.__loginForms[key] = form self.changed.emit() - + def __stripUrl(self, url): """ Private method to strip off all unneeded parts of a URL. - + @param url URL to be stripped (QUrl) @return stripped URL (QUrl) """ cleanUrl = QUrl(url) cleanUrl.setQuery("") cleanUrl.setUserInfo("") - + authority = cleanUrl.authority() if authority.startswith("@"): authority = authority[1:] - cleanUrl = QUrl("{0}://{1}{2}".format( - cleanUrl.scheme(), authority, cleanUrl.path())) + cleanUrl = QUrl( + "{0}://{1}{2}".format(cleanUrl.scheme(), authority, cleanUrl.path()) + ) cleanUrl.setFragment("") return cleanUrl - + def completePage(self, page): """ Public slot to complete login forms with saved data. - + @param page reference to the web page (WebBrowserPage) """ if page is None: return - + if not self.__loaded: self.__load() - + url = page.url() url = self.__stripUrl(url) key = self.__createKey(url, "") - if ( - key not in self.__loginForms or - key not in self.__logins - ): + if key not in self.__loginForms or key not in self.__logins: return - + form = self.__loginForms[key] if form.url != url: return - - postData = QByteArray(Utilities.crypto.pwConvert( - form.postData, encode=False).encode("utf-8")) + + postData = QByteArray( + Utilities.crypto.pwConvert(form.postData, encode=False).encode("utf-8") + ) script = Scripts.completeFormData(postData) page.runJavaScript(script, WebBrowserPage.SafeJsWorld) - + def masterPasswordChanged(self, oldPassword, newPassword): """ Public slot to handle the change of the master password. - + @param oldPassword current master password (string) @param newPassword new master password (string) """ if not self.__loaded: self.__load() - + progress = EricProgressDialog( self.tr("Re-encoding saved passwords..."), - None, 0, len(self.__logins) + len(self.__loginForms), + None, + 0, + len(self.__logins) + len(self.__loginForms), self.tr("%v/%m Passwords"), - QApplication.activeModalWidget()) + QApplication.activeModalWidget(), + ) progress.setMinimumDuration(0) progress.setWindowTitle(self.tr("Passwords")) count = 0 - + # step 1: do the logins for key in self.__logins: progress.setValue(count) QCoreApplication.processEvents() username, pwHash = self.__logins[key] - pwHash = Utilities.crypto.pwRecode( - pwHash, oldPassword, newPassword) + pwHash = Utilities.crypto.pwRecode(pwHash, oldPassword, newPassword) self.__logins[key] = (username, pwHash) count += 1 - + # step 2: do the login forms for key in self.__loginForms: progress.setValue(count) QCoreApplication.processEvents() postData = self.__loginForms[key].postData - postData = Utilities.crypto.pwRecode( - postData, oldPassword, newPassword) + postData = Utilities.crypto.pwRecode(postData, oldPassword, newPassword) self.__loginForms[key].postData = postData count += 1 - + progress.setValue(len(self.__logins) + len(self.__loginForms)) QCoreApplication.processEvents() self.changed.emit() + # # eflag: noqa = Y113