40
40
#include "statistics_task.h"
41
41
#include "theme_api.h" // Add theme API include
42
42
#include "axe-os/api/system/asic_settings.h"
43
+ #include "display.h"
43
44
#include "http_server.h"
44
45
45
46
#define JSON_ALL_STATS_ELEMENT_SIZE 120
46
47
#define JSON_DASHBOARD_STATS_ELEMENT_SIZE 60
47
48
49
+ #define NVS_STR_LIMIT (4000 - 1)
50
+
48
51
#define ARRAY_SIZE (arr ) (sizeof(arr) / sizeof((arr)[0]))
49
52
50
53
static const char * TAG = "http_server" ;
@@ -54,8 +57,13 @@ typedef struct {
54
57
const char * name ;
55
58
int json_type ;
56
59
nvs_type_t nvs_type ;
60
+ int min ;
61
+ int max ;
57
62
const char * nvs_name ;
58
- } SettingsFormat ;
63
+ bool updated ;
64
+ int int_value ;
65
+ char * str_value ;
66
+ } Settings ;
59
67
60
68
/* Handler for WiFi scan endpoint */
61
69
static esp_err_t GET_wifi_scan (httpd_req_t * req )
@@ -462,113 +470,171 @@ bool check_json_type(int expected_type, const cJSON * const item)
462
470
return false;
463
471
}
464
472
465
- bool check_settings_and_update (const cJSON * const root , bool update )
473
+ bool check_settings_and_update (const cJSON * const root )
466
474
{
475
+ bool result = true;
467
476
const int cJSON_Option = (cJSON_Number | cJSON_True | cJSON_False );
468
477
469
- const SettingsFormat settings_format [] = {
470
- { .name = "stratumURL" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_STRATUM_URL },
471
- { .name = "fallbackStratumURL" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_URL },
472
- { .name = "stratumUser" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_STRATUM_USER },
473
- { .name = "stratumPassword" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_STRATUM_PASS },
474
- { .name = "fallbackStratumUser" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_USER },
475
- { .name = "fallbackStratumPassword" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PASS },
476
- { .name = "stratumPort" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_STRATUM_PORT },
477
- { .name = "fallbackStratumPort" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PORT },
478
- { .name = "ssid" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_WIFI_SSID },
479
- { .name = "wifiPass" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_WIFI_PASS },
480
- { .name = "hostname" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_HOSTNAME },
481
- { .name = "coreVoltage" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_ASIC_VOLTAGE },
482
- { .name = "frequency" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_ASIC_FREQ },
483
- { .name = "overheat_mode" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_OVERHEAT_MODE },
484
- { .name = "display" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .nvs_name = NVS_CONFIG_DISPLAY },
485
- { .name = "flipscreen" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_FLIP_SCREEN },
486
- { .name = "invertscreen" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_INVERT_SCREEN },
487
- { .name = "displayTimeout" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_I32 , .nvs_name = NVS_CONFIG_DISPLAY_TIMEOUT },
488
- { .name = "autofanspeed" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_AUTO_FAN_SPEED },
489
- { .name = "fanspeed" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_FAN_SPEED },
490
- { .name = "temptarget" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_TEMP_TARGET },
491
- { .name = "statsFrequency" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_STATISTICS_FREQUENCY },
492
- { .name = "overclockEnabled" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .nvs_name = NVS_CONFIG_OVERCLOCK_ENABLED }
478
+ Settings settings [] = {
479
+ { .name = "stratumURL" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_STRATUM_URL },
480
+ { .name = "fallbackStratumURL" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_FALLBACK_STRATUM_URL },
481
+ { .name = "stratumUser" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_STRATUM_USER },
482
+ { .name = "stratumPassword" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_STRATUM_PASS },
483
+ { .name = "fallbackStratumUser" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_FALLBACK_STRATUM_USER },
484
+ { .name = "fallbackStratumPassword" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PASS },
485
+ { .name = "stratumPort" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_STRATUM_PORT },
486
+ { .name = "fallbackStratumPort" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PORT },
487
+ { .name = "ssid" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 1 , . max = 32 , . nvs_name = NVS_CONFIG_WIFI_SSID },
488
+ { .name = "wifiPass" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 1 , . max = 63 , . nvs_name = NVS_CONFIG_WIFI_PASS },
489
+ { .name = "hostname" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 1 , . max = 32 , . nvs_name = NVS_CONFIG_HOSTNAME },
490
+ { .name = "coreVoltage" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 1 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_ASIC_VOLTAGE },
491
+ { .name = "frequency" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 1 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_ASIC_FREQ },
492
+ { .name = "overheat_mode" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 0 , . nvs_name = NVS_CONFIG_OVERHEAT_MODE },
493
+ { .name = "display" , .json_type = cJSON_String , .nvs_type = NVS_TYPE_STR , .min = 0 , . max = NVS_STR_LIMIT , . nvs_name = NVS_CONFIG_DISPLAY },
494
+ { .name = "flipscreen" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 1 , . nvs_name = NVS_CONFIG_FLIP_SCREEN },
495
+ { .name = "invertscreen" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 1 , . nvs_name = NVS_CONFIG_INVERT_SCREEN },
496
+ { .name = "displayTimeout" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_I32 , .min = -1 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_DISPLAY_TIMEOUT },
497
+ { .name = "autofanspeed" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 1 , . nvs_name = NVS_CONFIG_AUTO_FAN_SPEED },
498
+ { .name = "fanspeed" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 100 , . nvs_name = NVS_CONFIG_FAN_SPEED },
499
+ { .name = "temptarget" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 35 , . max = 66 , . nvs_name = NVS_CONFIG_TEMP_TARGET },
500
+ { .name = "statsFrequency" , .json_type = cJSON_Number , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = USHRT_MAX , . nvs_name = NVS_CONFIG_STATISTICS_FREQUENCY },
501
+ { .name = "overclockEnabled" , .json_type = cJSON_Option , .nvs_type = NVS_TYPE_U16 , .min = 0 , . max = 1 , . nvs_name = NVS_CONFIG_OVERCLOCK_ENABLED }
493
502
};
494
503
495
- for (int i = 0 ; i < ARRAY_SIZE (settings_format ); i ++ ) {
496
- cJSON * item = cJSON_GetObjectItem (root , settings_format [i ].name );
504
+ // check for data type and data type range
505
+ for (int i = 0 ; i < ARRAY_SIZE (settings ); i ++ ) {
506
+ cJSON * item = cJSON_GetObjectItem (root , settings [i ].name );
497
507
if (item ) {
498
- if (check_json_type (settings_format [i ].json_type , item )) {
499
- switch (settings_format [i ].nvs_type ) {
508
+ // check data type
509
+ if (check_json_type (settings [i ].json_type , item )) {
510
+ // check data type range
511
+ switch (settings [i ].nvs_type ) {
500
512
case NVS_TYPE_U8 :
501
513
if ((0 > item -> valueint ) || (UCHAR_MAX < item -> valueint )) {
502
- ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U8" , item -> valueint , settings_format [i ].name );
503
- return false;
504
- }
505
- if (update ) {
506
- nvs_config_set_u16 (settings_format [i ].nvs_name , item -> valueint ); // nvs u8 is not used
514
+ ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U8" , item -> valueint , settings [i ].name );
515
+ result = false;
507
516
}
508
517
break ;
509
518
case NVS_TYPE_U16 :
510
519
if ((0 > item -> valueint ) || (USHRT_MAX < item -> valueint )) {
511
- ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U16" , item -> valueint , settings_format [i ].name );
512
- return false;
513
- }
514
- if (update ) {
515
- nvs_config_set_u16 (settings_format [i ].nvs_name , item -> valueint );
520
+ ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U16" , item -> valueint , settings [i ].name );
521
+ result = false;
516
522
}
517
523
break ;
518
524
case NVS_TYPE_U32 :
519
525
if (0 > item -> valueint ) {
520
- ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U32" , item -> valueint , settings_format [i ].name );
521
- return false;
522
- }
523
- if (update ) {
524
- nvs_config_set_u64 (settings_format [i ].nvs_name , item -> valueint ); // nvs u32 is not used
526
+ ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_U32" , item -> valueint , settings [i ].name );
527
+ result = false;
525
528
}
526
529
break ;
527
530
case NVS_TYPE_I8 :
528
531
if ((CHAR_MIN > item -> valueint ) || (CHAR_MAX < item -> valueint )) {
529
- ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_I8" , item -> valueint , settings_format [i ].name );
530
- return false;
531
- }
532
- if (update ) {
533
- nvs_config_set_i32 (settings_format [i ].nvs_name , item -> valueint ); // nvs i8 is not used
532
+ ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_I8" , item -> valueint , settings [i ].name );
533
+ result = false;
534
534
}
535
535
break ;
536
536
case NVS_TYPE_I16 :
537
537
if ((SHRT_MIN > item -> valueint ) || (SHRT_MAX < item -> valueint )) {
538
- ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_I16" , item -> valueint , settings_format [i ].name );
539
- return false;
540
- }
541
- if (update ) {
542
- nvs_config_set_i32 (settings_format [i ].nvs_name , item -> valueint ); // nvs i16 is not used
538
+ ESP_LOGW (TAG , "Value '%d' for '%s' is not compatible with NVS_TYPE_I16" , item -> valueint , settings [i ].name );
539
+ result = false;
543
540
}
544
541
break ;
545
542
case NVS_TYPE_I32 :
546
- if (update ) {
547
- nvs_config_set_i32 (settings_format [i ].nvs_name , item -> valueint );
548
- }
549
543
break ;
550
544
case NVS_TYPE_STR :
551
- if (update ) {
552
- nvs_config_set_string (settings_format [i ].nvs_name , item -> valuestring );
545
+ const size_t str_value_len = strlen (item -> valuestring );
546
+ settings [i ].str_value = strdup (item -> valuestring );
547
+
548
+ if (0 > settings [i ].min ) {
549
+ settings [i ].min = 0 ;
550
+ }
551
+
552
+ if ((str_value_len < settings [i ].min ) || (str_value_len > settings [i ].max )) {
553
+ ESP_LOGW (TAG , "Value '%s' for '%s' is out of length (%d-%d)" , item -> valuestring , settings [i ].name , settings [i ].min , settings [i ].max );
554
+ result = false;
553
555
}
554
556
break ;
555
557
default :
556
- ESP_LOGW (TAG , "NVS type (%d) for '%s' not supported" , settings_format [i ].nvs_type , settings_format [i ].name );
557
- return false;
558
+ ESP_LOGW (TAG , "NVS type (%d) for '%s' not supported" , settings [i ].nvs_type , settings [i ].name );
559
+ result = false;
560
+ break ;
558
561
}
562
+
563
+ // check value range
564
+ if (NVS_TYPE_STR != settings [i ].nvs_type ) {
565
+ if ((settings [i ].min > item -> valueint ) || (settings [i ].max < item -> valueint )) {
566
+ ESP_LOGW (TAG , "Value '%d' for '%s' is out of range (%d-%d)" , item -> valueint , settings [i ].name , settings [i ].min , settings [i ].max );
567
+ result = false;
568
+ }
569
+ }
570
+
571
+ // mark for update
572
+ settings [i ].int_value = item -> valueint ;
573
+ settings [i ].updated = true;
559
574
} else {
560
- ESP_LOGW (TAG , "Expected JSON type (%d) for setting '%s'" , settings_format [i ].json_type , settings_format [i ].name );
561
- return false;
575
+ ESP_LOGW (TAG , "Expected JSON type (%d) for setting '%s'" , settings [i ].json_type , settings [i ].name );
576
+ result = false;
577
+ }
578
+ }
579
+ }
580
+
581
+ // check individual values
582
+ if (result ) {
583
+ for (int i = 0 ; i < ARRAY_SIZE (settings ); i ++ ) {
584
+ if (settings [i ].updated ) {
585
+ if (strcmp (settings [i ].name , "display" ) == 0 ) {
586
+ if (NULL == get_display_config (settings [i ].str_value )) {
587
+ ESP_LOGW (TAG , "Display config '%s' for '%s' is not available" , settings [i ].str_value , settings [i ].name );
588
+ result = false;
589
+ }
590
+ break ;
591
+ }
592
+ }
593
+ }
594
+ }
595
+
596
+ // update NVS (if result is okay) clean up
597
+ for (int i = 0 ; i < ARRAY_SIZE (settings ); i ++ ) {
598
+ if (settings [i ].updated ) {
599
+ if (result ) {
600
+ switch (settings [i ].nvs_type ) {
601
+ case NVS_TYPE_U8 :
602
+ nvs_config_set_u16 (settings [i ].nvs_name , (uint16_t )settings [i ].int_value ); // nvs u8 is not used
603
+ break ;
604
+ case NVS_TYPE_U16 :
605
+ nvs_config_set_u16 (settings [i ].nvs_name , (uint16_t )settings [i ].int_value );
606
+ break ;
607
+ case NVS_TYPE_U32 :
608
+ nvs_config_set_u64 (settings [i ].nvs_name , (uint64_t )settings [i ].int_value ); // nvs u32 is not used
609
+ break ;
610
+ case NVS_TYPE_I8 :
611
+ nvs_config_set_i32 (settings [i ].nvs_name , settings [i ].int_value ); // nvs i8 is not used
612
+ break ;
613
+ case NVS_TYPE_I16 :
614
+ nvs_config_set_i32 (settings [i ].nvs_name , settings [i ].int_value ); // nvs i16 is not used
615
+ break ;
616
+ case NVS_TYPE_I32 :
617
+ nvs_config_set_i32 (settings [i ].nvs_name , settings [i ].int_value );
618
+ break ;
619
+ case NVS_TYPE_STR :
620
+ nvs_config_set_string (settings [i ].nvs_name , settings [i ].str_value );
621
+ break ;
622
+ default :
623
+ break ;
624
+ }
625
+ }
626
+
627
+ if (NVS_TYPE_STR == settings [i ].nvs_type ) {
628
+ free (settings [i ].str_value );
562
629
}
563
630
}
564
631
}
565
632
566
- return true ;
633
+ return result ;
567
634
}
568
635
569
636
static esp_err_t PATCH_update_settings (httpd_req_t * req )
570
637
{
571
-
572
638
if (is_network_allowed (req ) != ESP_OK ) {
573
639
return httpd_resp_send_err (req , HTTPD_401_UNAUTHORIZED , "Unauthorized" );
574
640
}
@@ -605,9 +671,8 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
605
671
return ESP_OK ;
606
672
}
607
673
608
- if (check_settings_and_update (root , false)) {
609
- check_settings_and_update (root , true);
610
- } else {
674
+ if (!check_settings_and_update (root )) {
675
+ cJSON_Delete (root );
611
676
httpd_resp_send_err (req , HTTPD_400_BAD_REQUEST , "Wrong API input" );
612
677
return ESP_OK ;
613
678
}
0 commit comments