Skip to content

Commit d839923

Browse files
Merge pull request #38 from MislavReversingLabs/main
v2.5.0
2 parents 741227c + 9d29087 commit d839923

File tree

15 files changed

+245
-140
lines changed

15 files changed

+245
-140
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ jobs:
2222
pip install pytest requests
2323
- name: Test with pytest
2424
run: |
25-
pytest
25+
pytest

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ __pycache__/
66

77
.vscode/
88
.DS_Store
9+
10+
*.pyc
11+
.pytest_cache
12+
.coverage
13+
.idea

CHANGELOG.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,20 @@ v2.4.3 (2024-02-07)
210210
-------------------
211211

212212
#### Improvements
213-
214213
- Python package dependencies are now set to the following values:
215214
- `requests>=2.28.2`
216215
- `urllib3>=1.26.14`
217216

218217

218+
v2.5.0 (2024-03-29)
219+
-------------------
219220

220-
### Scheduled removals
221-
- **March 2024.**:
222-
- `a1000.A1000.advanced_search_v2`
221+
#### Removals
222+
- **a1000** module:
223+
- Removed the `a1000.A1000.advanced_search_v2` method.
224+
225+
#### Improvements
226+
- Added unit tests.
227+
- Added CI/CD (Actions) workflows for running unit tests and publishing the package to PyPI.
228+
- **ticloud** module:
229+
- `md5` and `sha256` can now be used in `DynamicAnalysis.get_dynamic_analysis_results` for fetching sample analysis results.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
![ReversingLabs](https://raw.githubusercontent.com/reversinglabs/reversinglabs-sdk-py3/master/logo.png)
22

3-
# ReversingLabsSDK
3+
# ReversingLabs SDK
44

5-
A Python SDK for ReversingLabs REST services (TitaniumCloud and appliances) - Python 3 version.
5+
The official Python SDK for using ReversingLabs services.
66

77
The idea behind this SDK is to enable easier out-of-the-box development of software integrations and automation services that need to interact with ReversingLabs.
88

99
The SDK consists of several modules, where each module represents either one ReversingLabs service, ReversingLabs appliance or the ReversingLabs TitaniumCloud.
1010

11+
> **ReversingLabs SDK Cookbook**
12+
For a simple and comprehensive guide on how to start using the ReversingLabs SDK, visit the [ReversingLabs SDK Cookbook](https://github.com/reversinglabs/reversinglabs-sdk-cookbook)
13+
> and explore the provided steps and examples.
1114
1215
## Module: a1000
1316
A Python module representing the ReversingLabs A1000 malware analysis platform.

ReversingLabs/SDK/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
author: Mislav Sever
3+
4+
ReversingLabs SDK
5+
A Python SDK for communicating with ReversingLabs services.
6+
"""
7+
8+
__version__ = "2.5.0"

ReversingLabs/SDK/a1000.py

Lines changed: 1 addition & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import requests
1010
import time
1111
from urllib import parse
12-
from warnings import warn
1312

1413
from ReversingLabs.SDK.helper import ADVANCED_SEARCH_SORTING_CRITERIA, DEFAULT_USER_AGENT, RESPONSE_CODE_ERROR_MAP, \
1514
MD5, SHA1, SHA256, SHA512, \
@@ -1560,131 +1559,6 @@ def get_yara_cloud_retro_scan_status(self, ruleset_name):
15601559

15611560
return response
15621561

1563-
def advanced_search_v2(self, query_string, ticloud=False, page_number=1, records_per_page=20, sorting_criteria=None,
1564-
sorting_order="desc"):
1565-
"""THIS METHOD IS DEPRECATED. Use advanced_search_v3 instead.
1566-
1567-
Sends a query string to the A1000 Advanced Search API v2.
1568-
The query string must be composed of key-value pairs separated by space.
1569-
A key is separated from its value by a colon symbol and no spaces.
1570-
For directions on how to write advanced search queries, consult the A1000 documentation.
1571-
If a page number is not provided, the first page of results will be returned.
1572-
Query string example:
1573-
'av-count:5 available:TRUE'
1574-
1575-
:param query_string: query string
1576-
:type query_string: str
1577-
:param ticloud: show only cloud results
1578-
:type ticloud: bool
1579-
:param page_number: page number
1580-
:type page_number: int
1581-
:param records_per_page: number of records returned per page; maximum value is 100
1582-
:type records_per_page: int
1583-
:param sorting_criteria: define the criteria used in sorting; possible values are 'sha1', 'firstseen',
1584-
'threatname', 'sampletype', 'filecount', 'size'
1585-
:type sorting_criteria: str
1586-
:param sorting_order: sorting order; possible values are 'desc', 'asc'
1587-
:type sorting_order: str
1588-
:return: response
1589-
:rtype: requests.Response
1590-
"""
1591-
warn("This method is deprecated. Use advanced_search_v3 instead.", DeprecationWarning)
1592-
1593-
if not isinstance(query_string, str):
1594-
raise WrongInputError("The search query must be a string.")
1595-
1596-
if not isinstance(ticloud, bool):
1597-
raise WrongInputError("ticloud parameter must be boolean.")
1598-
1599-
if not isinstance(records_per_page, int) or not 1 <= records_per_page <= 100:
1600-
raise WrongInputError("records_per_page parameter must be an integer with a value "
1601-
"between 1 and 100 (included).")
1602-
1603-
url = self._url.format(endpoint=self.__ADVANCED_SEARCH_ENDPOINT_V2)
1604-
1605-
post_json = {"query": query_string, "ticloud": ticloud, "page": page_number,
1606-
"records_per_page": records_per_page}
1607-
1608-
if sorting_criteria:
1609-
if sorting_criteria not in ADVANCED_SEARCH_SORTING_CRITERIA or sorting_order not in ("desc", "asc"):
1610-
raise WrongInputError("Sorting criteria must be one of the following options: {criteria}. "
1611-
"Sorting order needs to be 'desc' or 'asc'.".format(
1612-
criteria=ADVANCED_SEARCH_SORTING_CRITERIA
1613-
))
1614-
sorting_expression = "{criteria} {order}".format(
1615-
criteria=sorting_criteria,
1616-
order=sorting_order
1617-
)
1618-
1619-
post_json["sort"] = sorting_expression
1620-
1621-
response = self.__post_request(url=url, post_json=post_json)
1622-
1623-
self.__raise_on_error(response)
1624-
1625-
return response
1626-
1627-
def advanced_search_v2_aggregated(self, query_string, ticloud=False, max_results=5000, sorting_criteria=None,
1628-
sorting_order="desc"):
1629-
"""THIS METHOD IS DEPRECATED. Use advanced_search_v3_aggregated instead.
1630-
1631-
Sends a query string to the A1000 Advanced Search API v2.
1632-
The query string must be composed of key-value pairs separated by space.
1633-
A key is separated from its value by a colon symbol and no spaces.
1634-
For directions on how to write advanced search queries, consult the A1000 documentation.
1635-
Paging is done automatically and results from individual
1636-
responses aggregated into one list and returned`.
1637-
The 'max_results' parameter defines the maximum desired number of results to be returned.
1638-
Query string example:
1639-
'av-count:5 available:TRUE'
1640-
1641-
:param query_string: search query - see API documentation for details on writing search queries
1642-
:type query_string: str
1643-
:param ticloud: show only cloud results
1644-
:type ticloud: bool
1645-
:param max_results: maximum results to be returned in a list; default value is 5000
1646-
:type max_results: int
1647-
:param sorting_criteria: define the criteria used in sorting; possible values are 'sha1', 'firstseen',
1648-
'threatname', 'sampletype', 'filecount', 'size'
1649-
:type sorting_criteria: str
1650-
:param sorting_order: sorting order; possible values are 'desc', 'asc'
1651-
:type sorting_order: str
1652-
:return: list of results
1653-
:rtype: list
1654-
"""
1655-
warn("This method is deprecated. Use advanced_search_v3_aggregated instead.", DeprecationWarning)
1656-
1657-
if not isinstance(max_results, int):
1658-
raise WrongInputError("max_results parameter must be integer.")
1659-
1660-
results = []
1661-
next_page = 1
1662-
more_pages = True
1663-
1664-
while more_pages:
1665-
response = self.advanced_search_v2(
1666-
query_string=query_string,
1667-
ticloud=ticloud,
1668-
page_number=next_page,
1669-
records_per_page=100,
1670-
sorting_criteria=sorting_criteria,
1671-
sorting_order=sorting_order
1672-
)
1673-
1674-
response_json = response.json()
1675-
1676-
entries = response_json.get("rl").get("web_search_api").get("entries", [])
1677-
results.extend(entries)
1678-
1679-
if len(results) > max_results:
1680-
results = results[:max_results]
1681-
return results
1682-
1683-
next_page = response_json.get("rl").get("web_search_api").get("next_page", None)
1684-
more_pages = response_json.get("rl").get("web_search_api").get("more_pages", False)
1685-
1686-
return results
1687-
16881562
def advanced_search_v3(self, query_string, ticloud=False, start_search_date=None, end_search_date=None,
16891563
page_number=1, records_per_page=20, sorting_criteria=None, sorting_order="desc"):
16901564
"""Sends a query string to the A1000 Advanced Search API v3.
@@ -2437,4 +2311,4 @@ def __raise_on_error(response):
24372311
exception = RESPONSE_CODE_ERROR_MAP.get(response.status_code, None)
24382312
if not exception:
24392313
return
2440-
raise exception
2314+
raise exception(response_object=response)

ReversingLabs/SDK/helper.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import codecs
99
import binascii
1010
from http import HTTPStatus
11+
from ReversingLabs.SDK import __version__
1112

1213

1314
MD5 = "md5"
@@ -22,7 +23,7 @@
2223
128: SHA512
2324
}
2425

25-
DEFAULT_USER_AGENT = "ReversingLabs SDK v2.4.3"
26+
DEFAULT_USER_AGENT = f"ReversingLabs SDK v{__version__}"
2627
ADVANCED_SEARCH_SORTING_CRITERIA = ("sha1", "firstseen", "threatname", "sampletype", "filecount", "size")
2728

2829

ReversingLabs/SDK/ticloud.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,8 +3127,8 @@ class DynamicAnalysis(TiCloudAPI):
31273127

31283128
__DETONATE_ENDPOINT = "/api/dynamic/analysis/analyze/v1/query/json"
31293129
__DETONATE_ARCHIVE_ENDPOINT = "/api/dynamic/analysis/analyze/v1/archive/query/json"
3130-
__GET_FILE_RESULTS = "/api/dynamic/analysis/report/v1/query/sha1"
3131-
__GET_ARCHIVE_RESULTS_ENDPOINT = "/api/dynamic/analysis/report/v1/archive/query/sha1"
3130+
__GET_FILE_RESULTS = "/api/dynamic/analysis/report/v1/query/{hash_type}"
3131+
__GET_ARCHIVE_RESULTS_ENDPOINT = "/api/dynamic/analysis/report/v1/archive/query/{hash_type}"
31323132
__GET_URL_RESULTS_BASE64 = "/api/dynamic/analysis/report/v1/query/url/base64"
31333133
__GET_URL_RESULTS_SHA1 = "/api/dynamic/analysis/report/v1/query/url/sha1"
31343134

@@ -3261,7 +3261,7 @@ def get_dynamic_analysis_results(self, sample_hash=None, url=None, url_sha1=None
32613261
if sample_hash:
32623262
validate_hashes(
32633263
hash_input=[sample_hash],
3264-
allowed_hash_types=(SHA1,)
3264+
allowed_hash_types=(SHA1, MD5, SHA256)
32653265
)
32663266
indicator = sample_hash
32673267

@@ -3271,6 +3271,9 @@ def get_dynamic_analysis_results(self, sample_hash=None, url=None, url_sha1=None
32713271
else:
32723272
endpoint_base = self.__GET_ARCHIVE_RESULTS_ENDPOINT
32733273

3274+
hashing_algorithm = HASH_LENGTH_MAP.get(len(sample_hash))
3275+
endpoint_base = endpoint_base.format(hash_type=hashing_algorithm)
3276+
32743277
elif url:
32753278
if not isinstance(url, str):
32763279
raise WrongInputError("url parameter must be a string")

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[metadata]
22
license_files = LICENSE
3+
4+
[aliases]
5+
test=pytest

setup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from setuptools import setup
2+
from ReversingLabs.SDK import __version__
23

34

45
requires = ["requests>=2.28.2", "urllib3>=1.26.14"]
@@ -11,8 +12,8 @@
1112

1213
setup(
1314
name="reversinglabs-sdk-py3",
14-
version="2.4.3",
15-
description="Python SDK for using ReversingLabs services - Python 3 version.",
15+
version=__version__,
16+
description="Python SDK for using ReversingLabs services.",
1617
long_description=long_description,
1718
long_description_content_type="text/markdown",
1819
author="ReversingLabs",
@@ -21,6 +22,7 @@
2122
packages=packages,
2223
python_requires=">=3.6",
2324
install_requires=requires,
25+
extras_require={"test": ["pytest"]},
2426
license="MIT",
2527
zip_safe=False,
2628
classifiers=[

0 commit comments

Comments
 (0)