vysion 2.1.6__tar.gz → 2.2.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.
- {vysion-2.1.6 → vysion-2.2.0}/PKG-INFO +2 -2
- {vysion-2.1.6 → vysion-2.2.0}/README.md +1 -1
- {vysion-2.1.6 → vysion-2.2.0}/pyproject.toml +3 -7
- {vysion-2.1.6 → vysion-2.2.0}/vysion/client/client.py +242 -4
- {vysion-2.1.6 → vysion-2.2.0}/vysion/dto/dto.py +51 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/version.py +1 -1
- {vysion-2.1.6 → vysion-2.2.0}/LICENSE +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/client/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/client/error.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/dto/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/dto/tag.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/dto/util.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/enum/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/enum/languages.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/enum/networks.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/enum/ransom_groups.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/model/enum/services.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/taxonomy/__init__.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/taxonomy/flavours.py +0 -0
- {vysion-2.1.6 → vysion-2.2.0}/vysion/taxonomy/taxonomy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vysion
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: The official Python client library for Vysion
|
|
5
5
|
Home-page: https://vysion.ai
|
|
6
6
|
License: Apache-2.0
|
|
@@ -29,7 +29,7 @@ Welcome to the PyPi webpage for Vysion, our implementation as a Python library t
|
|
|
29
29
|
|
|
30
30
|
You can request a demo for the web app or an API-key to use in this library at [vysion.ai](https://vysion.ai).
|
|
31
31
|
|
|
32
|
-
Latest version: [2.
|
|
32
|
+
Latest version: [2.2.0](https://pypi.org/project/vysion/)
|
|
33
33
|
|
|
34
34
|
You can visit [the documentation](https://developers.vysion.ai/?python) for more information on the searches and requests performed with the library or directly on the API.
|
|
35
35
|
|
|
@@ -4,7 +4,7 @@ Welcome to the PyPi webpage for Vysion, our implementation as a Python library t
|
|
|
4
4
|
|
|
5
5
|
You can request a demo for the web app or an API-key to use in this library at [vysion.ai](https://vysion.ai).
|
|
6
6
|
|
|
7
|
-
Latest version: [2.
|
|
7
|
+
Latest version: [2.2.0](https://pypi.org/project/vysion/)
|
|
8
8
|
|
|
9
9
|
You can visit [the documentation](https://developers.vysion.ai/?python) for more information on the searches and requests performed with the library or directly on the API.
|
|
10
10
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "vysion"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.2.0"
|
|
4
4
|
description = "The official Python client library for Vysion"
|
|
5
5
|
homepage = "https://vysion.ai"
|
|
6
6
|
repository = "https://github.com/ByronLabs/vysion-py"
|
|
@@ -25,18 +25,14 @@ softenum = "1.0.1"
|
|
|
25
25
|
requests = "^2.28.1"
|
|
26
26
|
pymisp = "^2.4.194"
|
|
27
27
|
|
|
28
|
-
[tool.poetry.dev
|
|
29
|
-
pytest = "
|
|
28
|
+
[tool.poetry.group.dev.dependencies]
|
|
29
|
+
pytest = "^8.3.2"
|
|
30
30
|
python-dotenv = "0.19.2"
|
|
31
|
-
|
|
32
31
|
flake8 = "4.0.1"
|
|
33
32
|
pyflakes = "2.4.0"
|
|
34
33
|
mypy = "^0.961"
|
|
35
34
|
black = "^24.3.0"
|
|
36
|
-
|
|
37
|
-
[tool.poetry.group.dev.dependencies]
|
|
38
35
|
ruff = "^0.5.2"
|
|
39
|
-
pytest = "^8.3.2"
|
|
40
36
|
|
|
41
37
|
[build-system]
|
|
42
38
|
requires = ["poetry-core>=1.0.0"]
|
|
@@ -38,6 +38,7 @@ from vysion.dto import (
|
|
|
38
38
|
ImMessageHit,
|
|
39
39
|
ImProfileHit,
|
|
40
40
|
ImServerHit,
|
|
41
|
+
LeakHit,
|
|
41
42
|
)
|
|
42
43
|
from vysion.version import __version__ as vysion_version
|
|
43
44
|
|
|
@@ -414,8 +415,7 @@ class Client(BaseClient):
|
|
|
414
415
|
page_size=page_size,
|
|
415
416
|
username=username,
|
|
416
417
|
)
|
|
417
|
-
|
|
418
|
-
|
|
418
|
+
|
|
419
419
|
result = VysionResponse[ImMessageHit].model_validate(self._make_request(url))
|
|
420
420
|
return result.data
|
|
421
421
|
|
|
@@ -438,7 +438,6 @@ class Client(BaseClient):
|
|
|
438
438
|
page=page,
|
|
439
439
|
page_size=page_size,
|
|
440
440
|
)
|
|
441
|
-
print(url)
|
|
442
441
|
|
|
443
442
|
result = VysionResponse[ImProfileHit].model_validate(self._make_request(url))
|
|
444
443
|
return result.data
|
|
@@ -462,7 +461,6 @@ class Client(BaseClient):
|
|
|
462
461
|
page=page,
|
|
463
462
|
page_size=page_size,
|
|
464
463
|
)
|
|
465
|
-
print(url)
|
|
466
464
|
|
|
467
465
|
result = VysionResponse[ImChannelHit].model_validate(self._make_request(url))
|
|
468
466
|
return result.data
|
|
@@ -559,6 +557,246 @@ class Client(BaseClient):
|
|
|
559
557
|
return result.data
|
|
560
558
|
|
|
561
559
|
|
|
560
|
+
#
|
|
561
|
+
# Leak search methods
|
|
562
|
+
#
|
|
563
|
+
|
|
564
|
+
@vysion_error_manager
|
|
565
|
+
def get_leak_by_email(
|
|
566
|
+
self,
|
|
567
|
+
email: str,
|
|
568
|
+
page: int = 1,
|
|
569
|
+
page_size: int = 50,
|
|
570
|
+
gte: datetime = None,
|
|
571
|
+
lte: datetime = None,
|
|
572
|
+
) -> VysionResponse[LeakHit]:
|
|
573
|
+
"""
|
|
574
|
+
Search for leaks containing a specific email address.
|
|
575
|
+
|
|
576
|
+
:param email: Email address to search for
|
|
577
|
+
:param page: Page number (default: 1)
|
|
578
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
579
|
+
:param gte: Start date filter (optional)
|
|
580
|
+
:param lte: End date filter (optional)
|
|
581
|
+
:return: VysionResponse containing LeakHit objects
|
|
582
|
+
"""
|
|
583
|
+
url = self._build_api_url__(
|
|
584
|
+
f"leak/email/{email}",
|
|
585
|
+
page=page,
|
|
586
|
+
page_size=page_size,
|
|
587
|
+
gte=gte,
|
|
588
|
+
lte=lte,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
592
|
+
return result.data
|
|
593
|
+
|
|
594
|
+
@vysion_error_manager
|
|
595
|
+
def get_leak_by_wallet(
|
|
596
|
+
self,
|
|
597
|
+
chain: str,
|
|
598
|
+
address: str,
|
|
599
|
+
page: int = 1,
|
|
600
|
+
page_size: int = 50,
|
|
601
|
+
gte: datetime = None,
|
|
602
|
+
lte: datetime = None,
|
|
603
|
+
) -> VysionResponse[LeakHit]:
|
|
604
|
+
"""
|
|
605
|
+
Search for leaks containing a cryptocurrency wallet address.
|
|
606
|
+
|
|
607
|
+
:param chain: Blockchain (btc, eth, xmr, xrp, zec, dot, bnb, dash)
|
|
608
|
+
:param address: Wallet address
|
|
609
|
+
:param page: Page number (default: 1)
|
|
610
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
611
|
+
:param gte: Start date filter (optional)
|
|
612
|
+
:param lte: End date filter (optional)
|
|
613
|
+
:return: VysionResponse containing LeakHit objects
|
|
614
|
+
"""
|
|
615
|
+
url = self._build_api_url__(
|
|
616
|
+
f"leak/wallet/{chain}/{address}",
|
|
617
|
+
page=page,
|
|
618
|
+
page_size=page_size,
|
|
619
|
+
gte=gte,
|
|
620
|
+
lte=lte,
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
624
|
+
return result.data
|
|
625
|
+
|
|
626
|
+
@vysion_error_manager
|
|
627
|
+
def get_leak_by_ip(
|
|
628
|
+
self,
|
|
629
|
+
ip_address: str,
|
|
630
|
+
page: int = 1,
|
|
631
|
+
page_size: int = 50,
|
|
632
|
+
gte: datetime = None,
|
|
633
|
+
lte: datetime = None,
|
|
634
|
+
) -> VysionResponse[LeakHit]:
|
|
635
|
+
"""
|
|
636
|
+
Search for leaks containing an IP address (IPv4 or IPv6).
|
|
637
|
+
|
|
638
|
+
:param ip_address: IP address to search for
|
|
639
|
+
:param page: Page number (default: 1)
|
|
640
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
641
|
+
:param gte: Start date filter (optional)
|
|
642
|
+
:param lte: End date filter (optional)
|
|
643
|
+
:return: VysionResponse containing LeakHit objects
|
|
644
|
+
"""
|
|
645
|
+
url = self._build_api_url__(
|
|
646
|
+
f"leak/ip/{ip_address}",
|
|
647
|
+
page=page,
|
|
648
|
+
page_size=page_size,
|
|
649
|
+
gte=gte,
|
|
650
|
+
lte=lte,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
654
|
+
return result.data
|
|
655
|
+
|
|
656
|
+
@vysion_error_manager
|
|
657
|
+
def get_leak_by_phone(
|
|
658
|
+
self,
|
|
659
|
+
country_code: str,
|
|
660
|
+
number: str,
|
|
661
|
+
page: int = 1,
|
|
662
|
+
page_size: int = 50,
|
|
663
|
+
gte: datetime = None,
|
|
664
|
+
lte: datetime = None,
|
|
665
|
+
) -> VysionResponse[LeakHit]:
|
|
666
|
+
"""
|
|
667
|
+
Search for leaks containing a phone number.
|
|
668
|
+
|
|
669
|
+
:param country_code: Country code (e.g., "1" for US, "34" for Spain)
|
|
670
|
+
:param number: Phone number without country code
|
|
671
|
+
:param page: Page number (default: 1)
|
|
672
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
673
|
+
:param gte: Start date filter (optional)
|
|
674
|
+
:param lte: End date filter (optional)
|
|
675
|
+
:return: VysionResponse containing LeakHit objects
|
|
676
|
+
"""
|
|
677
|
+
url = self._build_api_url__(
|
|
678
|
+
f"leak/phone/{country_code}/{number}",
|
|
679
|
+
page=page,
|
|
680
|
+
page_size=page_size,
|
|
681
|
+
gte=gte,
|
|
682
|
+
lte=lte,
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
686
|
+
return result.data
|
|
687
|
+
|
|
688
|
+
@vysion_error_manager
|
|
689
|
+
def get_leak_by_username(
|
|
690
|
+
self,
|
|
691
|
+
username: str,
|
|
692
|
+
page: int = 1,
|
|
693
|
+
page_size: int = 50,
|
|
694
|
+
gte: datetime = None,
|
|
695
|
+
lte: datetime = None,
|
|
696
|
+
) -> VysionResponse[LeakHit]:
|
|
697
|
+
"""
|
|
698
|
+
Search for leaks containing a specific username.
|
|
699
|
+
|
|
700
|
+
:param username: Username to search for
|
|
701
|
+
:param page: Page number (default: 1)
|
|
702
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
703
|
+
:param gte: Start date filter (optional)
|
|
704
|
+
:param lte: End date filter (optional)
|
|
705
|
+
:return: VysionResponse containing LeakHit objects
|
|
706
|
+
"""
|
|
707
|
+
url = self._build_api_url__(
|
|
708
|
+
f"leak/username/{username}",
|
|
709
|
+
page=page,
|
|
710
|
+
page_size=page_size,
|
|
711
|
+
gte=gte,
|
|
712
|
+
lte=lte,
|
|
713
|
+
)
|
|
714
|
+
|
|
715
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
716
|
+
return result.data
|
|
717
|
+
|
|
718
|
+
@vysion_error_manager
|
|
719
|
+
def get_leak_by_hash(
|
|
720
|
+
self,
|
|
721
|
+
hash_value: str,
|
|
722
|
+
page: int = 1,
|
|
723
|
+
page_size: int = 50,
|
|
724
|
+
gte: datetime = None,
|
|
725
|
+
lte: datetime = None,
|
|
726
|
+
) -> VysionResponse[LeakHit]:
|
|
727
|
+
"""
|
|
728
|
+
Search for leaks by file hash (SHA256, SHA1, or MD5).
|
|
729
|
+
Hash type is auto-detected based on length.
|
|
730
|
+
|
|
731
|
+
:param hash_value: File hash (32, 40, or 64 hex characters)
|
|
732
|
+
:param page: Page number (default: 1)
|
|
733
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
734
|
+
:param gte: Start date filter (optional)
|
|
735
|
+
:param lte: End date filter (optional)
|
|
736
|
+
:return: VysionResponse containing LeakHit objects
|
|
737
|
+
"""
|
|
738
|
+
url = self._build_api_url__(
|
|
739
|
+
f"leak/hash/{hash_value}",
|
|
740
|
+
page=page,
|
|
741
|
+
page_size=page_size,
|
|
742
|
+
gte=gte,
|
|
743
|
+
lte=lte,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
747
|
+
return result.data
|
|
748
|
+
|
|
749
|
+
@vysion_error_manager
|
|
750
|
+
def search_leaks(
|
|
751
|
+
self,
|
|
752
|
+
q: str,
|
|
753
|
+
page: int = 1,
|
|
754
|
+
page_size: int = 50,
|
|
755
|
+
gte: datetime = None,
|
|
756
|
+
lte: datetime = None,
|
|
757
|
+
) -> VysionResponse[LeakHit]:
|
|
758
|
+
"""
|
|
759
|
+
Generic search across all leak content and metadata fields.
|
|
760
|
+
|
|
761
|
+
:param q: Search query (minimum 3 characters)
|
|
762
|
+
:param page: Page number (default: 1)
|
|
763
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
764
|
+
:param gte: Start date filter (optional)
|
|
765
|
+
:param lte: End date filter (optional)
|
|
766
|
+
:return: VysionResponse containing LeakHit objects with highlights
|
|
767
|
+
"""
|
|
768
|
+
url = self._build_api_url__(
|
|
769
|
+
"leak/search",
|
|
770
|
+
q=q,
|
|
771
|
+
page=page,
|
|
772
|
+
page_size=page_size,
|
|
773
|
+
gte=gte,
|
|
774
|
+
lte=lte,
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
778
|
+
return result.data
|
|
779
|
+
|
|
780
|
+
@vysion_error_manager
|
|
781
|
+
def get_leak_by_id(
|
|
782
|
+
self,
|
|
783
|
+
leak_id: str,
|
|
784
|
+
) -> VysionResponse[LeakHit]:
|
|
785
|
+
"""
|
|
786
|
+
Retrieve a single leak document by its Elasticsearch ID.
|
|
787
|
+
Includes downloadUrl if available from linked Telegram message.
|
|
788
|
+
|
|
789
|
+
:param leak_id: Elasticsearch document ID
|
|
790
|
+
:return: VysionResponse containing a single LeakHit object
|
|
791
|
+
"""
|
|
792
|
+
url = self._build_api_url__(
|
|
793
|
+
f"leak/{leak_id}",
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
797
|
+
return result.data
|
|
798
|
+
|
|
799
|
+
|
|
562
800
|
#
|
|
563
801
|
# FEEDS
|
|
564
802
|
#
|
|
@@ -478,6 +478,57 @@ class ImServerHit(BaseModel):
|
|
|
478
478
|
raise ValueError("creationDate field cannot be empty")
|
|
479
479
|
return v
|
|
480
480
|
|
|
481
|
+
class LeakHit(BaseModel):
|
|
482
|
+
"""
|
|
483
|
+
Represents a leak document from telegram-leaks-* indices.
|
|
484
|
+
Contains file metadata and detected sensitive information.
|
|
485
|
+
"""
|
|
486
|
+
# Core identification
|
|
487
|
+
id: str
|
|
488
|
+
detectionDate: datetime
|
|
489
|
+
|
|
490
|
+
# File metadata
|
|
491
|
+
filePath: Optional[str] = Field(default_factory=lambda: None)
|
|
492
|
+
fileHash: Optional[str] = Field(default_factory=lambda: None) # SHA256, SHA1, or MD5
|
|
493
|
+
fileSize: Optional[int] = Field(default_factory=lambda: None)
|
|
494
|
+
fileType: Optional[str] = Field(default_factory=lambda: None)
|
|
495
|
+
detectedMimeType: Optional[str] = Field(default_factory=lambda: None)
|
|
496
|
+
decompressedFilename: Optional[str] = Field(default_factory=lambda: None)
|
|
497
|
+
|
|
498
|
+
# Archive metadata (if leak came from archive file)
|
|
499
|
+
archiveSource: Optional[str] = Field(default_factory=lambda: None)
|
|
500
|
+
archiveMemberPath: Optional[str] = Field(default_factory=lambda: None)
|
|
501
|
+
|
|
502
|
+
# Telegram source metadata
|
|
503
|
+
telegram: Optional[dict] = Field(default_factory=lambda: None) # Contains channel_id, message_id, etc.
|
|
504
|
+
|
|
505
|
+
# Detected sensitive information (enrichment data)
|
|
506
|
+
detectedInfo: Optional[dict] = Field(default_factory=lambda: None)
|
|
507
|
+
# detectedInfo contains: emails, usernames, phone_numbers, ipv4_addresses, ipv6_addresses,
|
|
508
|
+
# btc_wallets, eth_wallets, xmr_wallets, xrp_wallets, zec_wallets, dot_wallets, bnb_wallets, dash_wallets
|
|
509
|
+
|
|
510
|
+
# Language detection
|
|
511
|
+
language: Optional[str] = Field(default_factory=lambda: None)
|
|
512
|
+
languages: Optional[List[LanguagePair]] = Field(default_factory=lambda: None)
|
|
513
|
+
|
|
514
|
+
# Parse status
|
|
515
|
+
parseStatus: Optional[str] = Field(default_factory=lambda: None)
|
|
516
|
+
|
|
517
|
+
# Download URL (only present for /leak/{id} endpoint)
|
|
518
|
+
downloadUrl: Optional[str] = Field(default_factory=lambda: None)
|
|
519
|
+
|
|
520
|
+
# Search highlights (only present for search endpoints)
|
|
521
|
+
highlight: Optional[dict] = Field(default_factory=lambda: None)
|
|
522
|
+
|
|
523
|
+
model_config = ConfigDict(exclude_defaults=True)
|
|
524
|
+
|
|
525
|
+
@field_validator("detectionDate")
|
|
526
|
+
def validate_detectionDate(cls, v: datetime) -> datetime:
|
|
527
|
+
if not v:
|
|
528
|
+
raise ValueError("detectionDate field cannot be empty")
|
|
529
|
+
return v
|
|
530
|
+
|
|
531
|
+
|
|
481
532
|
class ImFeedHit(BaseModel):
|
|
482
533
|
id: str
|
|
483
534
|
telegram: List[str]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|