dissect.target 3.20.dev10__py3-none-any.whl → 3.20.dev12__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.
@@ -6,7 +6,7 @@ from dissect.target import Target
6
6
  from dissect.target.exceptions import UnsupportedPluginError
7
7
  from dissect.target.helpers.record import TargetRecordDescriptor
8
8
  from dissect.target.helpers.utils import year_rollover_helper
9
- from dissect.target.plugin import Plugin, export
9
+ from dissect.target.plugin import Plugin, alias, export
10
10
 
11
11
  MessagesRecord = TargetRecordDescriptor(
12
12
  "linux/log/messages",
@@ -24,7 +24,9 @@ RE_TS = re.compile(r"(\w+\s{1,2}\d+\s\d{2}:\d{2}:\d{2})")
24
24
  RE_DAEMON = re.compile(r"^[^:]+:\d+:\d+[^\[\]:]+\s([^\[:]+)[\[|:]{1}")
25
25
  RE_PID = re.compile(r"\w\[(\d+)\]")
26
26
  RE_MSG = re.compile(r"[^:]+:\d+:\d+[^:]+:\s(.*)$")
27
- RE_CLOUD_INIT_LINE = re.compile(r"(?P<ts>.*) - (?P<daemon>.*)\[(?P<log_level>\w+)\]\: (?P<message>.*)$")
27
+ RE_CLOUD_INIT_LINE = re.compile(
28
+ r"^(?P<ts>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) - (?P<daemon>.*)\[(?P<log_level>\w+)\]\: (?P<message>.*)$"
29
+ )
28
30
 
29
31
 
30
32
  class MessagesPlugin(Plugin):
@@ -43,19 +45,12 @@ class MessagesPlugin(Plugin):
43
45
  if not self.log_files:
44
46
  raise UnsupportedPluginError("No log files found")
45
47
 
46
- @export(record=MessagesRecord)
47
- def syslog(self) -> Iterator[MessagesRecord]:
48
- """Return contents of /var/log/messages*, /var/log/syslog* and cloud-init logs.
49
-
50
- See ``messages`` for more information.
51
- """
52
- return self.messages()
53
-
48
+ @alias("syslog")
54
49
  @export(record=MessagesRecord)
55
50
  def messages(self) -> Iterator[MessagesRecord]:
56
51
  """Return contents of /var/log/messages*, /var/log/syslog* and cloud-init logs.
57
52
 
58
- Note: due to year rollover detection, the contents of the files are returned in reverse.
53
+ Due to year rollover detection, the contents of the files are returned in reverse.
59
54
 
60
55
  The messages log file holds information about a variety of events such as the system error messages, system
61
56
  startups and shutdowns, change in the network configuration, etc. Aims to store valuable, non-debug and
@@ -0,0 +1,132 @@
1
+ from typing import Iterator
2
+
3
+ from dissect.target.exceptions import UnsupportedPluginError
4
+ from dissect.target.helpers import configutil
5
+ from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
6
+ from dissect.target.helpers.fsutil import TargetPath
7
+ from dissect.target.helpers.record import create_extended_descriptor
8
+ from dissect.target.plugin import Plugin, alias, export
9
+ from dissect.target.plugins.general.users import UserDetails
10
+ from dissect.target.target import Target
11
+
12
+ TrashRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
13
+ "linux/filesystem/recyclebin",
14
+ [
15
+ ("datetime", "ts"),
16
+ ("path", "path"),
17
+ ("filesize", "filesize"),
18
+ ("path", "deleted_path"),
19
+ ("path", "source"),
20
+ ],
21
+ )
22
+
23
+
24
+ class GnomeTrashPlugin(Plugin):
25
+ """Linux GNOME Trash plugin."""
26
+
27
+ PATHS = [
28
+ # Default $XDG_DATA_HOME/Trash
29
+ ".local/share/Trash",
30
+ ]
31
+
32
+ def __init__(self, target: Target):
33
+ super().__init__(target)
34
+ self.trashes = list(self._garbage_collector())
35
+
36
+ def _garbage_collector(self) -> Iterator[tuple[UserDetails, TargetPath]]:
37
+ """it aint much, but its honest work"""
38
+ for user_details in self.target.user_details.all_with_home():
39
+ for trash_path in self.PATHS:
40
+ if (path := user_details.home_path.joinpath(trash_path)).exists():
41
+ yield user_details, path
42
+
43
+ def check_compatible(self) -> None:
44
+ if not self.trashes:
45
+ raise UnsupportedPluginError("No Trash folder(s) found")
46
+
47
+ @export(record=TrashRecord)
48
+ @alias(name="recyclebin")
49
+ def trash(self) -> Iterator[TrashRecord]:
50
+ """Yield deleted files from GNOME Trash folders.
51
+
52
+ Recovers deleted files and artifacts from ``$HOME/.local/share/Trash``.
53
+ Probably also works with other desktop interfaces as long as they follow the Trash specification from FreeDesktop.
54
+
55
+ Currently does not parse media trash locations such as ``/media/$Label/.Trash-1000/*``.
56
+
57
+ Resources:
58
+ - https://specifications.freedesktop.org/trash-spec/latest/
59
+ - https://github.com/GNOME/glib/blob/main/gio/glocalfile.c
60
+ - https://specifications.freedesktop.org/basedir-spec/latest/
61
+
62
+ Yields ``TrashRecord``s with the following fields:
63
+
64
+ .. code-block:: text
65
+
66
+ ts (datetime): timestamp when the file was deleted or for expunged files when it could not be permanently deleted
67
+ path (path): path where the file was located before it was deleted
68
+ filesize (filesize): size in bytes of the deleted file
69
+ deleted_path (path): path to the current location of the deleted file
70
+ source (path): path to the .trashinfo file
71
+ """ # noqa: E501
72
+
73
+ for user_details, trash in self.trashes:
74
+ for trash_info_file in trash.glob("info/*.trashinfo"):
75
+ trash_info = configutil.parse(trash_info_file, hint="ini").get("Trash Info", {})
76
+ original_path = self.target.fs.path(trash_info.get("Path", ""))
77
+
78
+ # We use the basename of the .trashinfo file and not the Path variable inside the
79
+ # ini file. This way we can keep duplicate basenames of trashed files separated correctly.
80
+ deleted_path = trash / "files" / trash_info_file.name.replace(".trashinfo", "")
81
+
82
+ if deleted_path.exists():
83
+ deleted_files = [deleted_path]
84
+
85
+ if deleted_path.is_dir():
86
+ for child in deleted_path.rglob("*"):
87
+ deleted_files.append(child)
88
+
89
+ for file in deleted_files:
90
+ # NOTE: We currently do not 'fix' the original_path of files inside deleted directories.
91
+ # This would require guessing where the parent folder starts, which is impossible without
92
+ # making assumptions.
93
+ yield TrashRecord(
94
+ ts=trash_info.get("DeletionDate", 0),
95
+ path=original_path,
96
+ filesize=file.lstat().st_size if file.is_file() else None,
97
+ deleted_path=file,
98
+ source=trash_info_file,
99
+ _user=user_details.user,
100
+ _target=self.target,
101
+ )
102
+
103
+ # We cannot determine if the deleted entry is a directory since the path does
104
+ # not exist at $TRASH/files, so we work with what we have instead.
105
+ else:
106
+ self.target.log.warning(f"Expected trashed file(s) at {deleted_path}")
107
+ yield TrashRecord(
108
+ ts=trash_info.get("DeletionDate", 0),
109
+ path=original_path,
110
+ filesize=0,
111
+ deleted_path=deleted_path,
112
+ source=trash_info_file,
113
+ _user=user_details.user,
114
+ _target=self.target,
115
+ )
116
+
117
+ # We also iterate expunged folders, they can contain files that could not be
118
+ # deleted when the user pressed the "empty trash" button in the file manager.
119
+ # Resources:
120
+ # - https://gitlab.gnome.org/GNOME/glib/-/issues/1665
121
+ # - https://bugs.launchpad.net/ubuntu/+source/nautilus/+bug/422012
122
+ for item in (trash / "expunged").rglob("*/*"):
123
+ stat = item.lstat()
124
+ yield TrashRecord(
125
+ ts=stat.st_mtime, # NOTE: This is the timestamp at which the file failed to delete
126
+ path=None, # We do not know the original file path
127
+ filesize=stat.st_size if item.is_file() else None,
128
+ deleted_path=item,
129
+ source=trash / "expunged",
130
+ _user=user_details.user,
131
+ _target=self.target,
132
+ )
@@ -90,6 +90,10 @@ def generate_argparse_for_unbound_method(
90
90
  raise ValueError(f"Value `{method}` is not an unbound plugin method")
91
91
 
92
92
  desc = method.__doc__ or docs.get_func_description(method, with_docstrings=True)
93
+
94
+ if "\n" in desc:
95
+ desc = inspect.cleandoc(desc)
96
+
93
97
  help_formatter = argparse.RawDescriptionHelpFormatter
94
98
  parser = argparse.ArgumentParser(description=desc, formatter_class=help_formatter, conflict_handler="resolve")
95
99
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.20.dev10
3
+ Version: 3.20.dev12
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
@@ -198,6 +198,7 @@ dissect/target/plugins/os/unix/history.py,sha256=rvRlcHw3wEtgdyfjX-RBLQUQAd0uHzf
198
198
  dissect/target/plugins/os/unix/locale.py,sha256=XOcKBwfK3YJ266eBFKNc1xaZgY8QEQGJOS8PJRJt4ME,4292
199
199
  dissect/target/plugins/os/unix/packagemanager.py,sha256=Wm2AAJOD_B3FAcZNXgWtSm_YwbvrHBYOP8bPmOXNjG4,2427
200
200
  dissect/target/plugins/os/unix/shadow.py,sha256=W6W6rMru7IVnuBc6sl5wsRWTOrJdS1s7_2_q7QRf7Is,4148
201
+ dissect/target/plugins/os/unix/trash.py,sha256=wzq9nprRKjFs9SHaENz8PMbpQMfFoLH1KW4EPWMLJdA,6099
201
202
  dissect/target/plugins/os/unix/bsd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
202
203
  dissect/target/plugins/os/unix/bsd/_os.py,sha256=e5rttTOFOmd7e2HqP9ZZFMEiPLBr-8rfH0XH1IIeroQ,1372
203
204
  dissect/target/plugins/os/unix/bsd/citrix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -258,7 +259,7 @@ dissect/target/plugins/os/unix/log/audit.py,sha256=OjorWTmCFvCI5RJq6m6WNW0Lhb-po
258
259
  dissect/target/plugins/os/unix/log/auth.py,sha256=l7gCuRdvv9gL0U1N0yrR9hVsMnr4t_k4t-n-f6PrOxg,2388
259
260
  dissect/target/plugins/os/unix/log/journal.py,sha256=auVRfrW4NRU7HguoDLTz4l_IwNdPZLPAqD7jhrOTzH8,17404
260
261
  dissect/target/plugins/os/unix/log/lastlog.py,sha256=Wq89wRSFZSBsoKVCxjDofnC4yw9XJ4iOF0XJe9EucCo,2448
261
- dissect/target/plugins/os/unix/log/messages.py,sha256=CXA-SkMPLaCgnTQg9nzII-7tO8Il_ENQmuYvDxo33rI,4698
262
+ dissect/target/plugins/os/unix/log/messages.py,sha256=O10Uw3PGTanfGpphUWYqOwOIR7XiiM-clfboVCoiP0U,4501
262
263
  dissect/target/plugins/os/unix/log/utmp.py,sha256=1nPHIaBUHt_9z6PDrvyqg4huKLihUaWLrMmgMsbaeIo,7755
263
264
  dissect/target/plugins/os/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
264
265
  dissect/target/plugins/os/windows/_os.py,sha256=-x5TD5BvFw-7zEfqT6WG7n04YSeyr7wVLO07y6xkBP8,12476
@@ -350,7 +351,7 @@ dissect/target/tools/mount.py,sha256=8GRYnu4xEmFBHxuIZAYhOMyyTGX8fat1Ou07DNiUnW4
350
351
  dissect/target/tools/query.py,sha256=e-yAN9zdQjuOiTuoOQoo17mVEQGGcOgaA9YkF4GYpkM,15394
351
352
  dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
352
353
  dissect/target/tools/shell.py,sha256=dmshIriwdd_UwrdUcTfWkcYD8Z0mjzbDqwyZG-snDdM,50482
353
- dissect/target/tools/utils.py,sha256=cGk_DxEqVL0ofxlIC15GD4w3PV5RSE_IaKvVkAxEhR8,11974
354
+ dissect/target/tools/utils.py,sha256=JJZDSso1CEK2sv4Z3HJNgqxH6G9S5lbmV-C3h-XmcMo,12035
354
355
  dissect/target/tools/yara.py,sha256=70k-2VMulf1EdkX03nCACzejaOEcsFHOyX-4E40MdQU,2044
355
356
  dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
356
357
  dissect/target/tools/dump/run.py,sha256=aD84peRS4zHqC78fH7Vd4ni3m1ZmVP70LyMwBRvoDGY,9463
@@ -364,10 +365,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
364
365
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
365
366
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
366
367
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
367
- dissect.target-3.20.dev10.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
368
- dissect.target-3.20.dev10.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
369
- dissect.target-3.20.dev10.dist-info/METADATA,sha256=5OxnXAwEsto5SeG-Tz-CR8M_5sqbSNn3Z41qo9bgFYY,12897
370
- dissect.target-3.20.dev10.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
371
- dissect.target-3.20.dev10.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
372
- dissect.target-3.20.dev10.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
373
- dissect.target-3.20.dev10.dist-info/RECORD,,
368
+ dissect.target-3.20.dev12.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
369
+ dissect.target-3.20.dev12.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
370
+ dissect.target-3.20.dev12.dist-info/METADATA,sha256=PD0L9p9grMOhAAKSl17OUW03GOBhlRdnI6qX6nyKWT0,12897
371
+ dissect.target-3.20.dev12.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
372
+ dissect.target-3.20.dev12.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
373
+ dissect.target-3.20.dev12.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
374
+ dissect.target-3.20.dev12.dist-info/RECORD,,