From 9d74cd5aa0960c10a9d8b04196d049023281e908 Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Fri, 18 Sep 2020 17:47:52 -0400 Subject: [PATCH] Improve the enduser setup experience by triggering captive portal detection. (#3282) * Make captive portal detection work on macOS * Change the default SSID prefix to be NodeMCU --- app/include/user_config.h | 2 +- app/modules/enduser_setup.c | 77 +-- app/modules/enduser_setup/enduser_setup.html | 88 ++-- .../enduser_setup/enduser_setup.html.gz.def.h | 458 +++++++++--------- docs/modules/enduser-setup.md | 12 +- 5 files changed, 346 insertions(+), 291 deletions(-) diff --git a/app/include/user_config.h b/app/include/user_config.h index bf007baa..27b9d08a 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -174,7 +174,7 @@ // If you use the enduser_setup module, then you can also set the default // SSID when this module is running in AP mode. -#define ENDUSER_SETUP_AP_SSID "SetupGadget" +#define ENDUSER_SETUP_AP_SSID "NodeMCU" // I2C software driver partially supports use of GPIO16 (D0) pin for SCL line. diff --git a/app/modules/enduser_setup.c b/app/modules/enduser_setup.c index dfe5565d..a8297738 100644 --- a/app/modules/enduser_setup.c +++ b/app/modules/enduser_setup.c @@ -92,7 +92,7 @@ static const char http_html_gz_filename[] = "enduser_setup.html.gz"; static const char http_html_filename[] = "enduser_setup.html"; static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nConnection:close\r\nContent-Type:text/html; charset=utf-8\r\n"; /* Note single \r\n here! */ static const char http_header_204[] = "HTTP/1.1 204 No Content\r\nContent-Length:0\r\nConnection:close\r\n\r\n"; -static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: /\r\nContent-Length:0\r\nConnection:close\r\n\r\n"; +static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: http://nodemcu.portal/\r\nContent-Length:0\r\nConnection:close\r\n\r\n"; static const char http_header_302_trying[] = "HTTP/1.1 302 Moved\r\nLocation: /?trying=true\r\nContent-Length:0\r\nConnection:close\r\n\r\n"; static const char http_header_400[] = "HTTP/1.1 400 Bad request\r\nContent-Length:0\r\nConnection:close\r\n\r\n"; static const char http_header_404[] = "HTTP/1.1 404 Not found\r\nContent-Length:10\r\nConnection:close\r\n\r\nNot found\n"; @@ -135,6 +135,7 @@ typedef struct struct tcp_pcb *http_pcb; char *http_payload_data; uint32_t http_payload_len; + char *ap_ssid; os_timer_t check_station_timer; os_timer_t shutdown_timer; int lua_connected_cb_ref; @@ -931,6 +932,8 @@ static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len) { tcp_sent (pcb, 0); deferred_close (pcb); + free(state->http_payload_data); + state->http_payload_data = NULL; } else tcp_arg (pcb, (void *)offs); @@ -1123,9 +1126,9 @@ static void enduser_setup_handle_OPTIONS (struct tcp_pcb *http_client, char *dat int type = 0; - if (strncmp(data, "GET ", 4) == 0) + if (strncmp(data, "OPTIONS ", 8) == 0) { - if (strncmp(data + 4, "/aplist", 7) == 0 || strncmp(data + 4, "/setwifi?", 9) == 0 || strncmp(data + 4, "/status.json", 12) == 0) + if (strncmp(data + 8, "/aplist", 7) == 0 || strncmp(data + 8, "/setwifi?", 9) == 0 || strncmp(data + 8, "/status.json", 12) == 0) { enduser_setup_http_serve_header (http_client, json, strlen(json)); return; @@ -1153,7 +1156,7 @@ static void enduser_setup_handle_POST(struct tcp_pcb *http_client, char* data, s { case 0: { // all went fine, extract all the form data into a file - enduser_setup_write_file_with_extra_configuration_data(body, bodylength); + enduser_setup_write_file_with_extra_configuration_data(body, bodylength); // redirect user to the base page with the trying flag enduser_setup_http_serve_header(http_client, http_header_302_trying, LITLEN(http_header_302_trying)); break; @@ -1283,7 +1286,7 @@ static void on_scan_done (void *arg, STATUS status) const size_t hdr_sz = sizeof (header_fmt) +1 -1; /* +expand %4d, -\0 */ /* To be able to safely escape a pathological SSID, we need 2*32 bytes */ - const size_t max_entry_sz = 27 + 2*32 + 6; /* {"ssid":"","rssi":,"chan":} */ + const size_t max_entry_sz = 35 + 2*32 + 9; /* {"ssid":"","rssi":,"chan":,"auth":} */ const size_t alloc_sz = hdr_sz + num_nets * max_entry_sz + 3; char *http = calloc (1, alloc_sz); if (!http) @@ -1319,6 +1322,12 @@ static void on_scan_done (void *arg, STATUS status) p += sprintf (p, "%d", wn->channel); + const char entry_auth[] = ",\"auth\":"; + strcpy (p, entry_auth); + p += sizeof (entry_auth) -1; + + p += sprintf (p, "%d", wn->authmode); + *p++ = '}'; } *p++ = ']'; @@ -1579,15 +1588,10 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s break; } } - else if (strncmp(data + 4, "/generate_204", 13) == 0) - { - /* Convince Android devices that they have internet access to avoid pesky dialogues. */ - enduser_setup_http_serve_header(http_client, http_header_204, LITLEN(http_header_204)); - } else { - ENDUSER_SETUP_DEBUG("serving 404"); - enduser_setup_http_serve_header(http_client, http_header_404, LITLEN(http_header_404)); + // All other URLs redirect to http://nodemcu.portal/ -- this triggers captive portal. + enduser_setup_http_serve_header(http_client, http_header_302, LITLEN(http_header_302)); } } else if (strncmp(data, "OPTIONS ", 8) == 0) @@ -1706,18 +1710,23 @@ static void enduser_setup_ap_start(void) memset(&(cnf), 0, sizeof(struct softap_config)); #ifndef ENDUSER_SETUP_AP_SSID - #define ENDUSER_SETUP_AP_SSID "SetupGadget" + #define ENDUSER_SETUP_AP_SSID "NodeMCU" #endif - char ssid[] = ENDUSER_SETUP_AP_SSID; - int ssid_name_len = strlen(ssid); - memcpy(&(cnf.ssid), ssid, ssid_name_len); + if (state->ap_ssid) { + strncpy(cnf.ssid, state->ap_ssid, sizeof(cnf.ssid)); + cnf.ssid_len = strlen(cnf.ssid); + } else { + char ssid[] = ENDUSER_SETUP_AP_SSID; + int ssid_name_len = strlen(ssid); + memcpy(&(cnf.ssid), ssid, ssid_name_len); - uint8_t mac[6]; - wifi_get_macaddr(SOFTAP_IF, mac); - cnf.ssid[ssid_name_len] = '_'; - sprintf(cnf.ssid + ssid_name_len + 1, "%02X%02X%02X", mac[3], mac[4], mac[5]); - cnf.ssid_len = ssid_name_len + 7; + uint8_t mac[6]; + wifi_get_macaddr(SOFTAP_IF, mac); + cnf.ssid[ssid_name_len] = '_'; + sprintf(cnf.ssid + ssid_name_len + 1, "%02X%02X%02X", mac[3], mac[4], mac[5]); + cnf.ssid_len = ssid_name_len + 7; + } cnf.channel = state == NULL? 1 : state->softAPchannel; cnf.authmode = AUTH_OPEN; cnf.ssid_hidden = 0; @@ -1895,6 +1904,8 @@ static void enduser_setup_free(void) free_scan_listeners (); + free(state->ap_ssid); + free(state); state = NULL; } @@ -1999,21 +2010,33 @@ static int enduser_setup_init(lua_State *L) } } - if (!lua_isnoneornil(L, 1)) + int argno = 1; + + if (lua_isstring(L, argno)) { + /* Get the SSID */ + state->ap_ssid = strdup(lua_tostring(L, argno)); + argno++; + } + + if (!lua_isnoneornil(L, argno)) { - lua_pushvalue(L, 1); + lua_pushvalue(L, argno); state->lua_connected_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - if (!lua_isnoneornil(L, 2)) + argno++; + + if (!lua_isnoneornil(L, argno)) { - lua_pushvalue (L, 2); + lua_pushvalue (L, argno); state->lua_err_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - if (!lua_isnoneornil(L, 3)) + argno++; + + if (!lua_isnoneornil(L, argno)) { - lua_pushvalue (L, 3); + lua_pushvalue (L, argno); state->lua_dbg_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); ENDUSER_SETUP_DEBUG("enduser_setup_init: Debug callback has been set"); } diff --git a/app/modules/enduser_setup/enduser_setup.html b/app/modules/enduser_setup/enduser_setup.html index 6aab7675..44fcb134 100644 --- a/app/modules/enduser_setup/enduser_setup.html +++ b/app/modules/enduser_setup/enduser_setup.html @@ -160,7 +160,7 @@ - + @@ -262,46 +262,51 @@ xhr.send(); } function gotAp(s, json) { - var list; - if (s === 200 && json != null) { - if (typeof json === 'string' && json.length > 0) { - list = JSON.parse(json); - } else if (typeof json === 'object') { - list = json; - } + var list; + if (s === 200 && json != null) { + if (typeof json === 'string' && json.length > 0) { + list = JSON.parse(json); + } else if (typeof json === 'object') { + list = json; + } - list.sort(function (a, b) { - return b.rssi - a.rssi; - }); - var ops = ''; - var seen = {}; - for (var i = 0; i < list.length; ++i) { - var ssid = list[i].ssid; - if (!seen[ssid]) { - seen[ssid] = 1; - ops += ''; + var seen = {}; + for (var i = 0; i < list.length; ++i) { + var ssid = list[i].ssid; + if (!seen[ssid]) { + seen[ssid] = 1; + ops += '