dissect.database 1.2.dev2__py3-none-any.whl → 1.2.dev4__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.
@@ -10,11 +10,13 @@ from typing import TYPE_CHECKING, BinaryIO
10
10
  from dissect.database.ese.c_ese import c_ese, pgnoFDPMSO, ulDAEMagic
11
11
  from dissect.database.ese.exception import InvalidDatabase
12
12
  from dissect.database.ese.page import Page
13
- from dissect.database.ese.table import Catalog, Table
13
+ from dissect.database.ese.table import Catalog
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from collections.abc import Iterator
17
17
 
18
+ from dissect.database.ese.table import Table
19
+
18
20
 
19
21
  class ESE:
20
22
  """ESE database class.
@@ -1,6 +1,7 @@
1
1
  # Based on Wine source
2
2
  # https://github.com/wine-mirror/wine/blob/master/dlls/kernelbase/locale.c
3
3
  # http://www.flounder.com/localeexplorer.htm
4
+ from __future__ import annotations
4
5
 
5
6
  from enum import IntEnum, IntFlag
6
7
 
@@ -1,14 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, BinaryIO
4
+ from uuid import UUID
4
5
 
5
6
  from dissect.database.ese.ntds.database import Database
7
+ from dissect.database.ese.ntds.objects.secret import BackupKey
6
8
 
7
9
  if TYPE_CHECKING:
8
10
  from collections.abc import Iterator
9
11
 
10
- from dissect.database.ese.ntds.objects import Computer, DomainDNS, Group, GroupPolicyContainer, Object, Server, User
11
- from dissect.database.ese.ntds.objects.trusteddomain import TrustedDomain
12
+ from dissect.database.ese.ntds.objects import (
13
+ Computer,
14
+ DomainDNS,
15
+ Group,
16
+ GroupPolicyContainer,
17
+ Object,
18
+ Secret,
19
+ Server,
20
+ TrustedDomain,
21
+ User,
22
+ )
12
23
  from dissect.database.ese.ntds.pek import PEK
13
24
 
14
25
 
@@ -93,3 +104,37 @@ class NTDS:
93
104
  def group_policies(self) -> Iterator[GroupPolicyContainer]:
94
105
  """Get all group policy objects (GPO) objects from the database."""
95
106
  yield from self.search(objectClass="groupPolicyContainer")
107
+
108
+ def secrets(self) -> Iterator[Secret]:
109
+ """Get all secret objects from the database."""
110
+ yield from self.search(objectClass="secret")
111
+
112
+ def backup_keys(self) -> Iterator[BackupKey]:
113
+ """Get all DPAPI backup keys from the database."""
114
+ if not self.pek.unlocked:
115
+ raise ValueError("PEK must be unlocked to retrieve backup keys")
116
+
117
+ for secret in self.secrets():
118
+ if secret.is_phantom or not secret.name.startswith("BCKUPKEY_") or secret.name.startswith("BCKUPKEY_P"):
119
+ continue
120
+
121
+ yield BackupKey(secret)
122
+
123
+ def preferred_backup_keys(self) -> Iterator[BackupKey]:
124
+ """Get preferred DPAPI backup keys from the database."""
125
+ if not self.pek.unlocked:
126
+ raise ValueError("PEK must be unlocked to retrieve backup keys")
127
+
128
+ # We could do this the proper way (lookup the BCKUPKEY_P* secrets and then directly lookup the
129
+ # corresponding BCKUPKEY_* secrets), but in practice there are only a few backup keys, so just
130
+ # filter after the fact
131
+ preferred_guids = []
132
+ for secret in self.secrets():
133
+ if secret.is_phantom or not secret.name.startswith("BCKUPKEY_P"):
134
+ continue
135
+
136
+ preferred_guids.append(UUID(bytes_le=secret.current_value))
137
+
138
+ for key in self.backup_keys():
139
+ if key.guid in preferred_guids:
140
+ yield key
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from functools import cached_property
4
4
  from typing import TYPE_CHECKING, Any, ClassVar
5
5
 
6
- from dissect.database.ese.ntds.util import DN, InstanceType, SystemFlags, decode_value
6
+ from dissect.database.ese.ntds.util import InstanceType, decode_value
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from collections.abc import Iterator
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
11
11
 
12
12
  from dissect.database.ese.ntds.database import Database
13
13
  from dissect.database.ese.ntds.sd import SecurityDescriptor
14
+ from dissect.database.ese.ntds.util import DN, SystemFlags
14
15
  from dissect.database.ese.record import Record
15
16
 
16
17
 
@@ -1,7 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from functools import cached_property
4
+ from typing import TYPE_CHECKING
5
+ from uuid import UUID
6
+
7
+ from dissect.util.ts import wintimestamp
8
+
9
+ from dissect.database.ese.ntds.c_ds import c_ds
3
10
  from dissect.database.ese.ntds.objects.leaf import Leaf
4
11
 
12
+ if TYPE_CHECKING:
13
+ from datetime import datetime
14
+
5
15
 
6
16
  class Secret(Leaf):
7
17
  """Represents a secret object in the Active Directory.
@@ -11,3 +21,79 @@ class Secret(Leaf):
11
21
  """
12
22
 
13
23
  __object_class__ = "secret"
24
+
25
+ def __repr_body__(self) -> str:
26
+ return f"name={self.name!r} last_set_time={self.last_set_time} prior_set_time={self.prior_set_time}"
27
+
28
+ @property
29
+ def current_value(self) -> bytes:
30
+ """Return the current value of the secret."""
31
+ return self.get("currentValue")
32
+
33
+ @property
34
+ def last_set_time(self) -> datetime | None:
35
+ """Return the last set time of the secret."""
36
+ if (ts := self.get("lastSetTime")) is not None:
37
+ return wintimestamp(ts)
38
+ return None
39
+
40
+ @property
41
+ def prior_value(self) -> bytes:
42
+ """Return the prior value of the secret."""
43
+ return self.get("priorValue")
44
+
45
+ @property
46
+ def prior_set_time(self) -> datetime | None:
47
+ """Return the prior set time of the secret."""
48
+ if (ts := self.get("priorSetTime")) is not None:
49
+ return wintimestamp(ts)
50
+ return None
51
+
52
+
53
+ class BackupKey:
54
+ """Represents a DPAPI backup key object in the Active Directory."""
55
+
56
+ def __init__(self, secret: Secret):
57
+ self.secret = secret
58
+
59
+ def __repr__(self) -> str:
60
+ return f"<BackupKey guid={self.guid} version={self.version}>"
61
+
62
+ @cached_property
63
+ def guid(self) -> UUID:
64
+ """The GUID of the backup key."""
65
+ return UUID(self.secret.name.removeprefix("BCKUPKEY_").removesuffix(" Secret"))
66
+
67
+ @cached_property
68
+ def version(self) -> int:
69
+ """The version of the backup key."""
70
+ return c_ds.DWORD(self.secret.current_value)
71
+
72
+ @cached_property
73
+ def is_legacy(self) -> bool:
74
+ """Whether the backup key is a legacy key (version 1)."""
75
+ return self.version == 1
76
+
77
+ @cached_property
78
+ def key(self) -> bytes:
79
+ """The key bytes of the backup key, for legacy keys (version 1)."""
80
+ if self.version == 1:
81
+ return self.secret.current_value[4:]
82
+ raise TypeError(f"Backup key version {self.version} does not have a single key value")
83
+
84
+ @cached_property
85
+ def private_key(self) -> bytes:
86
+ """The private key bytes of the backup key, for version 2 keys."""
87
+ if self.version == 2:
88
+ private_length = c_ds.DWORD(self.secret.current_value[4:8])
89
+ return self.secret.current_value[12 : 12 + private_length]
90
+ raise TypeError(f"Backup key version {self.version} does not have a private key value")
91
+
92
+ @cached_property
93
+ def public_key(self) -> bytes:
94
+ """The public key bytes of the backup key, for version 2 keys."""
95
+ if self.version == 2:
96
+ private_length = c_ds.DWORD(self.secret.current_value[4:8])
97
+ public_length = c_ds.DWORD(self.secret.current_value[8:12])
98
+ return self.secret.current_value[12 + private_length : 12 + private_length + public_length]
99
+ raise TypeError(f"Backup key version {self.version} does not have a public key value")
@@ -3,13 +3,14 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from dissect.database.ese.ntds.objects.organizationalperson import OrganizationalPerson
6
- from dissect.database.ese.ntds.util import SAMAccountType, UserAccountControl
6
+ from dissect.database.ese.ntds.util import UserAccountControl
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from collections.abc import Iterator
10
10
 
11
11
  from dissect.database.ese.ntds.objects.group import Group
12
12
  from dissect.database.ese.ntds.objects.object import Object
13
+ from dissect.database.ese.ntds.util import SAMAccountType
13
14
 
14
15
 
15
16
  class User(OrganizationalPerson):
@@ -198,7 +198,6 @@ class Schema:
198
198
  Args:
199
199
  db: The database instance to load the schema from.
200
200
  """
201
-
202
201
  # Load the schema entries from the DMD object
203
202
  # This _should_ have all the attribute and class schema entries
204
203
  # We used to perform an index search on objectClass (ATTc0, INDEX_00000000), but apparently
@@ -14,7 +14,7 @@ from dissect.database.ese.c_ese import (
14
14
  from dissect.database.ese.cursor import RawCursor
15
15
  from dissect.database.ese.index import Index
16
16
  from dissect.database.ese.record import Record
17
- from dissect.database.ese.util import COLUMN_TYPE_MAP, ColumnType, RecordValue
17
+ from dissect.database.ese.util import COLUMN_TYPE_MAP
18
18
 
19
19
  if TYPE_CHECKING:
20
20
  from collections.abc import Iterator
@@ -22,6 +22,7 @@ if TYPE_CHECKING:
22
22
  from dissect.database.ese.cursor import Cursor
23
23
  from dissect.database.ese.ese import ESE
24
24
  from dissect.database.ese.page import Page
25
+ from dissect.database.ese.util import ColumnType, RecordValue
25
26
 
26
27
 
27
28
  class Table:
@@ -9,11 +9,12 @@ from dissect.util.sid import read_sid
9
9
  from dissect.util.ts import oatimestamp, wintimestamp
10
10
 
11
11
  from dissect.database.ese.ese import ESE
12
- from dissect.database.ese.record import Record, serialise_record_column_values
12
+ from dissect.database.ese.record import serialise_record_column_values
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from collections.abc import Iterator
16
16
 
17
+ from dissect.database.ese.record import Record
17
18
  from dissect.database.ese.table import Table
18
19
  from dissect.database.ese.util import RecordValue
19
20
 
@@ -1,17 +1,22 @@
1
+ from __future__ import annotations
2
+
1
3
  import argparse
2
4
  import datetime
3
5
  import ipaddress
4
6
  import json
5
- from collections.abc import Iterator
6
7
  from pathlib import Path
7
- from typing import BinaryIO
8
+ from typing import TYPE_CHECKING, BinaryIO
8
9
 
9
10
  from dissect.util.ts import wintimestamp
10
11
 
11
12
  from dissect.database.ese.ese import ESE
12
- from dissect.database.ese.table import Table
13
13
  from dissect.database.ese.util import RecordValue
14
14
 
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Iterator
17
+
18
+ from dissect.database.ese.table import Table
19
+
15
20
  UalValue = RecordValue | ipaddress.IPv4Address | ipaddress.IPv6Interface | tuple[datetime.datetime]
16
21
 
17
22
  SKIP_TABLES = [
@@ -178,7 +178,6 @@ class SQLCipherStream(AlignedStream):
178
178
 
179
179
  def _read(self, offset: int, length: int) -> bytes:
180
180
  """Calculates which pages to read from based on the given offset and length. Returns decrypted bytes."""
181
-
182
181
  start_page = offset // self.align
183
182
  num_pages = length // self.align
184
183
  return b"".join(
@@ -191,7 +190,6 @@ class SQLCipherStream(AlignedStream):
191
190
  References:
192
191
  - https://github.com/sqlcipher/sqlcipher-tools/blob/master/decrypt.c
193
192
  """
194
-
195
193
  if page_num < 1:
196
194
  raise ValueError("The first page number is 1")
197
195
 
@@ -294,7 +292,6 @@ class SQLCipher1(SQLCipher):
294
292
 
295
293
  def derive_key(passphrase: bytes, salt: bytes, kdf_iter: int, kdf_algo: str | None) -> bytes:
296
294
  """Derive the database key as SQLCipher would using PBKDF2."""
297
-
298
295
  if not kdf_iter or not kdf_algo:
299
296
  return passphrase
300
297
 
@@ -15,7 +15,7 @@ from dissect.database.sqlite3.exception import (
15
15
  NoCellData,
16
16
  )
17
17
  from dissect.database.sqlite3.util import parse_table_columns_constraints
18
- from dissect.database.sqlite3.wal import WAL, Checkpoint
18
+ from dissect.database.sqlite3.wal import WAL
19
19
 
20
20
  if TYPE_CHECKING:
21
21
  from collections.abc import Iterator
@@ -23,6 +23,8 @@ if TYPE_CHECKING:
23
23
 
24
24
  from typing_extensions import Self
25
25
 
26
+ from dissect.database.sqlite3.wal import Checkpoint
27
+
26
28
  ENCODING = {
27
29
  1: "utf-8",
28
30
  2: "utf-16-le",
@@ -259,7 +261,7 @@ class Column:
259
261
  self.default_value = self._parse_default_value_from_description(description)
260
262
 
261
263
  def _parse_default_value_from_description(self, description: str) -> bool | str | int | float | None:
262
- """Find the default from the description string"""
264
+ """Find the default from the description string."""
263
265
  if "DEFAULT" not in description.upper():
264
266
  return None
265
267
 
@@ -275,14 +277,13 @@ class Column:
275
277
  return [x for x in tokens if x and x != " "]
276
278
 
277
279
  def _get_default_value(self, tokens: list[str]) -> str:
278
- """Retrieve the default from the tokens"""
279
-
280
+ """Retrieve the default from the tokens."""
280
281
  # The +1 is to account for the space after the default
281
282
  value_index = [x.upper() for x in tokens].index("DEFAULT") + 1
282
283
  return tokens[value_index]
283
284
 
284
285
  def _parse_default_value(self, value: str) -> bool | str | int | float | None:
285
- """Parses the default value
286
+ """Parses the default value.
286
287
 
287
288
  The value can hold an expression surrounded by ().
288
289
  This can be a literal, so these values get stripped.
@@ -293,7 +294,7 @@ class Column:
293
294
  return None
294
295
 
295
296
  def _parse_literal(self, value: str) -> bool | str | int | float:
296
- """Tries to convert a literal from a string to any type
297
+ """Tries to convert a literal from a string to any type.
297
298
 
298
299
  CURRENT_(TIME|DATE|TIMESTAMP) isn't being taken into account.
299
300
  """
@@ -385,7 +386,6 @@ class Row:
385
386
  If there are any cell values with unknown column names
386
387
  they get added to the unknown list.
387
388
  """
388
-
389
389
  row_values = {}
390
390
  unknowns = []
391
391
 
@@ -109,7 +109,6 @@ def parse_table_columns_constraints(sql: str) -> tuple[str | None, list[str], li
109
109
 
110
110
  def split_column_def(sql: str, column_def: str) -> tuple[str, str]:
111
111
  """Splits the column definition to name and constraint."""
112
-
113
112
  column_parts = column_def.split(maxsplit=1)
114
113
  if not column_parts:
115
114
  raise InvalidSQL(f"Not a valid CREATE TABLE definition: empty column definition in {sql!r}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dissect.database
3
- Version: 1.2.dev2
3
+ Version: 1.2.dev4
4
4
  Summary: A Dissect module implementing parsers for various database formats, including Berkeley DB, Microsofts Extensible Storage Engine (ESE) and SQLite3
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License-Expression: Apache-2.0
@@ -13,14 +13,14 @@ dissect/database/ese/c_ese.py,sha256=kcn2GHTQ_fijY1CEX4gtNAUeTvu5feR-ya4C2_BzTpk
13
13
  dissect/database/ese/c_ese.pyi,sha256=v-h3If5kUxS8HN8G23m6AHbIQUoGHQ2XZih4zurxWTM,18874
14
14
  dissect/database/ese/compression.py,sha256=lLrriyvVjUuDEibUl_ECYVfvqmeU9ijKIaBnx38m98Q,2027
15
15
  dissect/database/ese/cursor.py,sha256=ju-mUewhW22bVW0MMdsaKolKCiKnztRcyU0nJw5bNOg,14346
16
- dissect/database/ese/ese.py,sha256=cFW2KYXoZ6ca6S-XzziwHEjXN22aP9VWtG2EaIgssFI,3500
16
+ dissect/database/ese/ese.py,sha256=CAObzKZSbMR47Lub8Fh6u9aG-MZqTSaX-m4S2UWrhX4,3543
17
17
  dissect/database/ese/exception.py,sha256=09xbltclWIBsGbk8Ry8RlKG-OwGSQvyLKsgj0d98T0k,210
18
18
  dissect/database/ese/index.py,sha256=dYngAWmmX7X8lkP2_q3vgBm1woXYfwtTIOsWORmM2Q0,9859
19
- dissect/database/ese/lcmapstring.py,sha256=ni_S4xXGCsJg9AIRVTyVWK0JoZbVzL8ocZ1eacnl9cQ,7004
19
+ dissect/database/ese/lcmapstring.py,sha256=sI0jnSHnuCYwXS3YqBruGixlHXm44L3au5llR2Ash4s,7039
20
20
  dissect/database/ese/page.py,sha256=TbR_pGBKCaYag1SBAYtcQp8EnGOw3QRp3tLMNeuVdCM,8325
21
21
  dissect/database/ese/record.py,sha256=DKBwkyuszsuUaBgu3iD41cidmw4GEpaoNNKPhI0Tnxg,19723
22
22
  dissect/database/ese/sorting_table.py,sha256=NsBchm4-XxyDKZrdt2M_wMuGELUQed5osKbv1RxmIbk,819383
23
- dissect/database/ese/table.py,sha256=kIgUp2VuUOO_irmpGpP9uepgYdmoL2agfeClnYNpk0Q,13311
23
+ dissect/database/ese/table.py,sha256=BpaI2WHXvXnoe46bumkZn5_HyGqtl0jAnyinrqo81zA,13352
24
24
  dissect/database/ese/util.py,sha256=5ZWurLGHahG4LL4iXpYCK9kbMLr53dVh18f1Ox9YHlA,3044
25
25
  dissect/database/ese/ntds/__init__.py,sha256=Fu6_i_7fAlDfJoOgbpsVlPxM4CXpDCNtXmgzNzkmesY,264
26
26
  dissect/database/ese/ntds/c_ds.py,sha256=ZaWdEcpJPJrRjiJFhi1s5KlOIVj0yoix4XAh-D31uLU,3055
@@ -30,10 +30,10 @@ dissect/database/ese/ntds/c_pek.pyi,sha256=lHfhvHWABT1vLmknu66phOXsylgwzGIWVdbqD
30
30
  dissect/database/ese/ntds/c_sd.py,sha256=DYICZsWCBzj0OtvhO6vhzzVjK9YP6tzBCsgKgr0pc-k,4294
31
31
  dissect/database/ese/ntds/c_sd.pyi,sha256=7717Y0EBVu37Liu26rqsDWkLIdSCqWn9KK9svtniLqY,5279
32
32
  dissect/database/ese/ntds/database.py,sha256=rKHdbQObLp9vSV2gquGZ_RBnIY5Y-2hACIe_atTvxbY,16189
33
- dissect/database/ese/ntds/ntds.py,sha256=UKJnfHrnqEoHnO_HS-ircUtjkjpO9vmLmLjRMW9u6Tk,3548
33
+ dissect/database/ese/ntds/ntds.py,sha256=qvyDsjHs1WyGbDccOtO5XXcvlKH6rkMnaW6KRxd9264,5080
34
34
  dissect/database/ese/ntds/pek.py,sha256=BEmxO175T8QkGVvFQLN9MI9uDCcK4jztuZetbwbbYqU,4154
35
35
  dissect/database/ese/ntds/query.py,sha256=orTuXH5jXYUVUVL6PtD9rOcdfCKHjOS-D8RzUMEl0sk,7972
36
- dissect/database/ese/ntds/schema.py,sha256=EbJYKvixpw7rUZgUxxNFjCvzYLufkwNVVGWI-qSGT1A,16660
36
+ dissect/database/ese/ntds/schema.py,sha256=1M0t5qDAcDOdY4MzAE5cLz4klDCTxrxa0Z9hIDFUCvw,16659
37
37
  dissect/database/ese/ntds/sd.py,sha256=Y-oYnJPcLMDB_4X8TLEGtt-n_nC4HLA0WqIS8qYAwAs,5995
38
38
  dissect/database/ese/ntds/util.py,sha256=mx_b-_mIINR1Mn01rH7bR4CeY0gl0gnkD2gjeMeiAU8,18348
39
39
  dissect/database/ese/ntds/objects/__init__.py,sha256=3lI4f0SwILAY4zJRDVtJpe9YaxKspR-1kHXnhpw91e4,10739
@@ -115,7 +115,7 @@ dissect/database/ese/ntds/objects/ntdsdsa.py,sha256=HJRbkL8vGeM0sjADYzxsUcfKCram
115
115
  dissect/database/ese/ntds/objects/ntdsservice.py,sha256=mTdpd2tzm8OOiGm6rJN35_dyeWtvzPYI_rVDBZz0gNc,326
116
116
  dissect/database/ese/ntds/objects/ntdssitesettings.py,sha256=VNlke-Vgxjh0fzd5o2X-4fwCBrkEI1coR4oto5OenPo,709
117
117
  dissect/database/ese/ntds/objects/ntfrssettings.py,sha256=PwIKT6t_zRxfdacWuvzMfq_mIhj_wyIhHzORNcF2eOU,745
118
- dissect/database/ese/ntds/objects/object.py,sha256=aZ9HpARfPS9q4yP2uU96HYJPIkfGzehjFsGAkpZeBIQ,9951
118
+ dissect/database/ese/ntds/objects/object.py,sha256=MQpHca7ev0oGsEC03DYbGptJUoVNK9sDIMBmUDjrDms,9997
119
119
  dissect/database/ese/ntds/objects/organizationalperson.py,sha256=X4QHT9AeGU7mDtIPlZbkhs1v2ZCPEarehFyn5EFszdY,559
120
120
  dissect/database/ese/ntds/objects/organizationalunit.py,sha256=H_VHrUgN92cXgGoV3ngiV4HjSaDndSUkQSjcNmb7WFs,715
121
121
  dissect/database/ese/ntds/objects/person.py,sha256=s67VHtsyN5t8icU9adPTLGcrIMH14yrEY1VqUqSw3Do,304
@@ -128,7 +128,7 @@ dissect/database/ese/ntds/objects/ridset.py,sha256=xpmfNsqKwSIL4D9bNvaOokbz-95bc
128
128
  dissect/database/ese/ntds/objects/rpccontainer.py,sha256=DWbV0h3te72VhxZHPX3kk52u0omOUwUzzjy0Q1th4sY,311
129
129
  dissect/database/ese/ntds/objects/rrasadministrationdictionary.py,sha256=dzS3xagmCx612jk5hg4YggJRPkpSYw85Z2Vhn0F1N10,390
130
130
  dissect/database/ese/ntds/objects/samserver.py,sha256=q32pI-Pjd1TOQle_LuR53rjZlDjCY2U2aAYCWjLEaDg,348
131
- dissect/database/ese/ntds/objects/secret.py,sha256=sQtKTPHHiGgaKnugdlkDzhRfISUePkOoPrd-AeQ2FFs,307
131
+ dissect/database/ese/ntds/objects/secret.py,sha256=0278o0wpy3n5JmhYKFpNDy1MgNcHBbjX0aUYXxeCUlQ,3392
132
132
  dissect/database/ese/ntds/objects/securityobject.py,sha256=hR0a0wjyrLFtSMtRZOwPCYXpfuOCtNMhozK4bkzly-A,330
133
133
  dissect/database/ese/ntds/objects/server.py,sha256=oCbwfzW7TQm3nSWD4KuWVzhOYnZXFyq6NZ2KuVB2-Wc,652
134
134
  dissect/database/ese/ntds/objects/serverscontainer.py,sha256=NnJ0M23RO-hsKd2vWcvViOMRV8psGJkwiaRC-ghmrk0,345
@@ -139,29 +139,29 @@ dissect/database/ese/ntds/objects/subnetcontainer.py,sha256=IEwSBFxoPXBIKuH-V7rK
139
139
  dissect/database/ese/ntds/objects/subschema.py,sha256=-vE76P_Yhj-Ny6ZAYnTTPMS0dtLNFZRUgyh9IXIm5Po,317
140
140
  dissect/database/ese/ntds/objects/top.py,sha256=1oPtivWGki1lfElWMs57zZ05g6dbWSa77A77ytf7hWs,527
141
141
  dissect/database/ese/ntds/objects/trusteddomain.py,sha256=J-besYk7tF3vxbJC3PogDk3iduBp_86A2SHA0LJQFb8,336
142
- dissect/database/ese/ntds/objects/user.py,sha256=RVpOJs4qxCd9x_T9PclZu6P4Yv-XS0n7ETehXsoS8po,2569
142
+ dissect/database/ese/ntds/objects/user.py,sha256=wuCViCevxboNXdkojQuKzaqWYnEz7k7Y017LisdAFOQ,2615
143
143
  dissect/database/ese/ntds/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
144
  dissect/database/ese/ntds/tools/ntds.py,sha256=6hgpoSr-QKgbz8ABkYsM-MZf6kkH_nlJbz_BCqbrGzE,861
145
145
  dissect/database/ese/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  dissect/database/ese/tools/certlog.py,sha256=7ZHq9b1_WLzUtgZf9XIoIc-9Jogx_VAoY1ha1FL696Q,5918
147
147
  dissect/database/ese/tools/impacket.py,sha256=SfMJoq7EcA8DxjD3zyNin0at9_jSlgzAQFgcywBTVZ4,2354
148
- dissect/database/ese/tools/sru.py,sha256=gp21wajecjZY3-jFHXoBKrQA_j46uCW5jc_Ube97ln4,6247
149
- dissect/database/ese/tools/ual.py,sha256=2KyVTC4wvqsNUGrJ3GCZGOMgMksw0nL7oB3aHyIv_FY,3310
148
+ dissect/database/ese/tools/sru.py,sha256=qWhYoTuEL7Rzj427PcyvbqAn8uhpaEPnW6TJeJTVoh4,6290
149
+ dissect/database/ese/tools/ual.py,sha256=YHI4hJjtCP9OugSe6DkTz7zWibPKZkUMBPei4eKzvEs,3389
150
150
  dissect/database/sqlite3/__init__.py,sha256=LIQQsLcZUMHAGzt_6rPDd1HSDXA6qcFyyvpufqdQLQA,492
151
151
  dissect/database/sqlite3/c_sqlite3.py,sha256=rFUlUi0ZfUq4kKEyOLB6-E9SxWwIU4I8-pMCNTdR7l0,1883
152
152
  dissect/database/sqlite3/c_sqlite3.pyi,sha256=49_sw1wNaNF3aqSRS_13SAk0i-9X6Eis1szb9oN7Wsk,5699
153
153
  dissect/database/sqlite3/exception.py,sha256=xYdpjNV8i5KsjliEveB7gcg3DRJlSYCYhK3kOuN2wtE,319
154
- dissect/database/sqlite3/sqlite3.py,sha256=_KqVVgKUN-tyQ3QpYJtvZEBVjNQgFvCNt-0qIMWgwB0,21970
155
- dissect/database/sqlite3/util.py,sha256=rWS1qgfqbiynUkxs81SHZT6HtOrgJpbROOAgZR095S0,5009
154
+ dissect/database/sqlite3/sqlite3.py,sha256=M3dhEMWlg2W8elzw9IZR1BJWD2cM9Q7GAT9VteZ2-po,22017
155
+ dissect/database/sqlite3/util.py,sha256=Xif-MfjReWZSsOzMC_2KI-4a0iVVTwmF_eObdIoEBHM,5008
156
156
  dissect/database/sqlite3/wal.py,sha256=HilseiVoKauqiDQ00wpcOFKB69YMNFzXS9Va9dDRMj0,6227
157
157
  dissect/database/sqlite3/encryption/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR6AOPSOoT8WBhpFbSsE,238
158
158
  dissect/database/sqlite3/encryption/sqlcipher/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR6AOPSOoT8WBhpFbSsE,238
159
159
  dissect/database/sqlite3/encryption/sqlcipher/exception.py,sha256=GKNtzcnAKlWkvjLluruA8LfzCwjRRWubibbH8WM9l2o,121
160
- dissect/database/sqlite3/encryption/sqlcipher/sqlcipher.py,sha256=YK6pTzbRl_c7ura5nY_vUAdM28s7KhNj6LMxCR-AkAY,11220
161
- dissect_database-1.2.dev2.dist-info/licenses/COPYRIGHT,sha256=pFH-OBYz6Xj23UB0Odz5IhoTR8nsTbJQNlCRV_wMaiE,317
162
- dissect_database-1.2.dev2.dist-info/licenses/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
163
- dissect_database-1.2.dev2.dist-info/METADATA,sha256=tv1ywwLkuTmIaWFVJCymTIPYDDeUe7AqXi_H-LjFW5k,5540
164
- dissect_database-1.2.dev2.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
165
- dissect_database-1.2.dev2.dist-info/entry_points.txt,sha256=ZVVKj3Nzjkgm1kBXGWyGNVUJzTbmVgivv9lgFcuLkpk,343
166
- dissect_database-1.2.dev2.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
167
- dissect_database-1.2.dev2.dist-info/RECORD,,
160
+ dissect/database/sqlite3/encryption/sqlcipher/sqlcipher.py,sha256=y_oJRKZqoJBeOQaBbniesZKm1sVTFvXZ466rJYZj2xE,11217
161
+ dissect_database-1.2.dev4.dist-info/licenses/COPYRIGHT,sha256=pFH-OBYz6Xj23UB0Odz5IhoTR8nsTbJQNlCRV_wMaiE,317
162
+ dissect_database-1.2.dev4.dist-info/licenses/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
163
+ dissect_database-1.2.dev4.dist-info/METADATA,sha256=6voYg3J9Spss_LphuTB00X7TrRUnZl2xkMA_GKlP0Uk,5540
164
+ dissect_database-1.2.dev4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
165
+ dissect_database-1.2.dev4.dist-info/entry_points.txt,sha256=ZVVKj3Nzjkgm1kBXGWyGNVUJzTbmVgivv9lgFcuLkpk,343
166
+ dissect_database-1.2.dev4.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
167
+ dissect_database-1.2.dev4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5