Skip to content

Commit 4ccf805

Browse files
committed
Fix: Stricter TFT version string validation in parser and tft_ver_gte
#98 (comment) #98 (comment)
1 parent 33b3286 commit 4ccf805

File tree

3 files changed

+31
-17
lines changed

3 files changed

+31
-17
lines changed

components/nspanel_easy/versioning.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,31 @@ bool tft_ver_gte(const std::string &version, const std::string &min_version) {
3434
int min_maj = 0, min_min = 0;
3535

3636
// Parse both version strings — accept "major.minor" or bare "major".
37-
// sscanf returns the number of fields successfully parsed; at least 1
38-
// is required. A bare integer (e.g. "16") yields 1 field with minor
39-
// defaulting to 0. An empty or non-numeric string yields 0, triggering
40-
// the < 1 guard below. NOLINT suppresses cert-err34-c; malformed input
41-
// is handled by the field count check.
37+
// After parsing, reject trailing garbage by checking that sscanf consumed
38+
// the entire string: re-format what was parsed and compare against input.
39+
// This rejects "16.", "16x", "16.1.2", etc.
40+
// NOLINT suppresses cert-err34-c; structural validation is done below.
4241
const int ver_fields = sscanf(version.c_str(), "%d.%d", &ver_maj, &ver_min); // NOLINT(cert-err34-c)
4342
const int min_fields = sscanf(min_version.c_str(), "%d.%d", &min_maj, &min_min); // NOLINT(cert-err34-c)
4443

4544
if (ver_fields < 1 || min_fields < 1)
4645
return false; // Fail conservatively on empty or unparseable input
4746

47+
// Reject partial matches by reconstructing the parsed value and comparing
48+
// it against the original string — catches "16.", "16x", "16.1.2", etc.
49+
char ver_buf[16], min_buf[16];
50+
if (ver_fields == 1)
51+
snprintf(ver_buf, sizeof(ver_buf), "%d", ver_maj);
52+
else
53+
snprintf(ver_buf, sizeof(ver_buf), "%d.%d", ver_maj, ver_min);
54+
if (min_fields == 1)
55+
snprintf(min_buf, sizeof(min_buf), "%d", min_maj);
56+
else
57+
snprintf(min_buf, sizeof(min_buf), "%d.%d", min_maj, min_min);
58+
59+
if (version != ver_buf || min_version != min_buf)
60+
return false; // Trailing garbage or extra segments detected
61+
4862
// Compare major first, then minor.
4963
// Returns false conservatively on any older segment.
5064
if (ver_maj != min_maj)

esphome/nspanel_esphome_page_boot.yaml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ script:
6767
display_mode = atoi(params[2].c_str());
6868
display_charset = atoi(params[3].c_str());
6969
70-
// Validate TFT version string — must be non-empty and match "major[.minor]" format
70+
// Validate TFT version string — must be bare "major" or "major.minor",
71+
// with both sides non-empty and no more than one dot.
7172
const std::string &ver_str = params[4];
72-
bool tft_ver_valid = !ver_str.empty();
73-
if (tft_ver_valid) {
74-
for (const char c : ver_str) {
75-
if (c != '.' && (c < '0' || c > '9')) {
76-
tft_ver_valid = false;
77-
break;
78-
}
79-
}
80-
}
73+
const size_t dot = ver_str.find('.');
74+
const bool tft_ver_valid =
75+
!ver_str.empty() &&
76+
ver_str.find_first_not_of("0123456789.") == std::string::npos && // digits and dot only
77+
(dot == std::string::npos || // bare integer, no dot
78+
(dot != 0 && // dot not at start
79+
dot != ver_str.size() - 1 && // dot not at end
80+
ver_str.find('.', dot + 1) == std::string::npos)); // no second dot
8181
version_tft->publish_state(tft_ver_valid ? ver_str : "");
8282
8383
ESP_LOGI("${TAG_PAGE_BOOT}", "Display params:");

nspanel_easy_blueprint.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
##################################################################################################
77
---
88
blueprint:
9-
name: NSPanel Easy Configuration (v2026.4.6)
9+
name: NSPanel Easy Configuration (v9999.99.9)
1010
author: Edward Firmo (https://github.com/edwardtfn)
1111
description: >
1212
# NSPanel Easy Configuration via Blueprint
@@ -4044,7 +4044,7 @@ trigger_variables:
40444044
}}
40454045

40464046
variables:
4047-
blueprint_version: 2026.4.6
4047+
blueprint_version: 9999.99.9
40484048
pages:
40494049
current: '{{ states(currentpage) }}'
40504050
alarm: "alarm"

0 commit comments

Comments
 (0)