Add typed account and password settings
- Add admin account list, create, role, delete, and password workflows - Execute identity-checked mutations through the existing dispatcher - Bound queued credential lifetime and wipe transient secrets - Add explicit password generation with saved-value acknowledgement - Handle self-revocation and uncertain outcomes without automatic retries - Register optional account routes without disrupting terminal transports - Expand host regressions and document contracts and pending target checks Validated host suites and pio run; hardware validation remains pending.
This commit is contained in:
+90
-12
@@ -295,7 +295,7 @@ static esp_err_t set_record_password(stored_user_t *user,
|
||||
return error;
|
||||
}
|
||||
|
||||
static esp_err_t generate_password(user_database_generated_password_t *generated)
|
||||
esp_err_t user_database_generate_password_value(user_database_generated_password_t *generated)
|
||||
{
|
||||
if (generated == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -788,6 +788,25 @@ esp_err_t user_database_get_snapshot(user_database_snapshot_t *snapshot)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t user_database_get_accounts(user_database_accounts_t *accounts)
|
||||
{
|
||||
if (accounts == NULL) return ESP_ERR_INVALID_ARG;
|
||||
memset(accounts, 0, sizeof(*accounts));
|
||||
if (!s_initialized || s_mutex == NULL) return ESP_ERR_INVALID_STATE;
|
||||
if (xSemaphoreTake(s_mutex, 0U) != pdTRUE) return ESP_ERR_TIMEOUT;
|
||||
for (size_t i = 0; i < USER_DATABASE_MAX_USERS; ++i) {
|
||||
const stored_user_t *user = &s_database.users[i];
|
||||
if (!user->active) continue;
|
||||
user_database_account_t *out = &accounts->users[accounts->count++];
|
||||
out->user_id = user->user_id;
|
||||
out->auth_generation = user->auth_generation;
|
||||
out->role = (user_role_t)user->role;
|
||||
memcpy(out->username, user->username, user->username_length);
|
||||
}
|
||||
xSemaphoreGive(s_mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void fill_principal(const stored_user_t *user, user_auth_method_t method,
|
||||
user_principal_t *principal)
|
||||
{
|
||||
@@ -986,7 +1005,7 @@ esp_err_t user_database_create_generated(
|
||||
const uint8_t *username, size_t username_length, user_role_t role,
|
||||
user_database_generated_password_t *generated_password)
|
||||
{
|
||||
esp_err_t error = generate_password(generated_password);
|
||||
esp_err_t error = user_database_generate_password_value(generated_password);
|
||||
if (error == ESP_OK) {
|
||||
error = user_database_create(username, username_length, role,
|
||||
generated_password->password,
|
||||
@@ -1037,7 +1056,7 @@ esp_err_t user_database_bootstrap_admin(const uint8_t *password,
|
||||
esp_err_t user_database_bootstrap_admin_generated(
|
||||
user_database_generated_password_t *generated_password)
|
||||
{
|
||||
esp_err_t error = generate_password(generated_password);
|
||||
esp_err_t error = user_database_generate_password_value(generated_password);
|
||||
if (error == ESP_OK) {
|
||||
error = user_database_bootstrap_admin(generated_password->password,
|
||||
generated_password->password_length);
|
||||
@@ -1062,14 +1081,26 @@ static esp_err_t mutate_user_begin(const uint8_t *username, size_t username_leng
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t user_database_delete(const uint8_t *username, size_t username_length)
|
||||
static bool target_matches_locked(const uint8_t *username, size_t length,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
if (!expected) return true;
|
||||
int index = find_user(&s_database, username, length);
|
||||
return index >= 0 && expected->user_id != 0 && expected->auth_generation != 0 &&
|
||||
s_database.users[index].user_id == expected->user_id &&
|
||||
s_database.users[index].auth_generation == expected->auth_generation;
|
||||
}
|
||||
|
||||
static esp_err_t delete_user(const uint8_t *username, size_t username_length,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
const stored_user_t *user = &s_database.users[index];
|
||||
bool protected_migrated_admin =
|
||||
@@ -1090,8 +1121,8 @@ esp_err_t user_database_delete(const uint8_t *username, size_t username_length)
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_role(const uint8_t *username, size_t username_length,
|
||||
user_role_t role)
|
||||
static esp_err_t set_role(const uint8_t *username, size_t username_length,
|
||||
user_role_t role, const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL ||
|
||||
(role != USER_ROLE_USER && role != USER_ROLE_ADMIN)) {
|
||||
@@ -1099,7 +1130,8 @@ esp_err_t user_database_set_role(const uint8_t *username, size_t username_length
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
stored_user_t *user = &s_candidate->users[index];
|
||||
if (user->role == role) {
|
||||
@@ -1125,8 +1157,37 @@ esp_err_t user_database_set_role(const uint8_t *username, size_t username_length
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_password(const uint8_t *username, size_t username_length,
|
||||
const uint8_t *password, size_t password_length)
|
||||
esp_err_t user_database_delete(const uint8_t *username, size_t length)
|
||||
{
|
||||
return delete_user(username, length, NULL);
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_role(const uint8_t *username, size_t length, user_role_t role)
|
||||
{
|
||||
return set_role(username, length, role, NULL);
|
||||
}
|
||||
|
||||
esp_err_t user_database_delete_current(const user_database_account_t *expected)
|
||||
{
|
||||
if (!expected) return ESP_ERR_INVALID_ARG;
|
||||
size_t length = strnlen(expected->username, sizeof(expected->username));
|
||||
if (!user_database_username_valid((const uint8_t *)expected->username, length))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
return delete_user((const uint8_t *)expected->username, length, expected);
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_role_current(const user_database_account_t *expected, user_role_t role)
|
||||
{
|
||||
if (!expected) return ESP_ERR_INVALID_ARG;
|
||||
size_t length = strnlen(expected->username, sizeof(expected->username));
|
||||
if (!user_database_username_valid((const uint8_t *)expected->username, length))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
return set_role((const uint8_t *)expected->username, length, role, expected);
|
||||
}
|
||||
|
||||
static esp_err_t set_password(const uint8_t *username, size_t username_length,
|
||||
const uint8_t *password, size_t password_length,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL ||
|
||||
!user_database_password_valid(password, password_length)) {
|
||||
@@ -1134,7 +1195,8 @@ esp_err_t user_database_set_password(const uint8_t *username, size_t username_le
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
stored_user_t *user = &s_candidate->users[index];
|
||||
error = set_record_password(user, password, password_length);
|
||||
@@ -1151,11 +1213,27 @@ esp_err_t user_database_set_password(const uint8_t *username, size_t username_le
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_password(const uint8_t *username, size_t username_length,
|
||||
const uint8_t *password, size_t password_length)
|
||||
{
|
||||
return set_password(username, username_length, password, password_length, NULL);
|
||||
}
|
||||
|
||||
esp_err_t user_database_set_password_current(const user_database_account_t *expected,
|
||||
const uint8_t *password, size_t password_length)
|
||||
{
|
||||
if (!expected) return ESP_ERR_INVALID_ARG;
|
||||
size_t length = strnlen(expected->username, sizeof(expected->username));
|
||||
if (!user_database_username_valid((const uint8_t *)expected->username, length))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
return set_password((const uint8_t *)expected->username, length, password, password_length, expected);
|
||||
}
|
||||
|
||||
esp_err_t user_database_generate_password(
|
||||
const uint8_t *username, size_t username_length,
|
||||
user_database_generated_password_t *generated_password)
|
||||
{
|
||||
esp_err_t error = generate_password(generated_password);
|
||||
esp_err_t error = user_database_generate_password_value(generated_password);
|
||||
if (error == ESP_OK) {
|
||||
error = user_database_set_password(username, username_length,
|
||||
generated_password->password,
|
||||
|
||||
Reference in New Issue
Block a user