assemblyline-v4-service 4.5.1.dev379__py3-none-any.whl → 4.5.1.dev381__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of assemblyline-v4-service might be problematic. Click here for more details.

@@ -1 +1 @@
1
- 4.5.1.dev379
1
+ 4.5.1.dev381
@@ -17,6 +17,7 @@ class SyncableBadlistClient(BadlistClient):
17
17
  def __init__(self, datastore, config=None):
18
18
  super().__init__(datastore, config)
19
19
  self.sync = False
20
+ self.classification_override = None
20
21
 
21
22
  def add_update_many(self, data: List[Union[dict, BadlistModel]]) -> Dict[str, Any]:
22
23
  return hashlist_add_update_many(self, self.datastore.badlist, data)
@@ -26,6 +27,7 @@ class SyncableSafelistClient(SafelistClient):
26
27
  def __init__(self, datastore, config=None):
27
28
  super().__init__(datastore, config)
28
29
  self.sync = False
30
+ self.classification_override = None
29
31
 
30
32
  def add_update_many(self, data: List[Union[dict, SafelistModel]]) -> Dict[str, Any]:
31
33
  return hashlist_add_update_many(self, self.datastore.safelist, data)
@@ -55,9 +57,14 @@ def hashlist_add_update_many(client: Union[SyncableBadlistClient, SyncableSafeli
55
57
  # Set the source name
56
58
  source = d["sources"][0]["name"]
57
59
 
60
+ if client.classification_override:
61
+ # Override the classification of the signature based on what's assigned to the client
62
+ d["sources"][0]["classification"] = client.classification_override
63
+
58
64
  if client.sync:
59
65
  # Compute the expected ID and add it to the list
60
66
  current_ids.add(client._preprocess_object(d))
67
+
61
68
  # Update with JSON-friendly version of data to be sent to API
62
69
  data[i] = d
63
70
 
@@ -122,6 +129,7 @@ class SyncableSignatureClient(SignatureClient):
122
129
  def __init__(self, datastore, config=None):
123
130
  super().__init__(datastore, config)
124
131
  self.sync = False
132
+ self.classification_override = None
125
133
 
126
134
  def add_update_many(self, source: str, sig_type: str, data: List[Union[dict, SignatureModel]],
127
135
  dedup_name: bool = True) -> Dict[str, Any]:
@@ -144,6 +152,10 @@ class SyncableSignatureClient(SignatureClient):
144
152
  d['status'] = sig_exists['status']
145
153
  d['state_change_user'] = sig_exists['state_change_user']
146
154
 
155
+ if self.classification_override:
156
+ # Override the classification of the signature based on what's assigned to the client
157
+ d['classification'] = self.classification_override
158
+
147
159
  if self.sync:
148
160
  # Add signature ID to the list
149
161
  current_signature_ids.add(sig_id)
@@ -208,6 +220,7 @@ class UpdaterClient(object):
208
220
  def __init__(self, datastore) -> None:
209
221
  self.datastore = datastore
210
222
  self._sync = False
223
+ self._classification_override = None
211
224
  self.badlist = SyncableBadlistClient(datastore)
212
225
  self.safelist = SyncableSafelistClient(datastore)
213
226
  self.signature = SyncableSignatureClient(datastore)
@@ -223,3 +236,14 @@ class UpdaterClient(object):
223
236
  self.safelist.sync = value
224
237
  self.signature.sync = value
225
238
  self._sync = value
239
+
240
+ @property
241
+ def classification_override(self):
242
+ return self._classification_override
243
+ @classification_override.setter
244
+ def classification_override(self, value: str):
245
+ # Set the classification override
246
+ self.badlist.classification_override = value
247
+ self.safelist.classification_override = value
248
+ self.signature.classification_override = value
249
+ self._classification_override = value
@@ -88,6 +88,7 @@ def url_download(source: Dict[str, Any], previous_update: int, logger: Logger, o
88
88
  ca_cert = source.get('ca_cert', None)
89
89
  ignore_ssl_errors = source.get('ssl_ignore_errors', False)
90
90
  auth = (username, password) if username and password else None
91
+ fetch_method = source.get('fetch_method', 'GET').lower()
91
92
 
92
93
  proxy = source.get('proxy', None)
93
94
  headers_list = source.get('headers', [])
@@ -134,7 +135,10 @@ def url_download(source: Dict[str, Any], previous_update: int, logger: Logger, o
134
135
  else:
135
136
  headers = {'If-Modified-Since': previous_update}
136
137
 
137
- response = session.get(uri, auth=auth, headers=headers, proxies=proxies, stream=True)
138
+ if fetch_method in ['get', 'post']:
139
+ response = getattr(session, fetch_method)(uri, auth=auth, headers=headers, proxies=proxies, stream=True)
140
+ else:
141
+ raise ValueError(f"Unknown fetch method: {fetch_method}")
138
142
 
139
143
  # Check the response code
140
144
  if response.status_code == requests.codes['not_modified']:
@@ -378,14 +378,37 @@ class ServiceUpdater(ThreadedCoreBase):
378
378
  source_obj = sources[source_name]
379
379
  old_update_time = self.get_source_update_time()
380
380
 
381
- self.push_status("UPDATING", "Starting..")
382
- source = source_obj.as_primitives()
383
- uri: str = source['uri']
384
- default_classification = source.get('default_classification', classification.UNRESTRICTED)
385
- # Enable syncing if the source specifies it
386
- self.client.sync = source.get('sync', False)
387
-
381
+ # Are we ignoring the cache for this source?
382
+ if source_obj.ignore_cache:
383
+ old_update_time = 0
388
384
  try:
385
+
386
+ source = source_obj.as_primitives()
387
+ uri: str = source_obj.uri
388
+
389
+ # If source is not currently enabled/active, skip..
390
+ if not source_obj.enabled:
391
+ raise SkipSource
392
+
393
+ # Is it time for this source to run?
394
+ elapsed_time = time.time() - old_update_time
395
+ if elapsed_time < source.get('update_interval', service.update_config.update_interval_seconds):
396
+ # Too early to run the update for this particular source, skip for now
397
+ raise SkipSource
398
+
399
+
400
+ self.push_status("UPDATING", "Starting..")
401
+ fetch_method = source.get('fetch_method', 'GET')
402
+ default_classification = source.get('default_classification', classification.UNRESTRICTED)
403
+
404
+ # Configure the client as necessary
405
+
406
+ # Enable syncing if the source specifies it
407
+ self.client.sync = source.get('sync', False)
408
+ # Override classfication of signatures if specified
409
+ self.client.classification_override = default_classification \
410
+ if source.get('override_classification', False) else None
411
+
389
412
  self.push_status("UPDATING", "Pulling..")
390
413
  output = None
391
414
  seen_fetch = seen_fetches.get(uri)
@@ -397,21 +420,20 @@ class ServiceUpdater(ThreadedCoreBase):
397
420
  self.log.info(f'Already visited {uri} in this run. Using cached download path..')
398
421
  output = seen_fetches[uri]
399
422
  else:
400
- # Pull sources from external locations (method depends on the URL)
401
- try:
423
+ self.log.info(f"Fetching {source_name} using {fetch_method}")
424
+ # Pull sources from external locations
425
+ if uri.startswith("file://"):
426
+ # Perform an update using a local mount
427
+ output = uri.split("file://", 1)[1]
428
+ if not os.path.exists(output):
429
+ raise FileNotFoundError(f"{output} doesn't exist within container.")
430
+ elif fetch_method == "GIT" or uri.endswith('.git'):
402
431
  # First we'll attempt by performing a Git clone
403
432
  # (since not all services hint at being a repository in their URL),
404
433
  output = git_clone_repo(source, old_update_time, self.log, update_dir)
405
- except SkipSource:
406
- raise
407
- except Exception as git_ex:
408
- # Should that fail, we'll attempt a direct-download using Python Requests
409
- if not uri.endswith('.git'):
410
- # Proceed with direct download, raise exception as required if necessary
411
- output = url_download(source, old_update_time, self.log, update_dir)
412
- else:
413
- # Raise Git Exception
414
- raise git_ex
434
+ else:
435
+ # Other fetch methods are meant for URL downloads using Requests
436
+ output = url_download(source, old_update_time, self.log, update_dir)
415
437
  # Add output path to the list of seen fetches in this run
416
438
  seen_fetches[uri] = output
417
439
 
@@ -430,7 +452,8 @@ class ServiceUpdater(ThreadedCoreBase):
430
452
 
431
453
  self.push_status("UPDATING", "Importing..")
432
454
  # Import into Assemblyline
433
- self.import_update(validated_files, source_name, default_classification)
455
+ self.import_update(validated_files, source_name, default_classification,
456
+ source.get('configuration') or {})
434
457
  self.push_status("DONE", "Signature(s) Imported.")
435
458
  except SkipSource:
436
459
  # This source hasn't changed, no need to re-import into Assemblyline
@@ -457,7 +480,8 @@ class ServiceUpdater(ThreadedCoreBase):
457
480
  return True
458
481
 
459
482
  # Define how your source update gets imported into Assemblyline
460
- def import_update(self, files_sha256: List[Tuple[str, str]], source_name: str, default_classification=None):
483
+ def import_update(self, files_sha256: List[Tuple[str, str]], source_name: str, default_classification=None,
484
+ configuration: dict = {}, *args, **kwargs):
461
485
  raise NotImplementedError()
462
486
 
463
487
  # Define how to prepare the output directory before being served, must return the path of the directory to serve.
@@ -486,7 +510,10 @@ class ServiceUpdater(ThreadedCoreBase):
486
510
  while self.running:
487
511
  # Stringify and hash the the current update configuration
488
512
  service = self._service
489
- update_interval = service.update_config.update_interval_seconds
513
+
514
+ # The update interval (or sleep interval) will be based on the smallest interval across sources
515
+ update_interval = min([service.update_config.update_interval_seconds] +
516
+ [s.update_interval for s in service.update_config.sources if s.update_interval])
490
517
 
491
518
  # Is it time to update yet?
492
519
  if time.time() - self.get_scheduled_update_time() < update_interval \
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: assemblyline-v4-service
3
- Version: 4.5.1.dev379
3
+ Version: 4.5.1.dev381
4
4
  Summary: Assemblyline 4 - Service base
5
5
  Home-page: https://github.com/CybercentreCanada/assemblyline-v4-service/
6
6
  Author: CCCS Assemblyline development team
@@ -1,4 +1,4 @@
1
- assemblyline_v4_service/VERSION,sha256=Iq2Hrx8-P0h74nvnG6J62t2ZLiDciQqSYHKDQLrr59o,13
1
+ assemblyline_v4_service/VERSION,sha256=GoI_N3ukyAbYAnqbnnVvNHDAsRDMZ6Ex_3AyNiQOTQ0,13
2
2
  assemblyline_v4_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  assemblyline_v4_service/healthz.py,sha256=sS1cFkDLw8hUPMpj7tbHXFv8ZmHcazrwZ0l6oQDwwkQ,1575
4
4
  assemblyline_v4_service/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,10 +19,10 @@ assemblyline_v4_service/dev/run_service_once.py,sha256=iEWkLnF4cWN0V3Mc6GhMKjDAP
19
19
  assemblyline_v4_service/updater/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  assemblyline_v4_service/updater/__main__.py,sha256=9Os-u8Tf7MD73JSrUSPmOaErTgfvesNLiEeszU4ujXA,133
21
21
  assemblyline_v4_service/updater/app.py,sha256=Mtmx4bkXfP4nFqqa5q15jW8QIXr4JK84lCovxAVyvPs,3317
22
- assemblyline_v4_service/updater/client.py,sha256=7_56Ie-2073FlrVWscS-3lIIkg8F-81u97FVNqEJLyQ,9798
22
+ assemblyline_v4_service/updater/client.py,sha256=mmCwNuGSDymbvrMuEXLgTR13vqaUEjs0Jjew-9QkQtM,10848
23
23
  assemblyline_v4_service/updater/gunicorn_config.py,sha256=p3j2KPBeD5jvMw9O5i7vAtlRgPSVVxIG9AO0DfN82J8,1247
24
- assemblyline_v4_service/updater/helper.py,sha256=-B35wdjpeY4t1R9SPDrTFHFKHwE3uzy9N69mV6mHy-g,9532
25
- assemblyline_v4_service/updater/updater.py,sha256=knl8X1xG5wF9nl8j--0WC3BmzQ0PO1Zq7RW58euVjn0,29687
24
+ assemblyline_v4_service/updater/helper.py,sha256=f0yB6iKExQAqCMkMs0aWPkzcaSy_z9sycgunoCOJlU4,9756
25
+ assemblyline_v4_service/updater/updater.py,sha256=3mKYnAwiEVxmcoa3158HSs_X-xPwn1hKCEnphmnF1H0,31239
26
26
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  test/conftest.py,sha256=W3SieQpZsZpGEmtLqY4aIlxREDSsHceyCrFcFsWUM0U,1851
28
28
  test/test_healthz.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
@@ -38,8 +38,8 @@ test/test_common/test_request.py,sha256=Ceyds8BNO1O0f1kH1VEb84faJcaupvSjVKIrGdHe
38
38
  test/test_common/test_result.py,sha256=6BiOKxEPrKBjOY44jv3TY-yiXm0qI1ok_CZBnjP9TM4,45447
39
39
  test/test_common/test_task.py,sha256=P44mNcSe-3tJgDk9ppN3KbM7oN4LBVIuhONG-Gveh74,19007
40
40
  test/test_common/test_utils.py,sha256=TbnBxqpS_ZC5ptXR9XJX3xtbItD0mTbtiBxxdyP8J5k,5904
41
- assemblyline_v4_service-4.5.1.dev379.dist-info/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
42
- assemblyline_v4_service-4.5.1.dev379.dist-info/METADATA,sha256=dQ9XH-JPcNBIyppzYK1xBz4ZzDCzLcc05M0y5ByoZXI,9493
43
- assemblyline_v4_service-4.5.1.dev379.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
44
- assemblyline_v4_service-4.5.1.dev379.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
45
- assemblyline_v4_service-4.5.1.dev379.dist-info/RECORD,,
41
+ assemblyline_v4_service-4.5.1.dev381.dist-info/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
42
+ assemblyline_v4_service-4.5.1.dev381.dist-info/METADATA,sha256=LSLNRHFtVgToOu0Kow7Vb9I3kmTW7HMT_3WqUGWX78s,9493
43
+ assemblyline_v4_service-4.5.1.dev381.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
44
+ assemblyline_v4_service-4.5.1.dev381.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
45
+ assemblyline_v4_service-4.5.1.dev381.dist-info/RECORD,,