assemblyline-v4-service 4.5.1.dev453__py3-none-any.whl → 4.5.1.dev455__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.
@@ -1 +1 @@
1
- 4.5.1.dev453
1
+ 4.5.1.dev455
@@ -1,15 +1,15 @@
1
1
  import argparse
2
+ import cProfile
3
+ import importlib
2
4
  import json
3
5
  import logging
4
6
  import os
5
7
  import pprint
6
8
  import shutil
7
9
  import tempfile
8
- import yaml
9
- import cProfile
10
+ from typing import Dict, Union
10
11
 
11
12
  from cart import get_metadata_only, unpack_stream
12
- from typing import Union, Dict
13
13
 
14
14
  from assemblyline.common import forge
15
15
  from assemblyline.common.heuristics import HeuristicHandler, InvalidHeuristicException
@@ -19,12 +19,14 @@ from assemblyline.common.uid import get_random_id
19
19
  from assemblyline.odm.messages.task import Task as ServiceTask
20
20
  from assemblyline.odm.models.result import Result
21
21
  from assemblyline.odm.models.service import Service
22
+ from assemblyline_v4_service.common.base import ServiceBase
22
23
  from assemblyline_v4_service.common.helper import get_heuristics, get_service_manifest
24
+ from assemblyline_v4_service.dev.updater import load_rules
23
25
 
24
26
 
25
27
  class RunService:
26
28
  def __init__(self):
27
- self.service = None
29
+ self.service: ServiceBase = None
28
30
  self.service_class = None
29
31
  self.submission_params = None
30
32
  self.file_dir = None
@@ -41,6 +43,10 @@ class RunService:
41
43
 
42
44
  self.load_service_manifest()
43
45
 
46
+ if self.service.service_attributes.update_config:
47
+ # Download required signatures and process them for the service run
48
+ load_rules(self.service)
49
+
44
50
  if not os.path.isfile(FILE_PATH):
45
51
  LOG.info(f"File not found: {FILE_PATH}")
46
52
  return
@@ -179,6 +185,10 @@ class RunService:
179
185
  LOG.info(f"Cleaning up file used for temporary processing: {target_file}")
180
186
  os.unlink(target_file)
181
187
 
188
+ if self.service.rules_directory:
189
+ LOG.info("Cleaning up downloaded signatures..")
190
+ shutil.rmtree(self.service.rules_directory)
191
+
182
192
  LOG.info(f"Moving {result_json} to the working directory: {working_dir}/result.json")
183
193
  shutil.move(result_json, os.path.join(working_dir, 'result.json'))
184
194
 
@@ -0,0 +1,150 @@
1
+ import importlib
2
+ import inspect
3
+ import json
4
+ import os
5
+ import tempfile
6
+ import threading
7
+
8
+ from assemblyline.common.isotime import now_as_iso
9
+ from assemblyline.odm.models.service import SIGNATURE_DELIMITERS
10
+ from assemblyline_v4_service.common.base import ServiceBase
11
+ from assemblyline_v4_service.updater.client import (
12
+ BadlistClient,
13
+ SafelistClient,
14
+ SignatureClient,
15
+ UpdaterClient,
16
+ )
17
+ from assemblyline_v4_service.updater.updater import (
18
+ SIGNATURES_META_FILENAME,
19
+ SOURCE_STATUS_KEY,
20
+ ServiceUpdater,
21
+ UniqueQueue,
22
+ )
23
+
24
+
25
+ class TestSignatureClient(SignatureClient):
26
+ def __init__(self, output_directory: str):
27
+ self.sync = False
28
+ self.output_directory = output_directory
29
+
30
+ def add_update_many(self, source, sig_type, data, dedup_name=True):
31
+ os.makedirs(os.path.join(self.output_directory, sig_type, source), exist_ok=True)
32
+ for d in data:
33
+ with open(os.path.join(self.output_directory, sig_type, source, d['name']), 'w') as f:
34
+ json.dump(d, f)
35
+
36
+ return {'success': len(data)}
37
+
38
+ class TestBadlistClient(BadlistClient):
39
+ def __init__(self, output_directory: str):
40
+ self.sync = False
41
+ self.output_directory = output_directory
42
+
43
+ def add_update_many(self, list_of_badlist_objects):
44
+ return {'success': len(list_of_badlist_objects)}
45
+
46
+ class TestSafelistClient(SafelistClient):
47
+ def __init__(self, output_directory: str):
48
+ self.sync = False
49
+ self.output_directory = output_directory
50
+
51
+ def add_update_many(self, list_of_safelist_objects):
52
+ return {'success': len(list_of_safelist_objects)}
53
+
54
+ class TestUpdaterClient(UpdaterClient):
55
+ def __init__(self, output_directory: str):
56
+ self._sync = False
57
+ self._classification_override = False
58
+ self.signature = TestSignatureClient(output_directory)
59
+ self.badlist = TestBadlistClient(output_directory)
60
+ self.safelist = TestSafelistClient(output_directory)
61
+
62
+ def load_rules(service: ServiceBase):
63
+ with tempfile.TemporaryDirectory() as latest_updates_dir:
64
+ updater_module = importlib.import_module(service.service_attributes.dependencies['updates'].container.command[-1])
65
+ # Find the UpdaterServer class
66
+ for v in updater_module.__dict__.values():
67
+ if inspect.isclass(v) and issubclass(v, ServiceUpdater) and v != ServiceUpdater:
68
+ updater_class = v
69
+ break
70
+
71
+
72
+ # Implement a class to be used with RunServiceOnce without a dependency on Assemblyline
73
+ class TestServiceUpdater(updater_class):
74
+ def __init__(self, *args, **kwargs):
75
+ self.update_data_hash = {}
76
+ self._current_source = ""
77
+ self.log = service.log
78
+ self._service = service.service_attributes
79
+ self.update_queue = UniqueQueue()
80
+ self.updater_type = self._service.name.lower()
81
+ self.delimiter = self._service.update_config.signature_delimiter
82
+ self.default_pattern = self._service.update_config.default_pattern
83
+ self.signatures_meta = {}
84
+ [self.update_queue.put(update.name) for update in self._service.update_config.sources]
85
+
86
+ self.latest_updates_dir = latest_updates_dir
87
+ self.client = TestUpdaterClient(latest_updates_dir)
88
+ self.source_update_flag = threading.Event()
89
+ self.local_update_flag = threading.Event()
90
+ self.local_update_start = threading.Event()
91
+
92
+ def set_source_update_time(self, update_time: float): ...
93
+
94
+ def set_source_extra(self, extra_data): ...
95
+
96
+ def set_active_config_hash(self, config_hash: int): ...
97
+
98
+ # Keep a record of the source status as a dictionary
99
+ def push_status(self, state: str, message: str):
100
+ # Push current state of updater with source
101
+ self.log.debug(f"Pushing state for {self._current_source}: [{state}] {message}")
102
+ self.update_data_hash[f'{self._current_source}.{SOURCE_STATUS_KEY}'] = \
103
+ dict(state=state, message=message, ts=now_as_iso())
104
+
105
+ def do_source_update(self):
106
+ super().do_source_update(self._service)
107
+
108
+ def do_local_update(self):
109
+ if self._service.update_config.generates_signatures:
110
+ signaure_data = []
111
+ updatepath = os.path.join(self.latest_updates_dir, self.updater_type)
112
+ for source in os.listdir(updatepath):
113
+ sourcepath = os.path.join(updatepath, source)
114
+
115
+ for file in os.listdir(sourcepath):
116
+ # Save signatures to disk
117
+ filepath = os.path.join(sourcepath, file)
118
+ with open(filepath) as f:
119
+ data = json.load(f)
120
+
121
+ signaure_data.append(data.pop('data'))
122
+ self.signatures_meta[data['signature_id']] = data
123
+
124
+ if self.delimiter != "file":
125
+ os.remove(filepath)
126
+
127
+ if self.delimiter != "file":
128
+ # Render the response when calling `client.signature.download`
129
+ os.removedirs(sourcepath)
130
+ with open(os.path.join(self.latest_updates_dir, source), 'w') as f:
131
+ f.write(SIGNATURE_DELIMITERS[self.delimiter].join(signaure_data))
132
+
133
+ else:
134
+ self.signatures_meta = {
135
+ source.name: {'classification': source['default_classification'].value}
136
+ for source in self._service.update_config.sources
137
+ }
138
+
139
+
140
+
141
+ # Initialize updater, download signatures, and load them into the service
142
+ updater = TestServiceUpdater()
143
+ updater.do_source_update()
144
+ updater.do_local_update()
145
+ rules_directory = updater.prepare_output_directory()
146
+ service.signatures_meta = updater.signatures_meta
147
+ service.rules_directory = rules_directory
148
+ service.rules_list = [os.path.join(rules_directory, i) for i in os.listdir(rules_directory)
149
+ if i != SIGNATURES_META_FILENAME]
150
+ service._load_rules()
@@ -1,37 +1,44 @@
1
1
  from __future__ import annotations
2
- import shutil
3
- from typing import Optional, Any, Tuple, List
4
- import typing
5
- import os
6
- import logging
7
- import time
2
+
3
+ import hashlib
8
4
  import json
9
- import tempfile
5
+ import logging
6
+ import os
7
+ import shutil
8
+ import subprocess
10
9
  import tarfile
10
+ import tempfile
11
11
  import threading
12
- import subprocess
13
- import hashlib
12
+ import time
13
+ import typing
14
14
  from io import BytesIO
15
15
  from queue import Queue
16
+ from typing import Any, List, Optional, Tuple
16
17
  from zipfile import ZipFile
17
18
 
18
- from assemblyline.common import forge, log as al_log
19
+ from assemblyline_core.server_base import ServiceStage, ThreadedCoreBase
20
+
21
+ from assemblyline.common import forge
22
+ from assemblyline.common import log as al_log
19
23
  from assemblyline.common.isotime import epoch_to_iso, now_as_iso
20
24
  from assemblyline.odm.messages.changes import Operation, ServiceChange, SignatureChange
21
- from assemblyline.remote.datatypes.events import EventSender, EventWatcher
22
-
23
- from assemblyline_core.server_base import ThreadedCoreBase, ServiceStage
24
25
  from assemblyline.odm.models.service import Service, UpdateSource
26
+ from assemblyline.remote.datatypes.events import EventSender, EventWatcher
25
27
  from assemblyline.remote.datatypes.hash import Hash
26
-
27
28
  from assemblyline_v4_service.common.base import SIGNATURES_META_FILENAME
28
29
  from assemblyline_v4_service.updater.client import UpdaterClient
29
- from assemblyline_v4_service.updater.helper import url_download, git_clone_repo, SkipSource, filter_downloads
30
+ from assemblyline_v4_service.updater.helper import (
31
+ SkipSource,
32
+ filter_downloads,
33
+ git_clone_repo,
34
+ url_download,
35
+ )
30
36
 
31
37
  if typing.TYPE_CHECKING:
32
38
  import redis
33
- from assemblyline.odm.models.config import Config
39
+
34
40
  from assemblyline.datastore.helper import AssemblylineDatastore
41
+ from assemblyline.odm.models.config import Config
35
42
  RedisType = redis.Redis[typing.Any]
36
43
 
37
44
  SERVICE_PULL_INTERVAL = 1200
@@ -65,10 +72,10 @@ class ServiceUpdater(ThreadedCoreBase):
65
72
  shutdown_timeout: float = None, config: Config = None,
66
73
  datastore: AssemblylineDatastore = None,
67
74
  redis: RedisType = None, redis_persist: RedisType = None,
68
- default_pattern=".*", downloadable_signature_statuses=['DEPLOYED', 'NOISY']):
75
+ downloadable_signature_statuses=['DEPLOYED', 'NOISY']):
69
76
 
70
77
  self.updater_type = os.environ['SERVICE_PATH'].split('.')[-1].lower()
71
- self.default_pattern = default_pattern
78
+ self.default_pattern = None
72
79
 
73
80
  if not logger:
74
81
  al_log.init_logging(f'updater.{self.updater_type}', log_level=os.environ.get('LOG_LEVEL', "WARNING"))
@@ -247,6 +254,10 @@ class ServiceUpdater(ThreadedCoreBase):
247
254
  # Download the service object from datastore
248
255
  self._service = self.datastore.get_service_with_delta(SERVICE_NAME)
249
256
 
257
+ # Set default pattern if not already set
258
+ if not self.default_pattern:
259
+ self.default_pattern = self._service.update_config.default_pattern
260
+
250
261
  # Update signature client with any changes to classification rewrites
251
262
  self.client.signature.classification_replace_map = \
252
263
  self._service.config.get('updater', {}).get('classification_replace', {})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: assemblyline-v4-service
3
- Version: 4.5.1.dev453
3
+ Version: 4.5.1.dev455
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=ebZs1rTqnub4bIpqlps2JL3Zu7V-GpViEdOtKpjFTdM,13
1
+ assemblyline_v4_service/VERSION,sha256=wHs-DuDtnVx9REMerMGYAVk7KidZ-A0fOnJzsGVi8YI,13
2
2
  assemblyline_v4_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  assemblyline_v4_service/healthz.py,sha256=3QGBg0EZuXC6UN411HFwpLNEop9UvS9feFhvBUTP-k4,1576
4
4
  assemblyline_v4_service/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -15,14 +15,15 @@ assemblyline_v4_service/common/result.py,sha256=9AqM6qCYiia_Bpyn_fBFhzNQMcqJbtFS
15
15
  assemblyline_v4_service/common/task.py,sha256=dJsvRpW0x88CCF_LW6w87jQ_UKTVaOs2Gb117IDNiU8,14233
16
16
  assemblyline_v4_service/common/utils.py,sha256=k2__d-V5LjB6o2IKbjVe7tJWKcKuUHto5TyT5oKhIa0,3890
17
17
  assemblyline_v4_service/dev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- assemblyline_v4_service/dev/run_service_once.py,sha256=1sdxkRBI7x9Sht8EVCTMIW3MgSxIeV6Ufw77Wx9Vf20,10150
18
+ assemblyline_v4_service/dev/run_service_once.py,sha256=wx_82hGwavxWhMsmNDfmlYs4KbcLnqeMg91ZGfXTZV0,10621
19
+ assemblyline_v4_service/dev/updater.py,sha256=b-FK6XPRZbETbl-SIYEhnYGT-W7EcQhnxwD6x2NMC7g,6411
19
20
  assemblyline_v4_service/updater/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
21
  assemblyline_v4_service/updater/__main__.py,sha256=9Os-u8Tf7MD73JSrUSPmOaErTgfvesNLiEeszU4ujXA,133
21
22
  assemblyline_v4_service/updater/app.py,sha256=Mtmx4bkXfP4nFqqa5q15jW8QIXr4JK84lCovxAVyvPs,3317
22
23
  assemblyline_v4_service/updater/client.py,sha256=tLY84gaGdFBVIDaMgRHIEa7x2S8jBl7lQLzp4seC6aI,11200
23
24
  assemblyline_v4_service/updater/gunicorn_config.py,sha256=p3j2KPBeD5jvMw9O5i7vAtlRgPSVVxIG9AO0DfN82J8,1247
24
25
  assemblyline_v4_service/updater/helper.py,sha256=Zy6OBmbTh0YurW0MnM0wM92vaKYMbo_MKnafe_5ONUI,10034
25
- assemblyline_v4_service/updater/updater.py,sha256=HqRVUs5nNIfKmHu7g1GUkgC7bvYWs2EC9ZFy1kj-Ltw,31609
26
+ assemblyline_v4_service/updater/updater.py,sha256=kli-5v1uVmk2FARAI9DsZ9YM4EhgirkmWJaMJWdm9GI,31795
26
27
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
28
  test/conftest.py,sha256=W3SieQpZsZpGEmtLqY4aIlxREDSsHceyCrFcFsWUM0U,1851
28
29
  test/test_healthz.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
@@ -38,8 +39,8 @@ test/test_common/test_request.py,sha256=Ceyds8BNO1O0f1kH1VEb84faJcaupvSjVKIrGdHe
38
39
  test/test_common/test_result.py,sha256=6BiOKxEPrKBjOY44jv3TY-yiXm0qI1ok_CZBnjP9TM4,45447
39
40
  test/test_common/test_task.py,sha256=P44mNcSe-3tJgDk9ppN3KbM7oN4LBVIuhONG-Gveh74,19007
40
41
  test/test_common/test_utils.py,sha256=TbnBxqpS_ZC5ptXR9XJX3xtbItD0mTbtiBxxdyP8J5k,5904
41
- assemblyline_v4_service-4.5.1.dev453.dist-info/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
42
- assemblyline_v4_service-4.5.1.dev453.dist-info/METADATA,sha256=zXKPiqpBNkTlyOEai0ypH-hT3VkhfZfex8xS-8aoFN0,5603
43
- assemblyline_v4_service-4.5.1.dev453.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
44
- assemblyline_v4_service-4.5.1.dev453.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
45
- assemblyline_v4_service-4.5.1.dev453.dist-info/RECORD,,
42
+ assemblyline_v4_service-4.5.1.dev455.dist-info/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
43
+ assemblyline_v4_service-4.5.1.dev455.dist-info/METADATA,sha256=p06bT3Ftf1HlTzKgyrzS-Bxv-5hdvlipGbHjJdYVE_w,5603
44
+ assemblyline_v4_service-4.5.1.dev455.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
45
+ assemblyline_v4_service-4.5.1.dev455.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
46
+ assemblyline_v4_service-4.5.1.dev455.dist-info/RECORD,,