diff --git a/.roo/commands/push.md b/.roo/commands/push.md index b9569b4..5bdf1ad 100644 --- a/.roo/commands/push.md +++ b/.roo/commands/push.md @@ -2,4 +2,4 @@ description: "increment and push" --- -Run increment_and_push.sh adding a good comment on the command line following the command. \ No newline at end of file +Run increment_and_push.sh adding a good comment on the command line following the command. Don't run any other git commands. \ No newline at end of file diff --git a/build/admin_api.o b/build/admin_api.o index 9efa6ca..a710538 100644 Binary files a/build/admin_api.o and b/build/admin_api.o differ diff --git a/build/bud08.o b/build/bud08.o index e14dde5..f6f0025 100644 Binary files a/build/bud08.o and b/build/bud08.o differ diff --git a/build/ginxsom-fcgi b/build/ginxsom-fcgi index b84cfa5..faab8cf 100755 Binary files a/build/ginxsom-fcgi and b/build/ginxsom-fcgi differ diff --git a/build/main.o b/build/main.o index 134d0c0..2615648 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/config/local-nginx.conf b/config/local-nginx.conf index c865d8f..cbc8f4d 100644 --- a/config/local-nginx.conf +++ b/config/local-nginx.conf @@ -298,7 +298,7 @@ http { } # GET requests - serve files directly with extension fallback - try_files /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; + try_files /$1.html /$1.js /$1.mjs /$1.css /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; # Cache headers for blob content add_header Cache-Control "public, max-age=31536000, immutable"; @@ -678,7 +678,7 @@ http { } # GET requests - serve files directly with extension fallback - try_files /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; + try_files /$1.html /$1.js /$1.mjs /$1.css /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; # Cache headers for blob content add_header Cache-Control "public, max-age=31536000, immutable"; diff --git a/remote.nginx.config b/remote.nginx.config index b500ca3..563ae1b 100644 --- a/remote.nginx.config +++ b/remote.nginx.config @@ -184,7 +184,7 @@ server { return 405; } - try_files /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; + try_files /$1.html /$1.js /$1.mjs /$1.css /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; # Cache headers add_header Cache-Control "public, max-age=31536000, immutable"; diff --git a/src/admin_api.c b/src/admin_api.c index d4f2b07..8c734f2 100644 --- a/src/admin_api.c +++ b/src/admin_api.c @@ -112,6 +112,14 @@ static const char* admin_mime_to_extension(const char* mime_type) { return ".ogg"; } else if (strstr(mime_type, "text/plain")) { return ".txt"; + } else if (strstr(mime_type, "text/html")) { + return ".html"; + } else if (strstr(mime_type, "text/css")) { + return ".css"; + } else if (strstr(mime_type, "application/javascript")) { + return ".js"; + } else if (strstr(mime_type, "text/javascript")) { + return ".mjs"; } else if (strstr(mime_type, "application/pdf")) { return ".pdf"; } else { diff --git a/src/bud08.c b/src/bud08.c index 932dea7..27f22f5 100644 --- a/src/bud08.c +++ b/src/bud08.c @@ -119,6 +119,14 @@ const char* mime_to_extension(const char* mime_type) { return ".ogg"; } else if (strstr(mime_type, "text/plain")) { return ".txt"; + } else if (strstr(mime_type, "text/html")) { + return ".html"; + } else if (strstr(mime_type, "text/css")) { + return ".css"; + } else if (strstr(mime_type, "application/javascript")) { + return ".js"; + } else if (strstr(mime_type, "text/javascript")) { + return ".mjs"; } else if (strstr(mime_type, "application/pdf")) { return ".pdf"; } else { diff --git a/src/ginxsom.h b/src/ginxsom.h index b6c351c..36ce3e4 100644 --- a/src/ginxsom.h +++ b/src/ginxsom.h @@ -10,8 +10,8 @@ // Version information (auto-updated by build system) #define VERSION_MAJOR 0 #define VERSION_MINOR 1 -#define VERSION_PATCH 30 -#define VERSION "v0.1.30" +#define VERSION_PATCH 31 +#define VERSION "v0.1.31" #include #include diff --git a/src/main.c b/src/main.c index 4dbc294..916ea62 100644 --- a/src/main.c +++ b/src/main.c @@ -1508,6 +1508,14 @@ void handle_delete_request_with_validation(const char *sha256, nostr_request_res extension = ".ogg"; } else if (strstr(blob_type_copy, "text/plain")) { extension = ".txt"; + } else if (strstr(blob_type_copy, "text/html")) { + extension = ".html"; + } else if (strstr(blob_type_copy, "text/css")) { + extension = ".css"; + } else if (strstr(blob_type_copy, "application/javascript")) { + extension = ".js"; + } else if (strstr(blob_type_copy, "text/javascript")) { + extension = ".mjs"; } else { extension = ".bin"; } diff --git a/tests/production_file_put_html_tmp.sh b/tests/production_file_put_html_tmp.sh new file mode 100755 index 0000000..f5a3d57 --- /dev/null +++ b/tests/production_file_put_html_tmp.sh @@ -0,0 +1,266 @@ +#!/bin/bash + +# file_put_production.sh - Test script for production Ginxsom Blossom server +# Tests upload functionality on blossom.laantungir.net + +set -e # Exit on any error + +# Configuration +SERVER_URL="https://blossom.laantungir.net" +UPLOAD_ENDPOINT="${SERVER_URL}/upload" +TEST_FILE="test_blob_$(date +%s).html" +CLEANUP_FILES=() + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Cleanup function +cleanup() { + echo -e "${YELLOW}Cleaning up temporary files...${NC}" + for file in "${CLEANUP_FILES[@]}"; do + if [[ -f "$file" ]]; then + rm -f "$file" + echo "Removed: $file" + fi + done +} + +# Set up cleanup on exit +trap cleanup EXIT + +# Helper functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Check prerequisites +check_prerequisites() { + log_info "Checking prerequisites..." + + # Check if nak is installed + if ! command -v nak &> /dev/null; then + log_error "nak command not found. Please install nak first." + log_info "Install with: go install github.com/fiatjaf/nak@latest" + exit 1 + fi + log_success "nak is installed" + + # Check if curl is available + if ! command -v curl &> /dev/null; then + log_error "curl command not found. Please install curl." + exit 1 + fi + log_success "curl is available" + + # Check if sha256sum is available + if ! command -v sha256sum &> /dev/null; then + log_error "sha256sum command not found." + exit 1 + fi + log_success "sha256sum is available" + + # Check if base64 is available + if ! command -v base64 &> /dev/null; then + log_error "base64 command not found." + exit 1 + fi + log_success "base64 is available" +} + +# Check if server is running +check_server() { + log_info "Checking if server is running..." + + if curl -s -f "${SERVER_URL}/health" > /dev/null 2>&1; then + log_success "Server is running at ${SERVER_URL}" + else + log_error "Server is not responding at ${SERVER_URL}" + exit 1 + fi +} + +# Create test file +create_test_file() { + log_info "Creating test file: ${TEST_FILE}" + + # Create test content with timestamp and random data + cat > "${TEST_FILE}" << EOF +Test blob content for Ginxsom Blossom server (PRODUCTION) +Timestamp: $(date -Iseconds) +Random data: $(openssl rand -hex 32) +Test message: Hello from production test! + +This file is used to test the upload functionality +of the Ginxsom Blossom server on blossom.laantungir.net +EOF + + CLEANUP_FILES+=("${TEST_FILE}") + log_success "Created test file with $(wc -c < "${TEST_FILE}") bytes" +} + +# Calculate file hash +calculate_hash() { + log_info "Calculating SHA-256 hash..." + + HASH=$(sha256sum "${TEST_FILE}" | cut -d' ' -f1) + + log_success "Data to hash: ${TEST_FILE}" + log_success "File hash: ${HASH}" +} + +# Generate nostr event +generate_nostr_event() { + log_info "Generating kind 24242 nostr event with nak using WSB's private key..." + + # Calculate expiration time (1 hour from now) + EXPIRATION=$(date -d '+1 hour' +%s) + + # Generate the event using nak with WSB's private key + EVENT_JSON=$(nak event -k 24242 -c "" \ + --sec "22cc83aa57928a2800234c939240c9a6f0f44a33ea3838a860ed38930b195afd" \ + -t "t=upload" \ + -t "x=${HASH}" \ + -t "expiration=${EXPIRATION}") + + if [[ -z "$EVENT_JSON" ]]; then + log_error "Failed to generate nostr event" + exit 1 + fi + + log_success "Generated nostr event" + echo "Event JSON: $EVENT_JSON" +} + +# Create authorization header +create_auth_header() { + log_info "Creating authorization header..." + + # Base64 encode the event (without newlines) + AUTH_B64=$(echo -n "$EVENT_JSON" | base64 -w 0) + AUTH_HEADER="Nostr ${AUTH_B64}" + + log_success "Created authorization header" + echo "Auth header length: ${#AUTH_HEADER} characters" +} + +# Perform upload +perform_upload() { + log_info "Performing upload to ${UPLOAD_ENDPOINT}..." + + # Create temporary file for response + RESPONSE_FILE=$(mktemp) + CLEANUP_FILES+=("${RESPONSE_FILE}") + + # Perform the upload with verbose output + HTTP_STATUS=$(curl -s -w "%{http_code}" \ + -X PUT \ + -H "Authorization: ${AUTH_HEADER}" \ + -H "Content-Type: text/plain" \ + -H "Content-Disposition: attachment; filename=\"${TEST_FILE}\"" \ + --data-binary "@${TEST_FILE}" \ + "${UPLOAD_ENDPOINT}" \ + -o "${RESPONSE_FILE}") + + echo "HTTP Status: ${HTTP_STATUS}" + echo "Response body:" + cat "${RESPONSE_FILE}" + echo + + # Check response + case "${HTTP_STATUS}" in + 200) + log_success "Upload successful!" + ;; + 201) + log_success "Upload successful (created)!" + ;; + 400) + log_error "Bad request - check the event format" + ;; + 401) + log_error "Unauthorized - authentication failed" + ;; + 405) + log_error "Method not allowed - check nginx configuration" + ;; + 413) + log_error "Payload too large" + ;; + 501) + log_warning "Upload endpoint not yet implemented (expected for now)" + ;; + *) + log_error "Upload failed with HTTP status: ${HTTP_STATUS}" + ;; + esac +} + +# Test file retrieval +test_retrieval() { + log_info "Testing file retrieval..." + + RETRIEVAL_URL="${SERVER_URL}/${HASH}" + + if curl -s -f "${RETRIEVAL_URL}" > /dev/null 2>&1; then + log_success "File can be retrieved at: ${RETRIEVAL_URL}" + + # Download and verify + DOWNLOADED_FILE=$(mktemp) + CLEANUP_FILES+=("${DOWNLOADED_FILE}") + curl -s "${RETRIEVAL_URL}" -o "${DOWNLOADED_FILE}" + + DOWNLOADED_HASH=$(sha256sum "${DOWNLOADED_FILE}" | cut -d' ' -f1) + if [[ "${DOWNLOADED_HASH}" == "${HASH}" ]]; then + log_success "Downloaded file hash matches! Verification successful." + else + log_error "Hash mismatch! Expected: ${HASH}, Got: ${DOWNLOADED_HASH}" + fi + else + log_warning "File not yet available for retrieval" + fi +} + +# Main execution +main() { + echo "=== Ginxsom Blossom Production Upload Test ===" + echo "Server: ${SERVER_URL}" + echo "Timestamp: $(date -Iseconds)" + echo + + check_prerequisites + check_server + create_test_file + calculate_hash + generate_nostr_event + create_auth_header + perform_upload + test_retrieval + + echo + log_info "Test completed!" + echo "Summary:" + echo " Test file: ${TEST_FILE}" + echo " File hash: ${HASH}" + echo " Server: ${SERVER_URL}" + echo " Upload endpoint: ${UPLOAD_ENDPOINT}" + echo " Retrieval URL: ${SERVER_URL}/${HASH}" +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/tests/test_upload.html b/tests/test_upload.html new file mode 100644 index 0000000..31aae12 --- /dev/null +++ b/tests/test_upload.html @@ -0,0 +1,11 @@ + + + + Ginxsom Test + + +

Ginxsom HTML Upload Test

+

This is a small test file to verify HTML uploads on blossom.laantungir.net.

+

Timestamp: 2026-03-11T21:55:00Z

+ + diff --git a/tests/upload_html_test.sh b/tests/upload_html_test.sh new file mode 100755 index 0000000..8d5df53 --- /dev/null +++ b/tests/upload_html_test.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +# upload_html_test.sh - Test script for uploading HTML to production Ginxsom Blossom server +# Tests upload functionality on blossom.laantungir.net + +set -e # Exit on any error + +# Configuration +SERVER_URL="https://blossom.laantungir.net" +UPLOAD_ENDPOINT="${SERVER_URL}/upload" +TEST_FILE="tests/test_upload.html" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Helper functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Calculate file hash +calculate_hash() { + log_info "Calculating SHA-256 hash..." + HASH=$(sha256sum "${TEST_FILE}" | cut -d' ' -f1) + log_success "File hash: ${HASH}" +} + +# Generate nostr event +generate_nostr_event() { + log_info "Generating kind 24242 nostr event..." + EXPIRATION=$(date -d '+1 hour' +%s) + EVENT_JSON=$(nak event -k 24242 -c "" \ + --sec "22cc83aa57928a2800234c939240c9a6f0f44a33ea3838a860ed38930b195afd" \ + -t "t=upload" \ + -t "x=${HASH}" \ + -t "expiration=${EXPIRATION}") + + if [[ -z "$EVENT_JSON" ]]; then + log_error "Failed to generate nostr event" + exit 1 + fi + log_success "Generated nostr event" +} + +# Create authorization header +create_auth_header() { + log_info "Creating authorization header..." + AUTH_B64=$(echo -n "$EVENT_JSON" | base64 -w 0) + AUTH_HEADER="Nostr ${AUTH_B64}" + log_success "Created authorization header" +} + +# Perform upload +perform_upload() { + log_info "Performing upload to ${UPLOAD_ENDPOINT}..." + RESPONSE_FILE=$(mktemp) + + HTTP_STATUS=$(curl -s -w "%{http_code}" \ + -X PUT \ + -H "Authorization: ${AUTH_HEADER}" \ + -H "Content-Type: text/html" \ + --data-binary "@${TEST_FILE}" \ + "${UPLOAD_ENDPOINT}" \ + -o "${RESPONSE_FILE}") + + echo "HTTP Status: ${HTTP_STATUS}" + echo "Response body:" + cat "${RESPONSE_FILE}" + echo + rm -f "${RESPONSE_FILE}" + + if [[ "${HTTP_STATUS}" == "200" || "${HTTP_STATUS}" == "201" ]]; then + log_success "Upload successful!" + else + log_error "Upload failed with HTTP status: ${HTTP_STATUS}" + exit 1 + fi +} + +# Test file retrieval +test_retrieval() { + log_info "Testing file retrieval..." + + # Try with .html extension + RETRIEVAL_URL_EXT="${SERVER_URL}/${HASH}.html" + log_info "Trying retrieval with extension: ${RETRIEVAL_URL_EXT}" + if curl -s -f -I "${RETRIEVAL_URL_EXT}" > /dev/null 2>&1; then + log_success "File found with .html extension!" + else + log_warning "File NOT found with .html extension" + fi + + # Try without extension + RETRIEVAL_URL="${SERVER_URL}/${HASH}" + log_info "Trying retrieval without extension: ${RETRIEVAL_URL}" + if curl -s -f -I "${RETRIEVAL_URL}" > /dev/null 2>&1; then + log_success "File found without extension!" + else + log_warning "File NOT found without extension" + fi +} + +# Main execution +main() { + calculate_hash + generate_nostr_event + create_auth_header + perform_upload + test_retrieval +} + +main "$@"