Skip to content

Commit 633ff50

Browse files
committed
feat: Added in support for number-based date representations
1 parent fae73ec commit 633ff50

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

src/macaron/malware_analyzer/pypi_heuristics/metadata/anomalistic_version.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class AnomalisticVersionAnalyzer(BaseHeuristicAnalyzer):
3737
"""
3838

3939
DETAIL_INFO_KEY: str = "versioning"
40+
DIGIT_DATE_FORMATS: list[str] = ["%Y%m%d", "%Y%d%m", "%d%m%Y", "%m%d%Y", "%y%m%d", "%y%d%m", "%d%m%y", "%m%d%y"]
4041

4142
def __init__(self) -> None:
4243
super().__init__(
@@ -146,10 +147,11 @@ def analyze(self, pypi_package_json: PyPIPackageJsonAsset) -> tuple[HeuristicRes
146147
calendar = True
147148
else:
148149
calendar_semantic = True
149-
# check for calendar versioning: M[M].D[D].YY[YY]... or D[D].M[M].YY[YY]...
150+
# check for calendar versioning: M[M].D[D].YY[YY]... or D[D].M[M].YY[YY]... or the whole digit rerpesenting a datetime
150151
elif (
151-
(version.major in months and version.minor in days) or (version.major in days and version.minor in months)
152-
) and version.micro in years:
152+
((version.major in months and version.minor in days) or (version.major in days and version.minor in months))
153+
and version.micro in years
154+
) or self.__integer_date(version.major, years, months, days):
153155
# must include day and year for this to be calendar
154156
calendar = True
155157

@@ -180,6 +182,16 @@ def analyze(self, pypi_package_json: PyPIPackageJsonAsset) -> tuple[HeuristicRes
180182

181183
return HeuristicResult.PASS, detail_info
182184

185+
def __integer_date(self, value: int, years: list[int], months: list[int], days: list[int]) -> bool:
186+
for date_format in self.DIGIT_DATE_FORMATS:
187+
if (date := parse_datetime(str(value), date_format)) is None:
188+
continue
189+
190+
if date.year in years and date.month in months and date.day in days:
191+
return True
192+
193+
return False
194+
183195

184196
class Versioning(Enum):
185197
"""Enum used to assign different versioning methods."""

tests/malware_analyzer/pypi/test_anomalistic_version.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,58 @@ def test_analyze_no_information(pypi_package_json: MagicMock) -> None:
6767
pytest.param(
6868
"16.10.16", "2016-10-13", HeuristicResult.PASS, Versioning.CALENDAR.value, id="test_calendar_MM.DD.YY_pass"
6969
),
70+
pytest.param(
71+
"20161011.0",
72+
"2016-10-13",
73+
HeuristicResult.PASS,
74+
Versioning.CALENDAR.value,
75+
id="test_calendar_YYYYMMDD_pass",
76+
),
77+
pytest.param(
78+
"20161210.6.1",
79+
"2016-10-13",
80+
HeuristicResult.PASS,
81+
Versioning.CALENDAR.value,
82+
id="test_calendar_YYYYDDMM_pass",
83+
),
84+
pytest.param(
85+
"161013.9.0.5",
86+
"2016-10-13",
87+
HeuristicResult.PASS,
88+
Versioning.CALENDAR.value,
89+
id="test_calendar_YYDDMM_pass",
90+
),
91+
pytest.param(
92+
"161410.2.5.7",
93+
"2016-10-13",
94+
HeuristicResult.PASS,
95+
Versioning.CALENDAR.value,
96+
id="test_calendar_YYMMDD_pass",
97+
),
98+
pytest.param(
99+
"10102016.0",
100+
"2016-10-13",
101+
HeuristicResult.PASS,
102+
Versioning.CALENDAR.value,
103+
id="test_calendar_MMDDYYYY_pass",
104+
),
105+
pytest.param(
106+
"09102016",
107+
"2016-10-13",
108+
HeuristicResult.PASS,
109+
Versioning.CALENDAR.value,
110+
id="test_calendar_DDMMYYYY_pass",
111+
),
112+
pytest.param(
113+
"101516.5.7", "2016-10-13", HeuristicResult.PASS, Versioning.CALENDAR.value, id="test_calendar_DDMMYY_pass"
114+
),
115+
pytest.param(
116+
"161016.0.0.0.0",
117+
"2016-10-13",
118+
HeuristicResult.PASS,
119+
Versioning.CALENDAR.value,
120+
id="test_calendar_MMDDYY_pass",
121+
),
70122
pytest.param(
71123
"2!16.10.17.2.5.3",
72124
"2016-10-13",

0 commit comments

Comments
 (0)