Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions main/global_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ typedef struct
uint32_t lastClockSync;
bool is_screen_active;
bool is_firmware_update;
int64_t ota_authorized_until;
char firmware_update_filename[20];
char firmware_update_status[20];
bool hardware_fault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,20 @@ <h3 class="mt-5">Statistics</h3>
</div>
</div>

<h3 class="mt-5">Update Security</h3>

<div class="card">
<div class="field-checkbox grid my-2">
<div class="col-1 md:col-10 md:flex-order-2">
<p-checkbox name="otaAuthRequired" formControlName="otaAuthRequired" inputId="otaAuthRequired" [binary]="true"></p-checkbox>
</div>
<label for="otaAuthRequired" class="col-11 m-0 pl-3 md:col-2 md:flex-order-1 md:p-2">Require BOOT Button for OTA</label>
</div>
<small class="block text-500">
Press BOOT once before changing this setting or uploading firmware.
</small>
</div>

<div class="flex mt-5 gap-3">
<button pButton [disabled]="!form.dirty || form.invalid" (click)="updateSystem()"
class="btn btn-primary">Save</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ export class EditComponent implements OnInit, OnDestroy, OnChanges {
Validators.required,
Validators.min(0),
Validators.max(this.statsFrequencyMaxValue)
]]
]],
otaAuthRequired: [info.otaAuthRequired, [Validators.required]]
});

this.formSubject.next(this.form);
Expand Down Expand Up @@ -342,7 +343,8 @@ export class EditComponent implements OnInit, OnDestroy, OnChanges {
'manualFanSpeed',
'temptarget',
'overheat_mode',
'statsFrequency'
'statsFrequency',
'otaAuthRequired'
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ <h2>Update</h2>
<div class="col-12 xl:col-4">
<div class="card h-full">
<h5>Current Version: {{(info$ | async)?.version}}</h5>
<p-message
*ngIf="(info$ | async)?.otaAuthRequired && !(info$ | async)?.otaAuthorized"
severity="warn"
text="Press BOOT once before uploading firmware or AxeOS."
styleClass="w-full mb-3">
</p-message>

<ng-container *ngIf="checkLatestRelease == false; else afterCheck">
<h3>Latest Release: <p-button (onClick)="handleReleaseCheck()">Check</p-button></h3>
Expand Down
2 changes: 2 additions & 0 deletions main/http_server/axe-os/src/app/services/system.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ export class SystemApiService {
boardtemp2: 40,
overheat_mode: 0,
statsLimit: 720,
otaAuthRequired: true,
otaAuthorized: false,

blockHeight: 811111,
scriptsig: "..%..h..,H...ckpool.eu/solo.ckpool.org/",
Expand Down
45 changes: 44 additions & 1 deletion main/http_server/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,42 @@ static const char * STATS_LABEL_FAN2_RPM = "fan2Rpm";
static const char * STATS_LABEL_WIFI_RSSI = "wifiRssi";
static const char * STATS_LABEL_FREE_HEAP = "freeHeap";
static const char * STATS_LABEL_RESPONSE_TIME = "responseTime";
#define OTA_AUTH_WINDOW_US (5LL * 60LL * 1000000LL)

static int system_info_prebuffer_len = 256;
static int system_statistics_prebuffer_len = 256;
static int system_wifi_scan_prebuffer_len = 256;
static int api_common_prebuffer_len = 256;
static GlobalState * GLOBAL_STATE;

void HTTP_authorize_ota_update(void)
{
if (!GLOBAL_STATE) {
return;
}

GLOBAL_STATE->SYSTEM_MODULE.ota_authorized_until = esp_timer_get_time() + OTA_AUTH_WINDOW_US;
ESP_LOGW(TAG, "OTA updates authorized for 5 minutes by physical button press");
}

bool HTTP_is_ota_update_authorized(void)
{
if (!GLOBAL_STATE || !nvs_config_get_bool(NVS_CONFIG_OTA_AUTH_REQUIRED)) {
return true;
}

return esp_timer_get_time() <= GLOBAL_STATE->SYSTEM_MODULE.ota_authorized_until;
}

static esp_err_t check_ota_update_authorized(httpd_req_t *req)
{
if (HTTP_is_ota_update_authorized()) {
return ESP_OK;
}

httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Press the BOOT button to authorize OTA updates for 5 minutes");
return ESP_FAIL;
}

typedef enum
{
Expand Down Expand Up @@ -145,7 +176,6 @@ static esp_err_t GET_system_logs(httpd_req_t *req)
return res;
}

static GlobalState * GLOBAL_STATE;
static httpd_handle_t server = NULL;

static int stratum_protocol_from_string(const char *s, uint16_t *out)
Expand Down Expand Up @@ -621,6 +651,13 @@ bool check_settings_and_update(const cJSON * const root)
ESP_LOGW(TAG, "Invalid display rotation: '%d'", item->valueint);
result = false;
}
if (key == NVS_CONFIG_OTA_AUTH_REQUIRED) {
bool requested_auth_required = item->valueint != 0 || cJSON_IsTrue(item);
if (!requested_auth_required && !HTTP_is_ota_update_authorized()) {
ESP_LOGW(TAG, "Refusing to disable OTA button authorization without a recent physical button press");
result = false;
}
}
}

if (result) {
Expand Down Expand Up @@ -1083,6 +1120,9 @@ esp_err_t POST_WWW_update(httpd_req_t * req)
if (is_network_allowed(req) != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
}
if (check_ota_update_authorized(req) != ESP_OK) {
return ESP_OK;
}

wifi_mode_t mode;
esp_wifi_get_mode(&mode);
Expand Down Expand Up @@ -1167,6 +1207,9 @@ esp_err_t POST_OTA_update(httpd_req_t * req)
if (is_network_allowed(req) != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
}
if (check_ota_update_authorized(req) != ESP_OK) {
return ESP_OK;
}

wifi_mode_t mode;
esp_wifi_get_mode(&mode);
Expand Down
3 changes: 3 additions & 0 deletions main/http_server/http_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
#define HTTP_SERVER_H_

#include <esp_http_server.h>
#include <stdbool.h>

#include "cJSON.h"

esp_err_t is_network_allowed(httpd_req_t * req);
esp_err_t start_rest_server(void *pvParameters);
esp_err_t HTTP_send_json(httpd_req_t * req, const cJSON * item, int * prebuffer_len);
void HTTP_authorize_ota_update(void);
bool HTTP_is_ota_update_authorized(void);

#endif /* HTTP_SERVER_H_ */
11 changes: 11 additions & 0 deletions main/http_server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ components:
- hashrateMonitor
- miningPaused
- statsLimit
- otaAuthRequired
- otaAuthorized
properties:
ASICModel:
type: string
Expand Down Expand Up @@ -533,6 +535,12 @@ components:
statsLimit:
type: integer
description: Maximum number of statistics data points
otaAuthRequired:
type: boolean
description: Whether OTA updates require recent physical button authorization
otaAuthorized:
type: boolean
description: Whether OTA updates are currently authorized by a recent physical button press

SystemASIC:
type: object
Expand Down Expand Up @@ -834,6 +842,9 @@ components:
minimum: 0
examples:
- 120
otaAuthRequired:
type: boolean
description: Require a recent physical BOOT button press before OTA updates. Disabling this also requires recent authorization.
additionalProperties: true

responses:
Expand Down
2 changes: 2 additions & 0 deletions main/http_server/system_api_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ static void system_api_add_config(cJSON *root, GlobalState *g) {
cJSON_AddFloatToObject(root, "frequency", nvs_config_get_float(NVS_CONFIG_ASIC_FREQUENCY));
cJSON_AddNumberToObject(root, "statsFrequency", nvs_config_get_u16(NVS_CONFIG_STATISTICS_FREQUENCY));
cJSON_AddNumberToObject(root, "statsLimit", MAX_STATISTICS_COUNT);
cJSON_AddBoolToObject(root, "otaAuthRequired", nvs_config_get_bool(NVS_CONFIG_OTA_AUTH_REQUIRED));
cJSON_AddBoolToObject(root, "otaAuthorized", g->SYSTEM_MODULE.ota_authorized_until >= esp_timer_get_time());
}

static void system_api_add_hashrate_monitor(cJSON *root, GlobalState *g) {
Expand Down
1 change: 1 addition & 0 deletions main/nvs_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ static Settings settings[NVS_CONFIG_COUNT] = {
[NVS_CONFIG_THEME_SCHEME] = {.nvs_key_name = "themescheme", .type = TYPE_STR, .default_value = {.str = DEFAULT_THEME}},
[NVS_CONFIG_THEME_COLORS] = {.nvs_key_name = "themecolors", .type = TYPE_STR, .default_value = {.str = DEFAULT_COLORS}},
[NVS_CONFIG_SCOREBOARD] = {.nvs_key_name = "scoreboard", .type = TYPE_STR, .array_size = MAX_SCOREBOARD},
[NVS_CONFIG_OTA_AUTH_REQUIRED] = {.nvs_key_name = "otaauthreq", .type = TYPE_BOOL, .default_value = {.b = true}, .rest_name = "otaAuthRequired", .min = 0, .max = 1},

[NVS_CONFIG_BOARD_VERSION] = {.nvs_key_name = "boardversion", .type = TYPE_STR, .default_value = {.str = "000"}},
[NVS_CONFIG_DEVICE_MODEL] = {.nvs_key_name = "devicemodel", .type = TYPE_STR, .default_value = {.str = "unknown"}},
Expand Down
1 change: 1 addition & 0 deletions main/nvs_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ typedef enum {
NVS_CONFIG_THEME_SCHEME,
NVS_CONFIG_THEME_COLORS,
NVS_CONFIG_SCOREBOARD,
NVS_CONFIG_OTA_AUTH_REQUIRED,

NVS_CONFIG_BOARD_VERSION,
NVS_CONFIG_DEVICE_MODEL,
Expand Down
3 changes: 3 additions & 0 deletions main/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "display.h"
#include "connect.h"
#include "esp_timer.h"
#include "http_server.h"

typedef enum {
SCR_SELF_TEST,
Expand Down Expand Up @@ -651,6 +652,8 @@ static void screen_update_cb(lv_timer_t * timer)

void screen_button_press()
{
HTTP_authorize_ota_update();

if (GLOBAL_STATE->SYSTEM_MODULE.identify_mode_time_ms > 0) {
GLOBAL_STATE->SYSTEM_MODULE.identify_mode_time_ms = 0;
} else {
Expand Down