|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Flash cookie manager. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 try: |
|
13 str = unicode # __IGNORE_EXCEPTION__ |
|
14 except NameError: |
|
15 pass |
|
16 |
|
17 import shutil |
|
18 |
|
19 from PyQt5.QtCore import QObject, QTimer, QDir, QFileInfo, QFile |
|
20 |
|
21 from .FlashCookie import FlashCookie |
|
22 |
|
23 import Helpviewer.HelpWindow |
|
24 |
|
25 import Preferences |
|
26 |
|
27 |
|
28 class FlashCookieManager(QObject): |
|
29 """ |
|
30 Class implementing the Flash cookie manager object. |
|
31 """ |
|
32 RefreshInterval = 60 * 1000 |
|
33 |
|
34 def __init__(self, parent=None): |
|
35 """ |
|
36 Constructor |
|
37 |
|
38 @param parent reference to the parent object |
|
39 @type QObject |
|
40 """ |
|
41 super(FlashCookieManager, self).__init__(parent) |
|
42 |
|
43 self.__flashCookieManagerDialog = None |
|
44 self.__flashCookies = [] # list of FlashCookie |
|
45 self.__newCookiesList = [] # list of str |
|
46 self.__whitelist = [] # list of str |
|
47 self.__blacklist = [] # list of str |
|
48 |
|
49 self.__timer = QTimer(self) |
|
50 self.__timer.setInterval(FlashCookieManager.RefreshInterval) |
|
51 self.__timer.timeout.connect(self.__autoRefresh) |
|
52 |
|
53 # start the timer if needed |
|
54 self.__startStopTimer() |
|
55 |
|
56 if Preferences.getHelp("FlashCookiesDeleteOnStartExit"): |
|
57 self.__loadFlashCookies() |
|
58 self.__removeAllButWhitelisted() |
|
59 |
|
60 def shutdown(self): |
|
61 """ |
|
62 Public method to perform shutdown actions. |
|
63 """ |
|
64 if self.__flashCookieManagerDialog is not None: |
|
65 self.__flashCookieManagerDialog.close() |
|
66 |
|
67 if Preferences.getHelp("FlashCookiesDeleteOnStartExit"): |
|
68 self.__removeAllButWhitelisted() |
|
69 |
|
70 def setFlashCookies(self, cookies): |
|
71 """ |
|
72 Public method to set the list of cached Flash cookies. |
|
73 |
|
74 @param cookies list of Flash cookies to store |
|
75 @type list of FlashCookie |
|
76 """ |
|
77 self.__flashCookies = cookies[:] |
|
78 |
|
79 def flashCookies(self): |
|
80 """ |
|
81 Public method to get the list of cached Flash cookies. |
|
82 |
|
83 @return list of Flash cookies |
|
84 @rtype list of FlashCookie |
|
85 """ |
|
86 if not self.__flashCookies: |
|
87 self.__loadFlashCookies() |
|
88 |
|
89 return self.__flashCookies[:] |
|
90 |
|
91 def newCookiesList(self): |
|
92 """ |
|
93 Public method to get the list of newly detected Flash cookies. |
|
94 |
|
95 @return list of newly detected Flash cookies |
|
96 @rtype list of str |
|
97 """ |
|
98 return self.__newCookiesList[:] |
|
99 |
|
100 def clearNewOrigins(self): |
|
101 """ |
|
102 Public method to clear the list of newly detected Flash cookies. |
|
103 """ |
|
104 self.__newCookiesList = [] |
|
105 |
|
106 def clearCache(self): |
|
107 """ |
|
108 Public method to clear the list of cached Flash cookies. |
|
109 """ |
|
110 self.__flashCookies = [] |
|
111 |
|
112 def __isBlacklisted(self, cookie): |
|
113 """ |
|
114 Private method to check for a blacklisted cookie. |
|
115 |
|
116 @param cookie Flash cookie to be tested |
|
117 @type FlashCookie |
|
118 """ |
|
119 return cookie.origin in Preferences.getHelp("FlashCookiesBlacklist") |
|
120 |
|
121 def __isWhitelisted(self, cookie): |
|
122 """ |
|
123 Private method to check for a whitelisted cookie. |
|
124 |
|
125 @param cookie Flash cookie to be tested |
|
126 @type FlashCookie |
|
127 """ |
|
128 return cookie.origin in Preferences.getHelp("FlashCookiesWhitelist") |
|
129 |
|
130 def __removeAllButWhitelisted(self): |
|
131 """ |
|
132 Private method to remove all non-whitelisted cookies. |
|
133 """ |
|
134 for cookie in self.__flashCookies[:]: |
|
135 if not self.__isWhitelisted(cookie): |
|
136 self.removeCookie(cookie) |
|
137 |
|
138 def __sharedObjectDirName(self): |
|
139 """ |
|
140 Private slot to determine the path of the shared data objects. |
|
141 |
|
142 @return path of the shared data objects |
|
143 @rtype str |
|
144 """ |
|
145 if "macromedia" in self.flashPlayerDataPath().lower() or \ |
|
146 "/.gnash" not in self.flashPlayerDataPath().lower(): |
|
147 return "/#SharedObjects/" |
|
148 else: |
|
149 return "/SharedObjects/" |
|
150 |
|
151 def flashPlayerDataPath(self): |
|
152 """ |
|
153 Public method to get the Flash Player data path. |
|
154 |
|
155 @return Flash Player data path |
|
156 @rtype str |
|
157 """ |
|
158 return Preferences.getHelp("FlashCookiesDataPath") |
|
159 |
|
160 def preferencesChanged(self): |
|
161 """ |
|
162 Public slot to handle a change of preferences. |
|
163 """ |
|
164 self.__startStopTimer() |
|
165 |
|
166 def removeCookie(self, cookie): |
|
167 """ |
|
168 Public method to remove a cookie of the list of cached cookies. |
|
169 |
|
170 @param cookie Flash cookie to be removed |
|
171 @type FlashCookie |
|
172 """ |
|
173 if cookie in self.__flashCookies: |
|
174 self.__flashCookies.remove(cookie) |
|
175 shutil.rmtree(cookie.path, True) |
|
176 |
|
177 def __autoRefresh(self): |
|
178 """ |
|
179 Private slot to refresh the list of cookies. |
|
180 """ |
|
181 if self.__flashCookieManagerDialog and \ |
|
182 self.__flashCookieManagerDialog.isVisible(): |
|
183 return |
|
184 |
|
185 oldFlashCookies = self.__flashCookies[:] |
|
186 self.__loadFlashCookies() |
|
187 newCookieList = [] |
|
188 |
|
189 for cookie in self.__flashCookies[:]: |
|
190 if self.__isBlacklisted(cookie): |
|
191 self.removeCookie(cookie) |
|
192 continue |
|
193 |
|
194 if self.__isWhitelisted(cookie): |
|
195 continue |
|
196 |
|
197 newCookie = True |
|
198 for oldCookie in oldFlashCookies: |
|
199 if (oldCookie.path + oldCookie.name == |
|
200 cookie.path + cookie.name): |
|
201 newCookie = False |
|
202 break |
|
203 |
|
204 if newCookie: |
|
205 newCookieList.append(cookie.path + "/" + cookie.name) |
|
206 |
|
207 if newCookieList and Preferences.getHelp("FlashCookieNotify"): |
|
208 self.__newCookiesList.extend(newCookieList) |
|
209 win = Helpviewer.HelpWindow.HelpWindow.mainWindow() |
|
210 if win is None: |
|
211 return |
|
212 |
|
213 view = win.currentBrowser() |
|
214 if view is None: |
|
215 return |
|
216 |
|
217 from .FlashCookieNotification import FlashCookieNotification |
|
218 notification = FlashCookieNotification( |
|
219 view, self, len(newCookieList)) |
|
220 notification.show() |
|
221 |
|
222 def showFlashCookieManagerDialog(self): |
|
223 """ |
|
224 Public method to show the Flash cookies management dialog. |
|
225 """ |
|
226 if self.__flashCookieManagerDialog is None: |
|
227 from .FlashCookieManagerDialog import FlashCookieManagerDialog |
|
228 self.__flashCookieManagerDialog = FlashCookieManagerDialog(self) |
|
229 |
|
230 self.__flashCookieManagerDialog.refreshView() |
|
231 self.__flashCookieManagerDialog.showPage(0) |
|
232 self.__flashCookieManagerDialog.show() |
|
233 self.__flashCookieManagerDialog.raise_() |
|
234 |
|
235 def __startStopTimer(self): |
|
236 """ |
|
237 Private slot to start or stop the auto refresh timer. |
|
238 """ |
|
239 if Preferences.getHelp("FlashCookieAutoRefresh"): |
|
240 if not self.__timer.isActive(): |
|
241 if not bool(self.__flashCookies): |
|
242 self.__loadFlashCookies() |
|
243 |
|
244 self.__timer.start() |
|
245 else: |
|
246 self.__timer.stop() |
|
247 |
|
248 def __loadFlashCookies(self): |
|
249 """ |
|
250 Private slot to load the Flash cookies to be cached. |
|
251 """ |
|
252 self.__flashCookies = [] |
|
253 self.__loadFlashCookiesFromPath(self.flashPlayerDataPath()) |
|
254 |
|
255 def __loadFlashCookiesFromPath(self, path): |
|
256 """ |
|
257 Private slot to load the Flash cookies from a path. |
|
258 |
|
259 @param path Flash cookies path |
|
260 @type str |
|
261 """ |
|
262 if path.endswith(("#SharedObjects", "#AppContainer")): |
|
263 # specific to IE and Windows |
|
264 return |
|
265 |
|
266 path = path.replace("\\", "/") |
|
267 solDir = QDir(path) |
|
268 entryList = solDir.entryList() |
|
269 for entry in entryList: |
|
270 if entry == "." or entry == "..": |
|
271 continue |
|
272 entryInfo = QFileInfo(path + "/" + entry) |
|
273 if entryInfo.isDir(): |
|
274 self.__loadFlashCookiesFromPath(entryInfo.filePath()) |
|
275 else: |
|
276 self.__insertFlashCookie(entryInfo.filePath()) |
|
277 |
|
278 def __insertFlashCookie(self, path): |
|
279 """ |
|
280 Private method to insert a Flash cookie into the cache. |
|
281 |
|
282 @param path Flash cookies path |
|
283 @type str |
|
284 """ |
|
285 solFile = QFile(path) |
|
286 if not solFile.open(QFile.ReadOnly): |
|
287 return |
|
288 |
|
289 # TODO: dissect the flash cookie (see gnash s2x.py for example) |
|
290 data = bytearray(solFile.readAll()) |
|
291 for i in range(len(data)): |
|
292 if not ((data[i] >= ord("a") and data[i] <= ord("z")) or |
|
293 (data[i] >= ord("A") and data[i] <= ord("Z")) or |
|
294 (data[i] >= ord("0") and data[i] <= ord("9"))): |
|
295 data[i] = 32 |
|
296 dataStr = str(data, "utf-8", "replace") |
|
297 dataStr = "\n".join([s for s in dataStr.split(".") if s]) |
|
298 |
|
299 solFileInfo = QFileInfo(solFile) |
|
300 |
|
301 cookie = FlashCookie() |
|
302 cookie.contents = dataStr |
|
303 cookie.name = solFileInfo.fileName() |
|
304 cookie.path = solFileInfo.canonicalPath() |
|
305 cookie.size = int(solFile.size()) |
|
306 cookie.lastModified = solFileInfo.lastModified() |
|
307 cookie.origin = self.__extractOriginFrom(path) |
|
308 |
|
309 self.__flashCookies.append(cookie) |
|
310 |
|
311 def __extractOriginFrom(self, path): |
|
312 """ |
|
313 Private method to extract the cookie origin given its file name. |
|
314 |
|
315 @param path file name of the cookie file |
|
316 @type str |
|
317 @return cookie origin |
|
318 @rtype str |
|
319 """ |
|
320 origin = path |
|
321 if path.startswith( |
|
322 self.flashPlayerDataPath() + self.__sharedObjectDirName()): |
|
323 origin = origin.replace( |
|
324 self.flashPlayerDataPath() + self.__sharedObjectDirName(), "") |
|
325 if "/" in origin: |
|
326 origin = origin.split("/", 1)[1] |
|
327 elif path.startswith( |
|
328 self.flashPlayerDataPath() + |
|
329 "/macromedia.com/support/flashplayer/sys/"): |
|
330 origin = origin.replace( |
|
331 self.flashPlayerDataPath() + |
|
332 "/macromedia.com/support/flashplayer/sys/", "") |
|
333 if origin == "settings.sol": |
|
334 return self.tr("!default") |
|
335 elif origin.startswith("#"): |
|
336 origin = origin[1:] |
|
337 else: |
|
338 origin = "" |
|
339 |
|
340 index = origin.find("/") |
|
341 if index == -1: |
|
342 return self.tr("!other") |
|
343 |
|
344 origin = origin[:index] |
|
345 if origin in ["localhost", "local"]: |
|
346 origin = "!localhost" |
|
347 |
|
348 return origin |