diff --git a/src/sys/svc/hasp_telnet.cpp b/src/sys/svc/hasp_telnet.cpp index b3bf5e65..ade74050 100644 --- a/src/sys/svc/hasp_telnet.cpp +++ b/src/sys/svc/hasp_telnet.cpp @@ -15,6 +15,9 @@ #include "../../hasp/hasp_dispatch.h" +#define IAC_SHOW_CHARACTERS "\xff\xfc\x01" +#define IAC_HIDE_CHARACTERS "\xff\xfb\x01" + #if defined(ARDUINO_ARCH_ESP32) #include WiFiClient telnetClient; @@ -44,14 +47,42 @@ ConsoleInput* telnetConsole; void telnet_update_prompt() { - if(telnetConsole) telnetConsole->update(); + if(telnetConsole) telnetConsole->update(__LINE__); bufferedTelnetClient.flush(); } +static inline void telnet_new_prompt(const char* prompt) +{ + if(!telnetConsole) return; + + telnetClient.println(IAC_SHOW_CHARACTERS); + telnetConsole->setPrompt(prompt); + telnetConsole->clearLine(); // avoid leaking information, updates the prompt + telnet_update_prompt(); +} + +static inline void telnet_echo_on() +{ + telnetClient.print(IAC_SHOW_CHARACTERS); +} + +static inline void telnet_password_prompt() +{ + telnetClient.print(IAC_SHOW_CHARACTERS D_PASSWORD " " IAC_HIDE_CHARACTERS); +} + +static inline void telnet_username_prompt() +{ + telnetClient.print(IAC_SHOW_CHARACTERS D_USERNAME " "); +} + static void telnetClientDisconnect() { if(telnetClient.connected()) LOG_TRACE(TAG_TELN, F(D_TELNET_CLOSING_CONNECTION), telnetClient.remoteIP().toString().c_str()); + bufferedTelnetClient.flush(); // empty buffer + telnetClient.flush(); // empty buffer + Log.unregisterOutput(1); // telnetClient telnetClient.stop(); @@ -70,21 +101,25 @@ void telnetStop(void) void telnetClientLogon() { - telnetClient.println(); debugPrintHaspHeader(&bufferedTelnetClient); telnetLoginState = TELNET_AUTHENTICATED; // User and Pass are correct telnetLoginAttempt = 0; // Reset attempt counter + // telnetClient.setTimeout(10); - /* Now register logger for telnet */ - Log.registerOutput(1, &bufferedTelnetClient, LOG_LEVEL_VERBOSE, true); + // empty buffers bufferedTelnetClient.flush(); - // telnetClient.setTimeout(10); + telnet_new_prompt("Prompt > "); + telnetClient.flush(); + /* Now register logger for telnet and switch to buffered stream */ + Log.registerOutput(1, &bufferedTelnetClient, LOG_LEVEL_VERBOSE, true); LOG_TRACE(TAG_TELN, F(D_TELNET_CLIENT_LOGIN_FROM), telnetClient.remoteIP().toString().c_str()); } void telnetAcceptClient() { + bufferedTelnetClient.flush(); // empty buffer + if(telnetClient) { telnetClient.stop(); // previous client has disconnected Log.unregisterOutput(1); // telnetClient @@ -96,6 +131,8 @@ void telnetAcceptClient() } LOG_INFO(TAG_TELN, F(D_TELNET_CLIENT_CONNECT_FROM), telnetClient.remoteIP().toString().c_str()); telnetClient.setNoDelay(true); + telnetClient.printf("\x1b]2;%s\x07" TERM_CLEAR_LINE, haspDevice.get_hostname()); + telnetClient.println("\r\nWelcome\r\n"); /* Avoid a buffer here */ // telnetClient.print((char)0xFF); // DO TERMINAL-TYPE @@ -104,13 +141,16 @@ void telnetAcceptClient() #if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 if(strlen(http_config.username) != 0 || strlen(http_config.password) != 0) { - telnetClient.println(F("\r\n" D_USERNAME " ")); telnetLoginState = TELNET_UNAUTHENTICATED; + telnetClient.println(); + telnet_username_prompt(); } else #endif { telnetClientLogon(); } + + telnetClient.flush(); telnetLoginAttempt = 0; // Initial attempt } @@ -202,30 +242,36 @@ static inline void telnetProcessCharacter(char ch) static void telnetProcessLine(const char* input) { + bufferedTelnetClient.flush(); + switch(telnetLoginState) { case TELNET_UNAUTHENTICATED: { - char buffer[20]; - snprintf_P(buffer, sizeof(buffer), PSTR(D_PASSWORD " %c%c%c\n"), 0xFF, 0xFB, - 0x01); // Hide characters - telnetClient.print(buffer); + #if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 - telnetLoginState = strcmp(input, http_config.username) == 0 ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; + bool username_is_valid = strcmp(input, http_config.username) == 0; + telnetLoginState = username_is_valid ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; + telnet_password_prompt(); break; } case TELNET_USERNAME_OK: case TELNET_USERNAME_NOK: { - telnetClient.printf(PSTR("%c%c%c\n"), 0xFF, 0xFC, 0x01); // Show characters - if(telnetLoginState == TELNET_USERNAME_OK && strcmp(input, http_config.password) == 0) { + bool password_is_valid = strcmp(input, http_config.password) == 0; + if(telnetConsole) telnetConsole->clearLine(); + telnet_echo_on(); // Show characters + + if(telnetLoginState == TELNET_USERNAME_OK && password_is_valid) { telnetClientLogon(); } else { telnetLoginState = TELNET_UNAUTHENTICATED; telnetLoginAttempt++; // Subsequent attempt - telnetClient.println(F(D_NETWORK_CONNECTION_UNAUTHORIZED "\r\n")); LOG_WARNING(TAG_TELN, F(D_TELNET_INCORRECT_LOGIN_ATTEMPT), telnetClient.remoteIP().toString().c_str()); + + telnetClient.println(F(D_NETWORK_CONNECTION_UNAUTHORIZED)); + if(telnetLoginAttempt >= 3) { telnetClientDisconnect(); } else { - telnetClient.print(F(D_USERNAME " ")); + telnetClient.println(F("\r\n\r\n" D_USERNAME " ")); } } #else @@ -240,7 +286,7 @@ static void telnetProcessLine(const char* input) } else if(strcasecmp_P(input, PSTR("logoff")) == 0) { #if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 if(strcmp(input, http_config.password) == 0) { - telnetClient.println(F("\r\n" D_USERNAME " ")); + telnet_username_prompt(); telnetLoginState = TELNET_UNAUTHENTICATED; } else #endif @@ -251,6 +297,8 @@ static void telnetProcessLine(const char* input) dispatch_text_line(input, TAG_TELN); } } + + telnetClient.flush(); } void telnetStart()