Skip to content

Commit c1cc1ca

Browse files
ZahidZafarborgbyte
andauthored
Custom SHA256 functionality added (#62)
* Support custom SHA 256 function * Custom sha256 unit tests added * custom SHA256 change log added * change log updated * Code analysis changes * Build exe to run unit tests assosicated with SQlite and CUstome sha-256 * MISRA 18.4 rule applied * CustomSHA functino pointer moved to constant file Co-authored-by: Borgbyte <[email protected]>
1 parent 9117e3a commit c1cc1ca

File tree

7 files changed

+77
-7
lines changed

7 files changed

+77
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
21.11.3
2+
* Added functionality to set custom SHA256.
3+
14
21.11.2
25
* Fixed a bug that occurred after trying to erase events from the SQLite database when there were none.
36
* Fixed a bug with the checksum calculation.

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ project(countly VERSION ${COUNTLY_SDK_VERSION} LANGUAGES CXX)
99
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
1010
option(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS "Create a module definition (.def) on Windows." ON)
1111
option(COUNTLY_USE_CUSTOM_HTTP "Use a custom HTTP library" OFF)
12+
option(COUNTLY_USE_CUSTOM_SHA256 "Use a custom SHA 256 library" OFF)
1213
option(COUNTLY_USE_SQLITE "Use SQLite" OFF)
1314
option(COUNTLY_BUILD_TESTS "Build test programs" OFF)
1415
option(COUNTLY_BUILD_SAMPLE "Build Sample programs" OFF)
@@ -35,12 +36,16 @@ target_link_libraries(countly Threads::Threads)
3536

3637
target_include_directories(countly PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/json/include)
3738

39+
if (COUNTLY_USE_CUSTOM_SHA256)
40+
target_compile_definitions(countly PRIVATE COUNTLY_USE_CUSTOM_SHA256)
41+
else()
3842
if (APPLE)
3943
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
4044
endif()
4145
find_package(OpenSSL REQUIRED)
4246
target_include_directories(countly PRIVATE ${OPENSSL_INCLUDE_DIR})
4347
target_link_libraries(countly ${OPENSSL_LIBRARIES})
48+
endif()
4449

4550
if(COUNTLY_USE_CUSTOM_HTTP)
4651
target_compile_definitions(countly PRIVATE COUNTLY_USE_CUSTOM_HTTP)
@@ -66,6 +71,9 @@ if(COUNTLY_BUILD_TESTS)
6671
target_compile_definitions(countly-tests PRIVATE COUNTLY_USE_SQLITE)
6772
target_include_directories(countly-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor/sqlite)
6873
endif()
74+
if(COUNTLY_USE_CUSTOM_SHA256)
75+
target_compile_definitions(countly-tests PRIVATE COUNTLY_USE_CUSTOM_SHA256)
76+
endif()
6977
target_include_directories(countly-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor/doctest/doctest)
7078
target_include_directories(countly-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/json/include)
7179
target_link_libraries(countly-tests countly)

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,9 @@ make
8585
./countly-tests
8686
```
8787

88+
To run unit tests associated with 'SQLITE' and 'Custom SHA-256' build executable with the options
89+
`COUNTLY_USE_SQLITE` and `COUNTLY_BUILD_TESTS`:
90+
91+
``` shell
92+
cmake -DCOUNTLY_BUILD_TESTS=1 -DCOUNTLY_USE_SQLITE=1 -DCOUNTLY_USE_CUSTOM_SHA256=1 -B build
93+
```

include/countly.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ using json = nlohmann::json;
2323
#undef ERROR
2424
#endif
2525

26+
using namespace::countly_sdk;
27+
2628
class Countly {
2729
public:
2830
Countly();
@@ -50,6 +52,8 @@ class Countly {
5052
bool success;
5153
json data;
5254
};
55+
56+
void setSha256(SHA256Function fun);
5357

5458
using HTTPClientFunction = std::function<HTTPResponse(bool, const std::string&, const std::string&)>;
5559
void setHTTPClient(HTTPClientFunction fun);
@@ -124,7 +128,7 @@ class Countly {
124128

125129
static std::string serializeForm(const std::map<std::string, std::string> data);
126130

127-
static std::string calculateChecksum(const std::string& salt, const std::string& data);
131+
std::string calculateChecksum(const std::string& salt, const std::string& data);
128132

129133
#ifdef COUNTLY_USE_SQLITE
130134
void setDatabasePath(const std::string& path);
@@ -248,6 +252,7 @@ class Countly {
248252

249253
void updateLoop();
250254

255+
SHA256Function sha256_function;
251256
LoggerFunction logger_function;
252257
HTTPClientFunction http_client_function;
253258

include/countly/constants.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
#ifndef COUNTLY_CONSTANTS_HPP_
22
#define COUNTLY_CONSTANTS_HPP_
33

4+
#include <string>
5+
#include <functional>
6+
47
#define COUNTLY_SDK_NAME "cpp-native-unknown"
58
#define COUNTLY_SDK_VERSION "0.1.0"
69
#define COUNTLY_API_VERSION "21.11.2"
710
#define COUNTLY_POST_THRESHOLD 2000
811
#define COUNTLY_KEEPALIVE_INTERVAL 3000
912
#define COUNTLY_MAX_EVENTS_DEFAULT 200
1013

14+
namespace countly_sdk {
15+
using SHA256Function = std::function<std::string(const std::string&)>;
16+
}
17+
1118
#endif

src/countly.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
#include <iostream>
77
#include <system_error>
88

9+
#ifndef COUNTLY_USE_CUSTOM_SHA256
910
#include "openssl/sha.h"
11+
#endif
1012

1113
#include "countly.hpp"
1214

@@ -71,6 +73,12 @@ void Countly::setHTTPClient(HTTPClientFunction fun) {
7173
mutex.unlock();
7274
}
7375

76+
void Countly::setSha256(SHA256Function fun) {
77+
mutex.lock();
78+
sha256_function = fun;
79+
mutex.unlock();
80+
}
81+
7482
void Countly::setMetrics(const std::string& os, const std::string& os_version, const std::string& device,
7583
const std::string& resolution, const std::string& carrier, const std::string& app_version) {
7684
json metrics = json::object();
@@ -793,8 +801,16 @@ static size_t countly_curl_write_callback(void *data, size_t byte_size, size_t n
793801
}
794802

795803
std::string Countly::calculateChecksum(const std::string& salt, const std::string& data) {
796-
unsigned char checksum[SHA256_DIGEST_LENGTH];
797804
std::string salted_data = data + salt;
805+
#ifdef COUNTLY_USE_CUSTOM_SHA256
806+
if (sha256_function == nullptr) {
807+
log(Countly::LogLevel::FATAL, "Missing SHA 256 function");
808+
return {};
809+
}
810+
811+
return sha256_function(salted_data);
812+
#else
813+
unsigned char checksum[SHA256_DIGEST_LENGTH];
798814
SHA256_CTX sha256;
799815

800816
SHA256_Init(&sha256);
@@ -806,9 +822,8 @@ std::string Countly::calculateChecksum(const std::string& salt, const std::strin
806822
checksum_stream << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(checksum[index]);
807823
}
808824

809-
std::string calcualtedChecksum = checksum_stream.str();
810-
811-
return calcualtedChecksum;
825+
return checksum_stream.str();
826+
#endif
812827
}
813828

814829
Countly::HTTPResponse Countly::sendHTTP(std::string path, std::string data) {

tests/main.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,41 @@ TEST_CASE("urlencoding is correct") {
128128
//CHECK(Countly::encodeURL("测试") == "%E6%B5%8B%E8%AF%95"); // UTF-8 TODO: Needs to be fixed. This is throwing an exception.
129129
}
130130

131+
#ifdef COUNTLY_USE_CUSTOM_SHA256
132+
std::string customChecksumCalculator(const std::string& data) {
133+
std::string result = data.c_str();
134+
result.append("-custom_sha");
135+
return result;
136+
}
137+
138+
TEST_CASE("custom sha256 function validation") {
139+
Countly& countly = Countly::getInstance();
140+
141+
std::string salt = "test-salt";
142+
std::string checksum = countly.calculateChecksum(salt, "hello world:");
143+
CHECK(checksum == ""); // when customSha256 isn't set.
144+
145+
countly.setSha256(customChecksumCalculator);
146+
salt = "test-salt";
147+
checksum = countly.calculateChecksum(salt, "hello world:");
148+
CHECK(checksum == "hello world:test-salt-custom_sha");
149+
150+
salt = "š ūļ ķ";
151+
checksum = countly.calculateChecksum(salt, "测试:");
152+
CHECK(checksum == "测试:š ūļ ķ-custom_sha");
153+
}
154+
#else
131155
TEST_CASE("checksum function validation") {
156+
Countly& countly = Countly::getInstance();
132157
std::string salt = "test-salt";
133-
std::string checksum = Countly::calculateChecksum(salt, "hello world");
158+
std::string checksum = countly.calculateChecksum(salt, "hello world");
134159
CHECK(checksum == "aaf992c81357b0ed1bb404826e01825568126ebeb004c3bc690d3d8e0766a3cc");
135160

136161
salt = "š ūļ ķ";
137-
checksum = Countly::calculateChecksum(salt, "测试");
162+
checksum = countly.calculateChecksum(salt, "测试");
138163
CHECK(checksum == "f51d24b0cb938e2f40b1f8609c62bf2508e24bcaa3b6b1a7fbf108d3c7f2f073");
139164
}
165+
#endif
140166

141167
TEST_CASE("forms are serialized correctly") {
142168
CHECK(Countly::serializeForm(std::map<std::string, std::string>({{"key1", "value1"}, {"key2", "value2"}})) == "key1=value1&key2=value2");

0 commit comments

Comments
 (0)