src/eric7/WebBrowser/SafeBrowsing/SafeBrowsingCache.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
15 # 15 #
16 16
17 import os 17 import os
18 18
19 from PyQt6.QtCore import ( 19 from PyQt6.QtCore import (
20 QObject, QByteArray, QCryptographicHash, QCoreApplication, QEventLoop 20 QObject,
21 QByteArray,
22 QCryptographicHash,
23 QCoreApplication,
24 QEventLoop,
21 ) 25 )
22 from PyQt6.QtSql import QSql, QSqlDatabase, QSqlQuery 26 from PyQt6.QtSql import QSql, QSqlDatabase, QSqlQuery
23 27
24 from .SafeBrowsingThreatList import ThreatList 28 from .SafeBrowsingThreatList import ThreatList
25 29
26 30
27 class SafeBrowsingCache(QObject): 31 class SafeBrowsingCache(QObject):
28 """ 32 """
29 Class implementing a cache for Google Safe Browsing. 33 Class implementing a cache for Google Safe Browsing.
30 """ 34 """
35
31 create_threat_list_stmt = """ 36 create_threat_list_stmt = """
32 CREATE TABLE threat_list 37 CREATE TABLE threat_list
33 (threat_type character varying(128) NOT NULL, 38 (threat_type character varying(128) NOT NULL,
34 platform_type character varying(128) NOT NULL, 39 platform_type character varying(128) NOT NULL,
35 threat_entry_type character varying(128) NOT NULL, 40 threat_entry_type character varying(128) NOT NULL,
37 timestamp timestamp without time zone DEFAULT current_timestamp, 42 timestamp timestamp without time zone DEFAULT current_timestamp,
38 PRIMARY KEY (threat_type, platform_type, threat_entry_type) 43 PRIMARY KEY (threat_type, platform_type, threat_entry_type)
39 ) 44 )
40 """ 45 """
41 drop_threat_list_stmt = """DROP TABLE IF EXISTS threat_list""" 46 drop_threat_list_stmt = """DROP TABLE IF EXISTS threat_list"""
42 47
43 create_full_hashes_stmt = """ 48 create_full_hashes_stmt = """
44 CREATE TABLE full_hash 49 CREATE TABLE full_hash
45 (value BLOB NOT NULL, 50 (value BLOB NOT NULL,
46 threat_type character varying(128) NOT NULL, 51 threat_type character varying(128) NOT NULL,
47 platform_type character varying(128) NOT NULL, 52 platform_type character varying(128) NOT NULL,
52 malware_threat_type varchar(32), 57 malware_threat_type varchar(32),
53 PRIMARY KEY (value, threat_type, platform_type, threat_entry_type) 58 PRIMARY KEY (value, threat_type, platform_type, threat_entry_type)
54 ) 59 )
55 """ 60 """
56 drop_full_hashes_stmt = """DROP TABLE IF EXISTS full_hash""" 61 drop_full_hashes_stmt = """DROP TABLE IF EXISTS full_hash"""
57 62
58 create_hash_prefix_stmt = """ 63 create_hash_prefix_stmt = """
59 CREATE TABLE hash_prefix 64 CREATE TABLE hash_prefix
60 (value BLOB NOT NULL, 65 (value BLOB NOT NULL,
61 cue character varying(4) NOT NULL, 66 cue character varying(4) NOT NULL,
62 threat_type character varying(128) NOT NULL, 67 threat_type character varying(128) NOT NULL,
70 REFERENCES threat_list(threat_type, platform_type, threat_entry_type) 75 REFERENCES threat_list(threat_type, platform_type, threat_entry_type)
71 ON DELETE CASCADE 76 ON DELETE CASCADE
72 ) 77 )
73 """ 78 """
74 drop_hash_prefix_stmt = """DROP TABLE IF EXISTS hash_prefix""" 79 drop_hash_prefix_stmt = """DROP TABLE IF EXISTS hash_prefix"""
75 80
76 create_full_hash_cue_idx = """ 81 create_full_hash_cue_idx = """
77 CREATE INDEX idx_hash_prefix_cue ON hash_prefix (cue) 82 CREATE INDEX idx_hash_prefix_cue ON hash_prefix (cue)
78 """ 83 """
79 drop_full_hash_cue_idx = """DROP INDEX IF EXISTS idx_hash_prefix_cue""" 84 drop_full_hash_cue_idx = """DROP INDEX IF EXISTS idx_hash_prefix_cue"""
80 85
81 create_full_hash_expires_idx = """ 86 create_full_hash_expires_idx = """
82 CREATE INDEX idx_full_hash_expires_at ON full_hash (expires_at) 87 CREATE INDEX idx_full_hash_expires_at ON full_hash (expires_at)
83 """ 88 """
84 drop_full_hash_expires_idx = """ 89 drop_full_hash_expires_idx = """
85 DROP INDEX IF EXISTS idx_full_hash_expires_at 90 DROP INDEX IF EXISTS idx_full_hash_expires_at
86 """ 91 """
87 92
88 create_full_hash_value_idx = """ 93 create_full_hash_value_idx = """
89 CREATE INDEX idx_full_hash_value ON full_hash (value) 94 CREATE INDEX idx_full_hash_value ON full_hash (value)
90 """ 95 """
91 drop_full_hash_value_idx = """DROP INDEX IF EXISTS idx_full_hash_value""" 96 drop_full_hash_value_idx = """DROP INDEX IF EXISTS idx_full_hash_value"""
92 97
93 maxProcessEventsTime = 500 98 maxProcessEventsTime = 500
94 99
95 def __init__(self, dbPath, parent=None): 100 def __init__(self, dbPath, parent=None):
96 """ 101 """
97 Constructor 102 Constructor
98 103
99 @param dbPath path to store the cache DB into 104 @param dbPath path to store the cache DB into
100 @type str 105 @type str
101 @param parent reference to the parent object 106 @param parent reference to the parent object
102 @type QObject 107 @type QObject
103 """ 108 """
104 super().__init__(parent) 109 super().__init__(parent)
105 110
106 self.__connectionName = "SafeBrowsingCache" 111 self.__connectionName = "SafeBrowsingCache"
107 112
108 if not os.path.exists(dbPath): 113 if not os.path.exists(dbPath):
109 os.makedirs(dbPath) 114 os.makedirs(dbPath)
110 115
111 self.__dbFileName = os.path.join(dbPath, "SafeBrowsingCache.db") 116 self.__dbFileName = os.path.join(dbPath, "SafeBrowsingCache.db")
112 preparationNeeded = not os.path.exists(self.__dbFileName) 117 preparationNeeded = not os.path.exists(self.__dbFileName)
113 118
114 self.__openCacheDb() 119 self.__openCacheDb()
115 if preparationNeeded: 120 if preparationNeeded:
116 self.prepareCacheDb() 121 self.prepareCacheDb()
117 122
118 def close(self): 123 def close(self):
119 """ 124 """
120 Public method to close the database. 125 Public method to close the database.
121 """ 126 """
122 if QSqlDatabase.database(self.__connectionName).isOpen(): 127 if QSqlDatabase.database(self.__connectionName).isOpen():
123 QSqlDatabase.database(self.__connectionName).close() 128 QSqlDatabase.database(self.__connectionName).close()
124 QSqlDatabase.removeDatabase(self.__connectionName) 129 QSqlDatabase.removeDatabase(self.__connectionName)
125 130
126 def __openCacheDb(self): 131 def __openCacheDb(self):
127 """ 132 """
128 Private method to open the cache database. 133 Private method to open the cache database.
129 134
130 @return flag indicating the open state 135 @return flag indicating the open state
131 @rtype bool 136 @rtype bool
132 """ 137 """
133 db = QSqlDatabase.database(self.__connectionName, False) 138 db = QSqlDatabase.database(self.__connectionName, False)
134 if not db.isValid(): 139 if not db.isValid():
139 if not opened: 144 if not opened:
140 QSqlDatabase.removeDatabase(self.__connectionName) 145 QSqlDatabase.removeDatabase(self.__connectionName)
141 else: 146 else:
142 opened = True 147 opened = True
143 return opened 148 return opened
144 149
145 def prepareCacheDb(self): 150 def prepareCacheDb(self):
146 """ 151 """
147 Public method to prepare the cache database. 152 Public method to prepare the cache database.
148 """ 153 """
149 db = QSqlDatabase.database(self.__connectionName) 154 db = QSqlDatabase.database(self.__connectionName)
167 query.exec(self.create_full_hash_expires_idx) 172 query.exec(self.create_full_hash_expires_idx)
168 query.exec(self.create_full_hash_value_idx) 173 query.exec(self.create_full_hash_value_idx)
169 finally: 174 finally:
170 del query 175 del query
171 db.commit() 176 db.commit()
172 177
173 def lookupFullHashes(self, hashValues): 178 def lookupFullHashes(self, hashValues):
174 """ 179 """
175 Public method to get a list of threat lists and expiration flag 180 Public method to get a list of threat lists and expiration flag
176 for the given hashes if a hash is blacklisted. 181 for the given hashes if a hash is blacklisted.
177 182
178 @param hashValues list of hash values to look up 183 @param hashValues list of hash values to look up
179 @type list of bytes 184 @type list of bytes
180 @return list of tuples containing the threat list info and the 185 @return list of tuples containing the threat list info and the
181 expiration flag 186 expiration flag
182 @rtype list of tuple of (ThreatList, bool) 187 @rtype list of tuple of (ThreatList, bool)
185 SELECT threat_type, platform_type, threat_entry_type, 190 SELECT threat_type, platform_type, threat_entry_type,
186 expires_at < current_timestamp AS has_expired 191 expires_at < current_timestamp AS has_expired
187 FROM full_hash WHERE value IN ({0}) 192 FROM full_hash WHERE value IN ({0})
188 """ 193 """
189 output = [] 194 output = []
190 195
191 db = QSqlDatabase.database(self.__connectionName) 196 db = QSqlDatabase.database(self.__connectionName)
192 if db.isOpen(): 197 if db.isOpen():
193 db.transaction() 198 db.transaction()
194 try: 199 try:
195 query = QSqlQuery(db) 200 query = QSqlQuery(db)
196 query.prepare( 201 query.prepare(queryStr.format(",".join(["?"] * len(hashValues))))
197 queryStr.format(",".join(["?"] * len(hashValues))))
198 for hashValue in hashValues: 202 for hashValue in hashValues:
199 query.addBindValue( 203 query.addBindValue(
200 QByteArray(hashValue), 204 QByteArray(hashValue),
201 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary) 205 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
202 206 )
203 query.exec() 207
204 208 query.exec()
205 while query.next(): # __IGNORE_WARNING_M523__ 209
210 while query.next(): # __IGNORE_WARNING_M523__
206 threatType = query.value(0) 211 threatType = query.value(0)
207 platformType = query.value(1) 212 platformType = query.value(1)
208 threatEntryType = query.value(2) 213 threatEntryType = query.value(2)
209 hasExpired = bool(query.value(3)) 214 hasExpired = bool(query.value(3))
210 threatList = ThreatList(threatType, platformType, 215 threatList = ThreatList(threatType, platformType, threatEntryType)
211 threatEntryType)
212 output.append((threatList, hasExpired)) 216 output.append((threatList, hasExpired))
213 QCoreApplication.processEvents( 217 QCoreApplication.processEvents(
214 QEventLoop.ProcessEventsFlag.AllEvents, 218 QEventLoop.ProcessEventsFlag.AllEvents,
215 self.maxProcessEventsTime) 219 self.maxProcessEventsTime,
216 del query 220 )
217 finally: 221 del query
218 db.commit() 222 finally:
219 223 db.commit()
224
220 return output 225 return output
221 226
222 def lookupHashPrefix(self, prefixes): 227 def lookupHashPrefix(self, prefixes):
223 """ 228 """
224 Public method to look up hash prefixes in the local cache. 229 Public method to look up hash prefixes in the local cache.
225 230
226 @param prefixes list of hash prefixes to look up 231 @param prefixes list of hash prefixes to look up
227 @type list of bytes 232 @type list of bytes
228 @return list of tuples containing the threat list, full hash and 233 @return list of tuples containing the threat list, full hash and
229 negative cache expiration flag 234 negative cache expiration flag
230 @rtype list of tuple of (ThreatList, bytes, bool) 235 @rtype list of tuple of (ThreatList, bytes, bool)
233 SELECT value,threat_type,platform_type,threat_entry_type, 238 SELECT value,threat_type,platform_type,threat_entry_type,
234 negative_expires_at < current_timestamp AS negative_cache_expired 239 negative_expires_at < current_timestamp AS negative_cache_expired
235 FROM hash_prefix WHERE cue IN ({0}) 240 FROM hash_prefix WHERE cue IN ({0})
236 """ 241 """
237 output = [] 242 output = []
238 243
239 db = QSqlDatabase.database(self.__connectionName) 244 db = QSqlDatabase.database(self.__connectionName)
240 if db.isOpen(): 245 if db.isOpen():
241 db.transaction() 246 db.transaction()
242 try: 247 try:
243 query = QSqlQuery(db) 248 query = QSqlQuery(db)
244 query.prepare( 249 query.prepare(queryStr.format(",".join(["?"] * len(prefixes))))
245 queryStr.format(",".join(["?"] * len(prefixes))))
246 for prefix in prefixes: 250 for prefix in prefixes:
247 query.addBindValue(prefix) 251 query.addBindValue(prefix)
248 252
249 query.exec() 253 query.exec()
250 254
251 while query.next(): # __IGNORE_WARNING_M523__ 255 while query.next(): # __IGNORE_WARNING_M523__
252 fullHash = bytes(query.value(0)) 256 fullHash = bytes(query.value(0))
253 threatType = query.value(1) 257 threatType = query.value(1)
254 platformType = query.value(2) 258 platformType = query.value(2)
255 threatEntryType = query.value(3) 259 threatEntryType = query.value(3)
256 negativeCacheExpired = bool(query.value(4)) 260 negativeCacheExpired = bool(query.value(4))
257 threatList = ThreatList(threatType, platformType, 261 threatList = ThreatList(threatType, platformType, threatEntryType)
258 threatEntryType)
259 output.append((threatList, fullHash, negativeCacheExpired)) 262 output.append((threatList, fullHash, negativeCacheExpired))
260 QCoreApplication.processEvents( 263 QCoreApplication.processEvents(
261 QEventLoop.ProcessEventsFlag.AllEvents, 264 QEventLoop.ProcessEventsFlag.AllEvents,
262 self.maxProcessEventsTime) 265 self.maxProcessEventsTime,
263 del query 266 )
264 finally: 267 del query
265 db.commit() 268 finally:
266 269 db.commit()
270
267 return output 271 return output
268 272
269 def storeFullHash(self, threatList, hashValue, cacheDuration, 273 def storeFullHash(self, threatList, hashValue, cacheDuration, malwareThreatType):
270 malwareThreatType):
271 """ 274 """
272 Public method to store full hash data in the cache database. 275 Public method to store full hash data in the cache database.
273 276
274 @param threatList threat list info object 277 @param threatList threat list info object
275 @type ThreatList 278 @type ThreatList
276 @param hashValue hash to be stored 279 @param hashValue hash to be stored
277 @type bytes 280 @type bytes
278 @param cacheDuration duration the data should remain in the cache 281 @param cacheDuration duration the data should remain in the cache
285 (value, threat_type, platform_type, threat_entry_type, 288 (value, threat_type, platform_type, threat_entry_type,
286 malware_threat_type, downloaded_at) 289 malware_threat_type, downloaded_at)
287 VALUES 290 VALUES
288 (?, ?, ?, ?, ?, current_timestamp) 291 (?, ?, ?, ?, ?, current_timestamp)
289 """ 292 """
290 updateQueryStr = ( 293 updateQueryStr = """
291 """
292 UPDATE full_hash SET 294 UPDATE full_hash SET
293 expires_at=datetime(current_timestamp, '+{0} SECONDS') 295 expires_at=datetime(current_timestamp, '+{0} SECONDS')
294 WHERE value=? AND threat_type=? AND platform_type=? AND 296 WHERE value=? AND threat_type=? AND platform_type=? AND
295 threat_entry_type=? 297 threat_entry_type=?
296 """.format(int(cacheDuration)) 298 """.format(
299 int(cacheDuration)
297 ) 300 )
298 301
299 db = QSqlDatabase.database(self.__connectionName) 302 db = QSqlDatabase.database(self.__connectionName)
300 if db.isOpen(): 303 if db.isOpen():
301 db.transaction() 304 db.transaction()
302 try: 305 try:
303 query = QSqlQuery(db) 306 query = QSqlQuery(db)
304 query.prepare(insertQueryStr) 307 query.prepare(insertQueryStr)
305 query.addBindValue( 308 query.addBindValue(
306 QByteArray(hashValue), 309 QByteArray(hashValue),
307 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary) 310 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
311 )
308 query.addBindValue(threatList.threatType) 312 query.addBindValue(threatList.threatType)
309 query.addBindValue(threatList.platformType) 313 query.addBindValue(threatList.platformType)
310 query.addBindValue(threatList.threatEntryType) 314 query.addBindValue(threatList.threatEntryType)
311 query.addBindValue(malwareThreatType) 315 query.addBindValue(malwareThreatType)
312 query.exec() 316 query.exec()
313 del query 317 del query
314 318
315 query = QSqlQuery(db) 319 query = QSqlQuery(db)
316 query.prepare(updateQueryStr) 320 query.prepare(updateQueryStr)
317 query.addBindValue( 321 query.addBindValue(
318 QByteArray(hashValue), 322 QByteArray(hashValue),
319 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary) 323 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
320 query.addBindValue(threatList.threatType) 324 )
321 query.addBindValue(threatList.platformType) 325 query.addBindValue(threatList.threatType)
322 query.addBindValue(threatList.threatEntryType) 326 query.addBindValue(threatList.platformType)
323 query.exec() 327 query.addBindValue(threatList.threatEntryType)
324 del query 328 query.exec()
325 finally: 329 del query
326 db.commit() 330 finally:
327 331 db.commit()
332
328 def deleteHashPrefixList(self, threatList): 333 def deleteHashPrefixList(self, threatList):
329 """ 334 """
330 Public method to delete hash prefixes for a given threat list. 335 Public method to delete hash prefixes for a given threat list.
331 336
332 @param threatList threat list info object 337 @param threatList threat list info object
333 @type ThreatList 338 @type ThreatList
334 """ 339 """
335 queryStr = """ 340 queryStr = """
336 DELETE FROM hash_prefix 341 DELETE FROM hash_prefix
337 WHERE threat_type=? AND platform_type=? AND threat_entry_type=? 342 WHERE threat_type=? AND platform_type=? AND threat_entry_type=?
338 """ 343 """
339 344
340 db = QSqlDatabase.database(self.__connectionName) 345 db = QSqlDatabase.database(self.__connectionName)
341 if db.isOpen(): 346 if db.isOpen():
342 db.transaction() 347 db.transaction()
343 try: 348 try:
344 query = QSqlQuery(db) 349 query = QSqlQuery(db)
345 query.prepare(queryStr) 350 query.prepare(queryStr)
346 query.addBindValue(threatList.threatType) 351 query.addBindValue(threatList.threatType)
347 query.addBindValue(threatList.platformType) 352 query.addBindValue(threatList.platformType)
348 query.addBindValue(threatList.threatEntryType) 353 query.addBindValue(threatList.threatEntryType)
349 query.exec() 354 query.exec()
350 del query 355 del query
351 finally: 356 finally:
352 db.commit() 357 db.commit()
353 358
354 def cleanupFullHashes(self, keepExpiredFor=43200): 359 def cleanupFullHashes(self, keepExpiredFor=43200):
355 """ 360 """
356 Public method to clean up full hash entries expired more than the 361 Public method to clean up full hash entries expired more than the
357 given time. 362 given time.
358 363
359 @param keepExpiredFor time period in seconds of entries to be expired 364 @param keepExpiredFor time period in seconds of entries to be expired
360 @type int or float 365 @type int or float
361 """ 366 """
362 queryStr = ( 367 queryStr = """
363 """
364 DELETE FROM full_hash 368 DELETE FROM full_hash
365 WHERE expires_at=datetime(current_timestamp, '{0} SECONDS') 369 WHERE expires_at=datetime(current_timestamp, '{0} SECONDS')
366 """.format(int(keepExpiredFor)) 370 """.format(
371 int(keepExpiredFor)
367 ) 372 )
368 373
369 db = QSqlDatabase.database(self.__connectionName) 374 db = QSqlDatabase.database(self.__connectionName)
370 if db.isOpen(): 375 if db.isOpen():
371 db.transaction() 376 db.transaction()
372 try: 377 try:
373 query = QSqlQuery(db) 378 query = QSqlQuery(db)
374 query.prepare(queryStr) 379 query.prepare(queryStr)
375 query.exec() 380 query.exec()
376 del query 381 del query
377 finally: 382 finally:
378 db.commit() 383 db.commit()
379 384
380 def updateHashPrefixExpiration(self, threatList, hashPrefix, 385 def updateHashPrefixExpiration(self, threatList, hashPrefix, negativeCacheDuration):
381 negativeCacheDuration):
382 """ 386 """
383 Public method to update the hash prefix expiration time. 387 Public method to update the hash prefix expiration time.
384 388
385 @param threatList threat list info object 389 @param threatList threat list info object
386 @type ThreatList 390 @type ThreatList
387 @param hashPrefix hash prefix 391 @param hashPrefix hash prefix
388 @type bytes 392 @type bytes
389 @param negativeCacheDuration time in seconds the entry should remain 393 @param negativeCacheDuration time in seconds the entry should remain
390 in the cache 394 in the cache
391 @type int or float 395 @type int or float
392 """ 396 """
393 queryStr = ( 397 queryStr = """
394 """
395 UPDATE hash_prefix 398 UPDATE hash_prefix
396 SET negative_expires_at=datetime(current_timestamp, '+{0} SECONDS') 399 SET negative_expires_at=datetime(current_timestamp, '+{0} SECONDS')
397 WHERE value=? AND threat_type=? AND platform_type=? AND 400 WHERE value=? AND threat_type=? AND platform_type=? AND
398 threat_entry_type=? 401 threat_entry_type=?
399 """.format(int(negativeCacheDuration)) 402 """.format(
403 int(negativeCacheDuration)
400 ) 404 )
401 405
402 db = QSqlDatabase.database(self.__connectionName) 406 db = QSqlDatabase.database(self.__connectionName)
403 if db.isOpen(): 407 if db.isOpen():
404 db.transaction() 408 db.transaction()
405 try: 409 try:
406 query = QSqlQuery(db) 410 query = QSqlQuery(db)
407 query.prepare(queryStr) 411 query.prepare(queryStr)
408 query.addBindValue( 412 query.addBindValue(
409 QByteArray(hashPrefix), 413 QByteArray(hashPrefix),
410 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary) 414 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
411 query.addBindValue(threatList.threatType) 415 )
412 query.addBindValue(threatList.platformType) 416 query.addBindValue(threatList.threatType)
413 query.addBindValue(threatList.threatEntryType) 417 query.addBindValue(threatList.platformType)
414 query.exec() 418 query.addBindValue(threatList.threatEntryType)
415 del query 419 query.exec()
416 finally: 420 del query
417 db.commit() 421 finally:
418 422 db.commit()
423
419 def getThreatLists(self): 424 def getThreatLists(self):
420 """ 425 """
421 Public method to get the available threat lists. 426 Public method to get the available threat lists.
422 427
423 @return list of available threat lists 428 @return list of available threat lists
424 @rtype list of tuples of (ThreatList, str) 429 @rtype list of tuples of (ThreatList, str)
425 """ 430 """
426 queryStr = """ 431 queryStr = """
427 SELECT threat_type,platform_type,threat_entry_type,client_state 432 SELECT threat_type,platform_type,threat_entry_type,client_state
428 FROM threat_list 433 FROM threat_list
429 """ 434 """
430 output = [] 435 output = []
431 436
432 db = QSqlDatabase.database(self.__connectionName) 437 db = QSqlDatabase.database(self.__connectionName)
433 if db.isOpen(): 438 if db.isOpen():
434 db.transaction() 439 db.transaction()
435 try: 440 try:
436 query = QSqlQuery(db) 441 query = QSqlQuery(db)
437 query.prepare(queryStr) 442 query.prepare(queryStr)
438 443
439 query.exec() 444 query.exec()
440 445
441 while query.next(): # __IGNORE_WARNING_M523__ 446 while query.next(): # __IGNORE_WARNING_M523__
442 threatType = query.value(0) 447 threatType = query.value(0)
443 platformType = query.value(1) 448 platformType = query.value(1)
444 threatEntryType = query.value(2) 449 threatEntryType = query.value(2)
445 clientState = query.value(3) 450 clientState = query.value(3)
446 threatList = ThreatList(threatType, platformType, 451 threatList = ThreatList(threatType, platformType, threatEntryType)
447 threatEntryType)
448 output.append((threatList, clientState)) 452 output.append((threatList, clientState))
449 QCoreApplication.processEvents( 453 QCoreApplication.processEvents(
450 QEventLoop.ProcessEventsFlag.AllEvents, 454 QEventLoop.ProcessEventsFlag.AllEvents,
451 self.maxProcessEventsTime) 455 self.maxProcessEventsTime,
452 del query 456 )
453 finally: 457 del query
454 db.commit() 458 finally:
455 459 db.commit()
460
456 return output 461 return output
457 462
458 def addThreatList(self, threatList): 463 def addThreatList(self, threatList):
459 """ 464 """
460 Public method to add a threat list to the cache. 465 Public method to add a threat list to the cache.
461 466
462 @param threatList threat list to be added 467 @param threatList threat list to be added
463 @type ThreatList 468 @type ThreatList
464 """ 469 """
465 queryStr = """ 470 queryStr = """
466 INSERT OR IGNORE INTO threat_list 471 INSERT OR IGNORE INTO threat_list
467 (threat_type, platform_type, threat_entry_type, timestamp) 472 (threat_type, platform_type, threat_entry_type, timestamp)
468 VALUES (?, ?, ?, current_timestamp) 473 VALUES (?, ?, ?, current_timestamp)
469 """ 474 """
470 475
471 db = QSqlDatabase.database(self.__connectionName) 476 db = QSqlDatabase.database(self.__connectionName)
472 if db.isOpen(): 477 if db.isOpen():
473 db.transaction() 478 db.transaction()
474 try: 479 try:
475 query = QSqlQuery(db) 480 query = QSqlQuery(db)
476 query.prepare(queryStr) 481 query.prepare(queryStr)
477 query.addBindValue(threatList.threatType) 482 query.addBindValue(threatList.threatType)
478 query.addBindValue(threatList.platformType) 483 query.addBindValue(threatList.platformType)
479 query.addBindValue(threatList.threatEntryType) 484 query.addBindValue(threatList.threatEntryType)
480 query.exec() 485 query.exec()
481 del query 486 del query
482 finally: 487 finally:
483 db.commit() 488 db.commit()
484 489
485 def deleteThreatList(self, threatList): 490 def deleteThreatList(self, threatList):
486 """ 491 """
487 Public method to delete a threat list from the cache. 492 Public method to delete a threat list from the cache.
488 493
489 @param threatList threat list to be deleted 494 @param threatList threat list to be deleted
490 @type ThreatList 495 @type ThreatList
491 """ 496 """
492 queryStr = """ 497 queryStr = """
493 DELETE FROM threat_list 498 DELETE FROM threat_list
494 WHERE threat_type=? AND platform_type=? AND threat_entry_type=? 499 WHERE threat_type=? AND platform_type=? AND threat_entry_type=?
495 """ 500 """
496 501
497 db = QSqlDatabase.database(self.__connectionName) 502 db = QSqlDatabase.database(self.__connectionName)
498 if db.isOpen(): 503 if db.isOpen():
499 db.transaction() 504 db.transaction()
500 try: 505 try:
501 query = QSqlQuery(db) 506 query = QSqlQuery(db)
502 query.prepare(queryStr) 507 query.prepare(queryStr)
503 query.addBindValue(threatList.threatType) 508 query.addBindValue(threatList.threatType)
504 query.addBindValue(threatList.platformType) 509 query.addBindValue(threatList.platformType)
505 query.addBindValue(threatList.threatEntryType) 510 query.addBindValue(threatList.threatEntryType)
506 query.exec() 511 query.exec()
507 del query 512 del query
508 finally: 513 finally:
509 db.commit() 514 db.commit()
510 515
511 def updateThreatListClientState(self, threatList, clientState): 516 def updateThreatListClientState(self, threatList, clientState):
512 """ 517 """
513 Public method to update the client state of a threat list. 518 Public method to update the client state of a threat list.
514 519
515 @param threatList threat list to update the client state for 520 @param threatList threat list to update the client state for
516 @type ThreatList 521 @type ThreatList
517 @param clientState new client state 522 @param clientState new client state
518 @type str 523 @type str
519 """ 524 """
520 queryStr = """ 525 queryStr = """
521 UPDATE threat_list SET timestamp=current_timestamp, client_state=? 526 UPDATE threat_list SET timestamp=current_timestamp, client_state=?
522 WHERE threat_type=? AND platform_type=? AND threat_entry_type=? 527 WHERE threat_type=? AND platform_type=? AND threat_entry_type=?
523 """ 528 """
524 529
525 db = QSqlDatabase.database(self.__connectionName) 530 db = QSqlDatabase.database(self.__connectionName)
526 if db.isOpen(): 531 if db.isOpen():
527 db.transaction() 532 db.transaction()
528 try: 533 try:
529 query = QSqlQuery(db) 534 query = QSqlQuery(db)
534 query.addBindValue(threatList.threatEntryType) 539 query.addBindValue(threatList.threatEntryType)
535 query.exec() 540 query.exec()
536 del query 541 del query
537 finally: 542 finally:
538 db.commit() 543 db.commit()
539 544
540 def hashPrefixListChecksum(self, threatList): 545 def hashPrefixListChecksum(self, threatList):
541 """ 546 """
542 Public method to calculate the SHA256 checksum for an alphabetically 547 Public method to calculate the SHA256 checksum for an alphabetically
543 sorted concatenated list of hash prefixes. 548 sorted concatenated list of hash prefixes.
544 549
545 @param threatList threat list to calculate checksum for 550 @param threatList threat list to calculate checksum for
546 @type ThreatList 551 @type ThreatList
547 @return SHA256 checksum 552 @return SHA256 checksum
548 @rtype bytes 553 @rtype bytes
549 """ 554 """
551 SELECT value FROM hash_prefix 556 SELECT value FROM hash_prefix
552 WHERE threat_type=? AND platform_type=? AND threat_entry_type=? 557 WHERE threat_type=? AND platform_type=? AND threat_entry_type=?
553 ORDER BY value 558 ORDER BY value
554 """ 559 """
555 checksum = None 560 checksum = None
556 561
557 db = QSqlDatabase.database(self.__connectionName) 562 db = QSqlDatabase.database(self.__connectionName)
558 if db.isOpen(): 563 if db.isOpen():
559 db.transaction() 564 db.transaction()
560 sha256Hash = QCryptographicHash( 565 sha256Hash = QCryptographicHash(QCryptographicHash.Algorithm.Sha256)
561 QCryptographicHash.Algorithm.Sha256) 566 try:
562 try: 567 query = QSqlQuery(db)
563 query = QSqlQuery(db) 568 query.prepare(queryStr)
564 query.prepare(queryStr) 569 query.addBindValue(threatList.threatType)
565 query.addBindValue(threatList.threatType) 570 query.addBindValue(threatList.platformType)
566 query.addBindValue(threatList.platformType) 571 query.addBindValue(threatList.threatEntryType)
567 query.addBindValue(threatList.threatEntryType) 572
568 573 query.exec()
569 query.exec() 574
570 575 while query.next(): # __IGNORE_WARNING_M523__
571 while query.next(): # __IGNORE_WARNING_M523__
572 sha256Hash.addData(query.value(0)) 576 sha256Hash.addData(query.value(0))
573 QCoreApplication.processEvents( 577 QCoreApplication.processEvents(
574 QEventLoop.ProcessEventsFlag.AllEvents, 578 QEventLoop.ProcessEventsFlag.AllEvents,
575 self.maxProcessEventsTime) 579 self.maxProcessEventsTime,
576 del query 580 )
577 finally: 581 del query
578 db.commit() 582 finally:
579 583 db.commit()
584
580 checksum = bytes(sha256Hash.result()) 585 checksum = bytes(sha256Hash.result())
581 586
582 return checksum 587 return checksum
583 588
584 def populateHashPrefixList(self, threatList, prefixes): 589 def populateHashPrefixList(self, threatList, prefixes):
585 """ 590 """
586 Public method to populate the hash prefixes for a threat list. 591 Public method to populate the hash prefixes for a threat list.
587 592
588 @param threatList threat list of the hash prefixes 593 @param threatList threat list of the hash prefixes
589 @type ThreatList 594 @type ThreatList
590 @param prefixes list of hash prefixes to be inserted 595 @param prefixes list of hash prefixes to be inserted
591 @type HashPrefixList 596 @type HashPrefixList
592 """ 597 """
594 INSERT INTO hash_prefix 599 INSERT INTO hash_prefix
595 (value, cue, threat_type, platform_type, threat_entry_type, 600 (value, cue, threat_type, platform_type, threat_entry_type,
596 timestamp) 601 timestamp)
597 VALUES (?, ?, ?, ?, ?, current_timestamp) 602 VALUES (?, ?, ?, ?, ?, current_timestamp)
598 """ 603 """
599 604
600 db = QSqlDatabase.database(self.__connectionName) 605 db = QSqlDatabase.database(self.__connectionName)
601 if db.isOpen(): 606 if db.isOpen():
602 db.transaction() 607 db.transaction()
603 try: 608 try:
604 for prefix in prefixes: 609 for prefix in prefixes:
605 query = QSqlQuery(db) 610 query = QSqlQuery(db)
606 query.prepare(queryStr) 611 query.prepare(queryStr)
607 query.addBindValue( 612 query.addBindValue(
608 QByteArray(prefix), 613 QByteArray(prefix),
609 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary) 614 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
615 )
610 query.addBindValue(prefix[:4].hex()) 616 query.addBindValue(prefix[:4].hex())
611 query.addBindValue(threatList.threatType) 617 query.addBindValue(threatList.threatType)
612 query.addBindValue(threatList.platformType) 618 query.addBindValue(threatList.platformType)
613 query.addBindValue(threatList.threatEntryType) 619 query.addBindValue(threatList.threatEntryType)
614 query.exec() 620 query.exec()
615 del query 621 del query
616 QCoreApplication.processEvents( 622 QCoreApplication.processEvents(
617 QEventLoop.ProcessEventsFlag.AllEvents, 623 QEventLoop.ProcessEventsFlag.AllEvents,
618 self.maxProcessEventsTime) 624 self.maxProcessEventsTime,
619 finally: 625 )
620 db.commit() 626 finally:
621 627 db.commit()
628
622 def getHashPrefixValuesToRemove(self, threatList, indexes): 629 def getHashPrefixValuesToRemove(self, threatList, indexes):
623 """ 630 """
624 Public method to get the hash prefix values to be removed from the 631 Public method to get the hash prefix values to be removed from the
625 cache. 632 cache.
626 633
627 @param threatList threat list to remove prefixes from 634 @param threatList threat list to remove prefixes from
628 @type ThreatList 635 @type ThreatList
629 @param indexes list of indexes of prefixes to be removed 636 @param indexes list of indexes of prefixes to be removed
630 @type list of int 637 @type list of int
631 @return list of hash prefixes to be removed 638 @return list of hash prefixes to be removed
636 WHERE threat_type=? AND platform_type=? AND threat_entry_type=? 643 WHERE threat_type=? AND platform_type=? AND threat_entry_type=?
637 ORDER BY value 644 ORDER BY value
638 """ 645 """
639 indexes = set(indexes) 646 indexes = set(indexes)
640 output = [] 647 output = []
641 648
642 db = QSqlDatabase.database(self.__connectionName) 649 db = QSqlDatabase.database(self.__connectionName)
643 if db.isOpen(): 650 if db.isOpen():
644 db.transaction() 651 db.transaction()
645 try: 652 try:
646 query = QSqlQuery(db) 653 query = QSqlQuery(db)
647 query.prepare(queryStr) 654 query.prepare(queryStr)
648 query.addBindValue(threatList.threatType) 655 query.addBindValue(threatList.threatType)
649 query.addBindValue(threatList.platformType) 656 query.addBindValue(threatList.platformType)
650 query.addBindValue(threatList.threatEntryType) 657 query.addBindValue(threatList.threatEntryType)
651 658
652 query.exec() 659 query.exec()
653 660
654 index = 0 661 index = 0
655 while query.next(): # __IGNORE_WARNING_M523__ 662 while query.next(): # __IGNORE_WARNING_M523__
656 if index in indexes: 663 if index in indexes:
657 prefix = bytes(query.value(0)) 664 prefix = bytes(query.value(0))
658 output.append(prefix) 665 output.append(prefix)
659 index += 1 666 index += 1
660 QCoreApplication.processEvents( 667 QCoreApplication.processEvents(
661 QEventLoop.ProcessEventsFlag.AllEvents, 668 QEventLoop.ProcessEventsFlag.AllEvents,
662 self.maxProcessEventsTime) 669 self.maxProcessEventsTime,
663 del query 670 )
664 finally: 671 del query
665 db.commit() 672 finally:
666 673 db.commit()
674
667 return output 675 return output
668 676
669 def removeHashPrefixIndices(self, threatList, indexes): 677 def removeHashPrefixIndices(self, threatList, indexes):
670 """ 678 """
671 Public method to remove hash prefixes from the cache. 679 Public method to remove hash prefixes from the cache.
672 680
673 @param threatList threat list to delete hash prefixes of 681 @param threatList threat list to delete hash prefixes of
674 @type ThreatList 682 @type ThreatList
675 @param indexes list of indexes of prefixes to be removed 683 @param indexes list of indexes of prefixes to be removed
676 @type list of int 684 @type list of int
677 """ 685 """
678 queryStr = ( 686 queryStr = """
679 """
680 DELETE FROM hash_prefix 687 DELETE FROM hash_prefix
681 WHERE threat_type=? AND platform_type=? AND 688 WHERE threat_type=? AND platform_type=? AND
682 threat_entry_type=? AND value IN ({0}) 689 threat_entry_type=? AND value IN ({0})
683 """ 690 """
684 )
685 batchSize = 40 691 batchSize = 40
686 692
687 prefixesToRemove = self.getHashPrefixValuesToRemove( 693 prefixesToRemove = self.getHashPrefixValuesToRemove(threatList, indexes)
688 threatList, indexes)
689 if prefixesToRemove: 694 if prefixesToRemove:
690 db = QSqlDatabase.database(self.__connectionName) 695 db = QSqlDatabase.database(self.__connectionName)
691 if db.isOpen(): 696 if db.isOpen():
692 db.transaction() 697 db.transaction()
693 try: 698 try:
694 for index in range(0, len(prefixesToRemove), batchSize): 699 for index in range(0, len(prefixesToRemove), batchSize):
695 removeBatch = prefixesToRemove[ 700 removeBatch = prefixesToRemove[index : (index + batchSize)]
696 index:(index + batchSize) 701
697 ]
698
699 query = QSqlQuery(db) 702 query = QSqlQuery(db)
700 query.prepare( 703 query.prepare(
701 queryStr.format(",".join(["?"] * len(removeBatch))) 704 queryStr.format(",".join(["?"] * len(removeBatch)))
702 ) 705 )
703 query.addBindValue(threatList.threatType) 706 query.addBindValue(threatList.threatType)
704 query.addBindValue(threatList.platformType) 707 query.addBindValue(threatList.platformType)
705 query.addBindValue(threatList.threatEntryType) 708 query.addBindValue(threatList.threatEntryType)
706 for prefix in removeBatch: 709 for prefix in removeBatch:
707 query.addBindValue( 710 query.addBindValue(
708 QByteArray(prefix), 711 QByteArray(prefix),
709 QSql.ParamTypeFlag.In | 712 QSql.ParamTypeFlag.In | QSql.ParamTypeFlag.Binary,
710 QSql.ParamTypeFlag.Binary) 713 )
711 query.exec() 714 query.exec()
712 del query 715 del query
713 QCoreApplication.processEvents( 716 QCoreApplication.processEvents(
714 QEventLoop.ProcessEventsFlag.AllEvents, 717 QEventLoop.ProcessEventsFlag.AllEvents,
715 self.maxProcessEventsTime) 718 self.maxProcessEventsTime,
719 )
716 finally: 720 finally:
717 db.commit() 721 db.commit()
718 722
723
719 # 724 #
720 # eflag: noqa = S608 725 # eflag: noqa = S608

eric ide

mercurial