src/eric7/WebBrowser/Sync/SyncHandler.py

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

eric ide

mercurial