v0.0.14 - Still working on commenting out old code and deleting
This commit is contained in:
Binary file not shown.
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
db/ginxsom.db
BIN
db/ginxsom.db
Binary file not shown.
@@ -15,7 +15,7 @@
|
||||
#define DB_PATH "db/ginxsom.db"
|
||||
|
||||
// Function declarations (moved from admin_api.h)
|
||||
void handle_admin_api_request(const char* method, const char* uri);
|
||||
void handle_admin_api_request(const char* method, const char* uri, const char* validated_pubkey, int is_authenticated);
|
||||
void handle_stats_api(void);
|
||||
void handle_config_get_api(void);
|
||||
void handle_config_put_api(void);
|
||||
@@ -120,7 +120,7 @@ static const char* admin_mime_to_extension(const char* mime_type) {
|
||||
}
|
||||
|
||||
// Main API request handler
|
||||
void handle_admin_api_request(const char* method, const char* uri) {
|
||||
void handle_admin_api_request(const char* method, const char* uri, const char* validated_pubkey, int is_authenticated) {
|
||||
const char* path = uri + 4; // Skip "/api"
|
||||
|
||||
// Check if admin interface is enabled
|
||||
@@ -129,15 +129,20 @@ void handle_admin_api_request(const char* method, const char* uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Re-enable authentication later
|
||||
// Authentication temporarily disabled for testing
|
||||
// if (strcmp(path, "/health") != 0) {
|
||||
// const char* auth_header = getenv("HTTP_AUTHORIZATION");
|
||||
// if (!authenticate_admin_request(auth_header)) {
|
||||
// send_json_error(401, "admin_auth_required", "Valid admin authentication required");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// Authentication now handled by centralized validation system
|
||||
// Health endpoint is exempt from authentication requirement
|
||||
if (strcmp(path, "/health") != 0) {
|
||||
if (!is_authenticated || !validated_pubkey) {
|
||||
send_json_error(401, "admin_auth_required", "Valid admin authentication required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify the authenticated pubkey has admin privileges
|
||||
if (!verify_admin_pubkey(validated_pubkey)) {
|
||||
send_json_error(403, "admin_forbidden", "Admin privileges required");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Route to appropriate handler
|
||||
if (strcmp(method, "GET") == 0) {
|
||||
|
||||
@@ -251,7 +251,7 @@ int validate_sha256_format(const char* sha256);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Admin API request handler
|
||||
void handle_admin_api_request(const char* method, const char* uri);
|
||||
void handle_admin_api_request(const char* method, const char* uri, const char* validated_pubkey, int is_authenticated);
|
||||
|
||||
// Individual endpoint handlers
|
||||
void handle_stats_api(void);
|
||||
|
||||
18
src/main.c
18
src/main.c
@@ -1024,6 +1024,8 @@ void handle_upload_request(void) {
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
// Legacy authentication check - now handled by centralized validation system
|
||||
/*
|
||||
// Check if authentication rules are enabled using nostr_core_lib system
|
||||
int auth_required = nostr_auth_rules_enabled();
|
||||
fprintf(stderr, "AUTH: auth_rules_enabled = %d, auth_header present: %s\r\n",
|
||||
@@ -1046,12 +1048,14 @@ void handle_upload_request(void) {
|
||||
// Skip validation and proceed to file processing
|
||||
goto process_file_upload;
|
||||
}
|
||||
*/
|
||||
|
||||
// Authentication is handled by centralized validation system
|
||||
// TODO: Get uploader_pubkey from centralized validation result
|
||||
// For now, keep existing uploader_pubkey extraction for compatibility
|
||||
|
||||
process_file_upload:
|
||||
// Legacy goto label - no longer needed with centralized validation
|
||||
// process_file_upload:
|
||||
// Get dimensions from in-memory buffer before saving file
|
||||
int width = 0, height = 0;
|
||||
nip94_get_dimensions(file_data, content_length, content_type, &width,
|
||||
@@ -1295,6 +1299,8 @@ void handle_upload_request_with_validation(nostr_request_result_t* validation_re
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
// Legacy authentication check - now handled by centralized validation system
|
||||
/*
|
||||
// Check if authentication rules are enabled using nostr_core_lib system
|
||||
int auth_required = nostr_auth_rules_enabled();
|
||||
fprintf(stderr, "AUTH: auth_rules_enabled = %d, auth_header present: %s\r\n",
|
||||
@@ -1317,11 +1323,13 @@ void handle_upload_request_with_validation(nostr_request_result_t* validation_re
|
||||
// Skip validation and proceed to file processing
|
||||
goto process_file_upload;
|
||||
}
|
||||
*/
|
||||
|
||||
// Authentication was handled by centralized validation system
|
||||
// uploader_pubkey should be set from validation result
|
||||
|
||||
process_file_upload:
|
||||
// Legacy goto label - no longer needed with centralized validation
|
||||
// process_file_upload:
|
||||
// Get dimensions from in-memory buffer before saving file
|
||||
int width = 0, height = 0;
|
||||
nip94_get_dimensions(file_data, file_size, content_type, &width,
|
||||
@@ -1650,6 +1658,8 @@ if (!config_loaded /* && !initialize_server_config() */) {
|
||||
// HEAD requests might not require auth depending on config - let handler decide
|
||||
} else if (strcmp(operation, "list") == 0) {
|
||||
// List operation might be optional auth - let handler decide
|
||||
} else if (strcmp(operation, "admin") == 0 && strcmp(request_uri, "/api/health") == 0) {
|
||||
// Health endpoint is public and doesn't require authentication - let handler decide
|
||||
} else {
|
||||
// For other operations, validation failure means auth failure
|
||||
const char *message = result.reason[0] ? result.reason : "Authentication failed";
|
||||
@@ -1732,8 +1742,8 @@ if (!config_loaded /* && !initialize_server_config() */) {
|
||||
|
||||
} else if (strncmp(request_uri, "/api/", 5) == 0) {
|
||||
// Handle admin API requests with pre-validated auth
|
||||
// TODO: Pass validated result to existing handler
|
||||
handle_admin_api_request(request_method, request_uri);
|
||||
const char *validated_pubkey = (result.valid && strlen(result.pubkey) == 64) ? result.pubkey : NULL;
|
||||
handle_admin_api_request(request_method, request_uri, validated_pubkey, result.valid);
|
||||
|
||||
|
||||
} else if (strcmp(request_method, "GET") == 0 &&
|
||||
|
||||
@@ -113,6 +113,7 @@ static int validate_blossom_event(cJSON *event, const char *expected_hash,
|
||||
const char *method);
|
||||
static int validate_nip42_event(cJSON *event, const char *relay_url,
|
||||
const char *challenge_id);
|
||||
static int validate_admin_event(cJSON *event, const char *method, const char *endpoint);
|
||||
static int check_database_auth_rules(const char *pubkey, const char *operation,
|
||||
const char *resource_hash);
|
||||
void nostr_request_validator_clear_violation(void);
|
||||
@@ -659,6 +660,79 @@ int nostr_validate_unified_request(const nostr_unified_request_t *request,
|
||||
"VALIDATOR_DEBUG: STEP 10 PASSED - Blossom authentication succeeded\n");
|
||||
strcpy(result->reason, "Blossom authentication passed");
|
||||
|
||||
} else if (event_kind == 33335) {
|
||||
// 10. Admin/Configuration Event Validation (Kind 33335)
|
||||
// Verify admin authorization, check required tags, validate expiration
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 - Processing Admin/Configuration "
|
||||
"authentication (kind 33335)\n");
|
||||
|
||||
char admin_valid_msg[512];
|
||||
sprintf(admin_valid_msg,
|
||||
"VALIDATOR_DEBUG: Validating Admin event for operation='%s', "
|
||||
"endpoint='%s'\n",
|
||||
request->operation ? request->operation : "NULL",
|
||||
request->resource_hash ? request->resource_hash : "admin_api");
|
||||
validator_debug_log(admin_valid_msg);
|
||||
|
||||
// For admin operations, we pass the HTTP method and API endpoint
|
||||
const char *admin_method = NULL;
|
||||
const char *admin_endpoint = NULL;
|
||||
|
||||
// Extract method and endpoint from request context
|
||||
// For admin API, we need to get the actual HTTP method and full endpoint
|
||||
if (request->operation && strcmp(request->operation, "admin") == 0) {
|
||||
// Admin events should contain method and endpoint tags that match the actual request
|
||||
// We don't enforce specific values here - let the event tags drive the validation
|
||||
admin_method = NULL; // Let validation check event tags without enforcing specific method
|
||||
admin_endpoint = NULL; // Let validation check event tags without enforcing specific endpoint
|
||||
}
|
||||
|
||||
int admin_result = validate_admin_event(event, admin_method, admin_endpoint);
|
||||
if (admin_result != NOSTR_SUCCESS) {
|
||||
char admin_fail_msg[256];
|
||||
sprintf(admin_fail_msg,
|
||||
"VALIDATOR_DEBUG: STEP 10 FAILED - Admin validation failed "
|
||||
"(error=%d)\n",
|
||||
admin_result);
|
||||
validator_debug_log(admin_fail_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = admin_result;
|
||||
|
||||
// Map specific Admin error codes to detailed error messages
|
||||
switch (admin_result) {
|
||||
case NOSTR_ERROR_EVENT_EXPIRED:
|
||||
strcpy(result->reason, "Admin authorization event has expired. Create a new signed event with future expiration.");
|
||||
break;
|
||||
case NOSTR_ERROR_EVENT_INVALID_CONTENT:
|
||||
strcpy(result->reason, "Admin event missing required tags. Admin events need 'method' and 'endpoint' tags.");
|
||||
break;
|
||||
case NOSTR_ERROR_EVENT_INVALID_TAGS:
|
||||
strcpy(result->reason, "Invalid or missing admin tags. Check 'method' tag matches HTTP method and 'endpoint' tag is valid.");
|
||||
break;
|
||||
case NOSTR_ERROR_EVENT_INVALID_SIGNATURE:
|
||||
strcpy(result->reason, "Admin event signature verification failed. Check private key and event serialization.");
|
||||
break;
|
||||
case NOSTR_ERROR_EVENT_INVALID_KIND:
|
||||
strcpy(result->reason, "Invalid event kind. Admin authorization events must use kind 33335.");
|
||||
break;
|
||||
case NOSTR_ERROR_AUTH_REQUIRED:
|
||||
strcpy(result->reason, "Admin access denied. Pubkey is not authorized for admin operations.");
|
||||
break;
|
||||
default:
|
||||
snprintf(result->reason, sizeof(result->reason),
|
||||
"Admin event does not authorize this operation (error code: %d). Check tags and admin permissions.",
|
||||
admin_result);
|
||||
break;
|
||||
}
|
||||
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
validator_debug_log(
|
||||
"VALIDATOR_DEBUG: STEP 10 PASSED - Admin authentication succeeded\n");
|
||||
strcpy(result->reason, "Admin authentication passed");
|
||||
|
||||
} else {
|
||||
char unsupported_msg[256];
|
||||
sprintf(unsupported_msg,
|
||||
@@ -668,7 +742,7 @@ int nostr_validate_unified_request(const nostr_unified_request_t *request,
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_EVENT_INVALID_KIND;
|
||||
snprintf(result->reason, sizeof(result->reason),
|
||||
"Unsupported event kind %d for authentication. Use kind 22242 for NIP-42 or kind 24242 for Blossom.",
|
||||
"Unsupported event kind %d for authentication. Use kind 22242 for NIP-42, kind 24242 for Blossom, or kind 33335 for Admin.",
|
||||
event_kind);
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
@@ -1423,6 +1497,118 @@ static int validate_nip42_event(cJSON *event, const char *relay_url,
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Admin/Configuration event (kind 33335)
|
||||
*/
|
||||
static int validate_admin_event(cJSON *event, const char *method, const char *endpoint) {
|
||||
if (!event) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Check event kind (must be 33335 for Admin operations)
|
||||
cJSON *kind_json = cJSON_GetObjectItem(event, "kind");
|
||||
if (!kind_json || !cJSON_IsNumber(kind_json)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
int kind = cJSON_GetNumberValue(kind_json);
|
||||
if (kind != 33335) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_KIND;
|
||||
}
|
||||
|
||||
// Get pubkey for admin authorization check
|
||||
cJSON *pubkey_json = cJSON_GetObjectItem(event, "pubkey");
|
||||
if (!pubkey_json || !cJSON_IsString(pubkey_json)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
const char *event_pubkey = cJSON_GetStringValue(pubkey_json);
|
||||
if (!event_pubkey || strlen(event_pubkey) != 64) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
// Check if pubkey is authorized for admin operations
|
||||
if (strlen(g_auth_cache.admin_pubkey) == 64) {
|
||||
if (strcmp(event_pubkey, g_auth_cache.admin_pubkey) != 0) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: Admin pubkey mismatch - access denied\n");
|
||||
return NOSTR_ERROR_AUTH_REQUIRED;
|
||||
}
|
||||
} else {
|
||||
validator_debug_log("VALIDATOR_DEBUG: No admin pubkey configured - access denied\n");
|
||||
return NOSTR_ERROR_AUTH_REQUIRED;
|
||||
}
|
||||
|
||||
// Validate admin event tag structure
|
||||
cJSON *tags = cJSON_GetObjectItem(event, "tags");
|
||||
if (!tags || !cJSON_IsArray(tags)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
// Track what we find in the event tags
|
||||
int has_method_tag = 0;
|
||||
int has_endpoint_tag = 0;
|
||||
int method_matches = (method == NULL); // If no expected method, consider it matched
|
||||
int endpoint_matches = (endpoint == NULL); // If no expected endpoint, consider it matched
|
||||
time_t expiration = 0;
|
||||
|
||||
cJSON *tag = NULL;
|
||||
cJSON_ArrayForEach(tag, tags) {
|
||||
if (!cJSON_IsArray(tag))
|
||||
continue;
|
||||
|
||||
cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (!tag_name || !cJSON_IsString(tag_name))
|
||||
continue;
|
||||
|
||||
const char *tag_name_str = cJSON_GetStringValue(tag_name);
|
||||
|
||||
if (strcmp(tag_name_str, "method") == 0) {
|
||||
has_method_tag = 1;
|
||||
cJSON *method_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (method_value && cJSON_IsString(method_value)) {
|
||||
const char *event_method = cJSON_GetStringValue(method_value);
|
||||
if (method && strcmp(event_method, method) == 0) {
|
||||
method_matches = 1;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(tag_name_str, "endpoint") == 0) {
|
||||
has_endpoint_tag = 1;
|
||||
cJSON *endpoint_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (endpoint_value && cJSON_IsString(endpoint_value)) {
|
||||
const char *event_endpoint = cJSON_GetStringValue(endpoint_value);
|
||||
// For endpoint matching, allow prefix matching for API endpoints
|
||||
if (endpoint && strncmp(event_endpoint, endpoint, strlen(endpoint)) == 0) {
|
||||
endpoint_matches = 1;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(tag_name_str, "expiration") == 0) {
|
||||
cJSON *exp_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (exp_value && cJSON_IsString(exp_value)) {
|
||||
expiration = (time_t)atol(cJSON_GetStringValue(exp_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Admin events should have method and endpoint tags
|
||||
if (!has_method_tag || !has_endpoint_tag) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
// If we have expected values, they must match
|
||||
if (!method_matches || !endpoint_matches) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_TAGS;
|
||||
}
|
||||
|
||||
// Check expiration
|
||||
time_t now = time(NULL);
|
||||
if (expiration > 0 && now > expiration) {
|
||||
return NOSTR_ERROR_EVENT_EXPIRED;
|
||||
}
|
||||
|
||||
validator_debug_log("VALIDATOR_DEBUG: Admin event validation passed\n");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// NIP-42 CHALLENGE MANAGEMENT FUNCTIONS
|
||||
//=============================================================================
|
||||
|
||||
@@ -83,12 +83,14 @@ generate_admin_keys() {
|
||||
|
||||
create_admin_event() {
|
||||
local method="$1"
|
||||
local endpoint="$2"
|
||||
local content="admin_request"
|
||||
local expiration=$(($(date +%s) + 3600)) # 1 hour from now
|
||||
|
||||
# Create Nostr event with nak - always use "admin" tag for admin operations
|
||||
local event=$(nak event -k 24242 -c "$content" \
|
||||
--tag t="admin" \
|
||||
# Create Nostr event with nak - use kind 33335 for admin/configuration events
|
||||
local event=$(nak event -k 33335 -c "$content" \
|
||||
--tag method="$method" \
|
||||
--tag endpoint="$endpoint" \
|
||||
--tag expiration="$expiration" \
|
||||
--sec "$ADMIN_PRIVKEY")
|
||||
|
||||
@@ -102,8 +104,8 @@ send_admin_request() {
|
||||
|
||||
log_info "Testing $method $endpoint"
|
||||
|
||||
# Create authenticated Nostr event
|
||||
local event=$(create_admin_event "$method")
|
||||
# Create authenticated Nostr event with method and endpoint
|
||||
local event=$(create_admin_event "$method" "$endpoint")
|
||||
local auth_header="Nostr $(echo "$event" | base64 -w 0)"
|
||||
|
||||
# Send request with curl
|
||||
|
||||
Reference in New Issue
Block a user