mithwire 0.50.3__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 (76) hide show
  1. mithwire/__init__.py +32 -0
  2. mithwire/cdp/README.md +4 -0
  3. mithwire/cdp/__init__.py +6 -0
  4. mithwire/cdp/accessibility.py +668 -0
  5. mithwire/cdp/animation.py +494 -0
  6. mithwire/cdp/audits.py +1995 -0
  7. mithwire/cdp/autofill.py +292 -0
  8. mithwire/cdp/background_service.py +215 -0
  9. mithwire/cdp/bluetooth_emulation.py +626 -0
  10. mithwire/cdp/browser.py +821 -0
  11. mithwire/cdp/cache_storage.py +311 -0
  12. mithwire/cdp/cast.py +172 -0
  13. mithwire/cdp/console.py +107 -0
  14. mithwire/cdp/crash_report_context.py +55 -0
  15. mithwire/cdp/css.py +2750 -0
  16. mithwire/cdp/database.py +179 -0
  17. mithwire/cdp/debugger.py +1405 -0
  18. mithwire/cdp/device_access.py +141 -0
  19. mithwire/cdp/device_orientation.py +45 -0
  20. mithwire/cdp/dom.py +2257 -0
  21. mithwire/cdp/dom_debugger.py +321 -0
  22. mithwire/cdp/dom_snapshot.py +876 -0
  23. mithwire/cdp/dom_storage.py +222 -0
  24. mithwire/cdp/emulation.py +1779 -0
  25. mithwire/cdp/event_breakpoints.py +56 -0
  26. mithwire/cdp/extensions.py +238 -0
  27. mithwire/cdp/fed_cm.py +283 -0
  28. mithwire/cdp/fetch.py +507 -0
  29. mithwire/cdp/file_system.py +115 -0
  30. mithwire/cdp/headless_experimental.py +115 -0
  31. mithwire/cdp/heap_profiler.py +401 -0
  32. mithwire/cdp/indexed_db.py +528 -0
  33. mithwire/cdp/input_.py +701 -0
  34. mithwire/cdp/inspector.py +95 -0
  35. mithwire/cdp/io.py +101 -0
  36. mithwire/cdp/layer_tree.py +464 -0
  37. mithwire/cdp/log.py +190 -0
  38. mithwire/cdp/media.py +313 -0
  39. mithwire/cdp/memory.py +305 -0
  40. mithwire/cdp/network.py +5342 -0
  41. mithwire/cdp/overlay.py +1468 -0
  42. mithwire/cdp/page.py +3972 -0
  43. mithwire/cdp/performance.py +124 -0
  44. mithwire/cdp/performance_timeline.py +200 -0
  45. mithwire/cdp/preload.py +575 -0
  46. mithwire/cdp/profiler.py +420 -0
  47. mithwire/cdp/pwa.py +278 -0
  48. mithwire/cdp/py.typed +0 -0
  49. mithwire/cdp/runtime.py +1589 -0
  50. mithwire/cdp/schema.py +50 -0
  51. mithwire/cdp/security.py +518 -0
  52. mithwire/cdp/service_worker.py +401 -0
  53. mithwire/cdp/smart_card_emulation.py +891 -0
  54. mithwire/cdp/storage.py +1573 -0
  55. mithwire/cdp/system_info.py +327 -0
  56. mithwire/cdp/target.py +829 -0
  57. mithwire/cdp/tethering.py +65 -0
  58. mithwire/cdp/tracing.py +377 -0
  59. mithwire/cdp/util.py +18 -0
  60. mithwire/cdp/web_audio.py +606 -0
  61. mithwire/cdp/web_authn.py +598 -0
  62. mithwire/cdp/web_mcp.py +293 -0
  63. mithwire/core/_contradict.py +142 -0
  64. mithwire/core/browser.py +923 -0
  65. mithwire/core/cf_templates/cf_dark_checkbox.png +0 -0
  66. mithwire/core/cf_templates/cf_light_checkbox.png +0 -0
  67. mithwire/core/config.py +323 -0
  68. mithwire/core/connection.py +564 -0
  69. mithwire/core/element.py +1205 -0
  70. mithwire/core/tab.py +2202 -0
  71. mithwire/core/util.py +5063 -0
  72. mithwire-0.50.3.dist-info/METADATA +1049 -0
  73. mithwire-0.50.3.dist-info/RECORD +76 -0
  74. mithwire-0.50.3.dist-info/WHEEL +5 -0
  75. mithwire-0.50.3.dist-info/licenses/LICENSE.txt +619 -0
  76. mithwire-0.50.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,323 @@
1
+ # Copyright 2024 by UltrafunkAmsterdam (https://github.com/UltrafunkAmsterdam)
2
+ # All rights reserved.
3
+ # This file is part of the mithwire package.
4
+ # and is released under the "GNU AFFERO GENERAL PUBLIC LICENSE".
5
+ # Please see the LICENSE.txt file that should have been included as part of this package.
6
+
7
+ import logging
8
+ import os
9
+ import pathlib
10
+ import secrets
11
+ import sys
12
+ import tempfile
13
+ import zipfile
14
+ from typing import List, Optional, TypeVar
15
+
16
+ __all__ = [
17
+ "Config",
18
+ "find_chrome_executable",
19
+ "temp_profile_dir",
20
+ "is_root",
21
+ "is_posix",
22
+ "PathLike",
23
+ ]
24
+
25
+ logger = logging.getLogger(__name__)
26
+ is_posix = sys.platform.startswith(("darwin", "cygwin", "linux", "linux2"))
27
+
28
+ PathLike = TypeVar("PathLike", bound=str | pathlib.Path)
29
+ AUTO = None
30
+
31
+
32
+ class Config:
33
+ """
34
+ Config object
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ user_data_dir: Optional[PathLike] = AUTO,
40
+ headless: Optional[bool] = False,
41
+ browser_executable_path: Optional[PathLike] = AUTO,
42
+ browser_args: Optional[List[str]] = AUTO,
43
+ sandbox: Optional[bool] = True,
44
+ lang: Optional[str] = "en-US",
45
+ host: str = AUTO,
46
+ port: int = AUTO,
47
+ expert: bool = AUTO,
48
+ **kwargs: dict,
49
+ ):
50
+ """
51
+ creates a config object.
52
+ Can be called without any arguments to generate a best-practice config, which is recommended.
53
+
54
+ calling the object, eg : myconfig() , will return the list of arguments which
55
+ are provided to the browser.
56
+
57
+ additional arguments can be added using the :py:obj:`~add_argument method`
58
+
59
+ Instances of this class are usually not instantiated by end users.
60
+
61
+ :param user_data_dir: the data directory to use
62
+ :param headless: set to True for headless mode
63
+ :param browser_executable_path: specify browser executable, instead of using autodetect
64
+ :param browser_args: forwarded to browser executable. eg : ["--some-chromeparam=somevalue", "some-other-param=someval"]
65
+ :param sandbox: disables sandbox
66
+ :param autodiscover_targets: use autodiscovery of targets
67
+ :param lang: language string to use other than the default "en-US,en;q=0.9"
68
+ :param expert: when set to True, enabled "expert" mode.
69
+ This conveys, the inclusion of parameters: ----disable-site-isolation-trials,
70
+ as well as some scripts and patching useful for debugging (for example, ensuring shadow-root is always in "open" mode)
71
+
72
+ :param kwargs:
73
+
74
+ :type user_data_dir: PathLike
75
+ :type headless: bool
76
+ :type browser_executable_path: PathLike
77
+ :type browser_args: list[str]
78
+ :type sandbox: bool
79
+ :type lang: str
80
+ :type kwargs: dict
81
+ """
82
+
83
+ if not browser_args:
84
+ browser_args = []
85
+
86
+ if not user_data_dir:
87
+ self._user_data_dir = temp_profile_dir()
88
+ self._custom_data_dir = False
89
+ else:
90
+ self.user_data_dir = user_data_dir
91
+
92
+ if not browser_executable_path:
93
+ browser_executable_path = find_chrome_executable()
94
+
95
+ self._browser_args = browser_args
96
+
97
+ self.browser_executable_path = browser_executable_path
98
+ self.headless = headless
99
+ self.sandbox = sandbox
100
+ self.host = host
101
+ self.port = port
102
+ self.expert = expert
103
+ self._extensions = []
104
+ # when using posix-ish operating system and running as root
105
+ # you must use no_sandbox = True, which in case is corrected here
106
+ if is_posix and is_root() and sandbox:
107
+ logger.info("detected root usage, auto disabling sandbox mode")
108
+ self.sandbox = False
109
+
110
+ self.autodiscover_targets = True
111
+ self.lang = lang
112
+
113
+ # other keyword args will be accessible by attribute
114
+ self.__dict__.update(kwargs)
115
+ super().__init__()
116
+ self._default_browser_args = [
117
+ "--remote-allow-origins=*",
118
+ "--no-first-run",
119
+ "--no-service-autorun",
120
+ "--no-default-browser-check",
121
+ "--homepage=about:blank",
122
+ "--no-pings",
123
+ "--password-store=basic",
124
+ "--disable-infobars",
125
+ "--disable-breakpad",
126
+ "--disable-dev-shm-usage",
127
+ "--disable-session-crashed-bubble",
128
+ "--disable-search-engine-choice-screen",
129
+ ]
130
+
131
+ @property
132
+ def browser_args(self):
133
+ return sorted(self._default_browser_args + self._browser_args)
134
+
135
+ @property
136
+ def user_data_dir(self):
137
+ return self._user_data_dir
138
+
139
+ @user_data_dir.setter
140
+ def user_data_dir(self, path: PathLike):
141
+ self._user_data_dir = str(path)
142
+ self._custom_data_dir = True
143
+
144
+ @property
145
+ def uses_custom_data_dir(self) -> bool:
146
+ return self._custom_data_dir
147
+
148
+ def add_extension(self, extension_path: PathLike):
149
+ """
150
+ adds an extension to load, you could point extension_path
151
+ to a folder (containing the manifest), or extension file (crx)
152
+
153
+ :param extension_path:
154
+ :type extension_path:
155
+ :return:
156
+ :rtype:
157
+ """
158
+ path = pathlib.Path(extension_path)
159
+
160
+ if not path.exists():
161
+ raise FileNotFoundError("could not find anything here: %s" % str(path))
162
+
163
+ if path.is_file():
164
+ tf = tempfile.mkdtemp(prefix=f"extension_", suffix=secrets.token_hex(4))
165
+ with zipfile.ZipFile(path, "r") as z:
166
+ z.extractall(tf)
167
+ self._extensions.append(tf)
168
+
169
+ elif path.is_dir():
170
+ for item in path.rglob("manifest.*"):
171
+ path = item.parent
172
+ self._extensions.append(path)
173
+
174
+ def __call__(self):
175
+ # the host and port will be added when starting
176
+ # the browser, as by the time it starts, the port
177
+ # is probably already taken
178
+ args = self._default_browser_args.copy()
179
+ args += ["--user-data-dir=%s" % self.user_data_dir]
180
+ args += ["--disable-session-crashed-bubble"]
181
+
182
+ disabled_features = "IsolateOrigins,site-per-process"
183
+ if self._extensions:
184
+ disabled_features += ",DisableLoadExtensionCommandLineSwitch"
185
+ args += [f"--disable-features={disabled_features}"]
186
+ if self._extensions:
187
+ args += ["--enable-unsafe-extension-debugging"]
188
+ if self.expert:
189
+ args += ["--disable-site-isolation-trials"]
190
+ if self._browser_args:
191
+ args.extend([arg for arg in self._browser_args if arg not in args])
192
+ if self.headless:
193
+ args.append("--headless=new")
194
+ if not self.sandbox:
195
+ args.append("--no-sandbox")
196
+ # Chrome 136+ silently ignores --remote-debugging-port unless an explicit
197
+ # bind address is also provided, which leaves the DevTools websocket
198
+ # unreachable and makes Browser.start fail with a "Failed to connect to
199
+ # browser" error. Always emit the host flag, defaulting to 127.0.0.1.
200
+ args.append("--remote-debugging-host=%s" % (self.host or "127.0.0.1"))
201
+ if self.port:
202
+ args.append("--remote-debugging-port=%s" % self.port)
203
+ return args
204
+
205
+ def add_argument(self, arg: str):
206
+ if any(
207
+ x in arg.lower()
208
+ for x in [
209
+ "headless",
210
+ "data-dir",
211
+ "data_dir",
212
+ "no-sandbox",
213
+ "no_sandbox",
214
+ "lang",
215
+ ]
216
+ ):
217
+ raise ValueError(
218
+ '"%s" not allowed. please use one of the attributes of the Config object to set it'
219
+ % arg
220
+ )
221
+ self._browser_args.append(arg)
222
+
223
+ def __repr__(self):
224
+ s = f"{self.__class__.__name__}"
225
+ for k, v in ({**self.__dict__, **self.__class__.__dict__}).items():
226
+ if k[0] == "_":
227
+ continue
228
+ if not v:
229
+ continue
230
+ if isinstance(v, property):
231
+ v = getattr(self, k)
232
+ if callable(v):
233
+ continue
234
+ s += f"\n\t{k} = {v}"
235
+ return s
236
+
237
+
238
+ def is_root():
239
+ """
240
+ helper function to determine if user trying to launch chrome
241
+ under linux as root, which needs some alternative handling
242
+ :return:
243
+ :rtype:
244
+ """
245
+ import ctypes
246
+ import os
247
+
248
+ try:
249
+ return os.getuid() == 0
250
+ except AttributeError:
251
+ return ctypes.windll.shell32.IsUserAnAdmin() != 0
252
+
253
+
254
+ def temp_profile_dir():
255
+ """generate a temp dir (path)"""
256
+ path = os.path.normpath(tempfile.mkdtemp(prefix="uc_"))
257
+ return path
258
+
259
+
260
+ def find_chrome_executable(return_all=False):
261
+ """
262
+ Finds the chrome, beta, canary, chromium executable
263
+ and returns the disk path
264
+ """
265
+ candidates = []
266
+ if is_posix:
267
+ for item in os.environ.get("PATH").split(os.pathsep):
268
+ for subitem in (
269
+ "google-chrome",
270
+ "chromium",
271
+ "chromium-browser",
272
+ "chrome",
273
+ "google-chrome-stable",
274
+ ):
275
+ candidates.append(os.sep.join((item, subitem)))
276
+ if "darwin" in sys.platform:
277
+ candidates += [
278
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
279
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
280
+ ]
281
+
282
+ else:
283
+ for item in map(
284
+ os.environ.get,
285
+ ("PROGRAMFILES", "PROGRAMFILES(X86)", "LOCALAPPDATA", "PROGRAMW6432"),
286
+ ):
287
+ if item is not None:
288
+ for subitem in (
289
+ "Google/Chrome/Application",
290
+ "Google/Chrome Beta/Application",
291
+ "Google/Chrome Canary/Application",
292
+ ):
293
+ candidates.append(os.sep.join((item, subitem, "chrome.exe")))
294
+ rv = []
295
+ for candidate in candidates:
296
+ if os.path.exists(candidate) and os.access(candidate, os.X_OK):
297
+ logger.debug("%s is a valid candidate... " % candidate)
298
+ rv.append(candidate)
299
+ else:
300
+ logger.debug(
301
+ "%s is not a valid candidate because don't exist or not executable "
302
+ % candidate
303
+ )
304
+
305
+ winner = None
306
+
307
+ if return_all and rv:
308
+ return rv
309
+
310
+ if rv and len(rv) > 1:
311
+ # assuming the shortest path wins
312
+ winner = min(rv, key=lambda x: len(x))
313
+
314
+ elif len(rv) == 1:
315
+ winner = rv[0]
316
+
317
+ if winner:
318
+ return os.path.normpath(winner)
319
+
320
+ raise FileNotFoundError(
321
+ "could not find a valid chrome browser binary. please make sure chrome is installed."
322
+ "or use the keyword argument 'browser_executable_path=/path/to/your/browser' "
323
+ )