29 synchronization (string) |
29 synchronization (string) |
30 @signal syncFinished(type_, done, download) emitted after a |
30 @signal syncFinished(type_, done, download) emitted after a |
31 synchronization has finished (string one of "bookmarks", "history", |
31 synchronization has finished (string one of "bookmarks", "history", |
32 "passwords", "useragents" or "speeddial", boolean, boolean) |
32 "passwords", "useragents" or "speeddial", boolean, boolean) |
33 """ |
33 """ |
|
34 |
34 syncStatus = pyqtSignal(str, str) |
35 syncStatus = pyqtSignal(str, str) |
35 syncError = pyqtSignal(str) |
36 syncError = pyqtSignal(str) |
36 syncMessage = pyqtSignal(str) |
37 syncMessage = pyqtSignal(str) |
37 syncFinished = pyqtSignal(str, bool, bool) |
38 syncFinished = pyqtSignal(str, bool, bool) |
38 |
39 |
39 def __init__(self, parent=None): |
40 def __init__(self, parent=None): |
40 """ |
41 """ |
41 Constructor |
42 Constructor |
42 |
43 |
43 @param parent reference to the parent object (QObject) |
44 @param parent reference to the parent object (QObject) |
44 """ |
45 """ |
45 super().__init__(parent) |
46 super().__init__(parent) |
46 |
47 |
47 self._firstTimeSynced = False |
48 self._firstTimeSynced = False |
48 |
49 |
49 self._remoteFiles = { |
50 self._remoteFiles = { |
50 "bookmarks": "Bookmarks", |
51 "bookmarks": "Bookmarks", |
51 "history": "History", |
52 "history": "History", |
52 "passwords": "Logins", |
53 "passwords": "Logins", |
53 "useragents": "UserAgentSettings", |
54 "useragents": "UserAgentSettings", |
54 "speeddial": "SpeedDial", |
55 "speeddial": "SpeedDial", |
55 } |
56 } |
56 |
57 |
57 self._messages = { |
58 self._messages = { |
58 "bookmarks": { |
59 "bookmarks": { |
59 "RemoteExists": self.tr( |
60 "RemoteExists": self.tr( |
60 "Remote bookmarks file exists! Syncing local copy..."), |
61 "Remote bookmarks file exists! Syncing local copy..." |
61 "RemoteMissing": self.tr( |
62 ), |
62 "Remote bookmarks file does NOT exist. Exporting" |
63 "RemoteMissing": self.tr( |
63 " local copy..."), |
64 "Remote bookmarks file does NOT exist. Exporting" " local copy..." |
64 "LocalNewer": self.tr( |
65 ), |
65 "Local bookmarks file is NEWER. Exporting local copy..."), |
66 "LocalNewer": self.tr( |
66 "LocalMissing": self.tr( |
67 "Local bookmarks file is NEWER. Exporting local copy..." |
67 "Local bookmarks file does NOT exist. Skipping" |
68 ), |
68 " synchronization!"), |
69 "LocalMissing": self.tr( |
|
70 "Local bookmarks file does NOT exist. Skipping" " synchronization!" |
|
71 ), |
69 "Uploading": self.tr("Uploading local bookmarks file..."), |
72 "Uploading": self.tr("Uploading local bookmarks file..."), |
70 }, |
73 }, |
71 "history": { |
74 "history": { |
72 "RemoteExists": self.tr( |
75 "RemoteExists": self.tr( |
73 "Remote history file exists! Syncing local copy..."), |
76 "Remote history file exists! Syncing local copy..." |
74 "RemoteMissing": self.tr( |
77 ), |
75 "Remote history file does NOT exist. Exporting" |
78 "RemoteMissing": self.tr( |
76 " local copy..."), |
79 "Remote history file does NOT exist. Exporting" " local copy..." |
77 "LocalNewer": self.tr( |
80 ), |
78 "Local history file is NEWER. Exporting local copy..."), |
81 "LocalNewer": self.tr( |
79 "LocalMissing": self.tr( |
82 "Local history file is NEWER. Exporting local copy..." |
80 "Local history file does NOT exist. Skipping" |
83 ), |
81 " synchronization!"), |
84 "LocalMissing": self.tr( |
|
85 "Local history file does NOT exist. Skipping" " synchronization!" |
|
86 ), |
82 "Uploading": self.tr("Uploading local history file..."), |
87 "Uploading": self.tr("Uploading local history file..."), |
83 }, |
88 }, |
84 "passwords": { |
89 "passwords": { |
85 "RemoteExists": self.tr( |
90 "RemoteExists": self.tr( |
86 "Remote logins file exists! Syncing local copy..."), |
91 "Remote logins file exists! Syncing local copy..." |
87 "RemoteMissing": self.tr( |
92 ), |
88 "Remote logins file does NOT exist. Exporting" |
93 "RemoteMissing": self.tr( |
89 " local copy..."), |
94 "Remote logins file does NOT exist. Exporting" " local copy..." |
90 "LocalNewer": self.tr( |
95 ), |
91 "Local logins file is NEWER. Exporting local copy..."), |
96 "LocalNewer": self.tr( |
92 "LocalMissing": self.tr( |
97 "Local logins file is NEWER. Exporting local copy..." |
93 "Local logins file does NOT exist. Skipping" |
98 ), |
94 " synchronization!"), |
99 "LocalMissing": self.tr( |
|
100 "Local logins file does NOT exist. Skipping" " synchronization!" |
|
101 ), |
95 "Uploading": self.tr("Uploading local logins file..."), |
102 "Uploading": self.tr("Uploading local logins file..."), |
96 }, |
103 }, |
97 "useragents": { |
104 "useragents": { |
98 "RemoteExists": self.tr( |
105 "RemoteExists": self.tr( |
99 "Remote user agent settings file exists! Syncing local" |
106 "Remote user agent settings file exists! Syncing local" " copy..." |
100 " copy..."), |
107 ), |
101 "RemoteMissing": self.tr( |
108 "RemoteMissing": self.tr( |
102 "Remote user agent settings file does NOT exist." |
109 "Remote user agent settings file does NOT exist." |
103 " Exporting local copy..."), |
110 " Exporting local copy..." |
|
111 ), |
104 "LocalNewer": self.tr( |
112 "LocalNewer": self.tr( |
105 "Local user agent settings file is NEWER. Exporting" |
113 "Local user agent settings file is NEWER. Exporting" |
106 " local copy..."), |
114 " local copy..." |
|
115 ), |
107 "LocalMissing": self.tr( |
116 "LocalMissing": self.tr( |
108 "Local user agent settings file does NOT exist." |
117 "Local user agent settings file does NOT exist." |
109 " Skipping synchronization!"), |
118 " Skipping synchronization!" |
110 "Uploading": self.tr( |
119 ), |
111 "Uploading local user agent settings file..."), |
120 "Uploading": self.tr("Uploading local user agent settings file..."), |
112 }, |
121 }, |
113 "speeddial": { |
122 "speeddial": { |
114 "RemoteExists": self.tr( |
123 "RemoteExists": self.tr( |
115 "Remote speed dial settings file exists! Syncing local" |
124 "Remote speed dial settings file exists! Syncing local" " copy..." |
116 " copy..."), |
125 ), |
117 "RemoteMissing": self.tr( |
126 "RemoteMissing": self.tr( |
118 "Remote speed dial settings file does NOT exist." |
127 "Remote speed dial settings file does NOT exist." |
119 " Exporting local copy..."), |
128 " Exporting local copy..." |
|
129 ), |
120 "LocalNewer": self.tr( |
130 "LocalNewer": self.tr( |
121 "Local speed dial settings file is NEWER. Exporting" |
131 "Local speed dial settings file is NEWER. Exporting" |
122 " local copy..."), |
132 " local copy..." |
|
133 ), |
123 "LocalMissing": self.tr( |
134 "LocalMissing": self.tr( |
124 "Local speed dial settings file does NOT exist." |
135 "Local speed dial settings file does NOT exist." |
125 " Skipping synchronization!"), |
136 " Skipping synchronization!" |
126 "Uploading": self.tr( |
137 ), |
127 "Uploading local speed dial settings file..."), |
138 "Uploading": self.tr("Uploading local speed dial settings file..."), |
128 }, |
139 }, |
129 } |
140 } |
130 |
141 |
131 def syncBookmarks(self): |
142 def syncBookmarks(self): |
132 """ |
143 """ |
133 Public method to synchronize the bookmarks. |
144 Public method to synchronize the bookmarks. |
134 |
145 |
135 @exception NotImplementedError raised to indicate that this method |
146 @exception NotImplementedError raised to indicate that this method |
136 must be implemented by subclasses |
147 must be implemented by subclasses |
137 """ |
148 """ |
138 raise NotImplementedError |
149 raise NotImplementedError |
139 |
150 |
140 def syncHistory(self): |
151 def syncHistory(self): |
141 """ |
152 """ |
142 Public method to synchronize the history. |
153 Public method to synchronize the history. |
143 |
154 |
144 @exception NotImplementedError raised to indicate that this method |
155 @exception NotImplementedError raised to indicate that this method |
145 must be implemented by subclasses |
156 must be implemented by subclasses |
146 """ |
157 """ |
147 raise NotImplementedError |
158 raise NotImplementedError |
148 |
159 |
149 def syncPasswords(self): |
160 def syncPasswords(self): |
150 """ |
161 """ |
151 Public method to synchronize the passwords. |
162 Public method to synchronize the passwords. |
152 |
163 |
153 @exception NotImplementedError raised to indicate that this method |
164 @exception NotImplementedError raised to indicate that this method |
154 must be implemented by subclasses |
165 must be implemented by subclasses |
155 """ |
166 """ |
156 raise NotImplementedError |
167 raise NotImplementedError |
157 |
168 |
158 def syncUserAgents(self): |
169 def syncUserAgents(self): |
159 """ |
170 """ |
160 Public method to synchronize the user agents. |
171 Public method to synchronize the user agents. |
161 |
172 |
162 @exception NotImplementedError raised to indicate that this method |
173 @exception NotImplementedError raised to indicate that this method |
163 must be implemented by subclasses |
174 must be implemented by subclasses |
164 """ |
175 """ |
165 raise NotImplementedError |
176 raise NotImplementedError |
166 |
177 |
167 def syncSpeedDial(self): |
178 def syncSpeedDial(self): |
168 """ |
179 """ |
169 Public method to synchronize the speed dial data. |
180 Public method to synchronize the speed dial data. |
170 |
181 |
171 @exception NotImplementedError raised to indicate that this method |
182 @exception NotImplementedError raised to indicate that this method |
172 must be implemented by subclasses |
183 must be implemented by subclasses |
173 """ |
184 """ |
174 raise NotImplementedError |
185 raise NotImplementedError |
175 |
186 |
176 def initialLoadAndCheck(self, forceUpload): |
187 def initialLoadAndCheck(self, forceUpload): |
177 """ |
188 """ |
178 Public method to do the initial check. |
189 Public method to do the initial check. |
179 |
190 |
180 @param forceUpload flag indicating a forced upload of the files |
191 @param forceUpload flag indicating a forced upload of the files |
181 (boolean) |
192 (boolean) |
182 @exception NotImplementedError raised to indicate that this method |
193 @exception NotImplementedError raised to indicate that this method |
183 must be implemented by subclasses |
194 must be implemented by subclasses |
184 """ |
195 """ |
185 raise NotImplementedError |
196 raise NotImplementedError |
186 |
197 |
187 def shutdown(self): |
198 def shutdown(self): |
188 """ |
199 """ |
189 Public method to shut down the handler. |
200 Public method to shut down the handler. |
190 |
201 |
191 @exception NotImplementedError raised to indicate that this method |
202 @exception NotImplementedError raised to indicate that this method |
192 must be implemented by subclasses |
203 must be implemented by subclasses |
193 """ |
204 """ |
194 raise NotImplementedError |
205 raise NotImplementedError |
195 |
206 |
196 def readFile(self, fileName, type_): |
207 def readFile(self, fileName, type_): |
197 """ |
208 """ |
198 Public method to read a file. |
209 Public method to read a file. |
199 |
210 |
200 If encrypted synchronization is enabled, the data will be encrypted |
211 If encrypted synchronization is enabled, the data will be encrypted |
201 using the relevant encryption key. |
212 using the relevant encryption key. |
202 |
213 |
203 @param fileName name of the file to be read (string) |
214 @param fileName name of the file to be read (string) |
204 @param type_ type of the synchronization event (string one |
215 @param type_ type of the synchronization event (string one |
205 of "bookmarks", "history", "passwords", "useragents" or |
216 of "bookmarks", "history", "passwords", "useragents" or |
206 "speeddial") |
217 "speeddial") |
207 @return data of the file, optionally encrypted (QByteArray) |
218 @return data of the file, optionally encrypted (QByteArray) |
210 try: |
221 try: |
211 with open(fileName, "rb") as inputFile: |
222 with open(fileName, "rb") as inputFile: |
212 data = inputFile.read() |
223 data = inputFile.read() |
213 except OSError: |
224 except OSError: |
214 return QByteArray() |
225 return QByteArray() |
215 |
226 |
216 if ( |
227 if Preferences.getWebBrowser("SyncEncryptData") and ( |
217 Preferences.getWebBrowser("SyncEncryptData") and |
228 not Preferences.getWebBrowser("SyncEncryptPasswordsOnly") |
218 (not Preferences.getWebBrowser("SyncEncryptPasswordsOnly") or |
229 or ( |
219 (Preferences.getWebBrowser("SyncEncryptPasswordsOnly") and |
230 Preferences.getWebBrowser("SyncEncryptPasswordsOnly") |
220 type_ == "passwords")) |
231 and type_ == "passwords" |
|
232 ) |
221 ): |
233 ): |
222 key = Preferences.getWebBrowser("SyncEncryptionKey") |
234 key = Preferences.getWebBrowser("SyncEncryptionKey") |
223 if not key: |
235 if not key: |
224 return QByteArray() |
236 return QByteArray() |
225 |
237 |
226 data, ok = dataEncrypt( |
238 data, ok = dataEncrypt( |
227 data, key, |
239 data, |
228 keyLength=Preferences.getWebBrowser( |
240 key, |
229 "SyncEncryptionKeyLength"), |
241 keyLength=Preferences.getWebBrowser("SyncEncryptionKeyLength"), |
230 hashIterations=100) |
242 hashIterations=100, |
|
243 ) |
231 if not ok: |
244 if not ok: |
232 return QByteArray() |
245 return QByteArray() |
233 |
246 |
234 return QByteArray(data) |
247 return QByteArray(data) |
235 |
248 |
236 return QByteArray() |
249 return QByteArray() |
237 |
250 |
238 def writeFile(self, data, fileName, type_, timestamp=0): |
251 def writeFile(self, data, fileName, type_, timestamp=0): |
239 """ |
252 """ |
240 Public method to write the data to a file. |
253 Public method to write the data to a file. |
241 |
254 |
242 If encrypted synchronization is enabled, the data will be decrypted |
255 If encrypted synchronization is enabled, the data will be decrypted |
243 using the relevant encryption key. |
256 using the relevant encryption key. |
244 |
257 |
245 @param data data to be written and optionally decrypted (QByteArray) |
258 @param data data to be written and optionally decrypted (QByteArray) |
246 @param fileName name of the file the data is to be written to (string) |
259 @param fileName name of the file the data is to be written to (string) |
247 @param type_ type of the synchronization event (string one |
260 @param type_ type of the synchronization event (string one |
248 of "bookmarks", "history", "passwords", "useragents" or |
261 of "bookmarks", "history", "passwords", "useragents" or |
249 "speeddial") |
262 "speeddial") |
250 @param timestamp timestamp to be given to the file (int) |
263 @param timestamp timestamp to be given to the file (int) |
251 @return tuple giving a success flag and an error string (boolean, |
264 @return tuple giving a success flag and an error string (boolean, |
252 string) |
265 string) |
253 """ |
266 """ |
254 data = bytes(data) |
267 data = bytes(data) |
255 |
268 |
256 if ( |
269 if Preferences.getWebBrowser("SyncEncryptData") and ( |
257 Preferences.getWebBrowser("SyncEncryptData") and |
270 not Preferences.getWebBrowser("SyncEncryptPasswordsOnly") |
258 (not Preferences.getWebBrowser("SyncEncryptPasswordsOnly") or |
271 or ( |
259 (Preferences.getWebBrowser("SyncEncryptPasswordsOnly") and |
272 Preferences.getWebBrowser("SyncEncryptPasswordsOnly") |
260 type_ == "passwords")) |
273 and type_ == "passwords" |
|
274 ) |
261 ): |
275 ): |
262 key = Preferences.getWebBrowser("SyncEncryptionKey") |
276 key = Preferences.getWebBrowser("SyncEncryptionKey") |
263 if not key: |
277 if not key: |
264 return False, self.tr("Invalid encryption key given.") |
278 return False, self.tr("Invalid encryption key given.") |
265 |
279 |
266 data, ok = dataDecrypt( |
280 data, ok = dataDecrypt( |
267 data, key, |
281 data, |
268 keyLength=Preferences.getWebBrowser("SyncEncryptionKeyLength")) |
282 key, |
|
283 keyLength=Preferences.getWebBrowser("SyncEncryptionKeyLength"), |
|
284 ) |
269 if not ok: |
285 if not ok: |
270 return False, self.tr("Data cannot be decrypted.") |
286 return False, self.tr("Data cannot be decrypted.") |
271 |
287 |
272 try: |
288 try: |
273 with open(fileName, "wb") as outputFile: |
289 with open(fileName, "wb") as outputFile: |
274 outputFile.write(data) |
290 outputFile.write(data) |
275 if timestamp > 0: |
291 if timestamp > 0: |
276 os.utime(fileName, (timestamp, timestamp)) |
292 os.utime(fileName, (timestamp, timestamp)) |