/** * @file config.c * @brief NVS Configuration Management */ #include #include "config.h" #include "nvs_flash.h" #include "nvs.h" #include "esp_log.h" static const char *TAG = "nexus_config"; /* NVS namespace */ static const char *NVS_NAMESPACE = "nexusguard"; /* NVS keys (all < 15 chars per NVS limit) */ static const char *KEY_DEVICE_ID = "device_id"; static const char *KEY_PRIVATE_KEY = "private_key"; static const char *KEY_PRESHARED_KEY = "preshared_key"; static const char *KEY_INTERNAL_IP = "internal_ip"; static const char *KEY_SERVER_PUB = "server_pub"; static const char *KEY_ENDPOINT = "endpoint"; static const char *KEY_DNS = "dns"; static const char *KEY_ALLOWED_IPS = "allowed_ips"; static const char *KEY_SERVER_WG_IP = "server_wgip"; static const char *KEY_CONFIG_HASH = "config_hash"; /* NVS handle (open once, reuse) */ static nvs_handle_t s_nvs_handle = 0; static bool s_nvs_open = false; /** * @brief Helper: write string to NVS */ static esp_err_t nvs_write_str(const char *key, const char *value) { if (!s_nvs_open) { return ESP_ERR_INVALID_STATE; } esp_err_t err = nvs_set_str(s_nvs_handle, key, value); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to write NVS key '%s': %s", key, esp_err_to_name(err)); } return err; } /** * @brief Helper: read string from NVS into buffer */ static esp_err_t nvs_read_str(const char *key, char *buf, size_t buf_len) { if (!s_nvs_open) { return ESP_ERR_INVALID_STATE; } size_t required_size = 0; esp_err_t err = nvs_get_str(s_nvs_handle, key, NULL, &required_size); if (err != ESP_OK) { return err; } if (required_size > buf_len) { ESP_LOGE(TAG, "NVS key '%s' value too large (%zu > %zu)", key, required_size, buf_len); return ESP_ERR_NVS_INVALID_LENGTH; } err = nvs_get_str(s_nvs_handle, key, buf, &buf_len); return err; } esp_err_t config_init(void) { ESP_LOGI(TAG, "Initializing NVS config module..."); esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &s_nvs_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open NVS namespace '%s': %s", NVS_NAMESPACE, esp_err_to_name(err)); return err; } s_nvs_open = true; ESP_LOGI(TAG, "NVS config module initialized"); return ESP_OK; } esp_err_t config_save(const wg_config_t *config) { if (config == NULL) { return ESP_ERR_INVALID_ARG; } ESP_LOGI(TAG, "Saving config for device: %s", config->device_id); esp_err_t err; esp_err_t final_err = ESP_OK; err = nvs_write_str(KEY_DEVICE_ID, config->device_id); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_PRIVATE_KEY, config->private_key); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_PRESHARED_KEY, config->preshared_key); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_INTERNAL_IP, config->internal_ip); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_SERVER_PUB, config->server_pub); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_ENDPOINT, config->endpoint); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_DNS, config->dns); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_ALLOWED_IPS, config->allowed_ips); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_SERVER_WG_IP, config->server_wg_ip); if (err != ESP_OK) final_err = err; err = nvs_write_str(KEY_CONFIG_HASH, config->config_hash); if (err != ESP_OK) final_err = err; if (final_err != ESP_OK) { ESP_LOGE(TAG, "Failed to save config"); return final_err; } /* Commit to flash */ err = nvs_commit(s_nvs_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to commit NVS: %s", esp_err_to_name(err)); return err; } ESP_LOGI(TAG, "Config saved successfully"); return ESP_OK; } esp_err_t config_load(wg_config_t *config) { if (config == NULL) { return ESP_ERR_INVALID_ARG; } /* Zero out the struct first */ memset(config, 0, sizeof(wg_config_t)); ESP_LOGI(TAG, "Loading config from NVS..."); esp_err_t err; esp_err_t final_err = ESP_OK; err = nvs_read_str(KEY_DEVICE_ID, config->device_id, sizeof(config->device_id)); if (err != ESP_OK) { ESP_LOGW(TAG, "No device_id in NVS (first boot?)"); return err; } err = nvs_read_str(KEY_PRIVATE_KEY, config->private_key, sizeof(config->private_key)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_PRESHARED_KEY, config->preshared_key, sizeof(config->preshared_key)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_INTERNAL_IP, config->internal_ip, sizeof(config->internal_ip)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_SERVER_PUB, config->server_pub, sizeof(config->server_pub)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_ENDPOINT, config->endpoint, sizeof(config->endpoint)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_DNS, config->dns, sizeof(config->dns)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_ALLOWED_IPS, config->allowed_ips, sizeof(config->allowed_ips)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_SERVER_WG_IP, config->server_wg_ip, sizeof(config->server_wg_ip)); if (err != ESP_OK) final_err = err; err = nvs_read_str(KEY_CONFIG_HASH, config->config_hash, sizeof(config->config_hash)); if (err != ESP_OK) final_err = err; if (final_err != ESP_OK) { ESP_LOGW(TAG, "Config loaded with errors"); return final_err; } ESP_LOGI(TAG, "Config loaded successfully for device: %s", config->device_id); return ESP_OK; } esp_err_t config_clear(void) { ESP_LOGI(TAG, "Clearing all NexusGuard NVS keys..."); if (!s_nvs_open) { return ESP_ERR_INVALID_STATE; } esp_err_t err; esp_err_t final_err = ESP_OK; err = nvs_erase_key(s_nvs_handle, KEY_DEVICE_ID); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_PRIVATE_KEY); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_PRESHARED_KEY); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_INTERNAL_IP); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_SERVER_PUB); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_ENDPOINT); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_DNS); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_ALLOWED_IPS); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_SERVER_WG_IP); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; err = nvs_erase_key(s_nvs_handle, KEY_CONFIG_HASH); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err; /* Commit erases to flash */ err = nvs_commit(s_nvs_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to commit NVS erase: %s", esp_err_to_name(err)); return err; } ESP_LOGI(TAG, "Config cleared"); return final_err; } bool config_is_valid(const wg_config_t *config) { if (config == NULL) { return false; } /* device_id and private_key must be non-empty */ if (strlen(config->device_id) == 0) { return false; } if (strlen(config->private_key) == 0) { return false; } return true; }