vysion 2.1.7__tar.gz → 2.2.1__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.7 → vysion-2.2.1}/PKG-INFO +2 -2
- {vysion-2.1.7 → vysion-2.2.1}/README.md +1 -1
- {vysion-2.1.7 → vysion-2.2.1}/pyproject.toml +3 -7
- {vysion-2.1.7 → vysion-2.2.1}/vysion/client/client.py +255 -5
- {vysion-2.1.7 → vysion-2.2.1}/vysion/dto/dto.py +57 -1
- {vysion-2.1.7 → vysion-2.2.1}/vysion/version.py +1 -1
- {vysion-2.1.7 → vysion-2.2.1}/LICENSE +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/client/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/client/error.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/dto/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/dto/tag.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/dto/util.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/enum/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/enum/languages.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/enum/networks.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/enum/ransom_groups.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/model/enum/services.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/taxonomy/__init__.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/taxonomy/flavours.py +0 -0
- {vysion-2.1.7 → vysion-2.2.1}/vysion/taxonomy/taxonomy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vysion
|
|
3
|
-
Version: 2.1
|
|
3
|
+
Version: 2.2.1
|
|
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.1
|
|
32
|
+
Latest version: [2.2.1](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.1
|
|
7
|
+
Latest version: [2.2.1](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.1
|
|
3
|
+
version = "2.2.1"
|
|
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,8 @@ from vysion.dto import (
|
|
|
38
38
|
ImMessageHit,
|
|
39
39
|
ImProfileHit,
|
|
40
40
|
ImServerHit,
|
|
41
|
+
LeakHit,
|
|
42
|
+
ImChatMessages,
|
|
41
43
|
)
|
|
42
44
|
from vysion.version import __version__ as vysion_version
|
|
43
45
|
|
|
@@ -509,14 +511,22 @@ class Client(BaseClient):
|
|
|
509
511
|
|
|
510
512
|
|
|
511
513
|
@vysion_error_manager
|
|
512
|
-
def
|
|
513
|
-
self,
|
|
514
|
-
|
|
514
|
+
def get_im_chat_messages(
|
|
515
|
+
self,
|
|
516
|
+
platform: str,
|
|
517
|
+
channelId: str,
|
|
518
|
+
messageId: str | None,
|
|
519
|
+
cursor: str | None,
|
|
520
|
+
limit: str = 30
|
|
521
|
+
) -> ImChatMessages:
|
|
515
522
|
url = self._build_api_url__(
|
|
516
|
-
"im/" + platform + "/chat/" + channelId,
|
|
523
|
+
"im/" + platform + "/chat/" + channelId,
|
|
524
|
+
messageId=messageId,
|
|
525
|
+
cursor=cursor,
|
|
526
|
+
limit=limit
|
|
517
527
|
)
|
|
518
528
|
|
|
519
|
-
result = VysionResponse[
|
|
529
|
+
result = VysionResponse[ImChatMessages].model_validate(self._make_request(url))
|
|
520
530
|
return result.data
|
|
521
531
|
|
|
522
532
|
@vysion_error_manager
|
|
@@ -556,6 +566,246 @@ class Client(BaseClient):
|
|
|
556
566
|
return result.data
|
|
557
567
|
|
|
558
568
|
|
|
569
|
+
#
|
|
570
|
+
# Leak search methods
|
|
571
|
+
#
|
|
572
|
+
|
|
573
|
+
@vysion_error_manager
|
|
574
|
+
def get_leak_by_email(
|
|
575
|
+
self,
|
|
576
|
+
email: str,
|
|
577
|
+
page: int = 1,
|
|
578
|
+
page_size: int = 50,
|
|
579
|
+
gte: datetime = None,
|
|
580
|
+
lte: datetime = None,
|
|
581
|
+
) -> VysionResponse[LeakHit]:
|
|
582
|
+
"""
|
|
583
|
+
Search for leaks containing a specific email address.
|
|
584
|
+
|
|
585
|
+
:param email: Email address to search for
|
|
586
|
+
:param page: Page number (default: 1)
|
|
587
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
588
|
+
:param gte: Start date filter (optional)
|
|
589
|
+
:param lte: End date filter (optional)
|
|
590
|
+
:return: VysionResponse containing LeakHit objects
|
|
591
|
+
"""
|
|
592
|
+
url = self._build_api_url__(
|
|
593
|
+
f"leak/email/{email}",
|
|
594
|
+
page=page,
|
|
595
|
+
page_size=page_size,
|
|
596
|
+
gte=gte,
|
|
597
|
+
lte=lte,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
601
|
+
return result.data
|
|
602
|
+
|
|
603
|
+
@vysion_error_manager
|
|
604
|
+
def get_leak_by_wallet(
|
|
605
|
+
self,
|
|
606
|
+
chain: str,
|
|
607
|
+
address: str,
|
|
608
|
+
page: int = 1,
|
|
609
|
+
page_size: int = 50,
|
|
610
|
+
gte: datetime = None,
|
|
611
|
+
lte: datetime = None,
|
|
612
|
+
) -> VysionResponse[LeakHit]:
|
|
613
|
+
"""
|
|
614
|
+
Search for leaks containing a cryptocurrency wallet address.
|
|
615
|
+
|
|
616
|
+
:param chain: Blockchain (btc, eth, xmr, xrp, zec, dot, bnb, dash)
|
|
617
|
+
:param address: Wallet address
|
|
618
|
+
:param page: Page number (default: 1)
|
|
619
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
620
|
+
:param gte: Start date filter (optional)
|
|
621
|
+
:param lte: End date filter (optional)
|
|
622
|
+
:return: VysionResponse containing LeakHit objects
|
|
623
|
+
"""
|
|
624
|
+
url = self._build_api_url__(
|
|
625
|
+
f"leak/wallet/{chain}/{address}",
|
|
626
|
+
page=page,
|
|
627
|
+
page_size=page_size,
|
|
628
|
+
gte=gte,
|
|
629
|
+
lte=lte,
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
633
|
+
return result.data
|
|
634
|
+
|
|
635
|
+
@vysion_error_manager
|
|
636
|
+
def get_leak_by_ip(
|
|
637
|
+
self,
|
|
638
|
+
ip_address: str,
|
|
639
|
+
page: int = 1,
|
|
640
|
+
page_size: int = 50,
|
|
641
|
+
gte: datetime = None,
|
|
642
|
+
lte: datetime = None,
|
|
643
|
+
) -> VysionResponse[LeakHit]:
|
|
644
|
+
"""
|
|
645
|
+
Search for leaks containing an IP address (IPv4 or IPv6).
|
|
646
|
+
|
|
647
|
+
:param ip_address: IP address to search for
|
|
648
|
+
:param page: Page number (default: 1)
|
|
649
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
650
|
+
:param gte: Start date filter (optional)
|
|
651
|
+
:param lte: End date filter (optional)
|
|
652
|
+
:return: VysionResponse containing LeakHit objects
|
|
653
|
+
"""
|
|
654
|
+
url = self._build_api_url__(
|
|
655
|
+
f"leak/ip/{ip_address}",
|
|
656
|
+
page=page,
|
|
657
|
+
page_size=page_size,
|
|
658
|
+
gte=gte,
|
|
659
|
+
lte=lte,
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
663
|
+
return result.data
|
|
664
|
+
|
|
665
|
+
@vysion_error_manager
|
|
666
|
+
def get_leak_by_phone(
|
|
667
|
+
self,
|
|
668
|
+
country_code: str,
|
|
669
|
+
number: str,
|
|
670
|
+
page: int = 1,
|
|
671
|
+
page_size: int = 50,
|
|
672
|
+
gte: datetime = None,
|
|
673
|
+
lte: datetime = None,
|
|
674
|
+
) -> VysionResponse[LeakHit]:
|
|
675
|
+
"""
|
|
676
|
+
Search for leaks containing a phone number.
|
|
677
|
+
|
|
678
|
+
:param country_code: Country code (e.g., "1" for US, "34" for Spain)
|
|
679
|
+
:param number: Phone number without country code
|
|
680
|
+
:param page: Page number (default: 1)
|
|
681
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
682
|
+
:param gte: Start date filter (optional)
|
|
683
|
+
:param lte: End date filter (optional)
|
|
684
|
+
:return: VysionResponse containing LeakHit objects
|
|
685
|
+
"""
|
|
686
|
+
url = self._build_api_url__(
|
|
687
|
+
f"leak/phone/{country_code}/{number}",
|
|
688
|
+
page=page,
|
|
689
|
+
page_size=page_size,
|
|
690
|
+
gte=gte,
|
|
691
|
+
lte=lte,
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
695
|
+
return result.data
|
|
696
|
+
|
|
697
|
+
@vysion_error_manager
|
|
698
|
+
def get_leak_by_username(
|
|
699
|
+
self,
|
|
700
|
+
username: str,
|
|
701
|
+
page: int = 1,
|
|
702
|
+
page_size: int = 50,
|
|
703
|
+
gte: datetime = None,
|
|
704
|
+
lte: datetime = None,
|
|
705
|
+
) -> VysionResponse[LeakHit]:
|
|
706
|
+
"""
|
|
707
|
+
Search for leaks containing a specific username.
|
|
708
|
+
|
|
709
|
+
:param username: Username to search for
|
|
710
|
+
:param page: Page number (default: 1)
|
|
711
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
712
|
+
:param gte: Start date filter (optional)
|
|
713
|
+
:param lte: End date filter (optional)
|
|
714
|
+
:return: VysionResponse containing LeakHit objects
|
|
715
|
+
"""
|
|
716
|
+
url = self._build_api_url__(
|
|
717
|
+
f"leak/username/{username}",
|
|
718
|
+
page=page,
|
|
719
|
+
page_size=page_size,
|
|
720
|
+
gte=gte,
|
|
721
|
+
lte=lte,
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
725
|
+
return result.data
|
|
726
|
+
|
|
727
|
+
@vysion_error_manager
|
|
728
|
+
def get_leak_by_hash(
|
|
729
|
+
self,
|
|
730
|
+
hash_value: str,
|
|
731
|
+
page: int = 1,
|
|
732
|
+
page_size: int = 50,
|
|
733
|
+
gte: datetime = None,
|
|
734
|
+
lte: datetime = None,
|
|
735
|
+
) -> VysionResponse[LeakHit]:
|
|
736
|
+
"""
|
|
737
|
+
Search for leaks by file hash (SHA256, SHA1, or MD5).
|
|
738
|
+
Hash type is auto-detected based on length.
|
|
739
|
+
|
|
740
|
+
:param hash_value: File hash (32, 40, or 64 hex characters)
|
|
741
|
+
:param page: Page number (default: 1)
|
|
742
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
743
|
+
:param gte: Start date filter (optional)
|
|
744
|
+
:param lte: End date filter (optional)
|
|
745
|
+
:return: VysionResponse containing LeakHit objects
|
|
746
|
+
"""
|
|
747
|
+
url = self._build_api_url__(
|
|
748
|
+
f"leak/hash/{hash_value}",
|
|
749
|
+
page=page,
|
|
750
|
+
page_size=page_size,
|
|
751
|
+
gte=gte,
|
|
752
|
+
lte=lte,
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
756
|
+
return result.data
|
|
757
|
+
|
|
758
|
+
@vysion_error_manager
|
|
759
|
+
def search_leaks(
|
|
760
|
+
self,
|
|
761
|
+
q: str,
|
|
762
|
+
page: int = 1,
|
|
763
|
+
page_size: int = 50,
|
|
764
|
+
gte: datetime = None,
|
|
765
|
+
lte: datetime = None,
|
|
766
|
+
) -> VysionResponse[LeakHit]:
|
|
767
|
+
"""
|
|
768
|
+
Generic search across all leak content and metadata fields.
|
|
769
|
+
|
|
770
|
+
:param q: Search query (minimum 3 characters)
|
|
771
|
+
:param page: Page number (default: 1)
|
|
772
|
+
:param page_size: Results per page (default: 50, max: 100)
|
|
773
|
+
:param gte: Start date filter (optional)
|
|
774
|
+
:param lte: End date filter (optional)
|
|
775
|
+
:return: VysionResponse containing LeakHit objects with highlights
|
|
776
|
+
"""
|
|
777
|
+
url = self._build_api_url__(
|
|
778
|
+
"leak/search",
|
|
779
|
+
q=q,
|
|
780
|
+
page=page,
|
|
781
|
+
page_size=page_size,
|
|
782
|
+
gte=gte,
|
|
783
|
+
lte=lte,
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
787
|
+
return result.data
|
|
788
|
+
|
|
789
|
+
@vysion_error_manager
|
|
790
|
+
def get_leak_by_id(
|
|
791
|
+
self,
|
|
792
|
+
leak_id: str,
|
|
793
|
+
) -> VysionResponse[LeakHit]:
|
|
794
|
+
"""
|
|
795
|
+
Retrieve a single leak document by its Elasticsearch ID.
|
|
796
|
+
Includes downloadUrl if available from linked Telegram message.
|
|
797
|
+
|
|
798
|
+
:param leak_id: Elasticsearch document ID
|
|
799
|
+
:return: VysionResponse containing a single LeakHit object
|
|
800
|
+
"""
|
|
801
|
+
url = self._build_api_url__(
|
|
802
|
+
f"leak/{leak_id}",
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
result = VysionResponse[LeakHit].model_validate(self._make_request(url))
|
|
806
|
+
return result.data
|
|
807
|
+
|
|
808
|
+
|
|
559
809
|
#
|
|
560
810
|
# FEEDS
|
|
561
811
|
#
|
|
@@ -412,6 +412,12 @@ class ImProfileHit(BaseModel):
|
|
|
412
412
|
return v
|
|
413
413
|
|
|
414
414
|
|
|
415
|
+
class ImChatMessages(BaseModel):
|
|
416
|
+
messages: List[ImMessageHit]
|
|
417
|
+
prev_cursor: Optional[str] = None
|
|
418
|
+
next_cursor: Optional[str] = None
|
|
419
|
+
|
|
420
|
+
|
|
415
421
|
class ImChannelHit(BaseModel):
|
|
416
422
|
channelId: Union[int, str]
|
|
417
423
|
channelTitles: Optional[List[str]] = Field(default_factory=lambda: None)
|
|
@@ -478,6 +484,57 @@ class ImServerHit(BaseModel):
|
|
|
478
484
|
raise ValueError("creationDate field cannot be empty")
|
|
479
485
|
return v
|
|
480
486
|
|
|
487
|
+
class LeakHit(BaseModel):
|
|
488
|
+
"""
|
|
489
|
+
Represents a leak document from telegram-leaks-* indices.
|
|
490
|
+
Contains file metadata and detected sensitive information.
|
|
491
|
+
"""
|
|
492
|
+
# Core identification
|
|
493
|
+
id: str
|
|
494
|
+
detectionDate: datetime
|
|
495
|
+
|
|
496
|
+
# File metadata
|
|
497
|
+
filePath: Optional[str] = Field(default_factory=lambda: None)
|
|
498
|
+
fileHash: Optional[str] = Field(default_factory=lambda: None) # SHA256, SHA1, or MD5
|
|
499
|
+
fileSize: Optional[int] = Field(default_factory=lambda: None)
|
|
500
|
+
fileType: Optional[str] = Field(default_factory=lambda: None)
|
|
501
|
+
detectedMimeType: Optional[str] = Field(default_factory=lambda: None)
|
|
502
|
+
decompressedFilename: Optional[str] = Field(default_factory=lambda: None)
|
|
503
|
+
|
|
504
|
+
# Archive metadata (if leak came from archive file)
|
|
505
|
+
archiveSource: Optional[str] = Field(default_factory=lambda: None)
|
|
506
|
+
archiveMemberPath: Optional[str] = Field(default_factory=lambda: None)
|
|
507
|
+
|
|
508
|
+
# Telegram source metadata
|
|
509
|
+
telegram: Optional[dict] = Field(default_factory=lambda: None) # Contains channel_id, message_id, etc.
|
|
510
|
+
|
|
511
|
+
# Detected sensitive information (enrichment data)
|
|
512
|
+
detectedInfo: Optional[dict] = Field(default_factory=lambda: None)
|
|
513
|
+
# detectedInfo contains: emails, usernames, phone_numbers, ipv4_addresses, ipv6_addresses,
|
|
514
|
+
# btc_wallets, eth_wallets, xmr_wallets, xrp_wallets, zec_wallets, dot_wallets, bnb_wallets, dash_wallets
|
|
515
|
+
|
|
516
|
+
# Language detection
|
|
517
|
+
language: Optional[str] = Field(default_factory=lambda: None)
|
|
518
|
+
languages: Optional[List[LanguagePair]] = Field(default_factory=lambda: None)
|
|
519
|
+
|
|
520
|
+
# Parse status
|
|
521
|
+
parseStatus: Optional[str] = Field(default_factory=lambda: None)
|
|
522
|
+
|
|
523
|
+
# Download URL (only present for /leak/{id} endpoint)
|
|
524
|
+
downloadUrl: Optional[str] = Field(default_factory=lambda: None)
|
|
525
|
+
|
|
526
|
+
# Search highlights (only present for search endpoints)
|
|
527
|
+
highlight: Optional[dict] = Field(default_factory=lambda: None)
|
|
528
|
+
|
|
529
|
+
model_config = ConfigDict(exclude_defaults=True)
|
|
530
|
+
|
|
531
|
+
@field_validator("detectionDate")
|
|
532
|
+
def validate_detectionDate(cls, v: datetime) -> datetime:
|
|
533
|
+
if not v:
|
|
534
|
+
raise ValueError("detectionDate field cannot be empty")
|
|
535
|
+
return v
|
|
536
|
+
|
|
537
|
+
|
|
481
538
|
class ImFeedHit(BaseModel):
|
|
482
539
|
id: str
|
|
483
540
|
telegram: List[str]
|
|
@@ -499,7 +556,6 @@ class CryptoFeedHit(BaseModel):
|
|
|
499
556
|
id: str
|
|
500
557
|
url: str
|
|
501
558
|
detectionDate: datetime
|
|
502
|
-
url: str
|
|
503
559
|
network: str
|
|
504
560
|
title: Optional[str] = Field(default_factory=lambda: None)
|
|
505
561
|
tag: List[Tag] = Field(default_factory=lambda: [])
|
|
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
|