Expand admin SSH command capabilities

Add per-session history, tab completion, interactive prompts, and
bounded input handling. Support deferred lifecycle and host-key actions
after output drains, and document the expanded administration workflow.
This commit is contained in:
2026-08-30 18:34:01 +02:00
parent 0a1bbd6782
commit c2c11fee4e
14 changed files with 699 additions and 224 deletions
+12 -68
View File
@@ -9,19 +9,16 @@
#include <stdlib.h>
#include <string.h>
#include "admin_ssh_console.h"
#include "driver/uart.h"
#include "console_input.h"
#include "esp_console.h"
#include "esp_err.h"
#include "esp_netif_ip_addr.h"
#include "esp_wifi_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "network_console.h"
#include "wifi_config.h"
#include "wifi_manager.h"
#define WIFI_CONSOLE_UART UART_NUM_0
#define WIFI_CONSOLE_SECRET_CAPACITY WIFI_CONFIG_PSK_MAX_LEN
static void print_usage(void)
@@ -243,72 +240,19 @@ static esp_err_t apply_candidate(wifi_app_config_t *candidate)
static esp_err_t read_secret_no_echo(uint8_t *secret, uint8_t *secret_len)
{
if (admin_ssh_console_dispatch_is_remote()) {
printf("Interactive secret entry is restricted to physical UART0.\n");
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t buffer[WIFI_CONSOLE_SECRET_CAPACITY];
uint8_t buffer[WIFI_CONSOLE_SECRET_CAPACITY + 1U] = {0};
size_t length = 0U;
memset(buffer, 0, sizeof(buffer));
/*
* esp_console may execute on CR while the terminal's trailing LF is still
* arriving. Let that line ending settle, then discard only pre-prompt RX so
* it cannot be mistaken for an immediately submitted empty secret.
*/
vTaskDelay(1U);
esp_err_t flush_error = uart_flush_input(WIFI_CONSOLE_UART);
if (flush_error != ESP_OK) {
wifi_config_secure_wipe(buffer, sizeof(buffer));
printf("Could not prepare secret input: %s\n", esp_err_to_name(flush_error));
return flush_error;
esp_err_t error = console_input_read_hidden(
"Enter 8..63 printable ASCII characters (input hidden, Ctrl-C cancels): ",
buffer, sizeof(buffer), WIFI_CONFIG_PSK_MIN_LEN,
WIFI_CONFIG_PSK_MAX_LEN, &length);
if (error == ESP_OK) {
memset(secret, 0, WIFI_CONFIG_PSK_MAX_LEN);
memcpy(secret, buffer, length);
*secret_len = (uint8_t)length;
}
printf("Enter 8..63 printable ASCII characters (input hidden, Ctrl-C cancels): ");
fflush(stdout);
for (;;) {
uint8_t byte = 0U;
int received = uart_read_bytes(WIFI_CONSOLE_UART, &byte, 1U, portMAX_DELAY);
if (received != 1) {
wifi_config_secure_wipe(buffer, sizeof(buffer));
printf("\nSecret input failed.\n");
return ESP_FAIL;
}
if (byte == 0x03U) {
wifi_config_secure_wipe(buffer, sizeof(buffer));
printf("\nCancelled.\n");
return ESP_ERR_INVALID_STATE;
}
if (byte == '\r' || byte == '\n') {
break;
}
if (byte == 0x08U || byte == 0x7fU) {
if (length > 0U) {
buffer[--length] = 0U;
}
continue;
}
if (byte < 0x20U || byte > 0x7eU || length >= sizeof(buffer)) {
putchar('\a');
fflush(stdout);
continue;
}
buffer[length++] = byte;
}
putchar('\n');
if (length < WIFI_CONFIG_PSK_MIN_LEN || length > WIFI_CONFIG_PSK_MAX_LEN) {
wifi_config_secure_wipe(buffer, sizeof(buffer));
printf("Secret length must be 8..63 characters.\n");
return ESP_ERR_INVALID_ARG;
}
memset(secret, 0, WIFI_CONFIG_PSK_MAX_LEN);
memcpy(secret, buffer, length);
*secret_len = (uint8_t)length;
wifi_config_secure_wipe(buffer, sizeof(buffer));
return ESP_OK;
return error;
}
static int set_profile(char **argv)