v1.1.1 - Fix NOTICE message silent failure - add pss parameter to send_notice_message()

Previously, send_notice_message() called queue_message() with NULL pss, causing
all NOTICE messages to fail silently. This affected filter validation errors
(e.g., invalid kinds > 65535 per NIP-01) where clients received no response.

Changes:
- Updated send_notice_message() signature to accept struct per_session_data* pss
- Updated 37 call sites across websockets.c (31) and nip042.c (6)
- Updated forward declarations in main.c, websockets.c, and nip042.c
- Added tests/invalid_kind_test.sh to verify NOTICE responses for invalid filters

Fixes issue where REQ with kinds:[99999] received no response instead of NOTICE.
This commit is contained in:
Your Name
2026-01-31 15:48:29 -04:00
parent 35b1461ff6
commit e8f8e3b0cf
7 changed files with 146 additions and 45 deletions

View File

@@ -94,7 +94,7 @@ void record_malformed_request(struct per_session_data *pss);
int validate_filter_array(cJSON* filters, char* error_message, size_t error_size);
// Forward declarations for NOTICE message support
void send_notice_message(struct lws* wsi, const char* message);
void send_notice_message(struct lws* wsi, struct per_session_data* pss, const char* message);
// Configuration functions from config.c
extern int get_config_bool(const char* key, int default_value);
@@ -475,7 +475,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Check if client is rate limited for malformed requests
if (is_client_rate_limited_for_malformed_requests(pss)) {
send_notice_message(wsi, "error: too many malformed requests - temporarily blocked");
send_notice_message(wsi, pss, "error: too many malformed requests - temporarily blocked");
return 0;
}
@@ -522,7 +522,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
pss->reassembly_size = 0;
pss->reassembly_capacity = 0;
pss->reassembly_active = 0;
send_notice_message(wsi, "error: message too large - memory allocation failed");
send_notice_message(wsi, pss, "error: message too large - memory allocation failed");
return 0;
}
pss->reassembly_buffer = new_buffer;
@@ -895,7 +895,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
if (!pss->auth_challenge_sent) {
send_nip42_auth_challenge(wsi, pss);
} else {
send_notice_message(wsi, "NIP-42 authentication required for subscriptions");
send_notice_message(wsi, pss, "NIP-42 authentication required for subscriptions");
DEBUG_WARN("REQ rejected: NIP-42 authentication required");
}
cJSON_Delete(json);
@@ -917,7 +917,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID before processing
if (!subscription_id) {
DEBUG_TRACE("REQ rejected: NULL subscription ID");
send_notice_message(wsi, "error: invalid subscription ID");
send_notice_message(wsi, pss, "error: invalid subscription ID");
DEBUG_WARN("REQ rejected: NULL subscription ID");
record_malformed_request(pss);
cJSON_Delete(json);
@@ -929,7 +929,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID
if (!validate_subscription_id(subscription_id)) {
DEBUG_TRACE("REQ rejected: invalid subscription ID format");
send_notice_message(wsi, "error: invalid subscription ID");
send_notice_message(wsi, pss, "error: invalid subscription ID");
DEBUG_WARN("REQ rejected: invalid subscription ID");
cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately
@@ -943,7 +943,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON* filters = cJSON_CreateArray();
if (!filters) {
DEBUG_TRACE("REQ failed: could not create filters array");
send_notice_message(wsi, "error: failed to process filters");
send_notice_message(wsi, pss, "error: failed to process filters");
DEBUG_ERROR("REQ failed: could not create filters array");
cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately
@@ -967,7 +967,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) {
DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error);
send_notice_message(wsi, filter_error);
send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("REQ rejected: invalid filters");
record_malformed_request(pss);
cJSON_Delete(filters);
@@ -1014,7 +1014,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON_Delete(eose_response);
}
} else {
send_notice_message(wsi, "error: missing or invalid subscription ID in REQ");
send_notice_message(wsi, pss, "error: missing or invalid subscription ID in REQ");
DEBUG_WARN("REQ rejected: missing or invalid subscription ID");
}
} else if (strcmp(msg_type, "COUNT") == 0) {
@@ -1023,7 +1023,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
if (!pss->auth_challenge_sent) {
send_nip42_auth_challenge(wsi, pss);
} else {
send_notice_message(wsi, "NIP-42 authentication required for count requests");
send_notice_message(wsi, pss, "NIP-42 authentication required for count requests");
DEBUG_WARN("COUNT rejected: NIP-42 authentication required");
}
cJSON_Delete(json);
@@ -1051,7 +1051,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing
char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) {
send_notice_message(wsi, filter_error);
send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("COUNT rejected: invalid filters");
record_malformed_request(pss);
cJSON_Delete(filters);
@@ -1074,7 +1074,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID before processing
if (!subscription_id) {
send_notice_message(wsi, "error: invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: NULL subscription ID");
cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately
@@ -1084,7 +1084,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID
if (!validate_subscription_id(subscription_id)) {
send_notice_message(wsi, "error: invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: invalid subscription ID");
cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately
@@ -1130,7 +1130,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Subscription closed
} else {
send_notice_message(wsi, "error: missing or invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: missing or invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: missing or invalid subscription ID");
}
} else if (strcmp(msg_type, "AUTH") == 0) {
@@ -1145,11 +1145,11 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// AUTH signed event: ["AUTH", <event>] (standard NIP-42)
handle_nip42_auth_signed_event(wsi, pss, auth_payload);
} else {
send_notice_message(wsi, "Invalid AUTH message format");
send_notice_message(wsi, pss, "Invalid AUTH message format");
DEBUG_WARN("Received AUTH message with invalid payload type");
}
} else {
send_notice_message(wsi, "AUTH message requires payload");
send_notice_message(wsi, pss, "AUTH message requires payload");
DEBUG_WARN("Received AUTH message without payload");
}
} else {
@@ -1157,7 +1157,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
char unknown_msg[128];
snprintf(unknown_msg, sizeof(unknown_msg), "Unknown message type: %.32s", msg_type);
DEBUG_WARN(unknown_msg);
send_notice_message(wsi, "Unknown message type");
send_notice_message(wsi, pss, "Unknown message type");
}
}
}
@@ -1254,7 +1254,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
snprintf(auth_msg, sizeof(auth_msg),
"NIP-42 authentication required for event kind %d", event_kind);
}
send_notice_message(wsi, auth_msg);
send_notice_message(wsi, pss, auth_msg);
DEBUG_WARN("Event rejected: NIP-42 authentication required for kind");
}
cJSON_Delete(json);
@@ -1597,7 +1597,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
if (!pss->auth_challenge_sent) {
send_nip42_auth_challenge(wsi, pss);
} else {
send_notice_message(wsi, "NIP-42 authentication required for subscriptions");
send_notice_message(wsi, pss, "NIP-42 authentication required for subscriptions");
DEBUG_WARN("REQ rejected: NIP-42 authentication required");
}
cJSON_Delete(json);
@@ -1618,7 +1618,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID before processing
if (!subscription_id) {
DEBUG_TRACE("REQ rejected: NULL subscription ID");
send_notice_message(wsi, "error: invalid subscription ID");
send_notice_message(wsi, pss, "error: invalid subscription ID");
DEBUG_WARN("REQ rejected: NULL subscription ID");
record_malformed_request(pss);
cJSON_Delete(json);
@@ -1629,7 +1629,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID
if (!validate_subscription_id(subscription_id)) {
DEBUG_TRACE("REQ rejected: invalid subscription ID format");
send_notice_message(wsi, "error: invalid subscription ID");
send_notice_message(wsi, pss, "error: invalid subscription ID");
DEBUG_WARN("REQ rejected: invalid subscription ID");
cJSON_Delete(json);
free(message);
@@ -1642,7 +1642,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON* filters = cJSON_CreateArray();
if (!filters) {
DEBUG_TRACE("REQ failed: could not create filters array");
send_notice_message(wsi, "error: failed to process filters");
send_notice_message(wsi, pss, "error: failed to process filters");
DEBUG_ERROR("REQ failed: could not create filters array");
cJSON_Delete(json);
free(message);
@@ -1665,7 +1665,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) {
DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error);
send_notice_message(wsi, filter_error);
send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("REQ rejected: invalid filters");
record_malformed_request(pss);
cJSON_Delete(filters);
@@ -1711,7 +1711,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON_Delete(eose_response);
}
} else {
send_notice_message(wsi, "error: missing or invalid subscription ID in REQ");
send_notice_message(wsi, pss, "error: missing or invalid subscription ID in REQ");
DEBUG_WARN("REQ rejected: missing or invalid subscription ID");
}
} else if (strcmp(msg_type, "COUNT") == 0) {
@@ -1720,7 +1720,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
if (!pss->auth_challenge_sent) {
send_nip42_auth_challenge(wsi, pss);
} else {
send_notice_message(wsi, "NIP-42 authentication required for count requests");
send_notice_message(wsi, pss, "NIP-42 authentication required for count requests");
DEBUG_WARN("COUNT rejected: NIP-42 authentication required");
}
cJSON_Delete(json);
@@ -1747,7 +1747,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing
char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) {
send_notice_message(wsi, filter_error);
send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("COUNT rejected: invalid filters");
record_malformed_request(pss);
cJSON_Delete(filters);
@@ -1769,7 +1769,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID before processing
if (!subscription_id) {
send_notice_message(wsi, "error: invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: NULL subscription ID");
cJSON_Delete(json);
free(message);
@@ -1778,7 +1778,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate subscription ID
if (!validate_subscription_id(subscription_id)) {
send_notice_message(wsi, "error: invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: invalid subscription ID");
cJSON_Delete(json);
free(message);
@@ -1823,7 +1823,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Subscription closed
} else {
send_notice_message(wsi, "error: missing or invalid subscription ID in CLOSE");
send_notice_message(wsi, pss, "error: missing or invalid subscription ID in CLOSE");
DEBUG_WARN("CLOSE rejected: missing or invalid subscription ID");
}
} else if (strcmp(msg_type, "AUTH") == 0) {
@@ -1838,11 +1838,11 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// AUTH signed event: ["AUTH", <event>] (standard NIP-42)
handle_nip42_auth_signed_event(wsi, pss, auth_payload);
} else {
send_notice_message(wsi, "Invalid AUTH message format");
send_notice_message(wsi, pss, "Invalid AUTH message format");
DEBUG_WARN("Received AUTH message with invalid payload type");
}
} else {
send_notice_message(wsi, "AUTH message requires payload");
send_notice_message(wsi, pss, "AUTH message requires payload");
DEBUG_WARN("Received AUTH message without payload");
}
} else {
@@ -1850,7 +1850,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
char unknown_msg[128];
snprintf(unknown_msg, sizeof(unknown_msg), "Unknown message type: %.32s", msg_type);
DEBUG_WARN(unknown_msg);
send_notice_message(wsi, "Unknown message type");
send_notice_message(wsi, pss, "Unknown message type");
}
}
}