dissect.target 3.20.dev7__py3-none-any.whl → 3.20.dev8__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.
@@ -4,7 +4,7 @@ import json
4
4
  import logging
5
5
  import re
6
6
  from pathlib import Path
7
- from typing import Iterator, Optional
7
+ from typing import Iterator
8
8
 
9
9
  from dissect.cstruct import cstruct
10
10
  from dissect.util import ts
@@ -128,12 +128,17 @@ class DockerPlugin(Plugin):
128
128
  for data_root in self.installs:
129
129
  images_path = data_root.joinpath("image/overlay2/repositories.json")
130
130
 
131
- if images_path.exists():
132
- repositories = json.loads(images_path.read_text()).get("Repositories")
133
- else:
131
+ if not images_path.exists():
134
132
  self.target.log.debug("No docker images found, file %s does not exist.", images_path)
135
133
  continue
136
134
 
135
+ try:
136
+ repositories = json.loads(images_path.read_text()).get("Repositories", {})
137
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
138
+ self.target.log.warning("Unable to parse JSON in: %s", images_path)
139
+ self.target.log.debug("", exc_info=e)
140
+ continue
141
+
137
142
  for name, tags in repositories.items():
138
143
  for tag, hash in tags.items():
139
144
  image_metadata_path = data_root.joinpath(
@@ -142,8 +147,12 @@ class DockerPlugin(Plugin):
142
147
  created = None
143
148
 
144
149
  if image_metadata_path.exists():
145
- image_metadata = json.loads(image_metadata_path.read_text())
146
- created = convert_timestamp(image_metadata.get("created"))
150
+ try:
151
+ image_metadata = json.loads(image_metadata_path.read_text())
152
+ created = convert_timestamp(image_metadata.get("created"))
153
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
154
+ self.target.log.warning("Unable to parse JSON in: %s", image_metadata_path)
155
+ self.target.log.debug("", exc_info=e)
147
156
 
148
157
  yield DockerImageRecord(
149
158
  name=name,
@@ -160,47 +169,51 @@ class DockerPlugin(Plugin):
160
169
 
161
170
  for data_root in self.installs:
162
171
  for config_path in data_root.joinpath("containers").glob("**/config.v2.json"):
163
- config = json.loads(config_path.read_text())
172
+ try:
173
+ config = json.loads(config_path.read_text())
174
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
175
+ self.target.log.warning("Unable to parse JSON in file: %s", config_path)
176
+ self.target.log.debug("", exc_info=e)
177
+ continue
178
+
164
179
  container_id = config.get("ID")
165
180
 
166
181
  # determine state
167
- running = config.get("State").get("Running")
182
+ running = config.get("State", {}).get("Running")
168
183
  if running:
169
- ports = config.get("NetworkSettings").get("Ports", {})
170
- pid = config.get("Pid")
171
- else:
172
- ports = config.get("Config").get("ExposedPorts", {})
173
- pid = None
184
+ ports = config.get("NetworkSettings", {}).get("Ports", {})
185
+
186
+ if not running or not ports:
187
+ ports = config.get("Config", {}).get("ExposedPorts", {})
174
188
 
175
189
  # parse volumes
176
190
  volumes = []
177
- if mount_points := config.get("MountPoints"):
178
- for mp in mount_points:
179
- mount_point = mount_points[mp]
191
+ if mount_points := config.get("MountPoints", {}):
192
+ for mount_point in mount_points.values():
180
193
  volumes.append(f"{mount_point.get('Source')}:{mount_point.get('Destination')}")
181
194
 
182
195
  # determine mount point
183
196
  mount_path = None
184
- if config.get("Driver") == "overlay2":
197
+ if container_id and config.get("Driver") == "overlay2":
185
198
  mount_path = data_root.joinpath("image/overlay2/layerdb/mounts", container_id)
186
199
  if not mount_path.exists():
187
- self.target.log.warning("Overlay2 mount path for container %s does not exist!", container_id)
200
+ self.target.log.warning("Overlay2 mount path does not exist for container: %s", container_id)
188
201
 
189
202
  else:
190
- self.target.log.warning("Encountered unsupported container filesystem %s", config.get("Driver"))
203
+ self.target.log.warning("Encountered unsupported container filesystem: %s", config.get("Driver"))
191
204
 
192
205
  yield DockerContainerRecord(
193
206
  container_id=container_id,
194
- image=config.get("Config").get("Image"),
195
- image_id=config.get("Image").split(":")[-1],
196
- command=config.get("Config").get("Cmd"),
207
+ image=config.get("Config", {}).get("Image"),
208
+ image_id=config.get("Image", "").split(":")[-1],
209
+ command=f"{config.get('Path', '')} {' '.join(config.get('Args', []))}".strip(),
197
210
  created=convert_timestamp(config.get("Created")),
198
211
  running=running,
199
- pid=pid,
200
- started=convert_timestamp(config.get("State").get("StartedAt")),
201
- finished=convert_timestamp(config.get("State").get("FinishedAt")),
212
+ pid=config.get("State", {}).get("Pid"),
213
+ started=convert_timestamp(config.get("State", {}).get("StartedAt")),
214
+ finished=convert_timestamp(config.get("State", {}).get("FinishedAt")),
202
215
  ports=convert_ports(ports),
203
- names=config.get("Name").replace("/", "", 1),
216
+ names=config.get("Name", "").replace("/", "", 1),
204
217
  volumes=volumes,
205
218
  mount_path=mount_path,
206
219
  config_path=config_path,
@@ -288,19 +301,19 @@ class DockerPlugin(Plugin):
288
301
  for line in open_decompress(path, "rt"):
289
302
  try:
290
303
  entry = json.loads(line)
291
- except json.JSONDecodeError as e:
292
- self.target.log.warning("Could not decode JSON line in file %s", path)
304
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
305
+ self.target.log.warning("Could not decode JSON line in file: %s", path)
293
306
  self.target.log.debug("", exc_info=e)
294
307
  continue
295
308
  yield entry
296
309
 
297
310
 
298
- def get_data_path(path: Path) -> Optional[str]:
311
+ def get_data_path(path: Path) -> str | None:
299
312
  """Returns the configured Docker daemon data-root path."""
300
313
  try:
301
314
  config = json.loads(path.open("rt").read())
302
- except json.JSONDecodeError as e:
303
- log.warning("Could not read JSON file '%s'", path)
315
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
316
+ log.warning("Could not read JSON file: %s", path)
304
317
  log.debug(exc_info=e)
305
318
 
306
319
  return config.get("data-root")
@@ -341,7 +354,7 @@ def find_installs(target: Target) -> Iterator[Path]:
341
354
  yield data_root_path
342
355
 
343
356
 
344
- def convert_timestamp(timestamp: str) -> str:
357
+ def convert_timestamp(timestamp: str | None) -> str:
345
358
  """Docker sometimes uses (unpadded) 9 digit nanosecond precision
346
359
  in their timestamp logs, eg. "2022-12-19T13:37:00.123456789Z".
347
360
 
@@ -350,6 +363,9 @@ def convert_timestamp(timestamp: str) -> str:
350
363
  compatbility with the 6 digit %f microsecond directive.
351
364
  """
352
365
 
366
+ if not timestamp:
367
+ return
368
+
353
369
  timestamp_nanoseconds_plus_postfix = timestamp[19:]
354
370
  match = RE_DOCKER_NS.match(timestamp_nanoseconds_plus_postfix)
355
371
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.20.dev7
3
+ Version: 3.20.dev8
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
@@ -127,7 +127,7 @@ dissect/target/plugins/apps/browser/edge.py,sha256=tuuIbm4s8nNstA6nIOEfU0LG0jt20
127
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
- dissect/target/plugins/apps/container/docker.py,sha256=KxQRbKGgxkf3YFBMa7fjeJ7qo8qjFys7zEmfQhDTnLw,15305
130
+ dissect/target/plugins/apps/container/docker.py,sha256=LTsZplaECSfO1Ysp_Y-9WsnNocsreu_iHO8fbSif3g0,16221
131
131
  dissect/target/plugins/apps/remoteaccess/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  dissect/target/plugins/apps/remoteaccess/anydesk.py,sha256=IdijK3F6ppaB_IgKL-xDljlEbb8l9S2U0xSWKqK9xRs,4294
133
133
  dissect/target/plugins/apps/remoteaccess/remoteaccess.py,sha256=DWXkRDVUpFr1icK2fYwSXdZD204Xz0yRuO7rcJOwIwc,825
@@ -363,10 +363,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
363
363
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
364
364
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
365
365
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
366
- dissect.target-3.20.dev7.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
367
- dissect.target-3.20.dev7.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
368
- dissect.target-3.20.dev7.dist-info/METADATA,sha256=ggSv2_Ve2dhbN7iv1CkzxquwwpMxT5pd9xPsfmr46TY,12896
369
- dissect.target-3.20.dev7.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
370
- dissect.target-3.20.dev7.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
371
- dissect.target-3.20.dev7.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
372
- dissect.target-3.20.dev7.dist-info/RECORD,,
366
+ dissect.target-3.20.dev8.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
367
+ dissect.target-3.20.dev8.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
368
+ dissect.target-3.20.dev8.dist-info/METADATA,sha256=VtQsgGmXH9A74YcDFwgv69F90Mk9mrD0-VQTWRKvFQU,12896
369
+ dissect.target-3.20.dev8.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
370
+ dissect.target-3.20.dev8.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
371
+ dissect.target-3.20.dev8.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
372
+ dissect.target-3.20.dev8.dist-info/RECORD,,