pylookyloo 1.23.0__tar.gz → 1.24.0__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.
Potentially problematic release.
This version of pylookyloo might be problematic. Click here for more details.
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/PKG-INFO +1 -1
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/pylookyloo/api.py +132 -117
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/pyproject.toml +4 -4
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/LICENSE +0 -0
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/README.md +0 -0
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/pylookyloo/__init__.py +0 -0
- {pylookyloo-1.23.0 → pylookyloo-1.24.0}/pylookyloo/py.typed +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
import base64
|
|
5
6
|
import warnings
|
|
6
7
|
|
|
7
8
|
from importlib.metadata import version
|
|
8
9
|
from io import BytesIO, StringIO
|
|
9
|
-
from typing import
|
|
10
|
+
from typing import Any, TypedDict, overload
|
|
10
11
|
from urllib.parse import urljoin, urlparse
|
|
11
|
-
from pathlib import Path
|
|
12
|
+
from pathlib import PurePosixPath, Path
|
|
12
13
|
|
|
13
14
|
import requests
|
|
14
15
|
|
|
@@ -24,39 +25,39 @@ class AuthError(PyLookylooError):
|
|
|
24
25
|
class CaptureSettings(TypedDict, total=False):
|
|
25
26
|
'''The capture settings that can be passed to Lookyloo.'''
|
|
26
27
|
|
|
27
|
-
url:
|
|
28
|
-
document_name:
|
|
29
|
-
document:
|
|
30
|
-
browser:
|
|
31
|
-
device_name:
|
|
32
|
-
user_agent:
|
|
33
|
-
proxy:
|
|
34
|
-
general_timeout_in_sec:
|
|
35
|
-
cookies:
|
|
36
|
-
headers:
|
|
37
|
-
http_credentials:
|
|
38
|
-
geolocation:
|
|
39
|
-
timezone_id:
|
|
40
|
-
locale:
|
|
41
|
-
color_scheme:
|
|
42
|
-
viewport:
|
|
43
|
-
referer:
|
|
44
|
-
|
|
45
|
-
listing:
|
|
46
|
-
auto_report:
|
|
28
|
+
url: str | None
|
|
29
|
+
document_name: str | None
|
|
30
|
+
document: str | None
|
|
31
|
+
browser: str | None
|
|
32
|
+
device_name: str | None
|
|
33
|
+
user_agent: str | None
|
|
34
|
+
proxy: str | dict[str, str] | None
|
|
35
|
+
general_timeout_in_sec: int | None
|
|
36
|
+
cookies: list[dict[str, Any]] | None
|
|
37
|
+
headers: str | dict[str, str] | None
|
|
38
|
+
http_credentials: dict[str, int] | None
|
|
39
|
+
geolocation: dict[str, float] | None
|
|
40
|
+
timezone_id: str | None
|
|
41
|
+
locale: str | None
|
|
42
|
+
color_scheme: str | None
|
|
43
|
+
viewport: dict[str, int] | None
|
|
44
|
+
referer: str | None
|
|
45
|
+
|
|
46
|
+
listing: bool | None
|
|
47
|
+
auto_report: bool | dict[str, str] | None
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
class CompareSettings(TypedDict, total=False):
|
|
50
51
|
'''The settings that can be passed to the compare method on lookyloo side to filter out some differences'''
|
|
51
52
|
|
|
52
|
-
ressources_ignore_domains:
|
|
53
|
-
ressources_ignore_regexes:
|
|
53
|
+
ressources_ignore_domains: list[str] | None
|
|
54
|
+
ressources_ignore_regexes: list[str] | None
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
class Lookyloo():
|
|
57
58
|
|
|
58
|
-
def __init__(self, root_url: str='https://lookyloo.circl.lu/', useragent:
|
|
59
|
-
*, proxies:
|
|
59
|
+
def __init__(self, root_url: str='https://lookyloo.circl.lu/', useragent: str | None=None,
|
|
60
|
+
*, proxies: dict[str, str] | None=None):
|
|
60
61
|
'''Query a specific lookyloo instance.
|
|
61
62
|
|
|
62
63
|
:param root_url: URL of the instance to query.
|
|
@@ -73,7 +74,7 @@ class Lookyloo():
|
|
|
73
74
|
self.session.headers['user-agent'] = useragent if useragent else f'PyLookyloo / {version("pylookyloo")}'
|
|
74
75
|
if proxies:
|
|
75
76
|
self.session.proxies.update(proxies)
|
|
76
|
-
self.apikey:
|
|
77
|
+
self.apikey: str | None = None
|
|
77
78
|
|
|
78
79
|
@property
|
|
79
80
|
def is_up(self) -> bool:
|
|
@@ -84,34 +85,34 @@ class Lookyloo():
|
|
|
84
85
|
return False
|
|
85
86
|
return r.status_code == 200
|
|
86
87
|
|
|
87
|
-
def get_status(self, tree_uuid: str) ->
|
|
88
|
+
def get_status(self, tree_uuid: str) -> dict[str, Any]:
|
|
88
89
|
'''Get the status of a capture:
|
|
89
90
|
* -1: Unknown capture.
|
|
90
91
|
* 0: The capture is queued up but not processed yet.
|
|
91
92
|
* 1: The capture is ready.
|
|
92
93
|
* 2: The capture is ongoing and will be ready soon.
|
|
93
94
|
'''
|
|
94
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
95
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'status'))))
|
|
95
96
|
return r.json()
|
|
96
97
|
|
|
97
|
-
def get_capture_stats(self, tree_uuid: str) ->
|
|
98
|
+
def get_capture_stats(self, tree_uuid: str) -> dict[str, Any]:
|
|
98
99
|
'''Get statistics of the capture'''
|
|
99
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
100
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'stats'))))
|
|
100
101
|
return r.json()
|
|
101
102
|
|
|
102
|
-
def get_info(self, tree_uuid: str) ->
|
|
103
|
+
def get_info(self, tree_uuid: str) -> dict[str, Any]:
|
|
103
104
|
'''Get information about the capture (url, timestamp, user agent)'''
|
|
104
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
105
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'info'))))
|
|
105
106
|
return r.json()
|
|
106
107
|
|
|
107
|
-
def get_comparables(self, tree_uuid: str) ->
|
|
108
|
+
def get_comparables(self, tree_uuid: str) -> dict[str, Any]:
|
|
108
109
|
'''Get comparable information from the capture'''
|
|
109
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
110
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'comparables'))))
|
|
110
111
|
return r.json()
|
|
111
112
|
|
|
112
|
-
def enqueue(self, url:
|
|
113
|
-
document:
|
|
114
|
-
document_name:
|
|
113
|
+
def enqueue(self, url: str | None=None, quiet: bool=False, # type: ignore[no-untyped-def]
|
|
114
|
+
document: Path | BytesIO | None=None,
|
|
115
|
+
document_name: str | None=None, **kwargs) -> str:
|
|
115
116
|
'''Enqueue an URL.
|
|
116
117
|
|
|
117
118
|
:param url: URL to enqueue
|
|
@@ -126,50 +127,50 @@ class Lookyloo():
|
|
|
126
127
|
|
|
127
128
|
@overload
|
|
128
129
|
def submit(self, *, quiet: bool=False,
|
|
129
|
-
capture_settings:
|
|
130
|
+
capture_settings: CaptureSettings | None=None) -> str:
|
|
130
131
|
...
|
|
131
132
|
|
|
132
133
|
@overload
|
|
133
134
|
def submit(self, *, quiet: bool=False,
|
|
134
|
-
url:
|
|
135
|
-
document_name:
|
|
136
|
-
browser:
|
|
137
|
-
user_agent:
|
|
138
|
-
proxy:
|
|
139
|
-
general_timeout_in_sec:
|
|
140
|
-
cookies:
|
|
141
|
-
headers:
|
|
142
|
-
http_credentials:
|
|
143
|
-
geolocation:
|
|
144
|
-
timezone_id:
|
|
145
|
-
locale:
|
|
146
|
-
color_scheme:
|
|
147
|
-
viewport:
|
|
148
|
-
referer:
|
|
149
|
-
listing:
|
|
150
|
-
auto_report:
|
|
135
|
+
url: str | None=None,
|
|
136
|
+
document_name: str | None=None, document: Path | BytesIO | None=None,
|
|
137
|
+
browser: str | None=None, device_name: str | None=None,
|
|
138
|
+
user_agent: str | None=None,
|
|
139
|
+
proxy: str | dict[str, str] | None=None,
|
|
140
|
+
general_timeout_in_sec: int | None=None,
|
|
141
|
+
cookies: list[dict[str, Any]] | None=None,
|
|
142
|
+
headers: str | dict[str, str] | None=None,
|
|
143
|
+
http_credentials: dict[str, int] | None=None,
|
|
144
|
+
geolocation: dict[str, float] | None=None,
|
|
145
|
+
timezone_id: str | None=None,
|
|
146
|
+
locale: str | None=None,
|
|
147
|
+
color_scheme: str | None=None,
|
|
148
|
+
viewport: dict[str, int] | None=None,
|
|
149
|
+
referer: str | None=None,
|
|
150
|
+
listing: bool | None=None,
|
|
151
|
+
auto_report: bool | dict[str, str] | None=None
|
|
151
152
|
) -> str:
|
|
152
153
|
...
|
|
153
154
|
|
|
154
155
|
def submit(self, *, quiet: bool=False,
|
|
155
|
-
capture_settings:
|
|
156
|
-
url:
|
|
157
|
-
document_name:
|
|
158
|
-
browser:
|
|
159
|
-
user_agent:
|
|
160
|
-
proxy:
|
|
161
|
-
general_timeout_in_sec:
|
|
162
|
-
cookies:
|
|
163
|
-
headers:
|
|
164
|
-
http_credentials:
|
|
165
|
-
geolocation:
|
|
166
|
-
timezone_id:
|
|
167
|
-
locale:
|
|
168
|
-
color_scheme:
|
|
169
|
-
viewport:
|
|
170
|
-
referer:
|
|
171
|
-
listing:
|
|
172
|
-
auto_report:
|
|
156
|
+
capture_settings: CaptureSettings | None=None,
|
|
157
|
+
url: str | None=None,
|
|
158
|
+
document_name: str | None=None, document: Path | BytesIO | None=None,
|
|
159
|
+
browser: str | None=None, device_name: str | None=None,
|
|
160
|
+
user_agent: str | None=None,
|
|
161
|
+
proxy: str | dict[str, str] | None=None,
|
|
162
|
+
general_timeout_in_sec: int | None=None,
|
|
163
|
+
cookies: list[dict[str, Any]] | None=None,
|
|
164
|
+
headers: str | dict[str, str] | None=None,
|
|
165
|
+
http_credentials: dict[str, int] | None=None,
|
|
166
|
+
geolocation: dict[str, float] | None=None,
|
|
167
|
+
timezone_id: str | None=None,
|
|
168
|
+
locale: str | None=None,
|
|
169
|
+
color_scheme: str | None=None,
|
|
170
|
+
viewport: dict[str, int] | None=None,
|
|
171
|
+
referer: str | None=None,
|
|
172
|
+
listing: bool | None=None,
|
|
173
|
+
auto_report: bool | dict[str, str] | None=None
|
|
173
174
|
) -> str:
|
|
174
175
|
'''Submit a URL to a lookyloo instance.
|
|
175
176
|
|
|
@@ -261,13 +262,13 @@ class Lookyloo():
|
|
|
261
262
|
return uuid
|
|
262
263
|
return urljoin(self.root_url, f'tree/{uuid}')
|
|
263
264
|
|
|
264
|
-
def get_apikey(self, username: str, password: str) ->
|
|
265
|
+
def get_apikey(self, username: str, password: str) -> dict[str, str]:
|
|
265
266
|
'''Get the API key for the given user.'''
|
|
266
267
|
to_post = {'username': username, 'password': password}
|
|
267
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
268
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'get_token'))), json=to_post)
|
|
268
269
|
return r.json()
|
|
269
270
|
|
|
270
|
-
def init_apikey(self, username:
|
|
271
|
+
def init_apikey(self, username: str | None=None, password: str | None=None, apikey: str | None=None) -> None:
|
|
271
272
|
'''Init the API key for the current session. All the requests against lookyloo after this call will be authenticated.'''
|
|
272
273
|
if apikey:
|
|
273
274
|
self.apikey = apikey
|
|
@@ -282,65 +283,65 @@ class Lookyloo():
|
|
|
282
283
|
else:
|
|
283
284
|
raise AuthError('Unable to initialize API key')
|
|
284
285
|
|
|
285
|
-
def misp_export(self, tree_uuid: str) ->
|
|
286
|
+
def misp_export(self, tree_uuid: str) -> dict[str, Any]:
|
|
286
287
|
'''Export the capture in MISP format'''
|
|
287
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
288
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'misp_export'))))
|
|
288
289
|
return r.json()
|
|
289
290
|
|
|
290
|
-
def misp_push(self, tree_uuid: str) ->
|
|
291
|
+
def misp_push(self, tree_uuid: str) -> dict[str, Any] | list[dict[str, Any]]:
|
|
291
292
|
'''Push the capture to a pre-configured MISP instance (requires an authenticated user, use init_apikey first)
|
|
292
293
|
Note: if the response is a dict, it is an error mesage. If it is a list, it's a list of MISP event.
|
|
293
294
|
'''
|
|
294
295
|
if not self.apikey:
|
|
295
296
|
raise AuthError('You need to initialize the apikey to use this method (see init_apikey)')
|
|
296
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
297
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'misp_push'))))
|
|
297
298
|
return r.json()
|
|
298
299
|
|
|
299
|
-
def trigger_modules(self, tree_uuid: str, force: bool=False) ->
|
|
300
|
+
def trigger_modules(self, tree_uuid: str, force: bool=False) -> dict[str, Any]:
|
|
300
301
|
'''Trigger all the available 3rd party modules on the given capture.
|
|
301
302
|
:param force: Trigger the modules even if they were already triggered today.
|
|
302
303
|
'''
|
|
303
304
|
to_send = {'force': force}
|
|
304
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
305
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'trigger_modules'))),
|
|
305
306
|
json=to_send)
|
|
306
307
|
return r.json()
|
|
307
308
|
|
|
308
|
-
def rebuild_capture(self, tree_uuid: str) ->
|
|
309
|
+
def rebuild_capture(self, tree_uuid: str) -> dict[str, str]:
|
|
309
310
|
'''Force rebuild a capture (requires an authenticated user, use init_apikey first)'''
|
|
310
311
|
if not self.apikey:
|
|
311
312
|
raise AuthError('You need to initialize the apikey to use this method (see init_apikey)')
|
|
312
|
-
r = self.session.
|
|
313
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('admin', tree_uuid, 'rebuild'))))
|
|
313
314
|
return r.json()
|
|
314
315
|
|
|
315
|
-
def hide_capture(self, tree_uuid: str) ->
|
|
316
|
+
def hide_capture(self, tree_uuid: str) -> dict[str, str]:
|
|
316
317
|
'''Hide a capture from the index page (requires an authenticated user, use init_apikey first)'''
|
|
317
318
|
if not self.apikey:
|
|
318
319
|
raise AuthError('You need to initialize the apikey to use this method (see init_apikey)')
|
|
319
|
-
r = self.session.
|
|
320
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('admin', tree_uuid, 'hide'))))
|
|
320
321
|
return r.json()
|
|
321
322
|
|
|
322
|
-
def get_redirects(self, capture_uuid: str) ->
|
|
323
|
+
def get_redirects(self, capture_uuid: str) -> dict[str, Any]:
|
|
323
324
|
'''Returns the initial redirects.
|
|
324
325
|
|
|
325
326
|
:param capture_uuid: UUID of the capture
|
|
326
327
|
'''
|
|
327
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
328
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', capture_uuid, 'redirects'))))
|
|
328
329
|
return r.json()
|
|
329
330
|
|
|
330
|
-
def get_urls(self, capture_uuid: str) ->
|
|
331
|
+
def get_urls(self, capture_uuid: str) -> dict[str, Any]:
|
|
331
332
|
'''Returns all the URLs seen during the capture.
|
|
332
333
|
|
|
333
334
|
:param capture_uuid: UUID of the capture
|
|
334
335
|
'''
|
|
335
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
336
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', capture_uuid, 'urls'))))
|
|
336
337
|
return r.json()
|
|
337
338
|
|
|
338
|
-
def get_hostnames(self, capture_uuid: str) ->
|
|
339
|
+
def get_hostnames(self, capture_uuid: str) -> dict[str, Any]:
|
|
339
340
|
'''Returns all the hostnames seen during the capture.
|
|
340
341
|
|
|
341
342
|
:param capture_uuid: UUID of the capture
|
|
342
343
|
'''
|
|
343
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
344
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', capture_uuid, 'hostnames'))))
|
|
344
345
|
return r.json()
|
|
345
346
|
|
|
346
347
|
def get_screenshot(self, capture_uuid: str) -> BytesIO:
|
|
@@ -348,7 +349,7 @@ class Lookyloo():
|
|
|
348
349
|
|
|
349
350
|
:param capture_uuid: UUID of the capture
|
|
350
351
|
'''
|
|
351
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
352
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('bin', capture_uuid, 'screenshot'))))
|
|
352
353
|
return BytesIO(r.content)
|
|
353
354
|
|
|
354
355
|
def get_data(self, capture_uuid: str) -> BytesIO:
|
|
@@ -356,15 +357,15 @@ class Lookyloo():
|
|
|
356
357
|
|
|
357
358
|
:param capture_uuid: UUID of the capture
|
|
358
359
|
'''
|
|
359
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
360
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('bin', capture_uuid, 'data'))))
|
|
360
361
|
return BytesIO(r.content)
|
|
361
362
|
|
|
362
|
-
def get_cookies(self, capture_uuid: str) ->
|
|
363
|
+
def get_cookies(self, capture_uuid: str) -> list[dict[str, str]]:
|
|
363
364
|
'''Returns the complete cookies jar.
|
|
364
365
|
|
|
365
366
|
:param capture_uuid: UUID of the capture
|
|
366
367
|
'''
|
|
367
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
368
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', capture_uuid, 'cookies'))))
|
|
368
369
|
return r.json()
|
|
369
370
|
|
|
370
371
|
def get_html(self, capture_uuid: str) -> StringIO:
|
|
@@ -372,7 +373,7 @@ class Lookyloo():
|
|
|
372
373
|
|
|
373
374
|
:param capture_uuid: UUID of the capture
|
|
374
375
|
'''
|
|
375
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
376
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('tree', capture_uuid, 'html'))))
|
|
376
377
|
return StringIO(r.text)
|
|
377
378
|
|
|
378
379
|
def get_hashes(self, capture_uuid: str, algorithm: str='sha512', hashes_only: bool=True) -> StringIO:
|
|
@@ -382,9 +383,9 @@ class Lookyloo():
|
|
|
382
383
|
:param algorithm: The algorithm of the hashes
|
|
383
384
|
:param hashes_only: If False, will also return the URLs related to the hashes
|
|
384
385
|
'''
|
|
385
|
-
params:
|
|
386
|
+
params: dict[str, str | int] = {'algorithm': algorithm, 'hashes_only': int(hashes_only)}
|
|
386
387
|
|
|
387
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
388
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', capture_uuid, 'hashes'))), params=params)
|
|
388
389
|
return r.json()
|
|
389
390
|
|
|
390
391
|
def get_complete_capture(self, capture_uuid: str) -> BytesIO:
|
|
@@ -392,29 +393,29 @@ class Lookyloo():
|
|
|
392
393
|
|
|
393
394
|
:param capture_uuid: UUID of the capture
|
|
394
395
|
'''
|
|
395
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
396
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('bin', capture_uuid, 'export'))))
|
|
396
397
|
return BytesIO(r.content)
|
|
397
398
|
|
|
398
|
-
def get_hash_occurrences(self, h: str) ->
|
|
399
|
+
def get_hash_occurrences(self, h: str) -> dict[str, Any]:
|
|
399
400
|
'''Returns the base 64 body related the the hash, and a list of all the captures containing that hash.
|
|
400
401
|
|
|
401
402
|
:param h: sha512 to search
|
|
402
403
|
'''
|
|
403
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
404
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', 'hash_info', h))))
|
|
404
405
|
return r.json()
|
|
405
406
|
|
|
406
|
-
def get_url_occurrences(self, url: str, limit: int=20, cached_captures_only: bool=True) ->
|
|
407
|
+
def get_url_occurrences(self, url: str, limit: int=20, cached_captures_only: bool=True) -> dict[str, Any]:
|
|
407
408
|
'''Returns all the captures contining the URL
|
|
408
409
|
|
|
409
410
|
:param url: URL to lookup
|
|
410
411
|
:param limit: The max amount of entries to return.
|
|
411
412
|
:param cached_captures_only: If False, Lookyloo will attempt to re-cache the missing captures. It might take some time.
|
|
412
413
|
'''
|
|
413
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
414
|
-
|
|
414
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'url_info'))),
|
|
415
|
+
json={'url': url, 'limit': limit})
|
|
415
416
|
return r.json()
|
|
416
417
|
|
|
417
|
-
def get_hostname_occurrences(self, hostname: str, with_urls_occurrences: bool=False, limit: int=20, cached_captures_only: bool=True) ->
|
|
418
|
+
def get_hostname_occurrences(self, hostname: str, with_urls_occurrences: bool=False, limit: int=20, cached_captures_only: bool=True) -> dict[str, Any]:
|
|
418
419
|
'''Returns all the captures contining the hostname. It will be pretty slow on very common domains.
|
|
419
420
|
|
|
420
421
|
:param hostname: Hostname to lookup
|
|
@@ -422,35 +423,49 @@ class Lookyloo():
|
|
|
422
423
|
:param limit: The max amount of entries to return.
|
|
423
424
|
:param cached_captures_only: If False, Lookyloo will attempt to re-cache the missing captures. It might take some time.
|
|
424
425
|
'''
|
|
425
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
426
|
-
|
|
427
|
-
'limit': limit})
|
|
426
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'hostname_info'))),
|
|
427
|
+
json={'hostname': hostname, 'with_urls_occurrences': with_urls_occurrences, 'limit': limit})
|
|
428
428
|
return r.json()
|
|
429
429
|
|
|
430
|
-
def get_stats(self) ->
|
|
430
|
+
def get_stats(self) -> dict[str, Any]:
|
|
431
431
|
'''Returns all the captures contining the URL'''
|
|
432
432
|
|
|
433
|
-
r = self.session.get(urljoin(self.root_url, str(
|
|
433
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', 'stats'))))
|
|
434
434
|
return r.json()
|
|
435
435
|
|
|
436
|
-
def get_takedown_information(self, capture_uuid: str) ->
|
|
436
|
+
def get_takedown_information(self, capture_uuid: str) -> dict[str, Any]:
|
|
437
437
|
'''Returns information required to request a takedown for a capture
|
|
438
438
|
|
|
439
439
|
:param capture_uuid: UUID of the capture
|
|
440
440
|
'''
|
|
441
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
441
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'takedown'))),
|
|
442
442
|
json={'capture_uuid': capture_uuid})
|
|
443
443
|
return r.json()
|
|
444
444
|
|
|
445
|
-
def compare_captures(self, capture_left: str, capture_right: str, /, *, compare_settings:
|
|
445
|
+
def compare_captures(self, capture_left: str, capture_right: str, /, *, compare_settings: CompareSettings | None=None) -> dict[str, Any]:
|
|
446
446
|
'''Compares two captures
|
|
447
447
|
|
|
448
448
|
:param capture_left: UUID of the capture to compare from
|
|
449
449
|
:param capture_right: UUID of the capture to compare to
|
|
450
450
|
:param compare_settings: The settings for the comparison itself (what to ignore without marking the captures as different)
|
|
451
451
|
'''
|
|
452
|
-
r = self.session.post(urljoin(self.root_url, str(
|
|
452
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', 'compare_captures'))),
|
|
453
453
|
json={'capture_left': capture_left,
|
|
454
454
|
'capture_right': capture_right,
|
|
455
455
|
'compare_settings': compare_settings})
|
|
456
456
|
return r.json()
|
|
457
|
+
|
|
458
|
+
def get_modules_responses(self, tree_uuid: str) -> dict[str, Any]:
|
|
459
|
+
'''Returns information from the 3rd party modules
|
|
460
|
+
|
|
461
|
+
:param capture_uuid: UUID of the capture
|
|
462
|
+
'''
|
|
463
|
+
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'modules'))))
|
|
464
|
+
return r.json()
|
|
465
|
+
|
|
466
|
+
def send_mail(self, tree_uuid: str, email: str = '', comment: str | None = None) -> bool | dict[str, Any]:
|
|
467
|
+
to_send = {'email': email}
|
|
468
|
+
if comment:
|
|
469
|
+
to_send['comment'] = comment
|
|
470
|
+
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('json', tree_uuid, 'report'))), json=to_send)
|
|
471
|
+
return r.json()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pylookyloo"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.24.0"
|
|
4
4
|
description = "Python CLI and module for Lookyloo"
|
|
5
5
|
authors = ["Raphaël Vinot <raphael.vinot@circl.lu>"]
|
|
6
6
|
license = "BSD-3-Clause"
|
|
@@ -38,14 +38,14 @@ Sphinx = [
|
|
|
38
38
|
]
|
|
39
39
|
|
|
40
40
|
[tool.poetry.group.dev.dependencies]
|
|
41
|
-
mypy = "^1.
|
|
42
|
-
types-requests = "^2.31.0.
|
|
41
|
+
mypy = "^1.9.0"
|
|
42
|
+
types-requests = "^2.31.0.20240311"
|
|
43
43
|
ipython = [
|
|
44
44
|
{version = "<8.13.0", python = "<3.9"},
|
|
45
45
|
{version = "^8.18.0", python = ">=3.9"},
|
|
46
46
|
{version = "^8.19.0", python = ">=3.10"}
|
|
47
47
|
]
|
|
48
|
-
pytest = "^8.
|
|
48
|
+
pytest = "^8.1.1"
|
|
49
49
|
|
|
50
50
|
[tool.poetry.extras]
|
|
51
51
|
docs = ["Sphinx"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|