dissect.target 3.20.dev10__py3-none-any.whl → 3.20.dev12__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,