Generally working.
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
BIN
build/bud06.o
BIN
build/bud06.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
db/ginxsom.db
BIN
db/ginxsom.db
Binary file not shown.
21
src/bud06.c
21
src/bud06.c
@@ -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
|
||||
|
||||
105
src/main.c
105
src/main.c
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
09127399ac6d531773cafe433bd6ffd0592b04480543b8225ba17d48fd61b5ac
|
||||
e3ba927d32ca105a8a4cafa2e013b97945a165c38e9ce573446a2332dc312fdb
|
||||
|
||||
@@ -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');"
|
||||
@@ -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 ""
|
||||
|
||||
Reference in New Issue
Block a user