parsek-cdp 0.1.0__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.
Files changed (242) hide show
  1. parsek_cdp/__init__.py +55 -0
  2. parsek_cdp/_logging.py +49 -0
  3. parsek_cdp/cdp/__init__.py +247 -0
  4. parsek_cdp/cdp/accessibility/__init__.py +15 -0
  5. parsek_cdp/cdp/accessibility/events.py +35 -0
  6. parsek_cdp/cdp/accessibility/functions.py +202 -0
  7. parsek_cdp/cdp/accessibility/types.py +235 -0
  8. parsek_cdp/cdp/animation/__init__.py +15 -0
  9. parsek_cdp/cdp/animation/events.py +52 -0
  10. parsek_cdp/cdp/animation/functions.py +140 -0
  11. parsek_cdp/cdp/animation/types.py +113 -0
  12. parsek_cdp/cdp/audits/__init__.py +15 -0
  13. parsek_cdp/cdp/audits/events.py +21 -0
  14. parsek_cdp/cdp/audits/functions.py +95 -0
  15. parsek_cdp/cdp/audits/types.py +1051 -0
  16. parsek_cdp/cdp/autofill/__init__.py +15 -0
  17. parsek_cdp/cdp/autofill/events.py +27 -0
  18. parsek_cdp/cdp/autofill/functions.py +64 -0
  19. parsek_cdp/cdp/autofill/types.py +108 -0
  20. parsek_cdp/cdp/backgroundservice/__init__.py +15 -0
  21. parsek_cdp/cdp/backgroundservice/events.py +40 -0
  22. parsek_cdp/cdp/backgroundservice/functions.py +59 -0
  23. parsek_cdp/cdp/backgroundservice/types.py +63 -0
  24. parsek_cdp/cdp/bluetoothemulation/__init__.py +15 -0
  25. parsek_cdp/cdp/bluetoothemulation/events.py +70 -0
  26. parsek_cdp/cdp/bluetoothemulation/functions.py +247 -0
  27. parsek_cdp/cdp/bluetoothemulation/types.py +120 -0
  28. parsek_cdp/cdp/browser/__init__.py +15 -0
  29. parsek_cdp/cdp/browser/events.py +46 -0
  30. parsek_cdp/cdp/browser/functions.py +350 -0
  31. parsek_cdp/cdp/browser/types.py +158 -0
  32. parsek_cdp/cdp/cachestorage/__init__.py +15 -0
  33. parsek_cdp/cdp/cachestorage/events.py +13 -0
  34. parsek_cdp/cdp/cachestorage/functions.py +126 -0
  35. parsek_cdp/cdp/cachestorage/types.py +89 -0
  36. parsek_cdp/cdp/cast/__init__.py +15 -0
  37. parsek_cdp/cdp/cast/events.py +38 -0
  38. parsek_cdp/cdp/cast/functions.py +77 -0
  39. parsek_cdp/cdp/cast/types.py +23 -0
  40. parsek_cdp/cdp/console/__init__.py +15 -0
  41. parsek_cdp/cdp/console/events.py +22 -0
  42. parsek_cdp/cdp/console/functions.py +36 -0
  43. parsek_cdp/cdp/console/types.py +30 -0
  44. parsek_cdp/cdp/css/__init__.py +15 -0
  45. parsek_cdp/cdp/css/events.py +79 -0
  46. parsek_cdp/cdp/css/functions.py +788 -0
  47. parsek_cdp/cdp/css/types.py +742 -0
  48. parsek_cdp/cdp/debugger/__init__.py +15 -0
  49. parsek_cdp/cdp/debugger/events.py +164 -0
  50. parsek_cdp/cdp/debugger/functions.py +663 -0
  51. parsek_cdp/cdp/debugger/types.py +171 -0
  52. parsek_cdp/cdp/deviceaccess/__init__.py +15 -0
  53. parsek_cdp/cdp/deviceaccess/events.py +30 -0
  54. parsek_cdp/cdp/deviceaccess/functions.py +54 -0
  55. parsek_cdp/cdp/deviceaccess/types.py +28 -0
  56. parsek_cdp/cdp/deviceorientation/__init__.py +15 -0
  57. parsek_cdp/cdp/deviceorientation/events.py +13 -0
  58. parsek_cdp/cdp/deviceorientation/functions.py +35 -0
  59. parsek_cdp/cdp/deviceorientation/types.py +10 -0
  60. parsek_cdp/cdp/dom/__init__.py +15 -0
  61. parsek_cdp/cdp/dom/events.py +228 -0
  62. parsek_cdp/cdp/dom/functions.py +1033 -0
  63. parsek_cdp/cdp/dom/types.py +293 -0
  64. parsek_cdp/cdp/domdebugger/__init__.py +15 -0
  65. parsek_cdp/cdp/domdebugger/events.py +13 -0
  66. parsek_cdp/cdp/domdebugger/functions.py +155 -0
  67. parsek_cdp/cdp/domdebugger/types.py +57 -0
  68. parsek_cdp/cdp/domsnapshot/__init__.py +15 -0
  69. parsek_cdp/cdp/domsnapshot/events.py +13 -0
  70. parsek_cdp/cdp/domsnapshot/functions.py +111 -0
  71. parsek_cdp/cdp/domsnapshot/types.py +312 -0
  72. parsek_cdp/cdp/domstorage/__init__.py +15 -0
  73. parsek_cdp/cdp/domstorage/events.py +60 -0
  74. parsek_cdp/cdp/domstorage/functions.py +79 -0
  75. parsek_cdp/cdp/domstorage/types.py +30 -0
  76. parsek_cdp/cdp/emulation/__init__.py +15 -0
  77. parsek_cdp/cdp/emulation/events.py +17 -0
  78. parsek_cdp/cdp/emulation/functions.py +688 -0
  79. parsek_cdp/cdp/emulation/types.py +305 -0
  80. parsek_cdp/cdp/eventbreakpoints/__init__.py +15 -0
  81. parsek_cdp/cdp/eventbreakpoints/events.py +13 -0
  82. parsek_cdp/cdp/eventbreakpoints/functions.py +41 -0
  83. parsek_cdp/cdp/eventbreakpoints/types.py +10 -0
  84. parsek_cdp/cdp/extensions/__init__.py +15 -0
  85. parsek_cdp/cdp/extensions/events.py +13 -0
  86. parsek_cdp/cdp/extensions/functions.py +118 -0
  87. parsek_cdp/cdp/extensions/types.py +19 -0
  88. parsek_cdp/cdp/fedcm/__init__.py +15 -0
  89. parsek_cdp/cdp/fedcm/events.py +45 -0
  90. parsek_cdp/cdp/fedcm/functions.py +93 -0
  91. parsek_cdp/cdp/fedcm/types.py +72 -0
  92. parsek_cdp/cdp/fetch/__init__.py +15 -0
  93. parsek_cdp/cdp/fetch/events.py +82 -0
  94. parsek_cdp/cdp/fetch/functions.py +215 -0
  95. parsek_cdp/cdp/fetch/types.py +81 -0
  96. parsek_cdp/cdp/filesystem/__init__.py +15 -0
  97. parsek_cdp/cdp/filesystem/events.py +13 -0
  98. parsek_cdp/cdp/filesystem/functions.py +36 -0
  99. parsek_cdp/cdp/filesystem/types.py +54 -0
  100. parsek_cdp/cdp/headlessexperimental/__init__.py +15 -0
  101. parsek_cdp/cdp/headlessexperimental/events.py +13 -0
  102. parsek_cdp/cdp/headlessexperimental/functions.py +77 -0
  103. parsek_cdp/cdp/headlessexperimental/types.py +24 -0
  104. parsek_cdp/cdp/heapprofiler/__init__.py +15 -0
  105. parsek_cdp/cdp/heapprofiler/events.py +65 -0
  106. parsek_cdp/cdp/heapprofiler/functions.py +193 -0
  107. parsek_cdp/cdp/heapprofiler/types.py +57 -0
  108. parsek_cdp/cdp/indexeddb/__init__.py +15 -0
  109. parsek_cdp/cdp/indexeddb/events.py +13 -0
  110. parsek_cdp/cdp/indexeddb/functions.py +232 -0
  111. parsek_cdp/cdp/indexeddb/types.py +120 -0
  112. parsek_cdp/cdp/input/__init__.py +15 -0
  113. parsek_cdp/cdp/input/events.py +25 -0
  114. parsek_cdp/cdp/input/functions.py +361 -0
  115. parsek_cdp/cdp/input/types.py +87 -0
  116. parsek_cdp/cdp/inspector/__init__.py +15 -0
  117. parsek_cdp/cdp/inspector/events.py +41 -0
  118. parsek_cdp/cdp/inspector/functions.py +27 -0
  119. parsek_cdp/cdp/inspector/types.py +10 -0
  120. parsek_cdp/cdp/io/__init__.py +15 -0
  121. parsek_cdp/cdp/io/events.py +13 -0
  122. parsek_cdp/cdp/io/functions.py +77 -0
  123. parsek_cdp/cdp/io/types.py +13 -0
  124. parsek_cdp/cdp/layertree/__init__.py +15 -0
  125. parsek_cdp/cdp/layertree/events.py +36 -0
  126. parsek_cdp/cdp/layertree/functions.py +178 -0
  127. parsek_cdp/cdp/layertree/types.py +104 -0
  128. parsek_cdp/cdp/log/__init__.py +15 -0
  129. parsek_cdp/cdp/log/events.py +22 -0
  130. parsek_cdp/cdp/log/functions.py +54 -0
  131. parsek_cdp/cdp/log/types.py +57 -0
  132. parsek_cdp/cdp/media/__init__.py +15 -0
  133. parsek_cdp/cdp/media/events.py +87 -0
  134. parsek_cdp/cdp/media/functions.py +27 -0
  135. parsek_cdp/cdp/media/types.py +101 -0
  136. parsek_cdp/cdp/memory/__init__.py +15 -0
  137. parsek_cdp/cdp/memory/events.py +13 -0
  138. parsek_cdp/cdp/memory/functions.py +164 -0
  139. parsek_cdp/cdp/memory/types.py +71 -0
  140. parsek_cdp/cdp/mixins/__init__.py +21 -0
  141. parsek_cdp/cdp/mixins/datatype.py +123 -0
  142. parsek_cdp/cdp/mixins/event.py +78 -0
  143. parsek_cdp/cdp/mixins/namespace.py +31 -0
  144. parsek_cdp/cdp/network/__init__.py +15 -0
  145. parsek_cdp/cdp/network/events.py +726 -0
  146. parsek_cdp/cdp/network/functions.py +734 -0
  147. parsek_cdp/cdp/network/types.py +1247 -0
  148. parsek_cdp/cdp/overlay/__init__.py +15 -0
  149. parsek_cdp/cdp/overlay/events.py +54 -0
  150. parsek_cdp/cdp/overlay/functions.py +407 -0
  151. parsek_cdp/cdp/overlay/types.py +328 -0
  152. parsek_cdp/cdp/page/__init__.py +15 -0
  153. parsek_cdp/cdp/page/events.py +416 -0
  154. parsek_cdp/cdp/page/functions.py +1081 -0
  155. parsek_cdp/cdp/page/types.py +1088 -0
  156. parsek_cdp/cdp/performance/__init__.py +15 -0
  157. parsek_cdp/cdp/performance/events.py +24 -0
  158. parsek_cdp/cdp/performance/functions.py +63 -0
  159. parsek_cdp/cdp/performance/types.py +22 -0
  160. parsek_cdp/cdp/performancetimeline/__init__.py +15 -0
  161. parsek_cdp/cdp/performancetimeline/events.py +22 -0
  162. parsek_cdp/cdp/performancetimeline/functions.py +30 -0
  163. parsek_cdp/cdp/performancetimeline/types.py +85 -0
  164. parsek_cdp/cdp/preload/__init__.py +15 -0
  165. parsek_cdp/cdp/preload/events.py +116 -0
  166. parsek_cdp/cdp/preload/functions.py +25 -0
  167. parsek_cdp/cdp/preload/types.py +267 -0
  168. parsek_cdp/cdp/profiler/__init__.py +15 -0
  169. parsek_cdp/cdp/profiler/events.py +64 -0
  170. parsek_cdp/cdp/profiler/functions.py +134 -0
  171. parsek_cdp/cdp/profiler/types.py +105 -0
  172. parsek_cdp/cdp/pwa/__init__.py +15 -0
  173. parsek_cdp/cdp/pwa/events.py +13 -0
  174. parsek_cdp/cdp/pwa/functions.py +196 -0
  175. parsek_cdp/cdp/pwa/types.py +45 -0
  176. parsek_cdp/cdp/runtime/__init__.py +15 -0
  177. parsek_cdp/cdp/runtime/events.py +123 -0
  178. parsek_cdp/cdp/runtime/functions.py +552 -0
  179. parsek_cdp/cdp/runtime/types.py +319 -0
  180. parsek_cdp/cdp/schema/__init__.py +15 -0
  181. parsek_cdp/cdp/schema/events.py +13 -0
  182. parsek_cdp/cdp/schema/functions.py +32 -0
  183. parsek_cdp/cdp/schema/types.py +22 -0
  184. parsek_cdp/cdp/security/__init__.py +15 -0
  185. parsek_cdp/cdp/security/events.py +64 -0
  186. parsek_cdp/cdp/security/functions.py +66 -0
  187. parsek_cdp/cdp/security/types.py +168 -0
  188. parsek_cdp/cdp/serviceworker/__init__.py +15 -0
  189. parsek_cdp/cdp/serviceworker/events.py +43 -0
  190. parsek_cdp/cdp/serviceworker/functions.py +115 -0
  191. parsek_cdp/cdp/serviceworker/types.py +95 -0
  192. parsek_cdp/cdp/storage/__init__.py +15 -0
  193. parsek_cdp/cdp/storage/events.py +288 -0
  194. parsek_cdp/cdp/storage/functions.py +571 -0
  195. parsek_cdp/cdp/storage/types.py +656 -0
  196. parsek_cdp/cdp/systeminfo/__init__.py +15 -0
  197. parsek_cdp/cdp/systeminfo/events.py +13 -0
  198. parsek_cdp/cdp/systeminfo/functions.py +75 -0
  199. parsek_cdp/cdp/systeminfo/types.py +132 -0
  200. parsek_cdp/cdp/target/__init__.py +15 -0
  201. parsek_cdp/cdp/target/events.py +109 -0
  202. parsek_cdp/cdp/target/functions.py +424 -0
  203. parsek_cdp/cdp/target/types.py +83 -0
  204. parsek_cdp/cdp/tethering/__init__.py +15 -0
  205. parsek_cdp/cdp/tethering/events.py +22 -0
  206. parsek_cdp/cdp/tethering/functions.py +35 -0
  207. parsek_cdp/cdp/tethering/types.py +10 -0
  208. parsek_cdp/cdp/tracing/__init__.py +15 -0
  209. parsek_cdp/cdp/tracing/events.py +61 -0
  210. parsek_cdp/cdp/tracing/functions.py +119 -0
  211. parsek_cdp/cdp/tracing/types.py +81 -0
  212. parsek_cdp/cdp/webaudio/__init__.py +15 -0
  213. parsek_cdp/cdp/webaudio/events.py +184 -0
  214. parsek_cdp/cdp/webaudio/functions.py +51 -0
  215. parsek_cdp/cdp/webaudio/types.py +155 -0
  216. parsek_cdp/cdp/webauthn/__init__.py +15 -0
  217. parsek_cdp/cdp/webauthn/events.py +69 -0
  218. parsek_cdp/cdp/webauthn/functions.py +214 -0
  219. parsek_cdp/cdp/webauthn/types.py +96 -0
  220. parsek_cdp/core/__init__.py +18 -0
  221. parsek_cdp/core/browser.py +240 -0
  222. parsek_cdp/core/browser_context.py +58 -0
  223. parsek_cdp/core/element.py +405 -0
  224. parsek_cdp/core/feature.py +376 -0
  225. parsek_cdp/core/frame.py +351 -0
  226. parsek_cdp/core/pagable.py +175 -0
  227. parsek_cdp/core/page.py +163 -0
  228. parsek_cdp/core/target.py +490 -0
  229. parsek_cdp/features/__init__.py +14 -0
  230. parsek_cdp/features/request_listener/__init__.py +256 -0
  231. parsek_cdp/features/request_listener/events.py +48 -0
  232. parsek_cdp/features/request_listener/types.py +235 -0
  233. parsek_cdp/generate.py +642 -0
  234. parsek_cdp/parsek/__init__.py +18 -0
  235. parsek_cdp/parsek/events.py +38 -0
  236. parsek_cdp/parsek/types.py +36 -0
  237. parsek_cdp/py.typed +0 -0
  238. parsek_cdp-0.1.0.dist-info/METADATA +277 -0
  239. parsek_cdp-0.1.0.dist-info/RECORD +242 -0
  240. parsek_cdp-0.1.0.dist-info/WHEEL +5 -0
  241. parsek_cdp-0.1.0.dist-info/licenses/LICENSE +201 -0
  242. parsek_cdp-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,15 @@
1
+ """The WebAuthn CDP domain (generated).
2
+
3
+ Importing ``WebAuthn`` from ``parsek_cdp.cdp`` gives a namespace with this
4
+ domain's events and types as attributes (``WebAuthn.SomeEvent`` /
5
+ ``WebAuthn.SomeType``); commands run on a target via ``page.cdp.WebAuthn``.
6
+ """
7
+ from . import events, functions, types
8
+ from .functions import WebAuthn
9
+ from .events import * # noqa: F401,F403 -- expose events on the namespace
10
+ from .types import * # noqa: F401,F403 -- expose types on the namespace
11
+
12
+ #: Protocol domain name (used by features that declare ``domains=(WebAuthn,)``).
13
+ DOMAIN = "WebAuthn"
14
+
15
+ __all__ = ["events", "functions", "types", "WebAuthn", "DOMAIN"]
@@ -0,0 +1,69 @@
1
+ """Events for the WebAuthn domain (generated)."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Literal, Optional
6
+
7
+ from ..mixins.datatype import FieldMeta
8
+ from ..mixins.event import Event, register_event
9
+
10
+ if TYPE_CHECKING:
11
+ from .types import (
12
+ AuthenticatorId,
13
+ Credential,
14
+ )
15
+
16
+ @register_event("WebAuthn.credentialAdded")
17
+ @dataclass
18
+ class CredentialAdded(Event):
19
+ """Triggered when a credential is added to an authenticator."""
20
+ authenticator_id: AuthenticatorId
21
+ credential: Credential
22
+ __FIELDS__: ClassVar[tuple] = (
23
+ FieldMeta('authenticator_id', 'authenticatorId', False, 'primitive'),
24
+ FieldMeta('credential', 'credential', False, 'object', ref='WebAuthn.Credential'),
25
+ )
26
+
27
+
28
+ @register_event("WebAuthn.credentialDeleted")
29
+ @dataclass
30
+ class CredentialDeleted(Event):
31
+ """
32
+ Triggered when a credential is deleted, e.g. through
33
+ PublicKeyCredential.signalUnknownCredential().
34
+ """
35
+ authenticator_id: AuthenticatorId
36
+ credential_id: str
37
+ __FIELDS__: ClassVar[tuple] = (
38
+ FieldMeta('authenticator_id', 'authenticatorId', False, 'primitive'),
39
+ FieldMeta('credential_id', 'credentialId', False, 'primitive'),
40
+ )
41
+
42
+
43
+ @register_event("WebAuthn.credentialUpdated")
44
+ @dataclass
45
+ class CredentialUpdated(Event):
46
+ """
47
+ Triggered when a credential is updated, e.g. through
48
+ PublicKeyCredential.signalCurrentUserDetails().
49
+ """
50
+ authenticator_id: AuthenticatorId
51
+ credential: Credential
52
+ __FIELDS__: ClassVar[tuple] = (
53
+ FieldMeta('authenticator_id', 'authenticatorId', False, 'primitive'),
54
+ FieldMeta('credential', 'credential', False, 'object', ref='WebAuthn.Credential'),
55
+ )
56
+
57
+
58
+ @register_event("WebAuthn.credentialAsserted")
59
+ @dataclass
60
+ class CredentialAsserted(Event):
61
+ """Triggered when a credential is used in a webauthn assertion."""
62
+ authenticator_id: AuthenticatorId
63
+ credential: Credential
64
+ __FIELDS__: ClassVar[tuple] = (
65
+ FieldMeta('authenticator_id', 'authenticatorId', False, 'primitive'),
66
+ FieldMeta('credential', 'credential', False, 'object', ref='WebAuthn.Credential'),
67
+ )
68
+
69
+ __all__ = ["CredentialAdded", "CredentialAsserted", "CredentialDeleted", "CredentialUpdated"]
@@ -0,0 +1,214 @@
1
+ """Commands for the WebAuthn domain (generated)."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Literal, Optional
6
+
7
+ from ..mixins.datatype import DataType, FieldMeta, encode
8
+
9
+ if TYPE_CHECKING:
10
+ from .types import (
11
+ AuthenticatorId,
12
+ Credential,
13
+ VirtualAuthenticatorOptions,
14
+ )
15
+
16
+ @dataclass
17
+ class AddVirtualAuthenticatorReturn(DataType):
18
+ """Return value of :meth:`WebAuthn.add_virtual_authenticator`."""
19
+ authenticator_id: AuthenticatorId
20
+ __FIELDS__: ClassVar[tuple] = (
21
+ FieldMeta('authenticator_id', 'authenticatorId', False, 'primitive'),
22
+ )
23
+
24
+
25
+ @dataclass
26
+ class GetCredentialReturn(DataType):
27
+ """Return value of :meth:`WebAuthn.get_credential`."""
28
+ credential: Credential
29
+ __FIELDS__: ClassVar[tuple] = (
30
+ FieldMeta('credential', 'credential', False, 'object', ref='WebAuthn.Credential'),
31
+ )
32
+
33
+
34
+ @dataclass
35
+ class GetCredentialsReturn(DataType):
36
+ """Return value of :meth:`WebAuthn.get_credentials`."""
37
+ credentials: List[Credential]
38
+ __FIELDS__: ClassVar[tuple] = (
39
+ FieldMeta('credentials', 'credentials', False, 'array', inner=FieldMeta('', '', False, 'object', ref='WebAuthn.Credential')),
40
+ )
41
+
42
+
43
+ class WebAuthn:
44
+ """Commands of the WebAuthn domain, bound to a target."""
45
+
46
+ def __init__(self, target: Any) -> None:
47
+ self._target = target
48
+
49
+
50
+ async def enable(self, *, enable_ui: Optional[bool] = None) -> None:
51
+ """
52
+ Enable the WebAuthn domain and start intercepting credential storage and
53
+ retrieval with a virtual authenticator.
54
+ :param enable_ui: Whether to enable the WebAuthn user interface. Enabling the UI is
55
+ recommended for debugging and demo purposes, as it is closer to the real
56
+ experience. Disabling the UI is recommended for automated testing.
57
+ Supported at the embedder's discretion if UI is available.
58
+ Defaults to false.
59
+ """
60
+ _params: Dict[str, Any] = {}
61
+ if enable_ui is not None:
62
+ _params['enableUI'] = encode(FieldMeta('', '', False, 'primitive'), enable_ui)
63
+ _result = await self._target.send('WebAuthn.enable', _params)
64
+ return None
65
+
66
+ async def disable(self) -> None:
67
+ """Disable the WebAuthn domain."""
68
+ _params: Dict[str, Any] = {}
69
+ _result = await self._target.send('WebAuthn.disable', _params)
70
+ return None
71
+
72
+ async def add_virtual_authenticator(self, *, options: VirtualAuthenticatorOptions) -> AddVirtualAuthenticatorReturn:
73
+ """
74
+ Creates and adds a virtual authenticator.
75
+ :param options:
76
+ """
77
+ _params: Dict[str, Any] = {}
78
+ _params['options'] = encode(FieldMeta('', '', False, 'object', ref='WebAuthn.VirtualAuthenticatorOptions'), options)
79
+ _result = await self._target.send('WebAuthn.addVirtualAuthenticator', _params)
80
+ return AddVirtualAuthenticatorReturn.from_json(_result)
81
+
82
+ async def set_response_override_bits(self, *, authenticator_id: AuthenticatorId, is_bogus_signature: Optional[bool] = None, is_bad_uv: Optional[bool] = None, is_bad_up: Optional[bool] = None) -> None:
83
+ """
84
+ Resets parameters isBogusSignature, isBadUV, isBadUP to false if they are not present.
85
+ :param authenticator_id:
86
+ :param is_bogus_signature: If isBogusSignature is set, overrides the signature in the authenticator response to be zero.
87
+ Defaults to false.
88
+ :param is_bad_uv: If isBadUV is set, overrides the UV bit in the flags in the authenticator response to
89
+ be zero. Defaults to false.
90
+ :param is_bad_up: If isBadUP is set, overrides the UP bit in the flags in the authenticator response to
91
+ be zero. Defaults to false.
92
+ """
93
+ _params: Dict[str, Any] = {}
94
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
95
+ if is_bogus_signature is not None:
96
+ _params['isBogusSignature'] = encode(FieldMeta('', '', False, 'primitive'), is_bogus_signature)
97
+ if is_bad_uv is not None:
98
+ _params['isBadUV'] = encode(FieldMeta('', '', False, 'primitive'), is_bad_uv)
99
+ if is_bad_up is not None:
100
+ _params['isBadUP'] = encode(FieldMeta('', '', False, 'primitive'), is_bad_up)
101
+ _result = await self._target.send('WebAuthn.setResponseOverrideBits', _params)
102
+ return None
103
+
104
+ async def remove_virtual_authenticator(self, *, authenticator_id: AuthenticatorId) -> None:
105
+ """
106
+ Removes the given authenticator.
107
+ :param authenticator_id:
108
+ """
109
+ _params: Dict[str, Any] = {}
110
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
111
+ _result = await self._target.send('WebAuthn.removeVirtualAuthenticator', _params)
112
+ return None
113
+
114
+ async def add_credential(self, *, authenticator_id: AuthenticatorId, credential: Credential) -> None:
115
+ """
116
+ Adds the credential to the specified authenticator.
117
+ :param authenticator_id:
118
+ :param credential:
119
+ """
120
+ _params: Dict[str, Any] = {}
121
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
122
+ _params['credential'] = encode(FieldMeta('', '', False, 'object', ref='WebAuthn.Credential'), credential)
123
+ _result = await self._target.send('WebAuthn.addCredential', _params)
124
+ return None
125
+
126
+ async def get_credential(self, *, authenticator_id: AuthenticatorId, credential_id: str) -> GetCredentialReturn:
127
+ """
128
+ Returns a single credential stored in the given virtual authenticator that
129
+ matches the credential ID.
130
+ :param authenticator_id:
131
+ :param credential_id:
132
+ """
133
+ _params: Dict[str, Any] = {}
134
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
135
+ _params['credentialId'] = encode(FieldMeta('', '', False, 'primitive'), credential_id)
136
+ _result = await self._target.send('WebAuthn.getCredential', _params)
137
+ return GetCredentialReturn.from_json(_result)
138
+
139
+ async def get_credentials(self, *, authenticator_id: AuthenticatorId) -> GetCredentialsReturn:
140
+ """
141
+ Returns all the credentials stored in the given virtual authenticator.
142
+ :param authenticator_id:
143
+ """
144
+ _params: Dict[str, Any] = {}
145
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
146
+ _result = await self._target.send('WebAuthn.getCredentials', _params)
147
+ return GetCredentialsReturn.from_json(_result)
148
+
149
+ async def remove_credential(self, *, authenticator_id: AuthenticatorId, credential_id: str) -> None:
150
+ """
151
+ Removes a credential from the authenticator.
152
+ :param authenticator_id:
153
+ :param credential_id:
154
+ """
155
+ _params: Dict[str, Any] = {}
156
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
157
+ _params['credentialId'] = encode(FieldMeta('', '', False, 'primitive'), credential_id)
158
+ _result = await self._target.send('WebAuthn.removeCredential', _params)
159
+ return None
160
+
161
+ async def clear_credentials(self, *, authenticator_id: AuthenticatorId) -> None:
162
+ """
163
+ Clears all the credentials from the specified device.
164
+ :param authenticator_id:
165
+ """
166
+ _params: Dict[str, Any] = {}
167
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
168
+ _result = await self._target.send('WebAuthn.clearCredentials', _params)
169
+ return None
170
+
171
+ async def set_user_verified(self, *, authenticator_id: AuthenticatorId, is_user_verified: bool) -> None:
172
+ """
173
+ Sets whether User Verification succeeds or fails for an authenticator.
174
+ The default is true.
175
+ :param authenticator_id:
176
+ :param is_user_verified:
177
+ """
178
+ _params: Dict[str, Any] = {}
179
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
180
+ _params['isUserVerified'] = encode(FieldMeta('', '', False, 'primitive'), is_user_verified)
181
+ _result = await self._target.send('WebAuthn.setUserVerified', _params)
182
+ return None
183
+
184
+ async def set_automatic_presence_simulation(self, *, authenticator_id: AuthenticatorId, enabled: bool) -> None:
185
+ """
186
+ Sets whether tests of user presence will succeed immediately (if true) or fail to resolve (if false) for an authenticator.
187
+ The default is true.
188
+ :param authenticator_id:
189
+ :param enabled:
190
+ """
191
+ _params: Dict[str, Any] = {}
192
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
193
+ _params['enabled'] = encode(FieldMeta('', '', False, 'primitive'), enabled)
194
+ _result = await self._target.send('WebAuthn.setAutomaticPresenceSimulation', _params)
195
+ return None
196
+
197
+ async def set_credential_properties(self, *, authenticator_id: AuthenticatorId, credential_id: str, backup_eligibility: Optional[bool] = None, backup_state: Optional[bool] = None) -> None:
198
+ """
199
+ Allows setting credential properties.
200
+ https://w3c.github.io/webauthn/#sctn-automation-set-credential-properties
201
+ :param authenticator_id:
202
+ :param credential_id:
203
+ :param backup_eligibility:
204
+ :param backup_state:
205
+ """
206
+ _params: Dict[str, Any] = {}
207
+ _params['authenticatorId'] = encode(FieldMeta('', '', False, 'primitive'), authenticator_id)
208
+ _params['credentialId'] = encode(FieldMeta('', '', False, 'primitive'), credential_id)
209
+ if backup_eligibility is not None:
210
+ _params['backupEligibility'] = encode(FieldMeta('', '', False, 'primitive'), backup_eligibility)
211
+ if backup_state is not None:
212
+ _params['backupState'] = encode(FieldMeta('', '', False, 'primitive'), backup_state)
213
+ _result = await self._target.send('WebAuthn.setCredentialProperties', _params)
214
+ return None
@@ -0,0 +1,96 @@
1
+ """Custom types and enums for the WebAuthn domain (generated)."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from enum import Enum
6
+ from typing import Any, ClassVar, Dict, List, Literal, Optional
7
+
8
+ from ..mixins.datatype import DataType, FieldMeta, register
9
+
10
+
11
+ type AuthenticatorId = str
12
+
13
+
14
+ @register("WebAuthn.AuthenticatorProtocol")
15
+ class AuthenticatorProtocol(str, Enum):
16
+ U2F = 'u2f'
17
+ CTAP2 = 'ctap2'
18
+
19
+
20
+ @register("WebAuthn.Ctap2Version")
21
+ class Ctap2Version(str, Enum):
22
+ CTAP2_0 = 'ctap2_0'
23
+ CTAP2_1 = 'ctap2_1'
24
+
25
+
26
+ @register("WebAuthn.AuthenticatorTransport")
27
+ class AuthenticatorTransport(str, Enum):
28
+ USB = 'usb'
29
+ NFC = 'nfc'
30
+ BLE = 'ble'
31
+ CABLE = 'cable'
32
+ INTERNAL = 'internal'
33
+
34
+
35
+ @register("WebAuthn.VirtualAuthenticatorOptions")
36
+ @dataclass
37
+ class VirtualAuthenticatorOptions(DataType):
38
+ protocol: AuthenticatorProtocol
39
+ transport: AuthenticatorTransport
40
+ ctap2_version: Optional[Ctap2Version] = None
41
+ has_resident_key: Optional[bool] = None
42
+ has_user_verification: Optional[bool] = None
43
+ has_large_blob: Optional[bool] = None
44
+ has_cred_blob: Optional[bool] = None
45
+ has_min_pin_length: Optional[bool] = None
46
+ has_prf: Optional[bool] = None
47
+ automatic_presence_simulation: Optional[bool] = None
48
+ is_user_verified: Optional[bool] = None
49
+ default_backup_eligibility: Optional[bool] = None
50
+ default_backup_state: Optional[bool] = None
51
+ __FIELDS__: ClassVar[tuple] = (
52
+ FieldMeta('protocol', 'protocol', False, 'enum', ref='WebAuthn.AuthenticatorProtocol'),
53
+ FieldMeta('transport', 'transport', False, 'enum', ref='WebAuthn.AuthenticatorTransport'),
54
+ FieldMeta('ctap2_version', 'ctap2Version', True, 'enum', ref='WebAuthn.Ctap2Version'),
55
+ FieldMeta('has_resident_key', 'hasResidentKey', True, 'primitive'),
56
+ FieldMeta('has_user_verification', 'hasUserVerification', True, 'primitive'),
57
+ FieldMeta('has_large_blob', 'hasLargeBlob', True, 'primitive'),
58
+ FieldMeta('has_cred_blob', 'hasCredBlob', True, 'primitive'),
59
+ FieldMeta('has_min_pin_length', 'hasMinPinLength', True, 'primitive'),
60
+ FieldMeta('has_prf', 'hasPrf', True, 'primitive'),
61
+ FieldMeta('automatic_presence_simulation', 'automaticPresenceSimulation', True, 'primitive'),
62
+ FieldMeta('is_user_verified', 'isUserVerified', True, 'primitive'),
63
+ FieldMeta('default_backup_eligibility', 'defaultBackupEligibility', True, 'primitive'),
64
+ FieldMeta('default_backup_state', 'defaultBackupState', True, 'primitive'),
65
+ )
66
+
67
+
68
+ @register("WebAuthn.Credential")
69
+ @dataclass
70
+ class Credential(DataType):
71
+ credential_id: str
72
+ is_resident_credential: bool
73
+ private_key: str
74
+ sign_count: int
75
+ rp_id: Optional[str] = None
76
+ user_handle: Optional[str] = None
77
+ large_blob: Optional[str] = None
78
+ backup_eligibility: Optional[bool] = None
79
+ backup_state: Optional[bool] = None
80
+ user_name: Optional[str] = None
81
+ user_display_name: Optional[str] = None
82
+ __FIELDS__: ClassVar[tuple] = (
83
+ FieldMeta('credential_id', 'credentialId', False, 'primitive'),
84
+ FieldMeta('is_resident_credential', 'isResidentCredential', False, 'primitive'),
85
+ FieldMeta('private_key', 'privateKey', False, 'primitive'),
86
+ FieldMeta('sign_count', 'signCount', False, 'primitive'),
87
+ FieldMeta('rp_id', 'rpId', True, 'primitive'),
88
+ FieldMeta('user_handle', 'userHandle', True, 'primitive'),
89
+ FieldMeta('large_blob', 'largeBlob', True, 'primitive'),
90
+ FieldMeta('backup_eligibility', 'backupEligibility', True, 'primitive'),
91
+ FieldMeta('backup_state', 'backupState', True, 'primitive'),
92
+ FieldMeta('user_name', 'userName', True, 'primitive'),
93
+ FieldMeta('user_display_name', 'userDisplayName', True, 'primitive'),
94
+ )
95
+
96
+ __all__ = ["AuthenticatorId", "AuthenticatorProtocol", "AuthenticatorTransport", "Credential", "Ctap2Version", "VirtualAuthenticatorOptions"]
@@ -0,0 +1,18 @@
1
+ """Core runtime: connection, targets, browser, page and request tracking."""
2
+
3
+ from .browser import Browser
4
+ from .browser_context import BrowserContext
5
+ from .element import Element
6
+ from .feature import Feature
7
+ from .page import Page
8
+ from .target import ProtocolError, Target
9
+
10
+ __all__ = [
11
+ "Browser",
12
+ "BrowserContext",
13
+ "Element",
14
+ "Feature",
15
+ "Page",
16
+ "ProtocolError",
17
+ "Target",
18
+ ]
@@ -0,0 +1,240 @@
1
+ """Browser-level target: the websocket endpoint and target management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import urllib.parse
8
+ import urllib.request
9
+ from typing import ClassVar, List, Optional
10
+
11
+ from ..cdp import CDP
12
+ from ..cdp import Target as TargetDomain
13
+ from .browser_context import BrowserContext
14
+ from .pagable import PagableTarget
15
+ from .page import Page
16
+ from .target import CDPConnection, Target, cdp_host, cdp_target_path, ws_origin
17
+
18
+
19
+ class Browser[T: Page](Target, PagableTarget[T]):
20
+ """The browser endpoint.
21
+
22
+ Connects to the browser-level websocket, discovers page targets and exposes
23
+ them as :class:`Page` objects -- each on its own websocket
24
+ (``{host}/devtools/page/{id}``), with the host kept in the :data:`cdp_host`
25
+ context variable. Pages are grouped into :class:`BrowserContext` profiles;
26
+ the default context holds pages created without an explicit one.
27
+
28
+ Generic over the page class: ``page_class`` drives ``T``, so
29
+ ``browser.pages``, ``new_page()`` and contexts are typed to the page type
30
+ you pass (e.g. ``Browser.connect_http(url, page_class=Page[RequestListener])``).
31
+ """
32
+
33
+ #: Page class captured from ``Browser[Page[...]]`` subscription, used by
34
+ #: :meth:`get_distant_browser` so the feature set is derived automatically.
35
+ _page_class_override: ClassVar[Optional[type]] = None
36
+
37
+ def __class_getitem__(cls, item):
38
+ """``Browser[Page[Feat]]`` -> a real subclass remembering that page class.
39
+
40
+ A bare type parameter (``Browser[P]`` inside generic code) falls back to
41
+ the normal typing machinery.
42
+ """
43
+ if isinstance(item, type) and issubclass(item, Page):
44
+ name = f"{cls.__name__}[{item.__name__}]"
45
+ return type(name, (cls,), {"_page_class_override": item})
46
+ return super().__class_getitem__(item) # type: ignore[misc]
47
+
48
+ def __init__(
49
+ self,
50
+ target_info: TargetDomain.TargetInfo,
51
+ *,
52
+ page_class: type[T] = Page,
53
+ ):
54
+ Target.__init__(self, target_info, None)
55
+ PagableTarget.__init__(self)
56
+ self.page_class: type[T] = page_class
57
+ self._contexts: dict[Optional[str], BrowserContext[T]] = {}
58
+ self.default_context: BrowserContext[T] | None = None
59
+
60
+ @property
61
+ def contexts(self):
62
+ return list(self._contexts.values())
63
+
64
+ @property
65
+ def _scope_context_id(self) -> Optional[str]:
66
+ return None
67
+
68
+ @classmethod
69
+ async def connect_http[P: Page = Page](
70
+ cls,
71
+ endpoint: str = "http://127.0.0.1:9222",
72
+ *,
73
+ page_class: type[P] = Page,
74
+ ) -> "Browser[P]":
75
+ """Discover the websocket via ``/json/version`` then connect.
76
+
77
+ Binds :data:`cdp_host` to the endpoint's origin so every page connected
78
+ afterwards reaches the browser at the same host without it being passed
79
+ around.
80
+ """
81
+ with urllib.request.urlopen(f"{endpoint.rstrip('/')}/json/version") as resp:
82
+ info = json.loads(resp.read())
83
+ ws_url = info["webSocketDebuggerUrl"]
84
+ cdp_host.set(ws_origin(ws_url))
85
+
86
+ boot = CDPConnection()
87
+ await boot._open(ws_url)
88
+ try:
89
+ browser_info = (await CDP(boot).Target.get_target_info()).target_info
90
+ finally:
91
+ await boot.close()
92
+
93
+ browser = Browser[P](browser_info, page_class=page_class)
94
+ await browser.connect(ws_url)
95
+ await browser._discover()
96
+ return browser
97
+
98
+ @classmethod
99
+ async def get_distant_browser(
100
+ cls,
101
+ server: str = "http://127.0.0.1:9333",
102
+ *,
103
+ features: Optional[tuple] = None,
104
+ page_class: Optional[type] = None,
105
+ **launch,
106
+ ) -> "Browser[T]":
107
+ """Create a browser on a parsek-cdp-server and return it, connected.
108
+
109
+ ``Browser[Page[RequestListener]].get_distant_browser("http://host:9333",
110
+ headless=True)`` issues ``POST /browsers?feature=RequestListener`` with the
111
+ launch settings (``headless``, ``executable``, ``extra_args``, ...) in the
112
+ body, then connects to the proxy's control channel. The returned browser
113
+ drives the *remote* browser exactly like a local one -- pages connect to
114
+ the proxy's per-target endpoints and the named features are aggregated
115
+ server-side.
116
+
117
+ The feature set defaults to the ones declared on the subscripted page
118
+ class (``Page[RequestListener]`` -> ``RequestListener``); pass ``features``
119
+ to override.
120
+ """
121
+ resolved_page = page_class or cls._page_class_override or Page
122
+ feats = (
123
+ features
124
+ if features is not None
125
+ else getattr(resolved_page, "_feature_classes", ())
126
+ )
127
+ query = "&".join(f"feature={urllib.parse.quote(f.__name__)}" for f in feats)
128
+ url = f"{server.rstrip('/')}/browsers" + (f"?{query}" if query else "")
129
+ payload = json.dumps(launch).encode()
130
+ # Run the blocking HTTP POST off the event loop so it never stalls it
131
+ # (notably when client and server share one loop in tests).
132
+ info = await asyncio.to_thread(cls._post_json, url, payload)
133
+
134
+ control_url = info["wsUrl"]
135
+ suffix = "/control"
136
+ ws_base = (
137
+ control_url[: -len(suffix)] if control_url.endswith(suffix) else control_url
138
+ )
139
+ cdp_host.set(ws_base)
140
+ cdp_target_path.set("/page/")
141
+
142
+ boot = CDPConnection()
143
+ await boot._open(control_url)
144
+ try:
145
+ browser_info = (await CDP(boot).Target.get_target_info()).target_info
146
+ finally:
147
+ await boot.close()
148
+
149
+ # Pages on a remote browser run their features as *clients* (consuming the
150
+ # server-aggregated ``Parsek.*`` events), not "local" (which would digest
151
+ # raw CDP -- exactly what the server already suppresses).
152
+ remote_page = type(
153
+ resolved_page.__name__,
154
+ (resolved_page,),
155
+ {"_feature_role": "client"},
156
+ )
157
+ browser = cls(browser_info, page_class=remote_page)
158
+ await browser.connect(control_url)
159
+ await browser._discover()
160
+ return browser
161
+
162
+ @staticmethod
163
+ def _post_json(url: str, payload: bytes) -> dict:
164
+ request = urllib.request.Request(
165
+ url,
166
+ data=payload,
167
+ method="POST",
168
+ headers={"Content-Type": "application/json"},
169
+ )
170
+ with urllib.request.urlopen(request) as resp:
171
+ return json.loads(resp.read())
172
+
173
+ async def _discover(self) -> None:
174
+ """Populate contexts and pages from the live browser (after connect)."""
175
+ contexts = await self.cdp.Target.get_browser_contexts()
176
+ for context_id in contexts.browser_context_ids:
177
+ self._contexts[context_id] = BrowserContext(self, context_id)
178
+ for target in self.targets:
179
+ target_data = target._target
180
+ if target_data.type_ not in ("page", "tab"):
181
+ continue
182
+ page = await self._ensure_page(target_data)
183
+ self._pages[target.id] = page
184
+ if target_data.browser_context_id not in self._contexts:
185
+ context = BrowserContext(self, target_data.browser_context_id)
186
+ self._contexts[target_data.browser_context_id] = context
187
+ self.default_context = context
188
+ self._contexts[target_data.browser_context_id]._pages[target.id] = page
189
+
190
+ async def connect(self, url: Optional[str] = None) -> "Browser[T]":
191
+ """Connect the browser websocket and start watching for page targets.
192
+
193
+ The browser endpoint's ws path id does not match its ``target_id``, so
194
+ :meth:`connect_http` passes the discovered ``webSocketDebuggerUrl`` as
195
+ ``url``. Generic target tracking is wired by :meth:`Target.connect`; the
196
+ page-specific discovery handling lives in :class:`PagableTarget` and is
197
+ registered here on the browser's own connection.
198
+ """
199
+ await super().connect(url)
200
+ await self.cdp.Target.set_discover_targets(discover=True)
201
+ await self.refresh_targets()
202
+ self.watch(self)
203
+ return self
204
+
205
+ async def create_context(
206
+ self,
207
+ *,
208
+ dispose_on_detach: Optional[bool] = None,
209
+ proxy_server: Optional[str] = None,
210
+ proxy_bypass_list: Optional[str] = None,
211
+ ):
212
+ """Create a fresh, isolated browser context (incognito-like)."""
213
+ result = await self.cdp.Target.create_browser_context(
214
+ dispose_on_detach=dispose_on_detach,
215
+ proxy_server=proxy_server,
216
+ proxy_bypass_list=proxy_bypass_list,
217
+ )
218
+ ctx = BrowserContext[T](self, result.browser_context_id)
219
+ self._contexts[ctx.id] = ctx
220
+ return ctx
221
+
222
+ async def fetch_contexts(self) -> List[BrowserContext]:
223
+ """Sync :attr:`contexts` with the browser and return them all."""
224
+ result = await self.cdp.Target.get_browser_contexts()
225
+ for cid in result.browser_context_ids:
226
+ self._contexts.setdefault(cid, BrowserContext(self, cid))
227
+ return list(self._contexts.values())
228
+
229
+ def _context_for(self, context_id: Optional[str]) -> BrowserContext[T]:
230
+ ctx = self._contexts.get(context_id)
231
+ if ctx is None:
232
+ ctx = BrowserContext(self, context_id)
233
+ self._contexts[context_id] = ctx
234
+ return ctx
235
+
236
+ def _forget_context(self, context_id: str) -> None:
237
+ ctx = self._contexts.pop(context_id, None)
238
+ if ctx is not None:
239
+ for target_id in list(ctx._pages):
240
+ self._drop_page(target_id)