pylookyloo 1.31.2__tar.gz → 1.36.3__tar.gz
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.
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/PKG-INFO +9 -9
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/pylookyloo/api.py +35 -10
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/pyproject.toml +8 -8
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/LICENSE +0 -0
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/README.md +0 -0
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/pylookyloo/__init__.py +0 -0
- {pylookyloo-1.31.2 → pylookyloo-1.36.3}/pylookyloo/py.typed +0 -0
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pylookyloo
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.36.3
|
|
4
4
|
Summary: Python CLI and module for Lookyloo
|
|
5
|
-
License: GPL-2.0-or-later
|
|
5
|
+
License-Expression: GPL-2.0-or-later
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Author: Raphaël Vinot
|
|
7
8
|
Author-email: raphael.vinot@circl.lu
|
|
8
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.10
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
11
|
Classifier: Environment :: Console
|
|
11
12
|
Classifier: Intended Audience :: Information Technology
|
|
12
13
|
Classifier: Intended Audience :: Science/Research
|
|
13
14
|
Classifier: Intended Audience :: Telecommunications Industry
|
|
14
|
-
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
|
|
15
15
|
Classifier: Operating System :: POSIX :: Linux
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
22
|
Classifier: Topic :: Internet
|
|
23
23
|
Classifier: Topic :: Security
|
|
24
24
|
Provides-Extra: docs
|
|
25
25
|
Provides-Extra: examples
|
|
26
|
-
Requires-Dist: Sphinx (>=
|
|
27
|
-
Requires-Dist: pylacus (>=1.
|
|
28
|
-
Requires-Dist: requests (>=2.32.
|
|
26
|
+
Requires-Dist: Sphinx (>=9.1.0) ; (python_version >= "3.12") and (extra == "docs")
|
|
27
|
+
Requires-Dist: pylacus (>=1.21.2) ; extra == "examples"
|
|
28
|
+
Requires-Dist: requests (>=2.32.5)
|
|
29
29
|
Project-URL: Documentation, https://pylookyloo.readthedocs.io/en/latest/
|
|
30
30
|
Project-URL: Repository, https://github.com/lookyloo/PyLookyloo
|
|
31
31
|
Project-URL: issues, https://github.com/lookyloo/PyLookyloo/issues
|
|
@@ -72,9 +72,11 @@ class CaptureSettings(TypedDict, total=False):
|
|
|
72
72
|
locale: str | None
|
|
73
73
|
color_scheme: str | None
|
|
74
74
|
java_script_enabled: bool
|
|
75
|
+
with_trusted_timestamps: bool
|
|
75
76
|
headless: bool
|
|
76
77
|
viewport: dict[str, int] | None
|
|
77
78
|
referer: str | None
|
|
79
|
+
categories: list[str] | None
|
|
78
80
|
|
|
79
81
|
listing: bool | None
|
|
80
82
|
auto_report: bool | dict[str, str] | None
|
|
@@ -89,7 +91,7 @@ class CompareSettings(TypedDict, total=False):
|
|
|
89
91
|
|
|
90
92
|
class Lookyloo():
|
|
91
93
|
|
|
92
|
-
def __init__(self, root_url: str=
|
|
94
|
+
def __init__(self, root_url: str | None=None, useragent: str | None=None,
|
|
93
95
|
*, proxies: dict[str, str] | None=None, verify: bool | str=True) -> None:
|
|
94
96
|
'''Query a specific lookyloo instance.
|
|
95
97
|
|
|
@@ -97,7 +99,7 @@ class Lookyloo():
|
|
|
97
99
|
:param useragent: The User Agent used by requests to run the HTTP requests against Lookyloo, it is *not* passed to the captures.
|
|
98
100
|
:param proxies: The proxies to use to connect to lookyloo (not the ones given to the capture itself) - More details: https://requests.readthedocs.io/en/latest/user/advanced/#proxies
|
|
99
101
|
'''
|
|
100
|
-
self.root_url = root_url
|
|
102
|
+
self.root_url = root_url if root_url else 'https://lookyloo.circl.lu/'
|
|
101
103
|
self.apikey: str | None = None
|
|
102
104
|
|
|
103
105
|
if not urlparse(self.root_url).scheme:
|
|
@@ -189,11 +191,13 @@ class Lookyloo():
|
|
|
189
191
|
locale: str | None=None,
|
|
190
192
|
color_scheme: str | None=None,
|
|
191
193
|
java_script_enabled: bool=True,
|
|
194
|
+
with_trusted_timestamps: bool=False,
|
|
192
195
|
headless: bool=True,
|
|
193
196
|
viewport: dict[str, int] | None=None,
|
|
194
197
|
referer: str | None=None,
|
|
195
198
|
listing: bool | None=None,
|
|
196
|
-
auto_report: bool | dict[str, str] | None=None
|
|
199
|
+
auto_report: bool | dict[str, str] | None=None,
|
|
200
|
+
categories: list[str] | None=None
|
|
197
201
|
) -> str:
|
|
198
202
|
...
|
|
199
203
|
|
|
@@ -215,11 +219,13 @@ class Lookyloo():
|
|
|
215
219
|
locale: str | None=None,
|
|
216
220
|
color_scheme: str | None=None,
|
|
217
221
|
java_script_enabled: bool | None=None,
|
|
222
|
+
with_trusted_timestamps: bool=False,
|
|
218
223
|
headless: bool=True,
|
|
219
224
|
viewport: dict[str, int] | None=None,
|
|
220
225
|
referer: str | None=None,
|
|
221
226
|
listing: bool | None=None,
|
|
222
|
-
auto_report: bool | dict[str, str] | None=None
|
|
227
|
+
auto_report: bool | dict[str, str] | None=None,
|
|
228
|
+
categories: list[str] | None=None
|
|
223
229
|
) -> str:
|
|
224
230
|
'''Submit a URL to a lookyloo instance.
|
|
225
231
|
|
|
@@ -244,6 +250,7 @@ class Lookyloo():
|
|
|
244
250
|
:param locale: The locale of the browser
|
|
245
251
|
:param color_scheme: The prefered color scheme of the browser (light or dark)
|
|
246
252
|
:param java_script_enabled: If False, no JS will run during the capture.
|
|
253
|
+
:param with_trusted_timestamps: If True, and a trusted timestamp provider is configured, trigger a request for trusted timestamps for forensic archival.
|
|
247
254
|
:param headless: If False, the browser will be headed, it requires the capture to be done on a desktop.
|
|
248
255
|
:param viewport: The viewport of the browser used for capturing
|
|
249
256
|
:param referer: The referer URL for the capture
|
|
@@ -252,6 +259,7 @@ class Lookyloo():
|
|
|
252
259
|
Pass True if you want to autoreport without any setting, or a dictionary with two keys:
|
|
253
260
|
* email (required): the email of the submitter, so the analyst to get in touch
|
|
254
261
|
* comment (optional): a comment about the capture to help the analyst
|
|
262
|
+
:param categories: (v1.37.0+) A list of categories to assign to the capture
|
|
255
263
|
'''
|
|
256
264
|
to_send: CaptureSettings
|
|
257
265
|
if capture_settings:
|
|
@@ -300,6 +308,8 @@ class Lookyloo():
|
|
|
300
308
|
to_send['color_scheme'] = color_scheme
|
|
301
309
|
if java_script_enabled is not None:
|
|
302
310
|
to_send['java_script_enabled'] = java_script_enabled
|
|
311
|
+
if with_trusted_timestamps is not None:
|
|
312
|
+
to_send['with_trusted_timestamps'] = with_trusted_timestamps
|
|
303
313
|
if headless is not None:
|
|
304
314
|
to_send['headless'] = headless
|
|
305
315
|
if viewport:
|
|
@@ -310,6 +320,8 @@ class Lookyloo():
|
|
|
310
320
|
to_send['listing'] = listing
|
|
311
321
|
if auto_report:
|
|
312
322
|
to_send['auto_report'] = auto_report
|
|
323
|
+
if categories:
|
|
324
|
+
to_send['categories'] = categories
|
|
313
325
|
|
|
314
326
|
response = self.session.post(urljoin(self.root_url, 'submit'), json=to_send)
|
|
315
327
|
response.raise_for_status()
|
|
@@ -666,7 +678,8 @@ class Lookyloo():
|
|
|
666
678
|
har: Path | BytesIO | str | None = None,
|
|
667
679
|
html: Path | BytesIO | str | None = None,
|
|
668
680
|
last_redirected_url: str | None = None,
|
|
669
|
-
screenshot: Path | BytesIO | str | None = None
|
|
681
|
+
screenshot: Path | BytesIO | str | None = None,
|
|
682
|
+
categories: list[str] | None=None) -> str:
|
|
670
683
|
...
|
|
671
684
|
|
|
672
685
|
@overload
|
|
@@ -676,7 +689,8 @@ class Lookyloo():
|
|
|
676
689
|
har: Path | BytesIO | str | None = None,
|
|
677
690
|
html: Path | BytesIO | str | None = None,
|
|
678
691
|
last_redirected_url: str | None = None,
|
|
679
|
-
screenshot: Path | BytesIO | str | None = None
|
|
692
|
+
screenshot: Path | BytesIO | str | None = None,
|
|
693
|
+
categories: list[str] | None=None) -> tuple[str, dict[str, str]]:
|
|
680
694
|
...
|
|
681
695
|
|
|
682
696
|
def upload_capture(self, *, quiet: bool = False,
|
|
@@ -685,7 +699,8 @@ class Lookyloo():
|
|
|
685
699
|
har: Path | BytesIO | str | None = None,
|
|
686
700
|
html: Path | BytesIO | str | None = None,
|
|
687
701
|
last_redirected_url: str | None = None,
|
|
688
|
-
screenshot: Path | BytesIO | str | None = None
|
|
702
|
+
screenshot: Path | BytesIO | str | None = None,
|
|
703
|
+
categories: list[str] | None=None) -> str | tuple[str, dict[str, str]]:
|
|
689
704
|
'''Upload a capture via har-file and others
|
|
690
705
|
|
|
691
706
|
:param quiet: Returns the UUID only, instead of the the UUID and the potential error / warning messages
|
|
@@ -695,6 +710,7 @@ class Lookyloo():
|
|
|
695
710
|
:param html: rendered HTML of the capture
|
|
696
711
|
:param last_redirected_url: The landing page of the capture
|
|
697
712
|
:param screenshot: Screenshot of the capture
|
|
713
|
+
:param categories: The categories assigned to the capture
|
|
698
714
|
'''
|
|
699
715
|
def encode_document(document: Path | BytesIO | str) -> str:
|
|
700
716
|
if isinstance(document, str):
|
|
@@ -707,6 +723,8 @@ class Lookyloo():
|
|
|
707
723
|
return base64.b64encode(document.getvalue()).decode()
|
|
708
724
|
|
|
709
725
|
to_send: dict[str, Any] = {'listing': listing}
|
|
726
|
+
if categories:
|
|
727
|
+
to_send['categories'] = categories
|
|
710
728
|
|
|
711
729
|
if full_capture:
|
|
712
730
|
b64_full_capture = encode_document(full_capture)
|
|
@@ -728,9 +746,16 @@ class Lookyloo():
|
|
|
728
746
|
else:
|
|
729
747
|
raise PyLookylooError("Full capture or at least har-file are required")
|
|
730
748
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
749
|
+
try:
|
|
750
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'upload'))), json=to_send)
|
|
751
|
+
json_response = r.json()
|
|
752
|
+
r.raise_for_status()
|
|
753
|
+
except requests.exceptions.HTTPError:
|
|
754
|
+
# We should have a response with details
|
|
755
|
+
raise PyLookylooError(f'Unable to upload capture: {json_response}.')
|
|
756
|
+
except Exception as e:
|
|
757
|
+
raise PyLookylooError(f'Unable to upload capture: {e}.')
|
|
758
|
+
|
|
734
759
|
uuid = json_response['uuid']
|
|
735
760
|
messages = json_response['messages']
|
|
736
761
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pylookyloo"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.36.3"
|
|
4
4
|
description = "Python CLI and module for Lookyloo"
|
|
5
5
|
authors = [
|
|
6
6
|
{name="Raphaël Vinot", email="raphael.vinot@circl.lu"}
|
|
7
7
|
]
|
|
8
8
|
license = "GPL-2.0-or-later"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
11
|
|
|
12
12
|
dynamic = [ "classifiers" ]
|
|
13
13
|
|
|
14
14
|
dependencies = [
|
|
15
|
-
"requests (>=2.32.
|
|
15
|
+
"requests (>=2.32.5)"
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
[project.urls]
|
|
@@ -36,13 +36,13 @@ classifiers = [
|
|
|
36
36
|
lookyloo = 'pylookyloo:main'
|
|
37
37
|
|
|
38
38
|
[project.optional-dependencies]
|
|
39
|
-
docs = ["Sphinx (>=
|
|
40
|
-
examples = ["pylacus (>=1.
|
|
39
|
+
docs = ["Sphinx (>=9.1.0) ; python_version >= \"3.12\""]
|
|
40
|
+
examples = ["pylacus (>=1.21.2)"]
|
|
41
41
|
|
|
42
42
|
[tool.poetry.group.dev.dependencies]
|
|
43
|
-
mypy = "^1.
|
|
44
|
-
types-requests = "^2.32.4.
|
|
45
|
-
pytest = "^
|
|
43
|
+
mypy = "^1.19.1"
|
|
44
|
+
types-requests = "^2.32.4.20260107"
|
|
45
|
+
pytest = "^9.0.2"
|
|
46
46
|
|
|
47
47
|
[build-system]
|
|
48
48
|
requires = ["poetry-core>=2.0"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|