@@ -317,9 +317,63 @@ void esp32FOTA::execOTA()
317
317
}
318
318
}
319
319
320
+ bool esp32FOTA::checkJSONManifest (JsonVariant JSONDocument) {
321
+
322
+ if (strcmp (JSONDocument[" type" ].as <const char *>(), _firmwareType.c_str ()) != 0 ) {
323
+ log_i (" Payload type in manifest %s doesn't match current firmware %s" , JSONDocument[" type" ].as <const char *>(), _firmwareType.c_str () );
324
+ log_i (" Doesn't match type: %s" , _firmwareType.c_str () );
325
+ return false ; // Move to the next entry in the manifest
326
+ }
327
+ log_i (" Payload type in manifest %s matches current firmware %s" , JSONDocument[" type" ].as <const char *>(), _firmwareType.c_str () );
328
+
329
+ semver_free (&_payloadVersion);
330
+ if (JSONDocument[" version" ].is <uint16_t >()) {
331
+ log_i (" JSON version: %d (int)" , JSONDocument[" version" ].as <uint16_t >());
332
+ _payloadVersion = semver_t {JSONDocument[" version" ].as <uint16_t >()};
333
+ } else if (JSONDocument[" version" ].is <const char *>()) {
334
+ log_i (" JSON version: %s (semver)" , JSONDocument[" version" ].as <const char *>() );
335
+ if (semver_parse (JSONDocument[" version" ].as <const char *>(), &_payloadVersion)) {
336
+ log_e ( " Invalid semver string received in manifest. Defaulting to 0" );
337
+ _payloadVersion = semver_t {0 };
338
+ }
339
+ } else {
340
+ log_e ( " Invalid semver format received in manifest. Defaulting to 0" );
341
+ _payloadVersion = semver_t {0 };
342
+ }
343
+
344
+ char version_no[256 ] = {' \0 ' };
345
+ semver_render (&_payloadVersion, version_no);
346
+ log_i (" Payload firmware version: %s" , version_no );
347
+
348
+
349
+ if (JSONDocument[" url" ].is <String>()) {
350
+ // We were provided a complete URL in the JSON manifest - use it
351
+ _firmwareUrl = JSONDocument[" url" ].as <String>();
352
+ if (JSONDocument[" host" ].is <String>()) // If the manifest provides both, warn the user
353
+ log_w (" Manifest provides both url and host - Using URL" );
354
+ } else if (JSONDocument[" host" ].is <String>() && JSONDocument[" port" ].is <uint16_t >() && JSONDocument[" bin" ].is <String>()){
355
+ // We were provided host/port/bin format - Build the URL
356
+ if ( JSONDocument[" port" ].as <uint16_t >() == 443 || JSONDocument[" port" ].as <uint16_t >() == 4433 )
357
+ _firmwareUrl = String ( " https://" );
358
+ else
359
+ _firmwareUrl = String ( " http://" );
360
+
361
+ _firmwareUrl += JSONDocument[" host" ].as <String>() + " :" + String ( JSONDocument[" port" ].as <uint16_t >() ) + JSONDocument[" bin" ].as <String>();
362
+
363
+ } else {
364
+ // JSON was malformed - no firmware target was provided
365
+ log_e (" JSON manifest was missing both 'url' and 'host'/'port'/'bin' keys" );
366
+ return false ;
367
+ }
368
+
369
+ if (semver_compare (_payloadVersion, _firmwareVersion) == 1 ) {
370
+ return true ;
371
+ }
372
+ return false ;
373
+ }
374
+
320
375
bool esp32FOTA::execHTTPcheck ()
321
376
{
322
-
323
377
String useURL;
324
378
325
379
if (useDeviceID)
@@ -334,112 +388,78 @@ bool esp32FOTA::execHTTPcheck()
334
388
335
389
log_i (" Getting HTTP: %s" ,useURL.c_str ());
336
390
log_i (" ------" );
337
- if ((WiFi.status () == WL_CONNECTED)) { // Check the current connection status
338
-
339
- HTTPClient http;
340
- WiFiClientSecure client;
341
-
342
- if ( useURL.substring ( 0 , 5 ) == " https" ) {
343
- if (!_allow_insecure_https) {
344
- // If the checkURL is https load the root-CA and connect with that
345
- log_i ( " Loading root_ca.pem" );
346
- File root_ca_file = SPIFFS.open ( " /root_ca.pem" );
347
- if ( !root_ca_file ) {
348
- log_e ( " Could not open root_ca.pem" );
349
- return false ;
350
- }
351
- {
352
- std::string root_ca = " " ;
353
- while ( root_ca_file.available () ){
354
- root_ca.push_back ( root_ca_file.read () );
355
- }
356
- root_ca_file.close ();
357
- http.begin ( useURL, root_ca.c_str () );
358
- }
359
- } else {
360
- // We're downloading from a secure port, but we don't want to validate the root cert.
361
- client.setInsecure ();
362
- http.begin (client, useURL);
363
- }
364
- } else {
365
- http.begin (useURL); // Specify the URL
366
- }
367
- int httpCode = http.GET (); // Make the request
368
-
369
- if ( httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY ) { // Check is a file was returned
370
-
371
- String payload = http.getString ();
372
-
373
- int str_len = payload.length () + 1 ;
374
- char JSONMessage[str_len];
375
- payload.toCharArray (JSONMessage, str_len);
391
+ if ((WiFi.status () != WL_CONNECTED)) { // Check the current connection status
392
+ log_w (" WiFi not connected - skipping HTTP check" );
393
+ return false ; // WiFi not connected
394
+ }
376
395
377
- StaticJsonDocument< 300 > JSONDocument; // Memory pool
378
- DeserializationError err = deserializeJson (JSONDocument, JSONMessage) ;
396
+ HTTPClient http;
397
+ WiFiClientSecure client ;
379
398
380
- if (err) { // Check for errors in parsing
381
- log_e (" Parsing failed" );
382
- http.end ();
399
+ if ( useURL.substring ( 0 , 5 ) == " https" ) {
400
+ if (!_allow_insecure_https) {
401
+ // If the checkURL is https load the root-CA and connect with that
402
+ log_i ( " Loading root_ca.pem" );
403
+ File root_ca_file = SPIFFS.open ( " /root_ca.pem" );
404
+ if ( !root_ca_file ) {
405
+ log_e ( " Could not open root_ca.pem" );
383
406
return false ;
384
407
}
385
-
386
- const char *pltype = JSONDocument[" type" ];
387
-
388
- semver_free (&_payloadVersion);
389
- if (JSONDocument[" version" ].is <uint16_t >()) {
390
- log_i (" JSON version: %d (int)" , JSONDocument[" version" ].as <uint16_t >());
391
- _payloadVersion = semver_t {JSONDocument[" version" ].as <uint16_t >()};
392
- } else if (JSONDocument[" version" ].is <const char *>()) {
393
- log_i (" JSON version: %s (semver)" , JSONDocument[" version" ].as <const char *>() );
394
- if (semver_parse (JSONDocument[" version" ].as <const char *>(), &_payloadVersion)) {
395
- log_e ( " Invalid semver string received in manifest. Defaulting to 0" );
396
- _payloadVersion = semver_t {0 };
408
+ {
409
+ std::string root_ca = " " ;
410
+ while ( root_ca_file.available () ){
411
+ root_ca.push_back ( root_ca_file.read () );
397
412
}
398
- } else {
399
- log_e ( " Invalid semver format received in manifest. Defaulting to 0" );
400
- _payloadVersion = semver_t {0 };
413
+ root_ca_file.close ();
414
+ http.begin ( useURL, root_ca.c_str () );
401
415
}
416
+ } else {
417
+ // We're downloading from a secure port, but we don't want to validate the root cert.
418
+ client.setInsecure ();
419
+ http.begin (client, useURL);
420
+ }
421
+ } else {
422
+ http.begin (useURL); // Specify the URL
423
+ }
424
+ int httpCode = http.GET (); // Make the request
402
425
403
- char version_no[256 ] = {' \0 ' };
404
- semver_render (&_payloadVersion, version_no);
405
- log_i (" Payload firmware version: %s" , version_no );
406
-
426
+ if ( httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY ) { // Check is a file was returned
407
427
408
- if (JSONDocument[" url" ].is <String>()) {
409
- // We were provided a complete URL in the JSON manifest - use it
410
- _firmwareUrl = JSONDocument[" url" ].as <String>();
411
- if (JSONDocument[" host" ].is <String>()) // If the manifest provides both, warn the user
412
- log_w (" Manifest provides both url and host - Using URL" );
413
- } else if (JSONDocument[" host" ].is <String>() && JSONDocument[" port" ].is <uint16_t >() && JSONDocument[" bin" ].is <String>()){
414
- // We were provided host/port/bin format - Build the URL
415
- if ( JSONDocument[" port" ].as <uint16_t >() == 443 || JSONDocument[" port" ].as <uint16_t >() == 4433 )
416
- _firmwareUrl = String ( " https://" );
417
- else
418
- _firmwareUrl = String ( " http://" );
428
+ String payload = http.getString ();
419
429
420
- _firmwareUrl += JSONDocument[" host" ].as <String>() + " :" + String ( JSONDocument[" port" ].as <uint16_t >() ) + JSONDocument[" bin" ].as <String>();
430
+ int str_len = payload.length () + 1 ;
431
+ char JSONMessage[str_len];
432
+ payload.toCharArray (JSONMessage, str_len);
421
433
422
- } else {
423
- // JSON was malformed - no firmware target was provided
424
- log_e (" JSON manifest was missing both 'url' and 'host'/'port'/'bin' keys" );
425
- http.end ();
426
- return false ;
427
- }
434
+ DynamicJsonDocument JSONResult (2048 );
435
+ DeserializationError err = deserializeJson (JSONResult, JSONMessage);
428
436
437
+ http.end (); // We're done with HTTP - free the resources
429
438
430
- String fwtype (pltype);
439
+ if (err) { // Check for errors in parsing
440
+ log_e (" Parsing failed" );
441
+ return false ;
442
+ }
431
443
432
- if (semver_compare (_payloadVersion, _firmwareVersion) == 1 && fwtype == _firmwareType) {
433
- http.end ();
434
- return true ;
444
+ if (JSONResult.is <JsonArray>()) {
445
+ // We already received an array of multiple firmware types
446
+ JsonArray arr = JSONResult.as <JsonArray>();
447
+ for (JsonVariant JSONDocument : arr) {
448
+ if (checkJSONManifest (JSONDocument)) {
449
+ return true ;
450
+ }
435
451
}
436
- } else {
437
- log_e (" Error on HTTP request" );
452
+ } else if (JSONResult.is <JsonObject>()) {
453
+ if (checkJSONManifest (JSONResult.as <JsonVariant>()))
454
+ return true ;
438
455
}
439
- http.end (); // Free the resources
456
+
457
+ return false ; // We didn't get a hit against the above, return false
458
+ } else {
459
+ log_e (" Error on HTTP request" );
460
+ http.end ();
440
461
return false ;
441
462
}
442
- return false ;
443
463
}
444
464
445
465
String esp32FOTA::getDeviceID ()
0 commit comments