dissect.target 3.19.dev28__py3-none-any.whl → 3.19.dev30__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.
- dissect/target/plugins/apps/browser/firefox.py +77 -32
- dissect/target/plugins/general/users.py +14 -10
- dissect/target/plugins/os/unix/esxi/_os.py +17 -17
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/METADATA +1 -1
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/RECORD +10 -10
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/LICENSE +0 -0
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/WHEEL +0 -0
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ import json
|
|
3
3
|
import logging
|
4
4
|
from base64 import b64decode
|
5
5
|
from hashlib import pbkdf2_hmac, sha1
|
6
|
+
from itertools import chain
|
6
7
|
from typing import Iterator, Optional
|
7
8
|
|
8
9
|
from dissect.sql import sqlite3
|
@@ -14,7 +15,7 @@ from dissect.target.exceptions import FileNotFoundError, UnsupportedPluginError
|
|
14
15
|
from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
|
15
16
|
from dissect.target.helpers.fsutil import TargetPath
|
16
17
|
from dissect.target.helpers.record import create_extended_descriptor
|
17
|
-
from dissect.target.plugin import export
|
18
|
+
from dissect.target.plugin import OperatingSystem, export
|
18
19
|
from dissect.target.plugins.apps.browser.browser import (
|
19
20
|
GENERIC_COOKIE_FIELDS,
|
20
21
|
GENERIC_DOWNLOAD_RECORD_FIELDS,
|
@@ -24,7 +25,7 @@ from dissect.target.plugins.apps.browser.browser import (
|
|
24
25
|
BrowserPlugin,
|
25
26
|
try_idna,
|
26
27
|
)
|
27
|
-
from dissect.target.plugins.general.users import
|
28
|
+
from dissect.target.plugins.general.users import UserRecord
|
28
29
|
|
29
30
|
try:
|
30
31
|
from asn1crypto import algos, core
|
@@ -44,7 +45,10 @@ try:
|
|
44
45
|
except ImportError:
|
45
46
|
HAS_CRYPTO = False
|
46
47
|
|
47
|
-
FIREFOX_EXTENSION_RECORD_FIELDS = [
|
48
|
+
FIREFOX_EXTENSION_RECORD_FIELDS = [
|
49
|
+
("uri", "source_uri"),
|
50
|
+
("string[]", "optional_permissions"),
|
51
|
+
]
|
48
52
|
|
49
53
|
log = logging.getLogger(__name__)
|
50
54
|
|
@@ -54,7 +58,7 @@ class FirefoxPlugin(BrowserPlugin):
|
|
54
58
|
|
55
59
|
__namespace__ = "firefox"
|
56
60
|
|
57
|
-
|
61
|
+
USER_DIRS = [
|
58
62
|
# Windows
|
59
63
|
"AppData/Roaming/Mozilla/Firefox/Profiles",
|
60
64
|
"AppData/local/Mozilla/Firefox/Profiles",
|
@@ -66,6 +70,10 @@ class FirefoxPlugin(BrowserPlugin):
|
|
66
70
|
"Library/Application Support/Firefox",
|
67
71
|
]
|
68
72
|
|
73
|
+
SYSTEM_DIRS = [
|
74
|
+
"/data/data/org.mozilla.vrbrowser/files/mozilla",
|
75
|
+
]
|
76
|
+
|
69
77
|
BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
|
70
78
|
"browser/firefox/history", GENERIC_HISTORY_RECORD_FIELDS
|
71
79
|
)
|
@@ -79,7 +87,8 @@ class FirefoxPlugin(BrowserPlugin):
|
|
79
87
|
)
|
80
88
|
|
81
89
|
BrowserExtensionRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
|
82
|
-
"browser/firefox/extension",
|
90
|
+
"browser/firefox/extension",
|
91
|
+
GENERIC_EXTENSION_RECORD_FIELDS + FIREFOX_EXTENSION_RECORD_FIELDS,
|
83
92
|
)
|
84
93
|
|
85
94
|
BrowserPasswordRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
|
@@ -88,27 +97,32 @@ class FirefoxPlugin(BrowserPlugin):
|
|
88
97
|
|
89
98
|
def __init__(self, target):
|
90
99
|
super().__init__(target)
|
91
|
-
self.
|
100
|
+
self.dirs: list[tuple[UserRecord, TargetPath]] = []
|
101
|
+
|
92
102
|
for user_details in self.target.user_details.all_with_home():
|
93
|
-
for directory in self.
|
103
|
+
for directory in self.USER_DIRS:
|
94
104
|
cur_dir = user_details.home_path.joinpath(directory)
|
95
105
|
if not cur_dir.exists():
|
96
106
|
continue
|
97
|
-
self.
|
107
|
+
self.dirs.append((user_details.user, cur_dir))
|
108
|
+
|
109
|
+
for directory in self.SYSTEM_DIRS:
|
110
|
+
if (cur_dir := target.fs.path(directory)).exists():
|
111
|
+
self.dirs.append((None, cur_dir))
|
98
112
|
|
99
113
|
def check_compatible(self) -> None:
|
100
|
-
if not len(self.
|
114
|
+
if not len(self.dirs):
|
101
115
|
raise UnsupportedPluginError("No Firefox directories found")
|
102
116
|
|
103
|
-
def _iter_profiles(self) -> Iterator[tuple[
|
117
|
+
def _iter_profiles(self) -> Iterator[tuple[UserRecord, TargetPath, TargetPath]]:
|
104
118
|
"""Yield user directories."""
|
105
|
-
for user, cur_dir in self.
|
119
|
+
for user, cur_dir in self.dirs:
|
106
120
|
for profile_dir in cur_dir.iterdir():
|
107
121
|
if not profile_dir.is_dir():
|
108
122
|
continue
|
109
123
|
yield user, cur_dir, profile_dir
|
110
124
|
|
111
|
-
def _iter_db(self, filename: str) -> Iterator[tuple[
|
125
|
+
def _iter_db(self, filename: str) -> Iterator[tuple[UserRecord, SQLite3]]:
|
112
126
|
"""Yield opened history database files of all users.
|
113
127
|
|
114
128
|
Args:
|
@@ -117,12 +131,24 @@ class FirefoxPlugin(BrowserPlugin):
|
|
117
131
|
Yields:
|
118
132
|
Opened SQLite3 databases.
|
119
133
|
"""
|
120
|
-
for user,
|
121
|
-
|
134
|
+
iter_system = ((None, system_dir, None) for user, system_dir in self.dirs if user is None)
|
135
|
+
|
136
|
+
for user, cur_dir, profile_dir in chain(iter_system, self._iter_profiles()):
|
137
|
+
if user is None and profile_dir is None:
|
138
|
+
db_file = cur_dir.parent.joinpath(filename)
|
139
|
+
# On some Android variants, some files may exist in the base directory (places.sqlite) but others
|
140
|
+
# in a nested profile directory (cookies.sqlite)
|
141
|
+
# /data/data/org.mozilla.vrbrowser/files/places.sqlite
|
142
|
+
# /data/data/org.mozilla.vrbrowser/files/mozilla/xxxxxx.default/cookies.sqlite
|
143
|
+
if not db_file.exists():
|
144
|
+
continue
|
145
|
+
else:
|
146
|
+
db_file = profile_dir.joinpath(filename)
|
147
|
+
|
122
148
|
try:
|
123
149
|
yield user, db_file, sqlite3.SQLite3(db_file.open())
|
124
150
|
except FileNotFoundError:
|
125
|
-
self.target.log.
|
151
|
+
self.target.log.info("Could not find %s file: %s", filename, db_file)
|
126
152
|
except SQLError as e:
|
127
153
|
self.target.log.warning("Could not open %s file: %s", filename, db_file)
|
128
154
|
self.target.log.debug("", exc_info=e)
|
@@ -151,6 +177,11 @@ class FirefoxPlugin(BrowserPlugin):
|
|
151
177
|
from_url (uri): URL of the "from" visit.
|
152
178
|
source: (path): The source file of the history record.
|
153
179
|
"""
|
180
|
+
if self.target.os == OperatingSystem.ANDROID:
|
181
|
+
from_timestamp = from_unix_ms
|
182
|
+
else:
|
183
|
+
from_timestamp = from_unix_us
|
184
|
+
|
154
185
|
for user, db_file, db in self._iter_db("places.sqlite"):
|
155
186
|
try:
|
156
187
|
places = {row.id: row for row in db.table("moz_places").rows()}
|
@@ -167,7 +198,7 @@ class FirefoxPlugin(BrowserPlugin):
|
|
167
198
|
from_visit, from_place = None, None
|
168
199
|
|
169
200
|
yield self.BrowserHistoryRecord(
|
170
|
-
ts=
|
201
|
+
ts=from_timestamp(row.visit_date),
|
171
202
|
browser="firefox",
|
172
203
|
id=row.id,
|
173
204
|
url=try_idna(place.url),
|
@@ -183,7 +214,7 @@ class FirefoxPlugin(BrowserPlugin):
|
|
183
214
|
from_url=try_idna(from_place.url) if from_place else None,
|
184
215
|
source=db_file,
|
185
216
|
_target=self.target,
|
186
|
-
_user=user
|
217
|
+
_user=user,
|
187
218
|
)
|
188
219
|
except SQLError as e:
|
189
220
|
self.target.log.warning("Error processing history file: %s", db_file, exc_info=e)
|
@@ -229,7 +260,7 @@ class FirefoxPlugin(BrowserPlugin):
|
|
229
260
|
same_site=bool(cookie.sameSite),
|
230
261
|
source=db_file,
|
231
262
|
_target=self.target,
|
232
|
-
_user=user
|
263
|
+
_user=user,
|
233
264
|
)
|
234
265
|
except SQLError as e:
|
235
266
|
self.target.log.warning("Error processing cookie file: %s", db_file, exc_info=e)
|
@@ -255,7 +286,10 @@ class FirefoxPlugin(BrowserPlugin):
|
|
255
286
|
for user, db_file, db in self._iter_db("places.sqlite"):
|
256
287
|
try:
|
257
288
|
places = {row.id: row for row in db.table("moz_places").rows()}
|
258
|
-
|
289
|
+
if not (moz_anno_attributes := db.table("moz_anno_attributes")):
|
290
|
+
continue
|
291
|
+
|
292
|
+
attributes = {row.id: row.name for row in moz_anno_attributes.rows()}
|
259
293
|
annotations = {}
|
260
294
|
|
261
295
|
for row in db.table("moz_annos"):
|
@@ -316,7 +350,7 @@ class FirefoxPlugin(BrowserPlugin):
|
|
316
350
|
state=state,
|
317
351
|
source=db_file,
|
318
352
|
_target=self.target,
|
319
|
-
_user=user
|
353
|
+
_user=user,
|
320
354
|
)
|
321
355
|
except SQLError as e:
|
322
356
|
self.target.log.warning("Error processing history file: %s", db_file, exc_info=e)
|
@@ -351,7 +385,9 @@ class FirefoxPlugin(BrowserPlugin):
|
|
351
385
|
|
352
386
|
if not extension_file.exists():
|
353
387
|
self.target.log.warning(
|
354
|
-
"No 'extensions.json' addon file found for user %s in directory %s",
|
388
|
+
"No 'extensions.json' addon file found for user %s in directory %s",
|
389
|
+
user.name,
|
390
|
+
profile_dir,
|
355
391
|
)
|
356
392
|
continue
|
357
393
|
|
@@ -360,8 +396,8 @@ class FirefoxPlugin(BrowserPlugin):
|
|
360
396
|
|
361
397
|
for extension in extensions.get("addons", []):
|
362
398
|
yield self.BrowserExtensionRecord(
|
363
|
-
ts_install=extension.get("installDate", 0)
|
364
|
-
ts_update=extension.get("updateDate", 0)
|
399
|
+
ts_install=from_unix_ms(extension.get("installDate", 0)),
|
400
|
+
ts_update=from_unix_ms(extension.get("updateDate", 0)),
|
365
401
|
browser="firefox",
|
366
402
|
id=extension.get("id"),
|
367
403
|
name=(extension.get("defaultLocale", {}) or {}).get("name"),
|
@@ -377,12 +413,14 @@ class FirefoxPlugin(BrowserPlugin):
|
|
377
413
|
optional_permissions=(extension.get("optionalPermissions", {}) or {}).get("permissions"),
|
378
414
|
source=extension_file,
|
379
415
|
_target=self.target,
|
380
|
-
_user=user
|
416
|
+
_user=user,
|
381
417
|
)
|
382
418
|
|
383
419
|
except FileNotFoundError:
|
384
420
|
self.target.log.info(
|
385
|
-
"No 'extensions.json' addon file found for user %s in directory %s",
|
421
|
+
"No 'extensions.json' addon file found for user %s in directory %s",
|
422
|
+
user.name,
|
423
|
+
profile_dir,
|
386
424
|
)
|
387
425
|
except json.JSONDecodeError:
|
388
426
|
self.target.log.warning(
|
@@ -410,7 +448,9 @@ class FirefoxPlugin(BrowserPlugin):
|
|
410
448
|
|
411
449
|
if not login_file.exists():
|
412
450
|
self.target.log.warning(
|
413
|
-
"No 'logins.json' password file found for user %s in directory %s",
|
451
|
+
"No 'logins.json' password file found for user %s in directory %s",
|
452
|
+
user.name,
|
453
|
+
profile_dir,
|
414
454
|
)
|
415
455
|
continue
|
416
456
|
|
@@ -445,9 +485,9 @@ class FirefoxPlugin(BrowserPlugin):
|
|
445
485
|
break
|
446
486
|
|
447
487
|
yield self.BrowserPasswordRecord(
|
448
|
-
ts_created=login.get("timeCreated", 0)
|
449
|
-
ts_last_used=login.get("timeLastUsed", 0)
|
450
|
-
ts_last_changed=login.get("timePasswordChanged", 0)
|
488
|
+
ts_created=from_unix_ms(login.get("timeCreated", 0)),
|
489
|
+
ts_last_used=from_unix_ms(login.get("timeLastUsed", 0)),
|
490
|
+
ts_last_changed=from_unix_ms(login.get("timePasswordChanged", 0)),
|
451
491
|
browser="firefox",
|
452
492
|
id=login.get("id"),
|
453
493
|
url=login.get("hostname"),
|
@@ -457,14 +497,19 @@ class FirefoxPlugin(BrowserPlugin):
|
|
457
497
|
decrypted_password=decrypted_password,
|
458
498
|
source=login_file,
|
459
499
|
_target=self.target,
|
460
|
-
_user=user
|
500
|
+
_user=user,
|
461
501
|
)
|
462
502
|
|
463
503
|
except FileNotFoundError:
|
464
|
-
self.target.log.info(
|
504
|
+
self.target.log.info(
|
505
|
+
"No password file found for user %s in directory %s",
|
506
|
+
user.name,
|
507
|
+
profile_dir,
|
508
|
+
)
|
465
509
|
except json.JSONDecodeError:
|
466
510
|
self.target.log.warning(
|
467
|
-
"logins.json file in directory %s is malformed, consider inspecting the file manually",
|
511
|
+
"logins.json file in directory %s is malformed, consider inspecting the file manually",
|
512
|
+
profile_dir,
|
468
513
|
)
|
469
514
|
|
470
515
|
|
@@ -1,5 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from functools import lru_cache
|
2
|
-
from typing import
|
4
|
+
from typing import Iterator, NamedTuple, Union
|
3
5
|
|
4
6
|
from dissect.target import Target
|
5
7
|
from dissect.target.exceptions import UnsupportedPluginError
|
@@ -7,10 +9,12 @@ from dissect.target.helpers.fsutil import TargetPath
|
|
7
9
|
from dissect.target.helpers.record import UnixUserRecord, WindowsUserRecord
|
8
10
|
from dissect.target.plugin import InternalPlugin
|
9
11
|
|
12
|
+
UserRecord = Union[UnixUserRecord, WindowsUserRecord]
|
13
|
+
|
10
14
|
|
11
15
|
class UserDetails(NamedTuple):
|
12
|
-
user:
|
13
|
-
home_path:
|
16
|
+
user: UserRecord
|
17
|
+
home_path: TargetPath | None
|
14
18
|
|
15
19
|
|
16
20
|
class UsersPlugin(InternalPlugin):
|
@@ -28,11 +32,11 @@ class UsersPlugin(InternalPlugin):
|
|
28
32
|
|
29
33
|
def find(
|
30
34
|
self,
|
31
|
-
sid:
|
32
|
-
uid:
|
33
|
-
username:
|
35
|
+
sid: str | None = None,
|
36
|
+
uid: str | None = None,
|
37
|
+
username: str | None = None,
|
34
38
|
force_case_sensitive: bool = False,
|
35
|
-
) ->
|
39
|
+
) -> UserDetails | None:
|
36
40
|
"""Find User record matching provided sid, uid or username and return UserDetails object"""
|
37
41
|
if all(map(lambda x: x is None, [sid, uid, username])):
|
38
42
|
raise ValueError("Either sid or uid or username is expected")
|
@@ -52,7 +56,7 @@ class UsersPlugin(InternalPlugin):
|
|
52
56
|
):
|
53
57
|
return self.get(user)
|
54
58
|
|
55
|
-
def get(self, user:
|
59
|
+
def get(self, user: UserRecord) -> UserDetails:
|
56
60
|
"""Return additional details about the user"""
|
57
61
|
# Resolving the user home can not use the user's environment variables,
|
58
62
|
# as those depend on the user's home to be known first. So we resolve
|
@@ -60,12 +64,12 @@ class UsersPlugin(InternalPlugin):
|
|
60
64
|
home_path = self.target.fs.path(self.target.resolve(str(user.home))) if user.home else None
|
61
65
|
return UserDetails(user=user, home_path=home_path)
|
62
66
|
|
63
|
-
def all(self) ->
|
67
|
+
def all(self) -> Iterator[UserDetails]:
|
64
68
|
"""Return UserDetails objects for all users found"""
|
65
69
|
for user in self.target.users():
|
66
70
|
yield self.get(user)
|
67
71
|
|
68
|
-
def all_with_home(self) ->
|
72
|
+
def all_with_home(self) -> Iterator[UserDetails]:
|
69
73
|
"""Return UserDetails objects for users that have existing directory set as home directory"""
|
70
74
|
for user in self.target.users():
|
71
75
|
if user.home:
|
@@ -8,7 +8,7 @@ import subprocess
|
|
8
8
|
from configparser import ConfigParser
|
9
9
|
from configparser import Error as ConfigParserError
|
10
10
|
from io import BytesIO
|
11
|
-
from typing import Any, BinaryIO, Iterator,
|
11
|
+
from typing import Any, BinaryIO, Iterator, TextIO
|
12
12
|
|
13
13
|
from defusedxml import ElementTree
|
14
14
|
from dissect.hypervisor.util import vmtar
|
@@ -73,7 +73,7 @@ class ESXiPlugin(UnixPlugin):
|
|
73
73
|
if configstore.exists():
|
74
74
|
self._configstore = parse_config_store(configstore.open())
|
75
75
|
|
76
|
-
def _cfg(self, path: str) ->
|
76
|
+
def _cfg(self, path: str) -> str | None:
|
77
77
|
if not self._config:
|
78
78
|
self.target.log.warning("No ESXi config!")
|
79
79
|
return None
|
@@ -87,7 +87,7 @@ class ESXiPlugin(UnixPlugin):
|
|
87
87
|
return obj.get(value_name) if obj else None
|
88
88
|
|
89
89
|
@classmethod
|
90
|
-
def detect(cls, target: Target) ->
|
90
|
+
def detect(cls, target: Target) -> Filesystem | None:
|
91
91
|
bootbanks = [
|
92
92
|
fs for fs in target.filesystems if fs.path("boot.cfg").exists() and list(fs.path("/").glob("*.v00"))
|
93
93
|
]
|
@@ -128,7 +128,7 @@ class ESXiPlugin(UnixPlugin):
|
|
128
128
|
return "localhost"
|
129
129
|
|
130
130
|
@export(property=True)
|
131
|
-
def domain(self) ->
|
131
|
+
def domain(self) -> str | None:
|
132
132
|
if hostname := self._cfg("/adv/Misc/HostName"):
|
133
133
|
return hostname.partition(".")[2]
|
134
134
|
|
@@ -146,7 +146,7 @@ class ESXiPlugin(UnixPlugin):
|
|
146
146
|
return list(result)
|
147
147
|
|
148
148
|
@export(property=True)
|
149
|
-
def version(self) ->
|
149
|
+
def version(self) -> str | None:
|
150
150
|
boot_cfg = self.target.fs.path("/bootbank/boot.cfg")
|
151
151
|
if not boot_cfg.exists():
|
152
152
|
return None
|
@@ -187,11 +187,11 @@ class ESXiPlugin(UnixPlugin):
|
|
187
187
|
return self._configstore
|
188
188
|
|
189
189
|
@export(property=True)
|
190
|
-
def os(self):
|
190
|
+
def os(self) -> str:
|
191
191
|
return OperatingSystem.ESXI.value
|
192
192
|
|
193
193
|
|
194
|
-
def _mount_modules(target: Target, sysvol: Filesystem, cfg: dict[str, str]):
|
194
|
+
def _mount_modules(target: Target, sysvol: Filesystem, cfg: dict[str, str]) -> None:
|
195
195
|
modules = [m.strip() for m in cfg["modules"].split("---")]
|
196
196
|
|
197
197
|
for module in modules:
|
@@ -218,20 +218,22 @@ def _mount_modules(target: Target, sysvol: Filesystem, cfg: dict[str, str]):
|
|
218
218
|
target.fs.append_layer().mount("/", tfs)
|
219
219
|
|
220
220
|
|
221
|
-
def _mount_local(target: Target, local_layer: VirtualFilesystem):
|
221
|
+
def _mount_local(target: Target, local_layer: VirtualFilesystem) -> None:
|
222
222
|
local_tgz = target.fs.path("local.tgz")
|
223
|
+
local_tgz_ve = target.fs.path("local.tgz.ve")
|
223
224
|
local_fs = None
|
224
225
|
|
225
226
|
if local_tgz.exists():
|
226
227
|
local_fs = tar.TarFilesystem(local_tgz.open())
|
227
|
-
|
228
|
-
local_tgz_ve = target.fs.path("local.tgz.ve")
|
228
|
+
elif local_tgz_ve.exists():
|
229
229
|
# In the case "encryption.info" does not exist, but ".#encryption.info" does
|
230
230
|
encryption_info = next(target.fs.path("/").glob("*encryption.info"), None)
|
231
231
|
if not local_tgz_ve.exists() or not encryption_info.exists():
|
232
232
|
raise ValueError("Unable to find valid configuration archive")
|
233
233
|
|
234
234
|
local_fs = _create_local_fs(target, local_tgz_ve, encryption_info)
|
235
|
+
else:
|
236
|
+
target.log.warning("No local.tgz or local.tgz.ve found, skipping local state")
|
235
237
|
|
236
238
|
if local_fs:
|
237
239
|
local_layer.mount("/", local_fs)
|
@@ -245,7 +247,7 @@ def _decrypt_envelope(local_tgz_ve: TargetPath, encryption_info: TargetPath) ->
|
|
245
247
|
return local_tgz
|
246
248
|
|
247
249
|
|
248
|
-
def _decrypt_crypto_util(local_tgz_ve: TargetPath) ->
|
250
|
+
def _decrypt_crypto_util(local_tgz_ve: TargetPath) -> BytesIO | None:
|
249
251
|
"""Decrypt ``local.tgz.ve`` using ESXi ``crypto-util``.
|
250
252
|
|
251
253
|
We write to stdout, but this results in ``crypto-util`` exiting with a non-zero return code
|
@@ -264,9 +266,7 @@ def _decrypt_crypto_util(local_tgz_ve: TargetPath) -> Optional[BytesIO]:
|
|
264
266
|
return BytesIO(result.stdout)
|
265
267
|
|
266
268
|
|
267
|
-
def _create_local_fs(
|
268
|
-
target: Target, local_tgz_ve: TargetPath, encryption_info: TargetPath
|
269
|
-
) -> Optional[tar.TarFilesystem]:
|
269
|
+
def _create_local_fs(target: Target, local_tgz_ve: TargetPath, encryption_info: TargetPath) -> tar.TarFilesystem | None:
|
270
270
|
local_tgz = None
|
271
271
|
|
272
272
|
if HAS_ENVELOPE:
|
@@ -292,7 +292,7 @@ def _create_local_fs(
|
|
292
292
|
return tar.TarFilesystem(local_tgz)
|
293
293
|
|
294
294
|
|
295
|
-
def _mount_filesystems(target: Target, sysvol: Filesystem, cfg: dict[str, str]):
|
295
|
+
def _mount_filesystems(target: Target, sysvol: Filesystem, cfg: dict[str, str]) -> None:
|
296
296
|
version = cfg["build"]
|
297
297
|
|
298
298
|
osdata_fs = None
|
@@ -371,7 +371,7 @@ def _mount_filesystems(target: Target, sysvol: Filesystem, cfg: dict[str, str]):
|
|
371
371
|
target.fs.symlink(f"/vmfs/volumes/LOCKER-{locker_fs.vmfs.uuid}", "/locker")
|
372
372
|
|
373
373
|
|
374
|
-
def _link_log_dir(target: Target, cfg: dict[str, str], plugin_obj: ESXiPlugin):
|
374
|
+
def _link_log_dir(target: Target, cfg: dict[str, str], plugin_obj: ESXiPlugin) -> None:
|
375
375
|
version = cfg["build"]
|
376
376
|
|
377
377
|
# Don't really know how ESXi does this, but let's just take a shortcut for now
|
@@ -441,7 +441,7 @@ def parse_esx_conf(fh: TextIO) -> dict[str, Any]:
|
|
441
441
|
return config
|
442
442
|
|
443
443
|
|
444
|
-
def _traverse(path: str, obj: dict[str, Any], create: bool = False):
|
444
|
+
def _traverse(path: str, obj: dict[str, Any], create: bool = False) -> dict[str, Any] | None:
|
445
445
|
parts = path.strip("/").split("/")
|
446
446
|
path_parts = parts[:-1]
|
447
447
|
for part in path_parts:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.19.
|
3
|
+
Version: 3.19.dev30
|
4
4
|
Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
6
6
|
License: Affero General Public License v3
|
@@ -124,7 +124,7 @@ dissect/target/plugins/apps/browser/browser.py,sha256=rBIwcgdl73gm-8APwx2jEUAYXR
|
|
124
124
|
dissect/target/plugins/apps/browser/chrome.py,sha256=DMONTYE95sI_jcmyQOapHwWQWwrezfYMllVCCPwhEP0,3117
|
125
125
|
dissect/target/plugins/apps/browser/chromium.py,sha256=V08Hq8GHMPd7snynh5RKQl4YHlhtwmlMsodLZeOnf_4,28103
|
126
126
|
dissect/target/plugins/apps/browser/edge.py,sha256=tuuIbm4s8nNstA6nIOEfU0LG0jt20a8gf3rve2SXtdM,2953
|
127
|
-
dissect/target/plugins/apps/browser/firefox.py,sha256=
|
127
|
+
dissect/target/plugins/apps/browser/firefox.py,sha256=mZBBagFfIdiz9kUyK4Hi989I4g3CWrClBbmpaGMRKxg,32472
|
128
128
|
dissect/target/plugins/apps/browser/iexplore.py,sha256=g_xw0toaiyjevxO8g9XPCOqc-CXZp39FVquRhPFGdTE,8801
|
129
129
|
dissect/target/plugins/apps/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
130
130
|
dissect/target/plugins/apps/container/docker.py,sha256=KxQRbKGgxkf3YFBMa7fjeJ7qo8qjFys7zEmfQhDTnLw,15305
|
@@ -181,7 +181,7 @@ dissect/target/plugins/general/loaders.py,sha256=6iUxhlSAgo7qSE8_XFxgiihK8sdMiP-
|
|
181
181
|
dissect/target/plugins/general/osinfo.py,sha256=RdK5mw3-H9H3sGXz8yP8U_p3wUG1Ww7_HBKZpFdsbTE,1358
|
182
182
|
dissect/target/plugins/general/plugins.py,sha256=4URjS6DN1Ey6Cqlbyx6NfFGgQZpWDrqxl8KLcZFODGE,4479
|
183
183
|
dissect/target/plugins/general/scrape.py,sha256=Fz7BNXflvuxlnVulyyDhLpyU8D_hJdH6vWVtER9vjTg,6651
|
184
|
-
dissect/target/plugins/general/users.py,sha256=
|
184
|
+
dissect/target/plugins/general/users.py,sha256=yy9gvRXfN9BT71v4Xqo5hpwfgN9he9Otu8TBPZ_Tegs,3009
|
185
185
|
dissect/target/plugins/os/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
186
186
|
dissect/target/plugins/os/unix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
187
187
|
dissect/target/plugins/os/unix/_os.py,sha256=u7m97qASdm_l90k4i7dzMtu2kcF6fVPKutx4_ISQTSg,14606
|
@@ -208,7 +208,7 @@ dissect/target/plugins/os/unix/bsd/osx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
|
|
208
208
|
dissect/target/plugins/os/unix/bsd/osx/_os.py,sha256=KvP7YJ7apVwoIop7MR-8q5QbVGoB6MdR42l6ssEe6es,4081
|
209
209
|
dissect/target/plugins/os/unix/bsd/osx/user.py,sha256=qopB0s3n7e6Q7NjWzn8Z-dKtDtU7e6In4Vm7hIvvedo,2322
|
210
210
|
dissect/target/plugins/os/unix/esxi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
211
|
-
dissect/target/plugins/os/unix/esxi/_os.py,sha256=
|
211
|
+
dissect/target/plugins/os/unix/esxi/_os.py,sha256=s6pAgUyfHh3QcY6sgvk5uVMmLvqK1tIHWR7MSbrFn8w,17789
|
212
212
|
dissect/target/plugins/os/unix/etc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
213
213
|
dissect/target/plugins/os/unix/etc/etc.py,sha256=WNCtO7NWOKRDBiV-XjXqgPuGRDE_Zyw6XWz3kTm__QE,2493
|
214
214
|
dissect/target/plugins/os/unix/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -346,10 +346,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
346
346
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
347
347
|
dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
|
348
348
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
349
|
-
dissect.target-3.19.
|
350
|
-
dissect.target-3.19.
|
351
|
-
dissect.target-3.19.
|
352
|
-
dissect.target-3.19.
|
353
|
-
dissect.target-3.19.
|
354
|
-
dissect.target-3.19.
|
355
|
-
dissect.target-3.19.
|
349
|
+
dissect.target-3.19.dev30.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
350
|
+
dissect.target-3.19.dev30.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
351
|
+
dissect.target-3.19.dev30.dist-info/METADATA,sha256=fH2AsY4Du8s64GYdA4y4mJGfiEihIMfqkbOgE1ALNqc,12719
|
352
|
+
dissect.target-3.19.dev30.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
353
|
+
dissect.target-3.19.dev30.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
354
|
+
dissect.target-3.19.dev30.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
355
|
+
dissect.target-3.19.dev30.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.19.dev28.dist-info → dissect.target-3.19.dev30.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|