Files
ginxsom/Trash/test_auth_debug.c
2025-09-02 12:54:22 -04:00

765 lines
32 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Debug test for Authorization header processing
* Tests the exact same flow as the ginxsom server with detailed step-by-step logging
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "nostr_core_lib/nostr_core/nip001.h"
#include "nostr_core_lib/nostr_core/nostr_common.h"
#include "nostr_core_lib/nostr_core/utils.h"
#include "nostr_core_lib/nostr_core/crypto/nostr_secp256k1.h"
#include "nostr_core_lib/cjson/cJSON.h"
// Logging utility
#define LOG_STEP(step, msg, ...) printf("🔍 STEP %s: " msg "\n", step, ##__VA_ARGS__)
#define LOG_SUCCESS(msg, ...) printf("✅ SUCCESS: " msg "\n", ##__VA_ARGS__)
#define LOG_ERROR(msg, ...) printf("❌ ERROR: " msg "\n", ##__VA_ARGS__)
#define LOG_INFO(msg, ...) printf(" INFO: " msg "\n", ##__VA_ARGS__)
#define LOG_DIVIDER() printf("═══════════════════════════════════════════════════════════════════\n")
// Forward declarations for detailed validation functions
int detailed_structure_validation(cJSON* event);
int detailed_signature_validation(cJSON* event);
void analyze_event_fields(cJSON* event);
void analyze_serialization(cJSON* event);
void hex_dump(const char* label, const unsigned char* data, size_t len);
// Copy the exact parse_authorization_header function from main.c
int parse_authorization_header(const char* auth_header, char* event_json, size_t json_size) {
if (!auth_header || !event_json) {
printf("DEBUG: parse_authorization_header - invalid parameters: auth_header=%p, event_json=%p\r\n",
(void*)auth_header, (void*)event_json);
return NOSTR_ERROR_INVALID_INPUT;
}
printf("DEBUG: parse_authorization_header called with header: %.50s...\r\n", auth_header);
// Check for "Nostr " prefix (case-insensitive)
const char* prefix = "nostr ";
size_t prefix_len = strlen(prefix);
if (strncasecmp(auth_header, prefix, prefix_len) != 0) {
printf("DEBUG: Authorization header missing 'Nostr ' prefix (found: %.10s)\r\n", auth_header);
return NOSTR_ERROR_INVALID_INPUT;
}
// Extract base64 encoded event after "Nostr "
const char* base64_event = auth_header + prefix_len;
printf("DEBUG: Extracted base64 event (length=%zu): %.100s...\r\n", strlen(base64_event), base64_event);
// Decode base64 to JSON using nostr_core_lib base64 decode
unsigned char decoded_buffer[4096];
size_t decoded_len = base64_decode(base64_event, decoded_buffer);
printf("DEBUG: Base64 decode result - decoded_len=%zu\r\n", decoded_len);
if (decoded_len == 0) {
printf("DEBUG: Failed to decode base64 event - base64_decode returned 0\r\n");
return NOSTR_ERROR_INVALID_INPUT;
}
if (decoded_len >= json_size) {
printf("DEBUG: Decoded JSON too large for buffer (decoded_len=%zu, json_size=%zu)\r\n", decoded_len, json_size);
return NOSTR_ERROR_INVALID_INPUT;
}
// Copy decoded JSON to output buffer
memcpy(event_json, decoded_buffer, decoded_len);
event_json[decoded_len] = '\0';
printf("DEBUG: Successfully decoded JSON (length=%zu): %s\r\n", decoded_len, event_json);
return NOSTR_SUCCESS;
}
/**
* Detailed structure validation with step-by-step logging
*/
int detailed_structure_validation(cJSON* event) {
LOG_DIVIDER();
LOG_STEP("STRUCT-1", "Starting detailed structure validation");
if (!event || !cJSON_IsObject(event)) {
LOG_ERROR("Event is null or not a JSON object");
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
}
LOG_SUCCESS("Event is valid JSON object");
// Check each required field existence
LOG_STEP("STRUCT-2", "Checking required field existence");
const char* required_fields[] = {"id", "pubkey", "created_at", "kind", "tags", "content", "sig"};
for (int i = 0; i < 7; i++) {
cJSON* field = cJSON_GetObjectItem(event, required_fields[i]);
if (!field) {
LOG_ERROR("Missing required field: %s", required_fields[i]);
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
}
LOG_SUCCESS("Field '%s' exists", required_fields[i]);
}
// Get all fields for detailed validation
cJSON* id_item = cJSON_GetObjectItem(event, "id");
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
cJSON* content_item = cJSON_GetObjectItem(event, "content");
cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
// Validate field types
LOG_STEP("STRUCT-3", "Validating field types");
if (!cJSON_IsString(id_item)) {
LOG_ERROR("Field 'id' is not a string (type: %d)", id_item->type);
return NOSTR_ERROR_EVENT_INVALID_ID;
}
LOG_SUCCESS("Field 'id' is string");
if (!cJSON_IsString(pubkey_item)) {
LOG_ERROR("Field 'pubkey' is not a string (type: %d)", pubkey_item->type);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
}
LOG_SUCCESS("Field 'pubkey' is string");
if (!cJSON_IsNumber(created_at_item)) {
LOG_ERROR("Field 'created_at' is not a number (type: %d)", created_at_item->type);
return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
}
LOG_SUCCESS("Field 'created_at' is number");
if (!cJSON_IsNumber(kind_item)) {
LOG_ERROR("Field 'kind' is not a number (type: %d)", kind_item->type);
return NOSTR_ERROR_EVENT_INVALID_KIND;
}
LOG_SUCCESS("Field 'kind' is number");
if (!cJSON_IsArray(tags_item)) {
LOG_ERROR("Field 'tags' is not an array (type: %d)", tags_item->type);
return NOSTR_ERROR_EVENT_INVALID_TAGS;
}
LOG_SUCCESS("Field 'tags' is array");
if (!cJSON_IsString(content_item)) {
LOG_ERROR("Field 'content' is not a string (type: %d)", content_item->type);
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
}
LOG_SUCCESS("Field 'content' is string");
if (!cJSON_IsString(sig_item)) {
LOG_ERROR("Field 'sig' is not a string (type: %d)", sig_item->type);
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
}
LOG_SUCCESS("Field 'sig' is string");
// Validate hex string lengths
LOG_STEP("STRUCT-4", "Validating hex string lengths");
const char* id_str = cJSON_GetStringValue(id_item);
const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
const char* sig_str = cJSON_GetStringValue(sig_item);
LOG_INFO("ID string: '%s' (length: %zu)", id_str, id_str ? strlen(id_str) : 0);
if (!id_str || strlen(id_str) != 64) {
LOG_ERROR("ID string invalid length (expected 64, got %zu)", id_str ? strlen(id_str) : 0);
return NOSTR_ERROR_EVENT_INVALID_ID;
}
LOG_SUCCESS("ID string length is correct (64 chars)");
LOG_INFO("Pubkey string: '%s' (length: %zu)", pubkey_str, pubkey_str ? strlen(pubkey_str) : 0);
if (!pubkey_str || strlen(pubkey_str) != 64) {
LOG_ERROR("Pubkey string invalid length (expected 64, got %zu)", pubkey_str ? strlen(pubkey_str) : 0);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
}
LOG_SUCCESS("Pubkey string length is correct (64 chars)");
LOG_INFO("Signature string: '%s' (length: %zu)", sig_str, sig_str ? strlen(sig_str) : 0);
if (!sig_str || strlen(sig_str) != 128) {
LOG_ERROR("Signature string invalid length (expected 128, got %zu)", sig_str ? strlen(sig_str) : 0);
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
}
LOG_SUCCESS("Signature string length is correct (128 chars)");
// Validate hex characters
LOG_STEP("STRUCT-5", "Validating hex characters");
LOG_INFO("Checking ID hex characters...");
for (int i = 0; i < 64; i++) {
char c = id_str[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
LOG_ERROR("Invalid hex character in ID at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
return NOSTR_ERROR_EVENT_INVALID_ID;
}
}
LOG_SUCCESS("ID hex characters are valid (lowercase)");
LOG_INFO("Checking pubkey hex characters...");
for (int i = 0; i < 64; i++) {
char c = pubkey_str[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
LOG_ERROR("Invalid hex character in pubkey at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
}
}
LOG_SUCCESS("Pubkey hex characters are valid (lowercase)");
LOG_INFO("Checking signature hex characters...");
for (int i = 0; i < 128; i++) {
char c = sig_str[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
LOG_ERROR("Invalid hex character in signature at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
}
}
LOG_SUCCESS("Signature hex characters are valid (lowercase)");
// Validate timestamp
LOG_STEP("STRUCT-6", "Validating timestamp");
double created_at = cJSON_GetNumberValue(created_at_item);
LOG_INFO("Created_at timestamp: %.0f", created_at);
if (created_at < 0) {
LOG_ERROR("Invalid timestamp (negative): %.0f", created_at);
return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
}
// Convert to human readable time
time_t timestamp = (time_t)created_at;
char time_str[100];
struct tm* tm_info = gmtime(&timestamp);
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S UTC", tm_info);
LOG_SUCCESS("Timestamp is valid: %s", time_str);
// Validate kind
LOG_STEP("STRUCT-7", "Validating kind");
double kind = cJSON_GetNumberValue(kind_item);
LOG_INFO("Event kind: %.0f", kind);
if (kind < 0 || kind > 65535 || kind != (int)kind) {
LOG_ERROR("Invalid kind value: %.0f (must be integer 0-65535)", kind);
return NOSTR_ERROR_EVENT_INVALID_KIND;
}
LOG_SUCCESS("Kind is valid: %d", (int)kind);
// Validate tags array structure
LOG_STEP("STRUCT-8", "Validating tags array structure");
int tag_count = cJSON_GetArraySize(tags_item);
LOG_INFO("Tags array has %d elements", tag_count);
cJSON* tag_item;
int tag_index = 0;
cJSON_ArrayForEach(tag_item, tags_item) {
if (!cJSON_IsArray(tag_item)) {
LOG_ERROR("Tag at index %d is not an array (type: %d)", tag_index, tag_item->type);
return NOSTR_ERROR_EVENT_INVALID_TAGS;
}
int tag_element_count = cJSON_GetArraySize(tag_item);
LOG_INFO("Tag[%d] has %d elements", tag_index, tag_element_count);
cJSON* tag_element;
int element_index = 0;
cJSON_ArrayForEach(tag_element, tag_item) {
if (!cJSON_IsString(tag_element)) {
LOG_ERROR("Tag[%d][%d] is not a string (type: %d)", tag_index, element_index, tag_element->type);
return NOSTR_ERROR_EVENT_INVALID_TAGS;
}
const char* tag_value = cJSON_GetStringValue(tag_element);
LOG_INFO("Tag[%d][%d]: '%s'", tag_index, element_index, tag_value);
element_index++;
}
tag_index++;
}
LOG_SUCCESS("Tags array structure is valid");
// Validate content
LOG_STEP("STRUCT-9", "Validating content");
const char* content_str = cJSON_GetStringValue(content_item);
LOG_INFO("Content: '%s' (length: %zu)", content_str, content_str ? strlen(content_str) : 0);
LOG_SUCCESS("Content is valid string");
LOG_SUCCESS("Structure validation completed successfully");
return NOSTR_SUCCESS;
}
/**
* Detailed signature validation with step-by-step logging
*/
int detailed_signature_validation(cJSON* event) {
LOG_DIVIDER();
LOG_STEP("CRYPTO-1", "Starting detailed signature validation");
if (!event) {
LOG_ERROR("Event is null");
return NOSTR_ERROR_INVALID_INPUT;
}
// Get event fields
cJSON* id_item = cJSON_GetObjectItem(event, "id");
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
cJSON* content_item = cJSON_GetObjectItem(event, "content");
cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
if (!id_item || !pubkey_item || !created_at_item || !kind_item ||
!tags_item || !content_item || !sig_item) {
LOG_ERROR("Missing required fields for signature validation");
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
}
// Create serialization array
LOG_STEP("CRYPTO-2", "Creating serialization array");
cJSON* serialize_array = cJSON_CreateArray();
if (!serialize_array) {
LOG_ERROR("Failed to create serialization array");
return NOSTR_ERROR_MEMORY_FAILED;
}
cJSON_AddItemToArray(serialize_array, cJSON_CreateNumber(0));
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(pubkey_item, 1));
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(created_at_item, 1));
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(kind_item, 1));
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(tags_item, 1));
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(content_item, 1));
LOG_SUCCESS("Serialization array created");
// Convert to JSON string
LOG_STEP("CRYPTO-3", "Converting to JSON string");
char* serialize_string = cJSON_PrintUnformatted(serialize_array);
cJSON_Delete(serialize_array);
if (!serialize_string) {
LOG_ERROR("Failed to serialize array to JSON string");
return NOSTR_ERROR_MEMORY_FAILED;
}
LOG_SUCCESS("JSON serialization string created");
LOG_INFO("Serialization string (length %zu): %s", strlen(serialize_string), serialize_string);
// Hash the serialized event
LOG_STEP("CRYPTO-4", "Computing SHA256 hash");
unsigned char event_hash[32];
if (nostr_sha256((const unsigned char*)serialize_string, strlen(serialize_string), event_hash) != 0) {
LOG_ERROR("SHA256 hashing failed");
free(serialize_string);
return NOSTR_ERROR_CRYPTO_FAILED;
}
LOG_SUCCESS("SHA256 hash computed");
hex_dump("Event hash", event_hash, 32);
// Convert hash to hex for event ID verification
LOG_STEP("CRYPTO-5", "Verifying event ID");
char calculated_id[65];
nostr_bytes_to_hex(event_hash, 32, calculated_id);
const char* provided_id = cJSON_GetStringValue(id_item);
LOG_INFO("Calculated ID: %s", calculated_id);
LOG_INFO("Provided ID: %s", provided_id);
if (!provided_id || strcmp(calculated_id, provided_id) != 0) {
LOG_ERROR("Event ID mismatch!");
LOG_ERROR(" Expected: %s", calculated_id);
LOG_ERROR(" Got: %s", provided_id ? provided_id : "NULL");
free(serialize_string);
return NOSTR_ERROR_EVENT_INVALID_ID;
}
LOG_SUCCESS("Event ID verification passed");
// Prepare signature verification
LOG_STEP("CRYPTO-6", "Preparing signature verification");
const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
const char* sig_str = cJSON_GetStringValue(sig_item);
if (!pubkey_str || !sig_str) {
LOG_ERROR("Missing pubkey or signature strings");
free(serialize_string);
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
}
// Convert hex strings to bytes
LOG_STEP("CRYPTO-7", "Converting hex strings to bytes");
unsigned char pubkey_bytes[32];
unsigned char sig_bytes[64];
if (nostr_hex_to_bytes(pubkey_str, pubkey_bytes, 32) != 0) {
LOG_ERROR("Failed to convert pubkey hex to bytes");
free(serialize_string);
return NOSTR_ERROR_CRYPTO_FAILED;
}
LOG_SUCCESS("Pubkey hex converted to bytes");
hex_dump("Pubkey bytes", pubkey_bytes, 32);
if (nostr_hex_to_bytes(sig_str, sig_bytes, 64) != 0) {
LOG_ERROR("Failed to convert signature hex to bytes");
free(serialize_string);
return NOSTR_ERROR_CRYPTO_FAILED;
}
LOG_SUCCESS("Signature hex converted to bytes");
hex_dump("Signature bytes", sig_bytes, 64);
// Parse the public key into secp256k1 format
LOG_STEP("CRYPTO-8", "Parsing public key into secp256k1 format");
nostr_secp256k1_xonly_pubkey xonly_pubkey;
if (!nostr_secp256k1_xonly_pubkey_parse(&xonly_pubkey, pubkey_bytes)) {
LOG_ERROR("Failed to parse public key into secp256k1 format");
free(serialize_string);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
}
LOG_SUCCESS("Public key parsed into secp256k1 format");
// Verify Schnorr signature
LOG_STEP("CRYPTO-9", "Verifying Schnorr signature");
if (!nostr_secp256k1_schnorrsig_verify(sig_bytes, event_hash, &xonly_pubkey)) {
LOG_ERROR("Schnorr signature verification FAILED!");
LOG_ERROR("This means the signature does not match the event hash and public key");
free(serialize_string);
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
}
LOG_SUCCESS("Schnorr signature verification PASSED!");
free(serialize_string);
return NOSTR_SUCCESS;
}
/**
* Analyze event fields in detail
*/
void analyze_event_fields(cJSON* event) {
LOG_DIVIDER();
LOG_STEP("ANALYZE-1", "Analyzing event field details");
cJSON* field;
cJSON_ArrayForEach(field, event) {
if (field->string) {
LOG_INFO("Field '%s':", field->string);
if (cJSON_IsString(field)) {
const char* value = cJSON_GetStringValue(field);
LOG_INFO(" Type: String");
LOG_INFO(" Value: '%s'", value);
LOG_INFO(" Length: %zu", value ? strlen(value) : 0);
} else if (cJSON_IsNumber(field)) {
double value = cJSON_GetNumberValue(field);
LOG_INFO(" Type: Number");
LOG_INFO(" Value: %.0f", value);
} else if (cJSON_IsArray(field)) {
int size = cJSON_GetArraySize(field);
LOG_INFO(" Type: Array");
LOG_INFO(" Size: %d", size);
} else {
LOG_INFO(" Type: Other (%d)", field->type);
}
}
}
}
/**
* Print hex dump of binary data
*/
void hex_dump(const char* label, const unsigned char* data, size_t len) {
LOG_INFO("%s (%zu bytes):", label, len);
for (size_t i = 0; i < len; i += 16) {
printf(" %04zx: ", i);
for (size_t j = 0; j < 16; j++) {
if (i + j < len) {
printf("%02x ", data[i + j]);
} else {
printf(" ");
}
}
printf(" |");
for (size_t j = 0; j < 16 && i + j < len; j++) {
unsigned char c = data[i + j];
printf("%c", (c >= 32 && c <= 126) ? c : '.');
}
printf("|\n");
}
}
/**
* Mirror the exact server-side validation flow for comparison
*/
int server_style_authentication(const char* auth_header, const char* method, const char* file_hash) {
LOG_DIVIDER();
LOG_STEP("SERVER-1", "Starting server-style authentication (mirroring main.c)");
if (!auth_header) {
LOG_ERROR("No authorization header provided");
return NOSTR_ERROR_INVALID_INPUT;
}
LOG_INFO("Server-style auth called with method: %s, hash: %s",
method ? method : "null", file_hash ? file_hash : "null");
// Parse authorization header (same as server)
char event_json[4096];
LOG_STEP("SERVER-2", "Calling parse_authorization_header");
int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
if (parse_result != NOSTR_SUCCESS) {
LOG_ERROR("Authorization header parsing failed: %d (%s)", parse_result, nostr_strerror(parse_result));
return parse_result;
}
LOG_SUCCESS("parse_authorization_header succeeded");
// Parse JSON event (same as server)
LOG_STEP("SERVER-3", "Calling cJSON_Parse on JSON string");
LOG_INFO("JSON to parse: %s", event_json);
cJSON* event = cJSON_Parse(event_json);
if (!event) {
LOG_ERROR("Failed to parse JSON event with cJSON_Parse");
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
}
LOG_SUCCESS("cJSON_Parse succeeded, event parsed");
// Print complete parsed JSON like server does
char* parsed_json_str = cJSON_Print(event);
LOG_INFO("Parsed JSON: %s", parsed_json_str ? parsed_json_str : "NULL");
if (parsed_json_str) free(parsed_json_str);
// Debug: Print event fields before validation (same as server)
cJSON* id_json = cJSON_GetObjectItem(event, "id");
cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
cJSON* sig_json = cJSON_GetObjectItem(event, "sig");
cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
cJSON* created_at_json = cJSON_GetObjectItem(event, "created_at");
LOG_STEP("SERVER-4", "Event fields before validation");
LOG_INFO(" id: %s", id_json && cJSON_IsString(id_json) ? cJSON_GetStringValue(id_json) : "MISSING/INVALID");
LOG_INFO(" pubkey: %s", pubkey_json && cJSON_IsString(pubkey_json) ? cJSON_GetStringValue(pubkey_json) : "MISSING/INVALID");
LOG_INFO(" sig: %s", sig_json && cJSON_IsString(sig_json) ? cJSON_GetStringValue(sig_json) : "MISSING/INVALID");
LOG_INFO(" kind: %d", kind_json && cJSON_IsNumber(kind_json) ? (int)cJSON_GetNumberValue(kind_json) : -999);
LOG_INFO(" created_at: %ld", created_at_json && cJSON_IsNumber(created_at_json) ? (long)cJSON_GetNumberValue(created_at_json) : -999);
// Detailed pubkey analysis (same as server)
if (pubkey_json && cJSON_IsString(pubkey_json)) {
const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
LOG_STEP("SERVER-5", "Detailed pubkey analysis");
LOG_INFO(" Pubkey: %s", pubkey_str ? pubkey_str : "NULL");
LOG_INFO(" Length: %zu", pubkey_str ? strlen(pubkey_str) : 0);
if (pubkey_str && strlen(pubkey_str) == 64) {
LOG_INFO(" Character analysis (first 10): ");
for (int i = 0; i < 10; i++) {
char c = pubkey_str[i];
printf("%c(0x%02x) ", c, (unsigned char)c);
}
printf("\n");
}
}
// Pre-validation pubkey analysis (same as server)
LOG_STEP("SERVER-6", "Pre-validation pubkey analysis");
if (pubkey_json && cJSON_IsString(pubkey_json)) {
const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
LOG_INFO(" Pubkey: %s", pubkey_str ? pubkey_str : "NULL");
LOG_INFO(" Length: %zu", pubkey_str ? strlen(pubkey_str) : 0);
if (pubkey_str && strlen(pubkey_str) == 64) {
LOG_INFO(" Character analysis (first 10): ");
for (int i = 0; i < 10; i++) {
char c = pubkey_str[i];
printf("%c(%d) ", c, (int)c);
}
printf("\n");
LOG_INFO(" Character validation test: ");
int valid_chars = 1;
for (int i = 0; i < 64; i++) {
char c = pubkey_str[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
printf("INVALID at pos %d: %c(%d) ", i, c, (int)c);
valid_chars = 0;
}
}
if (valid_chars) {
printf("ALL VALID (lowercase hex)\n");
} else {
printf("\n");
}
}
}
// Detailed validation analysis (same as server)
LOG_STEP("SERVER-7", "Starting detailed validation analysis");
// Test structure validation first (same as server)
LOG_INFO("Testing structure validation...");
int structure_result = nostr_validate_event_structure(event);
LOG_INFO("nostr_validate_event_structure returned: %d (%s)",
structure_result, nostr_strerror(structure_result));
if (structure_result != NOSTR_SUCCESS) {
LOG_ERROR("STRUCTURE validation failed!");
cJSON_Delete(event);
return structure_result;
}
LOG_SUCCESS("Structure validation PASSED");
// Test crypto validation separately (same as server)
LOG_INFO("Testing cryptographic verification...");
int crypto_result = nostr_verify_event_signature(event);
LOG_INFO("nostr_verify_event_signature returned: %d (%s)",
crypto_result, nostr_strerror(crypto_result));
if (crypto_result != NOSTR_SUCCESS) {
LOG_ERROR("CRYPTO verification failed!");
if (pubkey_json && cJSON_IsString(pubkey_json)) {
const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
LOG_ERROR("Failed pubkey: %s (length: %zu)",
pubkey_str ? pubkey_str : "NULL", pubkey_str ? strlen(pubkey_str) : 0);
}
cJSON_Delete(event);
return crypto_result;
}
LOG_SUCCESS("Crypto verification PASSED");
// Finally test complete validation (same as server)
LOG_INFO("Testing complete validation...");
int validation_result = nostr_validate_event(event);
LOG_INFO("nostr_validate_event returned: %d (%s)",
validation_result, nostr_strerror(validation_result));
if (validation_result != NOSTR_SUCCESS) {
LOG_ERROR("COMPLETE validation failed: %d (%s)",
validation_result, nostr_strerror(validation_result));
// Additional debug: Check specific validation issues (same as server)
if (pubkey_json && cJSON_IsString(pubkey_json)) {
const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
LOG_ERROR("Pubkey length: %zu, value: %s",
pubkey_str ? strlen(pubkey_str) : 0, pubkey_str ? pubkey_str : "NULL");
}
cJSON_Delete(event);
return validation_result;
}
LOG_SUCCESS("Complete validation PASSED");
cJSON_Delete(event);
LOG_SUCCESS("Server-style authentication successful, returning NOSTR_SUCCESS");
return NOSTR_SUCCESS;
}
int main(void) {
LOG_DIVIDER();
printf("🔧 COMPREHENSIVE NOSTR EVENT VALIDATION DEBUG TEST 🔧\n");
LOG_DIVIDER();
// Initialize crypto library
LOG_STEP("INIT-1", "Initializing nostr library");
if (nostr_init() != NOSTR_SUCCESS) {
LOG_ERROR("Failed to initialize nostr library");
return 1;
}
LOG_SUCCESS("Nostr library initialized");
// The actual failing Authorization header from your upload attempt
const char* auth_header = "Nostr eyJraW5kIjoyNDI0MiwiaWQiOiI5NTYxNjA1YjEwNjJjZTM3ZTk1YWI5YjgxZDMwMGQ5YWQ1YmZiOWM1NDRhZTM5NWUxZWI0MWYwMDBjN2Q4OWY2IiwicHVia2V5IjoiNzliZTY2N2VmOWRjYmJhYzU1YTA2Mjk1Y2U4NzBiMDcwMjliZmNkYjJkY2UyOGQ5NTlmMjgxNWIxNmY4MTc5OCIsImNyZWF0ZWRfYXQiOjE3NTU2ODU0MjgsInRhZ3MiOltbInQiLCJ1cGxvYWQiXSxbIngiLCI4NDcxNjE3MWJhYjE2YWQwMjFiZDg5NTMwNTAxODlmZTYwNzU5MTc0MzZjZDExY2M5MzNmMDIxYmJjNWQ1YjBiIl0sWyJleHBpcmF0aW9uIiwiMTc1NTY4OTAyOCJdXSwiY29udGVudCI6IiIsInNpZyI6Ijk1MzE2YWI3NWY4ZDAyYmI5OTVhMTI0OGMyNzRiOTlmOWJjNWRjMGFmNTY0OWU2OTQ5MDE1ZDA2OTkwNGQ0YmRmM2EzYzc5NDI3YWM4MjQ1Njk4NmEyZTkzN2IxZDI1YjZkMmVlOGVlMWU0NDZhODQ5Y2IxOTc3NGRmOTQ4ZWFkIn0=";
LOG_INFO("Testing Authorization header:");
printf("%s\n", auth_header);
// Step 1: Parse the Authorization header
LOG_DIVIDER();
LOG_STEP("PARSE-1", "Parsing Authorization header");
char event_json[4096];
int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
if (parse_result != NOSTR_SUCCESS) {
LOG_ERROR("Parse failed with error: %d (%s)", parse_result, nostr_strerror(parse_result));
nostr_cleanup();
return 1;
}
LOG_SUCCESS("Authorization header parsed successfully");
LOG_INFO("Decoded JSON: %s", event_json);
// Step 2: Parse the JSON
LOG_STEP("PARSE-2", "Parsing JSON string");
cJSON* event = cJSON_Parse(event_json);
if (!event) {
LOG_ERROR("JSON parsing failed - invalid JSON syntax");
nostr_cleanup();
return 1;
}
LOG_SUCCESS("JSON parsing successful");
// Step 3: Analyze event fields
analyze_event_fields(event);
// Step 4: Detailed structure validation
LOG_STEP("MAIN-1", "Running detailed structure validation");
int structure_result = detailed_structure_validation(event);
if (structure_result != NOSTR_SUCCESS) {
LOG_ERROR("Structure validation failed: %d (%s)", structure_result, nostr_strerror(structure_result));
LOG_ERROR("VALIDATION FAILED AT STRUCTURE LEVEL");
cJSON_Delete(event);
nostr_cleanup();
return 1;
}
LOG_SUCCESS("Detailed structure validation PASSED");
// Step 5: Detailed signature validation
LOG_STEP("MAIN-2", "Running detailed signature validation");
int crypto_result = detailed_signature_validation(event);
if (crypto_result != NOSTR_SUCCESS) {
LOG_ERROR("Signature validation failed: %d (%s)", crypto_result, nostr_strerror(crypto_result));
LOG_ERROR("VALIDATION FAILED AT CRYPTOGRAPHIC LEVEL");
cJSON_Delete(event);
nostr_cleanup();
return 1;
}
LOG_SUCCESS("Detailed signature validation PASSED");
// Step 6: Run standard nostr validation for comparison
LOG_DIVIDER();
LOG_STEP("COMPARE-1", "Running standard nostr_validate_event for comparison");
int validation_result = nostr_validate_event(event);
LOG_INFO("nostr_validate_event result: %d (%s)", validation_result, nostr_strerror(validation_result));
if (validation_result == NOSTR_SUCCESS) {
LOG_SUCCESS("Standard validation PASSED - matches detailed validation");
} else {
LOG_ERROR("Standard validation FAILED - inconsistent with detailed validation!");
LOG_ERROR("This indicates a potential issue in the standard validation logic");
}
// Step 7: Run server-style authentication for direct comparison
LOG_STEP("COMPARE-2", "Running server-style authentication (exact mirror of server code)");
int server_result = server_style_authentication(auth_header, "upload", "84716171bab16ad021bd8953050189fe6075917436cd11cc933f021bbc5d5b0b");
LOG_INFO("server_style_authentication result: %d (%s)", server_result, nostr_strerror(server_result));
if (server_result == NOSTR_SUCCESS) {
LOG_SUCCESS("Server-style validation PASSED");
} else {
LOG_ERROR("Server-style validation FAILED - this shows exactly where server diverges!");
}
// Final summary
LOG_DIVIDER();
if (structure_result == NOSTR_SUCCESS && crypto_result == NOSTR_SUCCESS) {
LOG_SUCCESS("🎉 ALL DETAILED VALIDATIONS PASSED! Event is completely valid.");
printf("✅ Structure validation: PASSED\n");
printf("✅ Signature validation: PASSED\n");
printf("✅ Standard validation: %s\n",
(validation_result == NOSTR_SUCCESS) ? "PASSED" : "FAILED (inconsistent!)");
printf("✅ Server-style validation: %s\n",
(server_result == NOSTR_SUCCESS) ? "PASSED" : "FAILED (shows server issue!)");
} else {
LOG_ERROR("❌ VALIDATION FAILED!");
printf("Structure validation: %s (%d)\n",
(structure_result == NOSTR_SUCCESS) ? "PASSED" : "FAILED", structure_result);
printf("Signature validation: %s (%d)\n",
(crypto_result == NOSTR_SUCCESS) ? "PASSED" : "FAILED", crypto_result);
printf("Server-style validation: %s (%d)\n",
(server_result == NOSTR_SUCCESS) ? "PASSED" : "FAILED", server_result);
}
LOG_DIVIDER();
LOG_SUCCESS("🔍 DETAILED COMPARISON COMPLETE");
if (structure_result == NOSTR_SUCCESS && crypto_result == NOSTR_SUCCESS &&
validation_result == NOSTR_SUCCESS && server_result == NOSTR_SUCCESS) {
LOG_SUCCESS("🎯 ALL VALIDATION METHODS AGREE: Event is valid");
} else {
LOG_ERROR("⚠️ VALIDATION METHODS DISAGREE: Check individual results above");
}
LOG_DIVIDER();
cJSON_Delete(event);
nostr_cleanup();
return (structure_result == NOSTR_SUCCESS && crypto_result == NOSTR_SUCCESS) ? 0 : 1;
}