diff --git a/.pubnub.yml b/.pubnub.yml index c5366136..960f5650 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,8 +1,13 @@ name: c-core schema: 1 -version: "4.11.1" +version: "4.11.2" scm: github.com/pubnub/c-core changelog: + - date: 2024-07-15 + version: v4.11.2 + changes: + - type: bug + text: "Added missing subscribe v2 crypto implementation." - date: 2024-06-28 version: v4.11.1 changes: @@ -814,7 +819,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -880,7 +885,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -946,7 +951,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -1008,7 +1013,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -1069,7 +1074,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -1125,7 +1130,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" @@ -1178,7 +1183,7 @@ sdks: distribution-type: source code distribution-repository: GitHub release package-name: C-Core - location: https://github.com/pubnub/c-core/releases/tag/v4.11.1 + location: https://github.com/pubnub/c-core/releases/tag/v4.11.2 requires: - name: "miniz" diff --git a/CHANGELOG.md b/CHANGELOG.md index ab86d746..de74cc3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v4.11.2 +July 15 2024 + +#### Fixed +- Added missing subscribe v2 crypto implementation. + ## v4.11.1 June 28 2024 diff --git a/core/Makefile b/core/Makefile index 34dbb677..73c10d12 100644 --- a/core/Makefile +++ b/core/Makefile @@ -93,14 +93,14 @@ pbcc_crypto_unittest: $(PROJECT_SOURCEFILES) $(CRYPTO_SOURCEFILES) pbcc_crypto_u $(CGREEN_RUNNER) ./pbcc_crypto_unit_test.so #$(GCOVR) -r . --html --html-details -o coverage.html -pubnub_crypto_unittest: $(PROJECT_SOURCEFILES) $(CRYPTO_SOURCEFILES) pubnub_crypto_unit_tests.c - gcc -o pubnub_crypto_unit_test.so -shared $(CFLAGS) $(LDFLAGS) $(CRYPTO_INCLUDES) $(CRYPTO_LIBS) -D PUBNUB_CRYPTO_API=1 -Wall $(COVERAGE_FLAGS) -fPIC $(PROJECT_SOURCEFILES) $(CRYPTO_SOURCEFILES) test/pubnub_test_mocks.c pubnub_crypto_unit_tests.c -lcgreen -lm +SUBSCRIBE_V2_SOURCEFILES += pubnub_subscribe_v2.c pbcc_subscribe_v2.c + +pubnub_crypto_unittest: $(PROJECT_SOURCEFILES) $(CRYPTO_SOURCEFILES) $(SUBSCRIBE_V2_SOURCEFILES) pubnub_crypto_unit_tests.c + gcc -o pubnub_crypto_unit_test.so -shared $(CFLAGS) $(LDFLAGS) $(CRYPTO_INCLUDES) $(CRYPTO_LIBS) -D PUBNUB_CRYPTO_API=1 -D PUBNUB_USE_SUBSCRIBE_V2=1 -Wall $(COVERAGE_FLAGS) -fPIC $(PROJECT_SOURCEFILES) $(CRYPTO_SOURCEFILES) $(SUBSCRIBE_V2_SOURCEFILES) test/pubnub_test_mocks.c pubnub_crypto_unit_tests.c -lcgreen -lm # gcc -o pubnub_core_unit_testo $(CFLAGS) -Wall $(COVERAGE_FLAGS) $(PROJECT_SOURCEFILES) pubnub_crypto_unit_tests.c -lcgreen -lm $(CGREEN_RUNNER) ./pubnub_crypto_unit_test.so -SUBSCRIBE_V2_SOURCEFILES += pubnub_subscribe_v2.c pbcc_subscribe_v2.c - pubnub_subscribe_v2_unittest: $(PROJECT_SOURCEFILES) $(SUBSCRIBE_V2_SOURCEFILES) pubnub_subscribe_v2_unit_test.c gcc -o pubnub_subscribe_v2_unit_test.so -shared $(CFLAGS) $(LDFLAGS) -D PUBNUB_ORIGIN_SETTABLE=1 -D PUBNUB_USE_SUBSCRIBE_V2=1 -Wall $(COVERAGE_FLAGS) -fPIC $(PROJECT_SOURCEFILES) $(SUBSCRIBE_V2_SOURCEFILES) test/pubnub_test_mocks.c pubnub_subscribe_v2_unit_test.c -lcgreen -lm $(CGREEN_RUNNER) ./pubnub_subscribe_v2_unit_test.so diff --git a/core/pbcc_crypto.c b/core/pbcc_crypto.c index e1a90497..c0e8b830 100644 --- a/core/pbcc_crypto.c +++ b/core/pbcc_crypto.c @@ -288,3 +288,54 @@ void pbcc_set_crypto_module(struct pbcc_context *ctx, struct pubnub_crypto_provi pubnub_crypto_provider_t *pbcc_get_crypto_module(struct pbcc_context *ctx) { return ctx->crypto_module; } + +#if PUBNUB_CRYPTO_API +const char* pbcc_decrypt_message(struct pbcc_context *pb, const char* message, size_t len, size_t* out_len) { + char* trimmed = (char*)malloc(len + 1); // same length as message + if (NULL == trimmed) { + PUBNUB_LOG_ERROR("pbcc_get_msg(pbcc=%p) - failed to allocate memory for trimmed string. Returning original message!\n", pb); + return NULL; + } + snprintf(trimmed, len + 1, "%s", message); + + trimmed[strlen(trimmed) - 1] = '\0'; + + pubnub_bymebl_t encrypted = pbcc_base64_decode(trimmed + 1); + free(trimmed); + + if (NULL == encrypted.ptr) { + PUBNUB_LOG_WARNING("pbcc_get_msg(pbcc=%p) - base64 decoding failed. Returning original message!\n", pb); + if (NULL != out_len) { + *out_len = strlen(message); + } + return message; + } + + pubnub_bymebl_t rslt_block = pb->crypto_module->decrypt(pb->crypto_module, encrypted); + free(encrypted.ptr); + if (NULL == rslt_block.ptr) { + PUBNUB_LOG_WARNING("pbcc_get_msg(pbcc=%p) - decryption failed. Returning original message!\n", pb); + if (NULL != out_len) { + *out_len = strlen(message); + } + return message; + } + + if (pb->decrypted_message_count >= PUBNUB_MAX_DECRYPTED_MESSAGES) { + PUBNUB_LOG_ERROR("pbcc_get_msg(pbcc=%p) - maximum number of decrypted messages reached. Returning original message!\n", pb); + if (NULL != out_len) { + *out_len = 0; + } + return NULL; + } + + pb->decrypted_messages[pb->decrypted_message_count] = rslt_block.ptr; + pb->decrypted_message_count++; + + if (NULL != out_len) { + *out_len = rslt_block.size; + } + + return (char*)rslt_block.ptr; +} +#endif /* PUBNUB_CRYPTO_API */ diff --git a/core/pbcc_crypto.h b/core/pbcc_crypto.h index 1ac89e60..90fae34e 100644 --- a/core/pbcc_crypto.h +++ b/core/pbcc_crypto.h @@ -293,6 +293,21 @@ void pbcc_set_crypto_module(struct pbcc_context *ctx, struct pubnub_crypto_provi @return Pointer to the crypto provider used by the pubnub context. */ pubnub_crypto_provider_t *pbcc_get_crypto_module(struct pbcc_context *ctx); + +#if PUBNUB_CRYPTO_API +/** + Decrypt the message received from PubNub with the crypto module. + + This function takes the message received from PubNub and decrypts it + for the user. It uses the crypto module used by the pubnub context. + + @param pubnub Pointer to the pubnub context. + @param message The message received from PubNub. + + @return The decrypted message or NULL on error. +*/ +const char* pbcc_decrypt_message(struct pbcc_context *ctx, const char* message, size_t len, size_t* out_len); +#endif /* PUBNUB_CRYPTO_API */ #endif /* PBCC_CRYPTO_H */ diff --git a/core/pbcc_subscribe_v2.c b/core/pbcc_subscribe_v2.c index e98121ef..90b2e36f 100644 --- a/core/pbcc_subscribe_v2.c +++ b/core/pbcc_subscribe_v2.c @@ -1,5 +1,6 @@ /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ +#include "pbcc_crypto.h" #if PUBNUB_USE_SUBSCRIBE_V2 #include "pubnub_internal.h" @@ -55,6 +56,13 @@ enum pubnub_res pbcc_subscribe_v2_prep(struct pbcc_context* p, p->http_content_len = 0; p->msg_ofs = p->msg_end = 0; +#if PUBNUB_CRYPTO_API + for (size_t i = 0; i < p->decrypted_message_count; i++) { + free(p->decrypted_messages[i]); + } + p->decrypted_message_count = 0; +#endif + p->http_buf_len = snprintf( p->http_buf, sizeof p->http_buf, "/v2/subscribe/%s/", p->subscribe_key); APPEND_URL_ENCODED_M(p, channel); @@ -212,12 +220,15 @@ struct pubnub_v2_message pbcc_get_msg_v2(struct pbcc_context* p) } PUBNUB_LOG_DEBUG("RESPONSE = %s\n", p->http_reply); start = p->http_reply + p->msg_ofs; + if (*start != '{') { PUBNUB_LOG_ERROR( "Message subscribe V2 response is not a JSON object\n"); return rslt; } + end = p->http_reply + p->msg_end; + seeker = pbjson_find_end_complex(start, end); if (seeker == end) { PUBNUB_LOG_ERROR( @@ -235,8 +246,19 @@ struct pubnub_v2_message pbcc_get_msg_v2(struct pbcc_context* p) jpresult = pbjson_get_object_value(&el, "d", &found); if (jonmpOK == jpresult) { +#if PUBNUB_CRYPTO_API + if (NULL != p->crypto_module) { + rslt.payload.ptr = (char*)pbcc_decrypt_message( + p, + (char*)found.start, + found.end - found.start, + &rslt.payload.size + ); + } +#else rslt.payload.ptr = (char*)found.start; rslt.payload.size = found.end - found.start; +#endif /* PUBNUB_CRYPTO_API */ } else { PUBNUB_LOG_ERROR("pbcc=%p: No message payload in subscribe V2 response " diff --git a/core/pubnub_ccore_pubsub.c b/core/pubnub_ccore_pubsub.c index 9bb67a73..e4af7ad6 100644 --- a/core/pubnub_ccore_pubsub.c +++ b/core/pubnub_ccore_pubsub.c @@ -113,49 +113,20 @@ bool pbcc_ensure_reply_buffer(struct pbcc_context* p) char const* pbcc_get_msg(struct pbcc_context* pb) { +#if PUBNUB_CRYPTO_API + size_t len; +#endif // PUBNUB_CRYPTO_API if (pb->msg_ofs < pb->msg_end) { PUBNUB_LOG_DEBUG("RESPONSE = %s\n", pb->http_reply); char const* rslt = pb->http_reply + pb->msg_ofs; pb->msg_ofs += strlen(rslt); if (pb->msg_ofs++ <= pb->msg_end) { #if PUBNUB_CRYPTO_API - if (NULL != pb->crypto_module) { - char* trimmed = (char*)malloc(strlen(rslt) + 1); // same length as rslt - if (NULL == trimmed) { - PUBNUB_LOG_ERROR("pbcc_get_msg(pbcc=%p) - failed to allocate memory for trimmed string. Returning original message!\n", pb); - return NULL; - } - sprintf(trimmed, "%s", rslt); - - trimmed[strlen(trimmed) - 1] = '\0'; - - pubnub_bymebl_t encrypted = pbcc_base64_decode(trimmed + 1); - free(trimmed); - - if (NULL == encrypted.ptr) { - PUBNUB_LOG_WARNING("pbcc_get_msg(pbcc=%p) - base64 decoding failed. Returning original message!\n", pb); - return rslt; - } - - pubnub_bymebl_t rslt_block = pb->crypto_module->decrypt(pb->crypto_module, encrypted); - free(encrypted.ptr); - if (NULL == rslt_block.ptr) { - PUBNUB_LOG_WARNING("pbcc_get_msg(pbcc=%p) - decryption failed. Returning original message!\n", pb); - return rslt; - } - - if (pb->decrypted_message_count >= PUBNUB_MAX_DECRYPTED_MESSAGES) { - PUBNUB_LOG_ERROR("pbcc_get_msg(pbcc=%p) - maximum number of decrypted messages reached. Returning original message!\n", pb); - return NULL; - } - - pb->decrypted_messages[pb->decrypted_message_count] = rslt_block.ptr; - pb->decrypted_message_count++; - - rslt = (char*)rslt_block.ptr; + if (pb->crypto_module != NULL) { + len = strlen(rslt); + rslt = pbcc_decrypt_message(pb, rslt, len, NULL); } #endif // PUBNUB_CRYPTO_API - return rslt; } } diff --git a/core/pubnub_crypto_unit_tests.c b/core/pubnub_crypto_unit_tests.c index 44b57df2..da40a754 100644 --- a/core/pubnub_crypto_unit_tests.c +++ b/core/pubnub_crypto_unit_tests.c @@ -5,6 +5,8 @@ #include "cgreen/cgreen.h" #include "cgreen/constraint_syntax_helpers.h" #include "cgreen/mocks.h" +#include "pubnub_coreapi_ex.h" +#include "pubnub_helper.h" #include "pubnub_memory_block.h" #include "test/pubnub_test_mocks.h" @@ -18,6 +20,8 @@ #include "pubnub_coreapi.h" #include "pubnub_crypto.h" #include "pbcc_crypto.h" +#include "pubnub_subscribe_v2.h" +#include "pubnub_subscribe_v2_message.h" #include #include @@ -167,6 +171,45 @@ Ensure(crypto_api, client_should_use_cryptors_for_history) { assert_that(pubnub_last_http_code(pbp), is_equal_to(200)); } +Ensure(crypto_api, client_should_use_cryptors_for_subscribe_v2) { + pubnub_set_crypto_module(pbp, pubnub_crypto_module_init(&x_cryptor, &y_cryptor, 1)); + + assert_that(pubnub_last_time_token(pbp), is_equal_to_string("0")); + expect_have_dns_for_pubnub_origin_on_ctx(pbp); + expect_outgoing_with_url_no_params_on_ctx(pbp, + "/v2/subscribe/sub_key/my-channel/0"); + incoming("HTTP/1.1 200\r\nContent-Length: " + "44\r\n\r\n{\"t\":{\"t\":\"15628652479932717\",\"r\":4},\"m\":[]}", + NULL); + expect(pbntf_lost_socket, when(pb, is_equal_to(pbp))); + expect(pbntf_trans_outcome, when(pb, is_equal_to(pbp))); + assert_that(pubnub_subscribe_v2(pbp, "my-channel", pubnub_subscribe_v2_defopts()), is_equal_to(PNR_OK)); + + assert_that(pubnub_get(pbp), is_equal_to(NULL)); + assert_that(pubnub_last_http_code(pbp), is_equal_to(200)); + assert_that(pubnub_last_time_token(pbp), is_equal_to_string("15628652479932717")); + /* Not publish operation */ + assert_that(pubnub_last_publish_result(pbp), is_equal_to_string("")); + + expect(pbntf_enqueue_for_processing, when(pb, is_equal_to(pbp)), will_return(0)); + expect(pbntf_got_socket, when(pb, is_equal_to(pbp)), will_return(0)); + expect_outgoing_with_url_no_params_on_ctx(pbp, + "/v2/subscribe/sub_key/my-channel/0"); + incoming("HTTP/1.1 200\r\nContent-Length: " + "198\r\n\r\n{\"t\":{\"t\":\"15628652479932717\",\"r\":4},\"m\":[{\"a\":\"1\",\"f\":514,\"i\":\"publisher_id\",\"s\":1,\"p\":{\"t\":\"15628652479933927\",\"r\":4},\"k\":\"demo\",\"c\":\"my-channel\",\"d\":\"UE5FRAF4eHh4BG1ldGF4eHh4\",\"b\":\"my-channel\"}]}", + NULL); + expect(pbntf_lost_socket, when(pb, is_equal_to(pbp))); + expect(pbntf_trans_outcome, when(pb, is_equal_to(pbp))); + assert_that(pubnub_subscribe_v2(pbp, "my-channel", pubnub_subscribe_v2_defopts()), is_equal_to(PNR_OK)); + assert_that(pubnub_last_time_token(pbp), is_equal_to_string("15628652479932717")); + + struct pubnub_v2_message msg = pubnub_get_v2(pbp); + assert_that(msg.payload.ptr, is_equal_to_string(X)); + assert_that(pubnub_get_v2(pbp).payload.ptr, is_equal_to(NULL)); + assert_that(pubnub_last_http_code(pbp), is_equal_to(200)); +} + + int x_encrypt(pubnub_cryptor_t const* _c, struct pubnub_encrypted_data *result, pubnub_bymebl_t _d) { result->data.ptr = (uint8_t*)X; result->data.size = X_SIZE; diff --git a/core/pubnub_version_internal.h b/core/pubnub_version_internal.h index 6eb1faff..c393fdd6 100644 --- a/core/pubnub_version_internal.h +++ b/core/pubnub_version_internal.h @@ -3,7 +3,7 @@ #define INC_PUBNUB_VERSION_INTERNAL -#define PUBNUB_SDK_VERSION "4.11.1" +#define PUBNUB_SDK_VERSION "4.11.2" #endif /* !defined INC_PUBNUB_VERSION_INTERNAL */