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.
- assemblyline_v4_service/VERSION +1 -1
- assemblyline_v4_service/dev/run_service_once.py +14 -4
- assemblyline_v4_service/dev/updater.py +150 -0
- assemblyline_v4_service/updater/updater.py +29 -18
- {assemblyline_v4_service-4.5.1.dev453.dist-info → assemblyline_v4_service-4.5.1.dev455.dist-info}/METADATA +1 -1
- {assemblyline_v4_service-4.5.1.dev453.dist-info → assemblyline_v4_service-4.5.1.dev455.dist-info}/RECORD +9 -8
- {assemblyline_v4_service-4.5.1.dev453.dist-info → assemblyline_v4_service-4.5.1.dev455.dist-info}/LICENCE.md +0 -0
- {assemblyline_v4_service-4.5.1.dev453.dist-info → assemblyline_v4_service-4.5.1.dev455.dist-info}/WHEEL +0 -0
- {assemblyline_v4_service-4.5.1.dev453.dist-info → assemblyline_v4_service-4.5.1.dev455.dist-info}/top_level.txt +0 -0
assemblyline_v4_service/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.5.1.
|
|
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
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
import typing
|
|
5
|
-
import os
|
|
6
|
-
import logging
|
|
7
|
-
import time
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
8
4
|
import json
|
|
9
|
-
import
|
|
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
|
|
13
|
-
import
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
75
|
+
downloadable_signature_statuses=['DEPLOYED', 'NOISY']):
|
|
69
76
|
|
|
70
77
|
self.updater_type = os.environ['SERVICE_PATH'].split('.')[-1].lower()
|
|
71
|
-
self.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,4 +1,4 @@
|
|
|
1
|
-
assemblyline_v4_service/VERSION,sha256=
|
|
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=
|
|
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=
|
|
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.
|
|
42
|
-
assemblyline_v4_service-4.5.1.
|
|
43
|
-
assemblyline_v4_service-4.5.1.
|
|
44
|
-
assemblyline_v4_service-4.5.1.
|
|
45
|
-
assemblyline_v4_service-4.5.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|