Helpviewer/Passwords/PasswordManager.py

changeset 1685
7640d5500966
parent 1626
a77c8ea8582c
child 1686
bd756cb42d5b
equal deleted inserted replaced
1683:ef9a9e86269e 1685:7640d5500966
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, QCoreApplication, \
13 QXmlStreamReader
13 from PyQt4.QtGui import QProgressDialog, QApplication 14 from PyQt4.QtGui import QProgressDialog, QApplication
14 from PyQt4.QtNetwork import QNetworkRequest 15 from PyQt4.QtNetwork import QNetworkRequest
15 from PyQt4.QtWebKit import QWebSettings, QWebPage 16 from PyQt4.QtWebKit import QWebSettings, QWebPage
16 17
17 from E5Gui import E5MessageBox 18 from E5Gui import E5MessageBox
18 19
19 from Helpviewer.JavaScriptResources import parseForms_js 20 from Helpviewer.JavaScriptResources import parseForms_js
21
22 from .LoginForm import LoginForm
23 from .PasswordWriter import PasswordWriter
24 from .PasswordReader import PasswordReader
20 25
21 from Utilities.AutoSaver import AutoSaver 26 from Utilities.AutoSaver import AutoSaver
22 import Utilities 27 import Utilities
23 import Utilities.crypto 28 import Utilities.crypto
24 import Preferences 29 import Preferences
25
26
27 class LoginForm(object):
28 """
29 Class implementing a data structure for login forms.
30 """
31 def __init__(self):
32 """
33 Constructor
34 """
35 self.url = QUrl()
36 self.name = ""
37 self.hasAPassword = False
38 self.elements = [] # list of tuples of element name and value
39 # (string, string)
40 self.elementTypes = {} # dict of element name as key and type as value
41
42 def isValid(self):
43 """
44 Public method to test for validity.
45
46 @return flag indicating a valid form (boolean)
47 """
48 return len(self.elements) > 0
49
50 def load(self, data):
51 """
52 Public method to load the form data from a file.
53
54 @param data list of strings to load data from (list of strings)
55 @return flag indicating success (boolean)
56 """
57 self.url = QUrl(data[0])
58 self.name = data[1]
59 self.hasAPassword = data[2] == "True"
60 for element in data[3:]:
61 name, value = element.split(" = ", 1)
62 self.elements.append((name, value))
63
64 def save(self, f):
65 """
66 Public method to save the form data to a file.
67
68 @param f file or file like object open for writing
69 @return flag indicating success (booelan)
70 """
71 f.write("{0}\n".format(self.url.toString()))
72 f.write("{0}\n".format(self.name))
73 f.write("{0}\n".format(self.hasAPassword))
74 for element in self.elements:
75 f.write("{0} = {1}\n".format(element[0], element[1]))
76 30
77 31
78 class PasswordManager(QObject): 32 class PasswordManager(QObject):
79 """ 33 """
80 Class implementing the password manager. 34 Class implementing the password manager.
172 """ 126 """
173 Public method to get the file name of the passwords file. 127 Public method to get the file name of the passwords file.
174 128
175 @return name of the passwords file (string) 129 @return name of the passwords file (string)
176 """ 130 """
177 return os.path.join(Utilities.getConfigDir(), "browser", "logins") 131 return os.path.join(Utilities.getConfigDir(), "browser", "logins.xml")
178 132
179 def save(self): 133 def save(self):
180 """ 134 """
181 Public slot to save the login entries to disk. 135 Public slot to save the login entries to disk.
182 """ 136 """
183 if not self.__loaded: 137 if not self.__loaded:
184 return 138 return
185 139
186 loginFile = self.getFileName() 140 loginFile = self.getFileName()
187 try: 141 writer = PasswordWriter()
188 f = open(loginFile, "w", encoding="utf-8") 142 if not writer.write(loginFile, self.__logins, self.__loginForms, self.__never):
189 for key, login in list(self.__logins.items()):
190 f.write("{0}\n".format(key))
191 f.write("{0}\n".format(login[0]))
192 f.write("{0}\n".format(login[1]))
193 f.write("{0}\n".format(self.SEPARATOR))
194 if self.__loginForms:
195 f.write("{0}\n".format(self.FORMS))
196 for key, form in list(self.__loginForms.items()):
197 f.write("{0}\n".format(key))
198 form.save(f)
199 f.write("{0}\n".format(self.SEPARATOR))
200 if self.__never:
201 f.write("{0}\n".format(self.NEVER))
202 for key in self.__never:
203 f.write("{0}\n".format(key))
204 f.close()
205 self.passwordsSaved.emit()
206 except IOError as err:
207 E5MessageBox.critical(None, 143 E5MessageBox.critical(None,
208 self.trUtf8("Saving login data"), 144 self.trUtf8("Saving login data"),
209 self.trUtf8("""<p>Login data could not be saved to <b>{0}</b></p>""" 145 self.trUtf8("""<p>Login data could not be saved to <b>{0}</b></p>"""
210 """<p>Reason: {1}</p>""").format(loginFile, str(err))) 146 ).format(loginFile))
211 return 147 else:
148 self.passwordsSaved.emit()
212 149
213 def __load(self): 150 def __load(self):
214 """ 151 """
215 Private method to load the saved login credentials. 152 Private method to load the saved login credentials.
216 """ 153 """
217 loginFile = self.getFileName() 154 loginFile = self.getFileName()
155 if not os.path.exists(loginFile):
156 self.__loadNonXml(os.path.splitext(loginFile)[0])
157 else:
158 reader = PasswordReader()
159 self.__logins, self.__loginForms, self.__never = reader.read(loginFile)
160 if reader.error() != QXmlStreamReader.NoError:
161 E5MessageBox.warning(None,
162 self.trUtf8("Loading login data"),
163 self.trUtf8("""Error when loading login data on"""
164 """ line {0}, column {1}:\n{2}""")\
165 .format(reader.lineNumber(),
166 reader.columnNumber(),
167 reader.errorString()))
168 pass
169
170 self.__loaded = True
171
172 def __loadNonXml(self, loginFile):
173 """
174 Private method to load non-XML password files.
175
176 This method is to convert from the old, non-XML format to the new
177 XML based format.
178
179 @param loginFile name of the non-XML password file (string)
180 """
218 if os.path.exists(loginFile): 181 if os.path.exists(loginFile):
219 try: 182 try:
220 f = open(loginFile, "r", encoding="utf-8") 183 f = open(loginFile, "r", encoding="utf-8")
221 lines = f.read() 184 lines = f.read()
222 f.close() 185 f.close()
258 if line != self.SEPARATOR: 221 if line != self.SEPARATOR:
259 data.append(line) 222 data.append(line)
260 else: 223 else:
261 key = data[0] 224 key = data[0]
262 form = LoginForm() 225 form = LoginForm()
263 form.load(data[1:]) 226 form.url = QUrl(data[1])
227 form.name = data[2]
228 form.hasAPassword = data[3] == "True"
229 for element in data[4:]:
230 name, value = element.split(" = ", 1)
231 form.elements.append((name, value))
264 self.__loginForms[key] = form 232 self.__loginForms[key] = form
265 data = [] 233 data = []
266 234
267 elif section == 2: 235 elif section == 2:
268 self.__never.append(line) 236 self.__never.append(line)
237
238 os.remove(loginFile)
269 239
270 self.__loaded = True 240 self.__loaded = True
241
242 # this does the conversion
243 self.save()
271 244
272 def reload(self): 245 def reload(self):
273 """ 246 """
274 Public method to reload the login data. 247 Public method to reload the login data.
275 """ 248 """

eric ide

mercurial