Skip to content

Commit 71ad0d9

Browse files
Copilotwillmmiles
andcommitted
Address final review feedback: improve error handling, remove debug duplication, use HTTP API for release name
Co-authored-by: willmmiles <6540455+willmmiles@users.noreply.github.com>
1 parent 70e8be6 commit 71ad0d9

File tree

6 files changed

+53
-54
lines changed

6 files changed

+53
-54
lines changed

pio-scripts/build_ui.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,7 @@
1313
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
1414
env.Execute("npm ci")
1515

16-
# Extract the release name from build flags
17-
release_name = None # Let cdata.js provide the default if not found
18-
build_flags = env.get("BUILD_FLAGS", [])
19-
for flag in build_flags:
20-
if 'WLED_RELEASE_NAME=' in flag:
21-
# Extract the release name, remove quotes and handle different formats
22-
parts = flag.split('WLED_RELEASE_NAME=')
23-
if len(parts) > 1:
24-
release_name = parts[1].split()[0].strip('\"\\')
25-
break
26-
27-
# Set environment variable for cdata.js to use (only if found)
28-
if release_name:
29-
os.environ['WLED_RELEASE_NAME'] = release_name
30-
print(f'Building web UI with release name: {release_name}')
31-
else:
32-
print('Building web UI with default release name (from cdata.js)')
16+
print('Building web UI')
3317

3418
# Call the bundling script
3519
exitCode = env.Execute("npm run build")

tools/cdata.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,6 @@ function adoptVersionAndRepo(html) {
9696
html = html.replaceAll("##VERSION##", version);
9797
}
9898

99-
// Replace ##RELEASE## with the actual release name from build environment
100-
const releaseName = process.env.WLED_RELEASE_NAME || 'Custom';
101-
html = html.replaceAll("##RELEASE##", releaseName);
102-
10399
return html;
104100
}
105101

wled00/data/update.htm

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,27 @@
1717
}
1818
window.open(getURL("/update?revert"),"_self");
1919
}
20-
function GetV() {/*injected values here*/}
20+
function GetV() {
21+
// Fetch device info via JSON API instead of compiling it in
22+
fetch('/json/info')
23+
.then(response => response.json())
24+
.then(data => {
25+
if (data.release) {
26+
var releaseSpan = document.querySelector('.release-name');
27+
if (releaseSpan) {
28+
releaseSpan.textContent = data.release;
29+
}
30+
}
31+
})
32+
.catch(error => {
33+
console.log('Could not fetch device info:', error);
34+
// Fallback to compiled-in value if API call fails
35+
var releaseSpan = document.querySelector('.release-name');
36+
if (releaseSpan && releaseSpan.textContent === 'Loading...') {
37+
releaseSpan.textContent = 'Unknown';
38+
}
39+
});
40+
}
2141
</script>
2242
<style>
2343
@import url("style.css");
@@ -28,7 +48,7 @@
2848
<h2>WLED Software Update</h2>
2949
<form method='POST' action='./update' id='upd' enctype='multipart/form-data' onsubmit="toggle('upd')">
3050
Installed version: <span class="sip">WLED ##VERSION##</span><br>
31-
Release: <span class="sip">##RELEASE##</span><br>
51+
Release: <span class="sip release-name">Loading...</span><br>
3252
Download the latest binary: <a href="https://github.com/wled-dev/WLED/releases" target="_blank"
3353
style="vertical-align: text-bottom; display: inline-flex;">
3454
<img src="https://img.shields.io/github/release/wled-dev/WLED.svg?style=flat-square"></a><br>

wled00/ota_release_check.cpp

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ bool extractWledCustomDesc(const uint8_t* binaryData, size_t dataSize, wled_cust
1313

1414
// Search in first 8KB only. This range was chosen because:
1515
// - ESP32 .rodata.wled_desc sections appear early in the binary (typically within first 2-4KB)
16-
// - ESP8266 .ver_number sections also appear early (typically within first 1-2KB)
16+
// - ESP8266 .ver_number sections also appear early (typically within first 1-2KB)
1717
// - 8KB provides ample coverage for metadata discovery while minimizing processing time
1818
// - Larger firmware files (>1MB) would take significantly longer to process with full search
19-
// - Real-world testing shows all valid metadata appears well within this range
19+
// - Analysis of typical WLED binary layouts shows metadata appears well within this range
2020
const size_t search_limit = min(dataSize, (size_t)8192);
2121

2222
for (size_t offset = 0; offset <= search_limit - sizeof(wled_custom_desc_t); offset++) {
@@ -41,13 +41,8 @@ bool extractWledCustomDesc(const uint8_t* binaryData, size_t dataSize, wled_cust
4141
// Valid structure found - copy entire structure
4242
memcpy(extractedDesc, custom_desc, sizeof(wled_custom_desc_t));
4343

44-
#ifdef ESP32
45-
DEBUG_PRINTF_P(PSTR("Extracted ESP32 WLED structure from .rodata.wled_desc section at offset %u: '%s'\n"),
44+
DEBUG_PRINTF_P(PSTR("Extracted WLED structure at offset %u: '%s'\n"),
4645
offset, extractedDesc->release_name);
47-
#else
48-
DEBUG_PRINTF_P(PSTR("Extracted ESP8266 WLED structure from .ver_number section at offset %u: '%s'\n"),
49-
offset, extractedDesc->release_name);
50-
#endif
5146
return true;
5247
}
5348
}
@@ -57,59 +52,61 @@ bool extractWledCustomDesc(const uint8_t* binaryData, size_t dataSize, wled_cust
5752
}
5853

5954
bool validateReleaseCompatibility(const char* extractedRelease) {
60-
if (!extractedRelease || strlen(extractedRelease) == 0) {
55+
if (!extractedRelease) {
56+
return false;
57+
}
58+
59+
// Ensure extractedRelease is properly null terminated (guard against fixed-length buffer issues)
60+
char safeRelease[WLED_RELEASE_NAME_MAX_LEN];
61+
strncpy(safeRelease, extractedRelease, WLED_RELEASE_NAME_MAX_LEN - 1);
62+
safeRelease[WLED_RELEASE_NAME_MAX_LEN - 1] = '\0';
63+
64+
if (strlen(safeRelease) == 0) {
6165
return false;
6266
}
6367

6468
// Simple string comparison - releases must match exactly
65-
bool match = strcmp(releaseString, extractedRelease) == 0;
69+
bool match = strcmp(releaseString, safeRelease) == 0;
6670

6771
DEBUG_PRINTF_P(PSTR("Release compatibility check: current='%s', uploaded='%s', match=%s\n"),
68-
releaseString, extractedRelease, match ? "YES" : "NO");
72+
releaseString, safeRelease, match ? "YES" : "NO");
6973

7074
return match;
7175
}
7276

73-
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool skipValidation, char* errorMessage) {
77+
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, char* errorMessage, size_t errorMessageLen) {
7478
// Clear error message
75-
if (errorMessage) {
79+
if (errorMessage && errorMessageLen > 0) {
7680
errorMessage[0] = '\0';
7781
}
7882

7983
// Ensure our custom description structure is referenced (prevents optimization)
8084
const wled_custom_desc_t* local_desc = getWledCustomDesc();
8185
(void)local_desc; // Suppress unused variable warning
8286

83-
// If user chose to skip validation, allow OTA immediately
84-
if (skipValidation) {
85-
DEBUG_PRINTLN(F("OTA release check bypassed by user"));
86-
return true;
87-
}
88-
8987
// Try to extract WLED structure directly from binary data
9088
wled_custom_desc_t extractedDesc;
9189
bool hasCustomDesc = extractWledCustomDesc(binaryData, dataSize, &extractedDesc);
9290

9391
if (!hasCustomDesc) {
9492
// No custom description - this could be a legacy binary
95-
if (errorMessage) {
96-
strcpy(errorMessage, "This firmware file is missing compatibility metadata. Enable 'Ignore firmware validation' to proceed anyway.");
93+
if (errorMessage && errorMessageLen > 0) {
94+
const char* msg = "This firmware file is missing compatibility metadata. Enable 'Ignore firmware validation' to proceed anyway.";
95+
strncpy(errorMessage, msg, errorMessageLen - 1);
96+
errorMessage[errorMessageLen - 1] = '\0';
9797
}
98-
DEBUG_PRINTLN(F("OTA declined: No custom description found"));
9998
return false;
10099
}
101100

102101
// Validate compatibility using extracted release name
103102
if (!validateReleaseCompatibility(extractedDesc.release_name)) {
104-
if (errorMessage) {
105-
snprintf(errorMessage, 127, "Firmware compatibility mismatch: current='%s', uploaded='%s'. Enable 'Ignore firmware validation' to proceed anyway.",
103+
if (errorMessage && errorMessageLen > 0) {
104+
snprintf(errorMessage, errorMessageLen, "Firmware compatibility mismatch: current='%s', uploaded='%s'. Enable 'Ignore firmware validation' to proceed anyway.",
106105
releaseString, extractedDesc.release_name);
106+
errorMessage[errorMessageLen - 1] = '\0'; // Ensure null termination
107107
}
108-
DEBUG_PRINTF_P(PSTR("OTA declined: Release mismatch current='%s', uploaded='%s'\n"),
109-
releaseString, extractedDesc.release_name);
110108
return false;
111109
}
112110

113-
DEBUG_PRINTLN(F("OTA allowed: Release names match"));
114111
return true;
115112
}

wled00/ota_release_check.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ bool validateReleaseCompatibility(const char* extractedRelease);
6767
* Check if OTA should be allowed based on release compatibility using custom description
6868
* @param binaryData Pointer to binary file data (not modified)
6969
* @param dataSize Size of binary data in bytes
70-
* @param skipValidation If true, skip release validation
71-
* @param errorMessage Buffer to store error message if validation fails (should be at least 128 bytes)
70+
* @param errorMessage Buffer to store error message if validation fails
71+
* @param errorMessageLen Maximum length of error message buffer
7272
* @return true if OTA should proceed, false if it should be blocked
7373
*/
74-
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool skipValidation, char* errorMessage);
74+
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, char* errorMessage, size_t errorMessageLen);
7575

7676
/**
7777
* Get pointer to the embedded custom description structure

wled00/wled_server.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,14 @@ void initServer()
442442
} else {
443443
// Validate OTA release compatibility using the first chunk data directly
444444
char errorMessage[128];
445-
releaseCheckPassed = shouldAllowOTA(data, len, false, errorMessage);
445+
releaseCheckPassed = shouldAllowOTA(data, len, errorMessage, sizeof(errorMessage));
446446

447447
if (!releaseCheckPassed) {
448448
DEBUG_PRINTF_P(PSTR("OTA declined: %s\n"), errorMessage);
449449
request->send(400, FPSTR(CONTENT_TYPE_PLAIN), errorMessage);
450450
return;
451+
} else {
452+
DEBUG_PRINTLN(F("OTA allowed: Release compatibility check passed"));
451453
}
452454
}
453455

0 commit comments

Comments
 (0)