Generally working.

This commit is contained in:
Your Name
2025-09-11 13:28:54 -04:00
parent e1741fb1fc
commit 22f6224008
14 changed files with 51 additions and 160 deletions

View File

@@ -13,4 +13,5 @@ This file provides guidance to agents when working with code in this repository.
- **Testing Setup**: Tests require `nak` tool for Nostr event generation - not standard HTTP testing
- **Development Ports**: Local development uses port 9001, production typically uses nginx proxy on standard ports
- **Setup Wizard**: Interactive setup creates cryptographically signed config files - not typical config generation
- **Extension Handling**: nginx config uses wildcards to serve files regardless of URL extension - Blossom protocol compliance
- **Extension Handling**: nginx config uses wildcards to serve files regardless of URL extension - Blossom protocol compliance
- **Configuration Events**: Uses Nostr kind 33333 events with 1-year default expiration - XDG paths take priority over database

View File

@@ -15,4 +15,8 @@ This file provides guidance to agents when working with code in this repository.
- **Configuration Loading**: File config takes priority over database - check XDG paths first, fallback to database
- **Blob Metadata**: Database is single source of truth - use `get_blob_metadata()`, not filesystem checks
- **nostr_core_lib Build**: Uses `build.sh` script, NOT `make` - run `./build.sh` to compile the library
- **Server Testing**: Use `./restart-all.sh` to properly restart and test ginxsom server, NOT direct binary execution
- **Server Testing**: Use `./restart-all.sh` to properly restart and test ginxsom server, NOT direct binary execution
- **spawn-fcgi Parameters**: Must use `-M 666 -u "$USER" -g "$USER"` for socket permissions and ownership
- **Admin Event Structure**: Admin auth uses kind 24242 with "t" tag containing HTTP method, expiration typically 1 hour
- **Key File Permissions**: `.admin_keys` file must be chmod 600 or auth tests will fail
- **Development Environment**: Set `GINX_DEBUG=1` for pubkey extraction diagnostics during development

View File

@@ -13,4 +13,6 @@ This file provides guidance to agents when working with code in this repository.
- **Config Loading**: File config errors are silent - check stderr for "CONFIG:" messages during startup
- **Admin Key Mismatch**: Database admin_pubkey vs .admin_keys file often cause auth failures
- **Nginx Port Conflicts**: Local nginx on 9001 conflicts with system nginx on 80 - check with `netstat -tlnp`
- **Hash Calculation**: File data buffer must be complete before `nostr_sha256()` call or hash is wrong
- **Hash Calculation**: File data buffer must be complete before `nostr_sha256()` call or hash is wrong
- **Admin Key File**: `.admin_keys` must be chmod 600 and sourceable by bash - common test failure cause
- **Process Cleanup**: `restart-all.sh` performs force kill if graceful shutdown fails - check logs for hung processes

View File

@@ -18,7 +18,7 @@ This file provides guidance to agents when working with code in this repository.
## Non-Standard Commands
```bash
# make clean && make && Restart nginx
# make clean && make && Restart nginx
./restart-all.sh
# Start FastCGI daemon

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -204,14 +204,7 @@ void handle_head_upload_request(void) {
return;
}
// Check if blob already exists (duplicate detection)
if (check_blob_exists(sha256)) {
send_upload_error_response(409, "blob_exists", "Blob with this hash already exists", XREASON_BLOB_EXISTS);
log_request("HEAD", "/upload", "none", 409);
return;
}
// Check for optional authorization
// Check for authorization first (before duplicate detection)
const char* auth_header = getenv("HTTP_AUTHORIZATION");
const char* auth_status = "none";
@@ -220,6 +213,18 @@ void handle_head_upload_request(void) {
// This handler receives pre-validated requests, so if we reach here with auth_header,
// the authentication was already successful
auth_status = "authenticated";
} else {
// Check if server requires authorization for uploads
// If auth is required but not provided, return 401 before checking for duplicates
// TODO: This should check server configuration for auth requirements
// For now, assume auth is optional unless configured otherwise
}
// Check if blob already exists (duplicate detection - after auth validation)
if (check_blob_exists(sha256)) {
send_upload_error_response(409, "blob_exists", "Blob with this hash already exists", XREASON_BLOB_EXISTS);
log_request("HEAD", "/upload", auth_status, 409);
return;
}
// All validations passed - return success

View File

@@ -28,16 +28,6 @@
// Database path
#define DB_PATH "db/ginxsom.db"
// ===== COMMENTED OUT UNUSED CODE =====
// Forward declarations for config system (all commented out)
/*
int initialize_server_config(void);
int apply_config_from_event(cJSON *event);
int get_config_file_path(char *path, size_t path_size);
int load_server_config(const char *config_path);
int run_interactive_setup(const char *config_path);
*/
// ===== END COMMENTED OUT CODE =====
// Configuration system implementation
#include <stdlib.h>
@@ -536,15 +526,6 @@ const char *extract_sha256_from_uri(const char *uri) {
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// ===== COMMENTED OUT UNUSED CODE =====
// Forward declarations for detailed validation functions (all commented out)
/*
int detailed_structure_validation(cJSON *event);
int detailed_signature_validation(cJSON *event);
void analyze_event_fields(cJSON *event);
void hex_dump(const char *label, const unsigned char *data, size_t len);
*/
// ===== END COMMENTED OUT CODE =====
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1024,38 +1005,7 @@ 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",
auth_required, auth_header ? "YES" : "NO");
// If authentication is required but no auth header provided, fail immediately
if (auth_required && !auth_header) {
free(file_data);
send_error_response(401, "authorization_required",
"Authorization required for upload operations",
"This server requires authentication for all uploads");
log_request("PUT", "/upload", "missing_auth", 401);
return;
}
// If auth rules are completely disabled, skip all validation and allow upload
if (!auth_required) {
fprintf(stderr, "AUTH: Authentication rules disabled - skipping all "
"validation and allowing upload\n");
// 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
// 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,
@@ -1299,37 +1249,7 @@ 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",
auth_required, auth_header ? "YES" : "NO");
// If authentication is required but no auth header provided, fail immediately
if (auth_required && !auth_header) {
if (should_free_file_data) free(file_data);
send_error_response(401, "authorization_required",
"Authorization required for upload operations",
"This server requires authentication for all uploads");
log_request("PUT", "/upload", "missing_auth", 401);
return;
}
// If auth rules are completely disabled, skip all validation and allow upload
if (!auth_required) {
fprintf(stderr, "AUTH: Authentication rules disabled - skipping all "
"validation and allowing upload\n");
// 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
// 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,
@@ -1523,23 +1443,6 @@ int main(void) {
// Try file-based config first, then fall back to database config
int config_loaded = 0;
// All file-based config and interactive setup are commented out
/*
char config_path[512];
if (get_config_file_path(config_path, sizeof(config_path))) {
fprintf(stderr, "STARTUP: Checking for config file at: %s\n", config_path);
if (load_server_config(config_path)) {
fprintf(stderr,
"STARTUP: File-based configuration loaded successfully\n");
config_loaded = 1;
} else {
fprintf(stderr, "STARTUP: No valid file-based config found, trying "
"database config\n");
}
}
*/
// Fall back to database configuration if file config failed
if (!config_loaded /* && !initialize_server_config() */) {
fprintf(
@@ -1547,13 +1450,7 @@ if (!config_loaded /* && !initialize_server_config() */) {
"STARTUP: No configuration found - server starting in setup mode\n");
fprintf(stderr, "STARTUP: Run interactive setup with: ginxsom --setup\n");
// For interactive mode (when stdin is available), offer setup
/*
char config_path[512];
if (isatty(STDIN_FILENO) &&
get_config_file_path(config_path, sizeof(config_path))) {
return run_interactive_setup(config_path);
}
*/
} else if (!config_loaded) {
fprintf(stderr, "STARTUP: Database configuration loaded successfully\n");
}

View File

@@ -283,7 +283,17 @@ int nostr_validate_unified_request(const nostr_unified_request_t *request,
// PHASE 2: NOSTR EVENT VALIDATION (CPU Intensive ~2ms)
/////////////////////////////////////////////////////////////////////
// Check if authentication header is provided
// Check if this is a BUD-09 report request - allow anonymous reporting
if (request->operation && strcmp(request->operation, "report") == 0) {
// BUD-09 allows anonymous reporting - pass through to bud09.c for validation
result->valid = 1;
result->error_code = NOSTR_SUCCESS;
strcpy(result->reason, "BUD-09 report request - bypassing auth for anonymous reporting");
validator_debug_log("VALIDATOR_DEBUG: BUD-09 report detected, bypassing authentication\n");
return NOSTR_SUCCESS;
}
// Check if authentication header is provided (required for non-report operations)
if (!request->auth_header) {
result->valid = 0;

View File

@@ -1 +1 @@
09127399ac6d531773cafe433bd6ffd0592b04480543b8225ba17d48fd61b5ac
e3ba927d32ca105a8a4cafa2e013b97945a165c38e9ce573446a2332dc312fdb

View File

@@ -1,33 +0,0 @@
#!/bin/bash
# Admin Initialization Script for Ginxsom Testing
# Sets up the test admin key in the database
set -e
# Test admin public key (must match TEST_ADMIN_PUBKEY from admin_test.sh)
TEST_ADMIN_PUBKEY="2ef05348f28d24e0f0ed0751278442c27b62c823c37af8d8d89d8592c6ee84e7"
echo "Initializing admin access for testing..."
# Check if database exists
if [ ! -f "db/ginxsom.db" ]; then
echo "Error: Database db/ginxsom.db not found. Run ./db/init.sh first."
exit 1
fi
# Configure admin settings
sqlite3 db/ginxsom.db << EOF
INSERT OR REPLACE INTO config (key, value, description) VALUES
('admin_pubkey', '$TEST_ADMIN_PUBKEY', 'Nostr public key authorized for admin operations (test key)'),
('admin_enabled', 'true', 'Enable admin interface');
EOF
echo "Admin access configured successfully!"
echo "Test admin public key: $TEST_ADMIN_PUBKEY"
echo "Use private key from admin_test.sh to generate authentication tokens"
# Verify configuration
echo ""
echo "Current admin configuration:"
sqlite3 db/ginxsom.db "SELECT key, value FROM config WHERE key IN ('admin_pubkey', 'admin_enabled');"

View File

@@ -11,11 +11,16 @@ echo "=== BUD-06 Upload Requirements Test Suite ==="
SERVER_URL="http://localhost:9001"
UPLOAD_ENDPOINT="${SERVER_URL}/upload"
# Test file properties
TEST_SHA256="24308d48eb498b593e55a87b6300ccffdea8432babc0bb898b1eff21ebbb72de"
# Test file properties - generate unique hashes for each test run
TIMESTAMP=$(date +%s)
TEST_SHA256=$(echo "test_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1)
TEST_CONTENT_TYPE="image/png"
TEST_CONTENT_LENGTH="71418"
# Generate additional unique hashes for tests that need fresh hashes
TEST_SHA256_FRESH=$(echo "fresh_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1)
TEST_SHA256_AUTH=$(echo "auth_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1)
# Helper function to make HEAD request with custom headers
make_head_request() {
local sha256="$1"
@@ -59,11 +64,11 @@ echo ""
echo "=== Test 1: Valid Upload Requirements ==="
echo "Testing HEAD /upload with valid headers..."
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
RESPONSE=$(make_head_request "$TEST_SHA256_FRESH" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
STATUS=$(get_status_code "$RESPONSE")
echo "Request Headers:"
echo " X-SHA-256: $TEST_SHA256"
echo " X-SHA-256: $TEST_SHA256_FRESH"
echo " X-Content-Type: $TEST_CONTENT_TYPE"
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
echo ""
@@ -185,12 +190,12 @@ echo "=== Test 6: Unsupported Media Type ==="
echo "Testing HEAD /upload with potentially unsupported MIME type..."
UNSUPPORTED_TYPE="application/x-malware"
RESPONSE=$(make_head_request "$TEST_SHA256" "$UNSUPPORTED_TYPE" "$TEST_CONTENT_LENGTH")
RESPONSE=$(make_head_request "$TEST_SHA256_FRESH" "$UNSUPPORTED_TYPE" "$TEST_CONTENT_LENGTH")
STATUS=$(get_status_code "$RESPONSE")
REASON=$(get_x_reason "$RESPONSE")
echo "Request Headers:"
echo " X-SHA-256: $TEST_SHA256"
echo " X-SHA-256: $TEST_SHA256_FRESH"
echo " X-Content-Type: $UNSUPPORTED_TYPE"
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
echo ""
@@ -267,13 +272,13 @@ echo "=== Test 9: Authorization Handling ==="
echo "Testing HEAD /upload authorization requirements..."
# Test without authorization first
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
RESPONSE=$(make_head_request "$TEST_SHA256_AUTH" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
STATUS=$(get_status_code "$RESPONSE")
REASON=$(get_x_reason "$RESPONSE")
echo "Request Headers (no authorization):"
echo " X-SHA-256: $TEST_SHA256"
echo " X-Content-Type: $TEST_CONTENT_TYPE"
echo " X-SHA-256: $TEST_SHA256_AUTH"
echo " X-Content-Type: $TEST_CONTENT_TYPE"
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
echo " Authorization: (missing)"
echo ""