8000 Merge pull request #6638 from Neradoc/nera-web-workflow · tannewt/circuitpython@39a0639 · GitHub
[go: up one dir, main page]

Skip to content

Commit 39a0639

Browse files
authored
Merge pull request micropython#6638 from Neradoc/nera-web-workflow
Refine web workflow access control and http responses
2 parents acdfda7 + 09915ab commit 39a0639

File tree

1 file changed

+42
-36
lines changed

1 file changed

+42
-36
lines changed

supervisor/shared/web_workflow/web_workflow.c

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -350,38 +350,40 @@ static bool _endswith(const char *str, const char *suffix) {
350350
return strcmp(str + (strlen(str) - strlen(suffix)), suffix) == 0;
351351
}
352352

353-
const char *ok_hosts[] = {"code.circuitpython.org"};
353+
const char *ok_hosts[] = {
354+
"code.circuitpython.org",
355+
"127.0.0.1",
356+
"localhost",
357+
};
354358

355359
static bool _origin_ok(const char *origin) {
356360
const char *http = "http://";
357361
const char *local = ".local";
358362

359-
if (memcmp(origin, http, strlen(http)) != 0) {
363+
// note: redirected requests send an Origin of "null" and will be caught by this
364+
if (strncmp(origin, http, strlen(http)) != 0) {
360365
return false;
361366
}
362367
// These are prefix checks up to : so that any port works.
363368
const char *hostname = common_hal_mdns_server_get_hostname(&mdns);
364369
const char *end = origin + strlen(http) + strlen(hostname) + strlen(local);
365-
if (memcmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
366-
memcmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
370+
if (strncmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
371+
strncmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
367372
(end[0] == '\0' || end[0] == ':')) {
368373
return true;
369374
}
370375

371376
end = origin + strlen(http) + strlen(_our_ip_encoded);
372-
if (memcmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
377+
if (strncmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
373378
(end[0] == '\0' || end[0] == ':')) {
374379
return true;
375380
}
376381

377-
const char *localhost = "127.0.0.1:";
378-
if (memcmp(origin + strlen(http), localhost, strlen(localhost)) == 0) {
379-
return true;
380-
}
381-
382382
for (size_t i = 0; i < MP_ARRAY_SIZE(ok_hosts); i++) {
383-
// This checks exactly.
384-
if (strcmp(origin + strlen(http), ok_hosts[i]) == 0) {
383+
// Allows any port
384+
end = origin + strlen(http) + strlen(ok_hosts[i]);
385+
if (strncmp(origin + strlen(http), ok_hosts[i], strlen(ok_hosts[i])) == 0
386+
&& (end[0] == '\0' || end[0] == ':')) {
385387
return true;
386388
}
387389
}
@@ -908,8 +910,11 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
908910
} else if (strlen(request->origin) > 0 && !_origin_ok(request->origin)) {
909911
ESP_LOGE(TAG, "bad origin %s", request->origin);
910912
_reply_forbidden(socket, request);
911-
} else if (memcmp(request->path, "/fs/", 4) == 0) {
912-
if (!request->authenticated) {
913+
} else if (strncmp(request->path, "/fs/", 4) == 0) {
914+
if (strcasecmp(request->method, "OPTIONS") == 0) {
915+
// OPTIONS is sent for CORS preflight, unauthenticated
916+
_reply_access_control(socket, request);
917+
} else if (!request->authenticated) {
913918
if (_api_password[0] != '\0') {
914919
_reply_unauthorized(socket, request);
915920
} else {
@@ -930,9 +935,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
930935
}
931936
// Delete is almost identical for files and directories so share the
932937
// implementation.
933-
if (strcmp(request->method, "OPTIONS") == 0) {
934-
_reply_access_control(socket, request);
935-
} else if (strcmp(request->method, "DELETE") == 0) {
938+
if (strcasecmp(request->method, "DELETE") == 0) {
936939
if (_usb_active()) {
937940
_reply_conflict(socket, request);
938941
return false;
@@ -962,7 +965,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
962965
return true;
963966
}
964967
} else if (directory) {
965-
if (strcmp(request->method, "GET") == 0) {
968+
if (strcasecmp(request->method, "GET") == 0) {
966969
FF_DIR dir;
967970
FRESULT res = f_opendir(fs, &dir, path);
968971
// Put the / back for replies.
@@ -982,7 +985,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
982985
}
983986

984987
f_closedir(&dir);
985-
} else if (strcmp(request->method, "PUT") == 0) {
988+
} else if (strcasecmp(request->method, "PUT") == 0) {
986989
if (_usb_active()) {
987990
_reply_conflict(socket, request);
988991
return false;
@@ -1011,7 +1014,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
10111014
}
10121015
}
10131016
} else { // Dealing with a file.
1014-
if (strcmp(request->method, "GET") == 0) {
1017+
if (strcasecmp(request->method, "GET") == 0) {
10151018
FIL active_file;
10161019
FRESULT result = f_open(fs, &active_file, path, FA_READ);
10171020

@@ -1022,15 +1025,18 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
10221025
}
10231026

10241027
f_close(&active_file);
1025-
} else if (strcmp(request->method, "PUT") == 0) {
1028+
} else if (strcasecmp(request->method, "PUT") == 0) {
10261029
_write_file_and_reply(socket, request, fs, path);
10271030
return true;
10281031
}
10291032
}
10301033
}
1031-
} else if (memcmp(request->path, "/cp/", 4) == 0) {
1034+
} else if (strncmp(request->path, "/cp/", 4) == 0) {
10321035
const char *path = request->path + 3;
1033-
if (strcmp(request->method, "GET") != 0) {
1036+
if (strcasecmp(request->method, "OPTIONS") == 0) {
1037+
// handle preflight requests to /cp/
1038+
_reply_access_control(socket, request);
1039+
} else if (strcasecmp(request->method, "GET") != 0) {
10341040
_reply_method_not_allowed(socket, request);
10351041
} else if (strcmp(path, "/devices.json") == 0) {
10361042
_reply_with_devices_json(socket, request);
@@ -1051,7 +1057,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
10511057
} else {
10521058
_reply_missing(socket, request);
10531059
}
1054-
} else if (strcmp(request->method, "GET") != 0) {
1060+
} else if (strcasecmp(request->method, "GET") != 0) {
10551061
_reply_method_not_allowed(socket, request);
10561062
} else {
10571063
if (strcmp(request->path, "/") == 0) {
@@ -1168,27 +1174,27 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
11681174
request->header_value[request->offset - 1] = '\0';
11691175
request->offset = 0;
11701176
request->state = STATE_HEADER_KEY;
1171-
if (strcmp(request->header_key, "Authorization") == 0) {
1177+
if (strcasecmp(request->header_key, "Authorization") == 0) {
11721178
const char *prefix = "Basic ";
1173-
request->authenticated = memcmp(request->header_value, prefix, strlen(prefix)) == 0 &&
1179+
request->authenticated = strncmp(request->header_value, prefix, strlen(prefix)) == 0 &&
11741180
strcmp(_api_password, request->header_value + strlen(prefix)) == 0;
1175-
} else if (strcmp(request->header_key, "Host") == 0) {
1181+
} else if (strcasecmp(request->header_key, "Host") == 0) {
11761182
request->redirect = strcmp(request->header_value, "circuitpython.local") == 0;
1177-
} else if (strcmp(request->header_key, "Content-Length") == 0) {
1183+
} else if (strcasecmp(request->header_key, "Content-Length") == 0) {
11781184
request->content_length = strtoul(request->header_value, NULL, 10);
1179-
} else if (strcmp(request->header_key, "Expect") == 0) {
1185+
} else if (strcasecmp(request->header_key, "Expect") == 0) {
11801186
request->expect = strcmp(request->header_value, "100-continue") == 0;
1181-
} else if (strcmp(request->header_key, "Accept") == 0) {
1182-
request->json = strcmp(request->header_value, "application/json") == 0;
1183-
} else if (strcmp(request->header_key, "Origin") == 0) {
1187+
} else if (strcasecmp(request->header_key, "Accept") == 0) {
1188+
request->json = strcasecmp(request->header_value, "application/json") == 0;
1189+
} else if (strcasecmp(request->header_key, "Origin") == 0) {
11841190
strcpy(request->origin, request->header_value);
1185-
} else if (strcmp(request->header_key, "X-Timestamp") == 0) {
1191+
} else if (strcasecmp(request->header_key, "X-Timestamp") == 0) {
11861192
request->timestamp_ms = strtoull(request->header_value, NULL, 10);
1187-
} else if (strcmp(request->header_key, "Upgrade") == 0) {
1193+
} else if (strcasecmp(request->header_key, "Upgrade") == 0) {
11881194
request->websocket = strcmp(request->header_value, "websocket") == 0;
1189-
} else if (strcmp(request->header_key, "Sec-WebSocket-Version") == 0) {
1195+
} else if (strcasecmp(request->header_key, "Sec-WebSocket-Version") == 0) {
11901196
request->websocket_version = strtoul(request->header_value, NULL, 10);
1191-
} else if (strcmp(request->header_key, "Sec-WebSocket-Key") == 0 &&
1197+
} else if (strcasecmp(request->header_key, "Sec-WebSocket-Key") == 0 &&
11921198
strlen(request->header_value) == 24) {
11931199
strcpy(request->websocket_key, request->header_value);
11941200
}

0 commit comments

Comments
 (0)
0