Skip to content

Commit 5246f20

Browse files
committed
Download OTA workaround
1 parent 094bf8c commit 5246f20

File tree

9 files changed

+12509
-12445
lines changed

9 files changed

+12509
-12445
lines changed

docs/buildprocess.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ The script will download a public certificate store from Mozilla (`board_ssl_cer
168168

169169
To enable SSL the feature `FT_NTP=1` must be enabled as well.
170170

171+
!!! bug
172+
173+
At the moment there is a bug with the certificate bundle when using the firmware download e.g. from Github. By using the build flag `-D DOWNLOAD_OTA_SKIP_CERT_VERIFY` you may skip certificate validation to keep OTA working. Only OTA seems affected, not MQTT. Keep in mind, that this voids the main security feature of SSL and allows man-in-the-middle attacks.
174+
171175
## Vite and LittleFS 32 Character Limit
172176

173177
The static files for the website are build using vite. By default vite adds a unique hash value to all filenames for improved caching performance. However, LittleFS on the ESP32 is limited to filenames with 32 characters. This restricts the number of characters available for the user to name svelte files. To give a little bit more headroom a vite-plugin removes all hash values, as they offer no benefit on an ESP32. However, have the 32 character limit in mind when naming files. Excessively long names may still cause some issues when building the LittleFS binary.

interface/src/lib/components/GithubUpdateDialog.svelte

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
} else if ($telemetry.download_ota.status == 'finished') {
4040
message = 'Restarting ...';
4141
progress = 0;
42-
// Reload page after 5 sec
42+
// Reload page after 20 sec
4343
timerId = setTimeout(() => {
4444
modals.closeAll();
4545
location.reload();
46-
}, 5000);
46+
}, 20000);
4747
}
4848
});
4949
@@ -52,9 +52,6 @@
5252
// prevents modal from closing
5353
return false;
5454
} else {
55-
$telemetry.download_ota.status = 'idle';
56-
$telemetry.download_ota.error = '';
57-
$telemetry.download_ota.progress = 0;
5855
return true;
5956
}
6057
});
@@ -90,7 +87,6 @@
9087
disabled={updating}
9188
onclick={() => {
9289
modals.closeAll();
93-
location.reload();
9490
}}
9591
>
9692
<Cancel class="mr-2 h-5 w-5" /><span>Close</span></button

interface/src/routes/system/update/GithubFirmwareManager.svelte

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { user } from '$lib/stores/user';
33
import { page } from '$app/state';
44
import { modals } from 'svelte-modals';
5+
import type { ModalComponent } from 'svelte-modals';
56
import { slide } from 'svelte/transition';
67
import { cubicOut } from 'svelte/easing';
78
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
@@ -66,8 +67,7 @@
6667
}
6768
}
6869
if (url === '') {
69-
// if no asset was found, use the first one
70-
modals.open(InfoDialog, {
70+
modals.open(InfoDialog as unknown as ModalComponent<any>, {
7171
title: 'No matching firmware found',
7272
message:
7373
'No matching firmware was found for the current device. Upload the firmware manually or build from sources.',
@@ -76,8 +76,7 @@
7676
});
7777
return;
7878
}
79-
80-
modals.open(ConfirmDialog, {
79+
modals.open(ConfirmDialog as unknown as ModalComponent<any>, {
8180
title: 'Confirm flashing new firmware to the device',
8281
message: 'Are you sure you want to overwrite the existing firmware with a new one?',
8382
labels: {
@@ -86,8 +85,8 @@
8685
},
8786
onConfirm: () => {
8887
postGithubDownload(url);
89-
modals.open(GithubUpdateDialog, {
90-
onConfirm: () => modals.closeAlls()
88+
modals.open(GithubUpdateDialog as unknown as ModalComponent<any>, {
89+
onConfirm: () => modals.closeAll()
9190
});
9291
}
9392
});
@@ -96,22 +95,28 @@
9695

9796
<SettingsCard collapsible={false}>
9897
{#snippet icon()}
99-
<Github class="lex-shrink-0 mr-2 h-6 w-6 self-end rounded-full" />
98+
<Github class="lex-shrink-0 mr-2 h-6 w-6 self-end rounded-full" />
10099
{/snippet}
101100
{#snippet title()}
102-
<span >Github Firmware Manager</span>
101+
<span>Github Firmware Manager</span>
103102
{/snippet}
104103
{#await getGithubAPI()}
105104
<Spinner />
106105
{:then githubReleases}
106+
<div class="alert alert-info">
107+
<div>
108+
<span class="font-bold">Current Firmware Version:</span>
109+
v{page.data.features.firmware_version}
110+
</div>
111+
</div>
107112
<div class="relative w-full overflow-visible">
108113
<div class="overflow-x-auto" transition:slide|local={{ duration: 300, easing: cubicOut }}>
109114
<table class="table w-full table-auto">
110115
<thead>
111116
<tr class="font-bold">
112117
<th align="left">Release</th>
113118
<th align="center" class="hidden sm:block">Release Date</th>
114-
<th align="center">Experimental</th>
119+
<th align="center">Exp.</th>
115120
<th align="center">Install</th>
116121
</tr>
117122
</thead>

interface/vite.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ const config: UserConfig = {
1818
proxy: {
1919
// Proxying REST: http://localhost:5173/rest/bar -> http://192.168.1.83/rest/bar
2020
'/rest': {
21-
target: 'http://192.168.1.110',
21+
target: 'http://192.168.1.111',
2222
changeOrigin: true
2323
},
2424
// Proxying websockets ws://localhost:5173/ws -> ws://192.168.1.83/ws
2525
'/ws': {
26-
target: 'ws://192.168.1.110',
26+
target: 'ws://192.168.1.111',
2727
changeOrigin: true,
2828
ws: true
2929
}

lib/framework/DownloadFirmwareService.cpp

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,45 @@
1616
extern const uint8_t rootca_crt_bundle_start[] asm("_binary_src_certs_x509_crt_bundle_bin_start");
1717
extern const uint8_t rootca_crt_bundle_end[] asm("_binary_src_certs_x509_crt_bundle_bin_end");
1818

19+
/**
20+
* This is github-io.pem
21+
*/
22+
const char *githubCACertificate = "-----BEGIN CERTIFICATE-----\n"
23+
"MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB\n"
24+
"iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n"
25+
"cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n"
26+
"BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx\n"
27+
"MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV\n"
28+
"BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE\n"
29+
"ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g\n"
30+
"VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\n"
31+
"AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N\n"
32+
"TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj\n"
33+
"eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E\n"
34+
"oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk\n"
35+
"Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY\n"
36+
"uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j\n"
37+
"BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb\n"
38+
"+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G\n"
39+
"A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw\n"
40+
"CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0\n"
41+
"LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr\n"
42+
"BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv\n"
43+
"bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov\n"
44+
"L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H\n"
45+
"ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH\n"
46+
"7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi\n"
47+
"H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx\n"
48+
"RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv\n"
49+
"xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38\n"
50+
"sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL\n"
51+
"l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq\n"
52+
"6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY\n"
53+
"LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5\n"
54+
"yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K\n"
55+
"00u/I5sUKUErmgQfky3xxzlIPK1aEn8=\n"
56+
"-----END CERTIFICATE-----\n";
57+
1958
static EventSocket *_socket = nullptr;
2059
static int previousProgress = 0;
2160
static String *otaURL = nullptr;
@@ -27,7 +66,7 @@ void update_started()
2766
doc["status"] = "preparing";
2867
JsonObject jsonObject = doc.as<JsonObject>();
2968
_socket->emitEvent(EVENT_DOWNLOAD_OTA, jsonObject);
30-
ESP_LOGD(SVK_TAG, "HTTP onUpdate started");
69+
ESP_LOGD(SVK_TAG, "HTTP Update started");
3170
}
3271

3372
void update_progress(int currentBytes, int totalBytes)
@@ -44,20 +83,40 @@ void update_progress(int currentBytes, int totalBytes)
4483
previousProgress = progress;
4584
}
4685

86+
void update_finished()
87+
{
88+
String output;
89+
doc["status"] = "finished";
90+
doc["progress"] = 100;
91+
JsonObject jsonObject = doc.as<JsonObject>();
92+
_socket->emitEvent(EVENT_DOWNLOAD_OTA, jsonObject);
93+
ESP_LOGI(SVK_TAG, "HTTP Update successful - Restarting");
94+
#ifdef SERIAL_INFO
95+
Serial.println("HTTP Update successful - Restarting");
96+
#endif
97+
98+
vTaskDelay(250 / portTICK_PERIOD_MS);
99+
}
100+
47101
void updateTask(void *param)
48102
{
49103
String url = *((String *)param);
50104
delete (String *)param; // Clean up the allocated memory
51105

52106
WiFiClientSecure client;
53107

108+
#ifndef DOWNLOAD_OTA_SKIP_CERT_VERIFY
109+
54110
#if ESP_ARDUINO_VERSION_MAJOR == 3
55111
client.setCACertBundle(rootca_crt_bundle_start, rootca_crt_bundle_end - rootca_crt_bundle_start);
56112
#else
57113
client.setCACertBundle(rootca_crt_bundle_start);
58114
#endif
59115

60-
// client.setInsecure(); // For testing purposes only, remove this line for production code
116+
#else
117+
ESP_LOGW(SVK_TAG, "Skipping SSL certificate verification for OTA update!");
118+
client.setInsecure();
119+
#endif
61120

62121
client.setTimeout(12000);
63122

@@ -67,6 +126,7 @@ void updateTask(void *param)
67126
String output;
68127
httpUpdate.onStart(update_started);
69128
httpUpdate.onProgress(update_progress);
129+
httpUpdate.onEnd(update_finished);
70130

71131
t_httpUpdate_return ret = httpUpdate.update(client, url.c_str());
72132
JsonObject jsonObject;
@@ -98,16 +158,6 @@ void updateTask(void *param)
98158
ESP_LOGE(SVK_TAG, "HTTP Update failed, has same firmware version");
99159
#ifdef SERIAL_INFO
100160
Serial.println("HTTP Update failed, has same firmware version");
101-
#endif
102-
break;
103-
case HTTP_UPDATE_OK:
104-
105-
doc["status"] = "finished";
106-
_emitEvent = true;
107-
108-
ESP_LOGI(SVK_TAG, "HTTP Update successful - Restarting");
109-
#ifdef SERIAL_INFO
110-
Serial.println("HTTP Update successful - Restarting");
111161
#endif
112162
break;
113163
}

lib/framework/DownloadFirmwareService.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
#include <WiFiClientSecure.h>
2626
#include <HTTPUpdate.h>
27-
// #include <SSLCertBundle.h>
2827

2928
#define GITHUB_FIRMWARE_PATH "/rest/downloadUpdate"
3029
#define EVENT_DOWNLOAD_OTA "otastatus"

0 commit comments

Comments
 (0)