From f63a29c3bf0fe919828b6b916f34b7c4e71bbf04 Mon Sep 17 00:00:00 2001 From: HowJMay Date: Tue, 28 Jul 2020 11:35:04 +0800 Subject: [PATCH] feat(mam): Register user ID with MAM channel seed Register user identity with MAM channel seed. The return user ID is an UUID. Asymmetric encryption for key exchange will be implemented in the coming PR. For #560 --- accelerator/core/apis.c | 27 +++++++ accelerator/core/apis.h | 13 +++ accelerator/core/core.c | 6 +- accelerator/core/mam_core.c | 26 ++++++ accelerator/core/mam_core.h | 14 ++++ accelerator/core/request/request.h | 1 + .../core/request/ta_register_mam_channel.c | 14 ++++ .../core/request/ta_register_mam_channel.h | 49 ++++++++++++ accelerator/core/serializer/ser_mam.c | 79 +++++++++++++++++++ accelerator/core/serializer/ser_mam.h | 48 +++++++++++ tests/api/mam_test.c | 13 +++ tests/unit-test/test_cache.c | 6 +- tests/unit-test/test_serializer.c | 20 ++++- 13 files changed, 309 insertions(+), 7 deletions(-) create mode 100644 accelerator/core/request/ta_register_mam_channel.c create mode 100644 accelerator/core/request/ta_register_mam_channel.h diff --git a/accelerator/core/apis.c b/accelerator/core/apis.c index 563e57b5..f442eed7 100644 --- a/accelerator/core/apis.c +++ b/accelerator/core/apis.c @@ -394,6 +394,33 @@ status_t api_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* cons return ret; } +status_t api_register_mam_channel(const ta_cache_t* const cache, const char* const obj, char** json_result) { + status_t ret = SC_OK; + ta_register_mam_channel_req_t* req = ta_register_mam_channel_req_new(); + char uuid[UUID_STR_LEN]; + + ret = register_mam_channel_req_deserialize(obj, req); + if (ret) { + ta_log_error("%s\n", ta_error_to_string(ret)); + goto done; + } + + ret = ta_register_mam_channel(cache, req, uuid); + if (ret) { + ta_log_error("%s\n", ta_error_to_string(ret)); + goto done; + } + + ret = register_mam_channel_res_serialize(uuid, json_result); + if (ret) { + ta_log_error("%s\n", ta_error_to_string(ret)); + } + +done: + ta_register_mam_channel_req_free(&req); + return ret; +} + #ifdef DB_ENABLE status_t api_find_transactions_by_id(const iota_client_service_t* const iota_service, const db_client_service_t* const db_service, const char* const obj, diff --git a/accelerator/core/apis.h b/accelerator/core/apis.h index fb462387..a9091afa 100644 --- a/accelerator/core/apis.h +++ b/accelerator/core/apis.h @@ -213,6 +213,19 @@ status_t api_get_node_status(const iota_client_service_t* const service, char** */ status_t api_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* const uuid, char** json_result); +/** + * @brief Register user identity with MAM channel seed + * + * @param[in] cache Redis configuration variables + * @param[in] obj Request in JSON format + * @param[out] json_result Result contains the user id. + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t api_register_mam_channel(const ta_cache_t* const cache, const char* const obj, char** json_result); + #ifdef DB_ENABLE /** * @brief Return transaction object with given single identity number. diff --git a/accelerator/core/core.c b/accelerator/core/core.c index 46ce5a01..7f18c135 100644 --- a/accelerator/core/core.c +++ b/accelerator/core/core.c @@ -565,9 +565,9 @@ status_t push_txn_to_buffer(const ta_cache_t* const cache, hash8019_array_p raw_ goto done; } - uuid_t binuuid; - uuid_generate_random(binuuid); - uuid_unparse(binuuid, uuid); + uuid_t bin_uuid; + uuid_generate_random(bin_uuid); + uuid_unparse(bin_uuid, uuid); if (!uuid[0]) { ta_log_error("%s\n", "Failed to generate UUID"); goto done; diff --git a/accelerator/core/mam_core.c b/accelerator/core/mam_core.c index 54cd2a6b..ca4c52e4 100644 --- a/accelerator/core/mam_core.c +++ b/accelerator/core/mam_core.c @@ -776,3 +776,29 @@ status_t ta_recv_mam_message(const iota_config_t *const iconf, const iota_client mam_encrypt_key_free(&mam_key); return ret; } + +status_t ta_register_mam_channel(const ta_cache_t *const cache, const ta_register_mam_channel_req_t *const req, + char *uuid) { + if (!cache || !req || !uuid) { + ta_log_error("%s\n", ta_error_to_string(SC_NULL)); + return SC_NULL; + } + status_t ret = SC_OK; + + uuid_t bin_uuid; + uuid_generate_random(bin_uuid); + uuid_unparse(bin_uuid, uuid); + if (!uuid[0]) { + ta_log_error("%s\n", "Failed to generate UUID"); + goto done; + } + + ret = cache_set(uuid, UUID_STR_LEN - 1, req->seed, NUM_TRYTES_ADDRESS, cache->timeout); + if (ret) { + ta_log_error("%s\n", ta_error_to_string(ret)); + goto done; + } + +done: + return ret; +} diff --git a/accelerator/core/mam_core.h b/accelerator/core/mam_core.h index 242537c9..6b0c0e4f 100644 --- a/accelerator/core/mam_core.h +++ b/accelerator/core/mam_core.h @@ -79,6 +79,20 @@ status_t ta_send_mam_message(const ta_config_t* const info, const iota_config_t* status_t ta_recv_mam_message(const iota_config_t* const iconf, const iota_client_service_t* const service, ta_recv_mam_req_t* const req, ta_recv_mam_res_t* const res); +/** + * @brief Register user identity with MAM channel seed. + * + * @param[in] cache redis configuration variables + * @param[in] req Request in 'ta_register_mam_channel_req_t' datatype + * @param[out] uuid Returned UUID + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t ta_register_mam_channel(const ta_cache_t* const cache, const ta_register_mam_channel_req_t* const req, + char* uuid); + #ifdef __cplusplus } #endif diff --git a/accelerator/core/request/request.h b/accelerator/core/request/request.h index 349be492..8653b24f 100644 --- a/accelerator/core/request/request.h +++ b/accelerator/core/request/request.h @@ -11,6 +11,7 @@ #include "ta_find_transaction_objects.h" #include "ta_recv_mam.h" +#include "ta_register_mam_channel.h" #include "ta_send_mam.h" #include "ta_send_transfer.h" diff --git a/accelerator/core/request/ta_register_mam_channel.c b/accelerator/core/request/ta_register_mam_channel.c new file mode 100644 index 00000000..4bc03cb0 --- /dev/null +++ b/accelerator/core/request/ta_register_mam_channel.c @@ -0,0 +1,14 @@ +#include "ta_register_mam_channel.h" + +ta_register_mam_channel_req_t* ta_register_mam_channel_req_new() { + ta_register_mam_channel_req_t* req = (ta_register_mam_channel_req_t*)malloc(sizeof(ta_register_mam_channel_req_t)); + if (req != NULL) { + return req; + } + return NULL; +} + +void ta_register_mam_channel_req_free(ta_register_mam_channel_req_t** req) { + free(*req); + *req = NULL; +} diff --git a/accelerator/core/request/ta_register_mam_channel.h b/accelerator/core/request/ta_register_mam_channel.h new file mode 100644 index 00000000..aba3f86e --- /dev/null +++ b/accelerator/core/request/ta_register_mam_channel.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 BiiLabs Co., Ltd. and Contributors + * All Rights Reserved. + * This is free software; you can redistribute it and/or modify it under the + * terms of the MIT license. A copy of the license can be found in the file + * "LICENSE" at the root of this distribution. + */ + +#ifndef REQUEST_TA_REGISTER_MAM_CHANNEL_H_ +#define REQUEST_TA_REGISTER_MAM_CHANNEL_H_ + +#include "common/model/transaction.h" +#include "common/ta_errors.h" +#include "utils/containers/hash/hash243_queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file accelerator/core/request/ta_register_mam_channel.h + */ + +/** struct of ta_register_mam_channel_req_t */ +typedef struct ta_register_mam_channel_req { + char seed[NUM_TRYTES_ADDRESS + 1]; +} ta_register_mam_channel_req_t; + +/** + * @brief Allocate memory of ta_register_mam_channel_req_t + * + * @return + * - struct of ta_register_mam_channel_req_t on success + * - NULL on error + */ +ta_register_mam_channel_req_t* ta_register_mam_channel_req_new(); + +/** + * @brief Free memory of ta_register_mam_channel_req_t + * + * @param[in] req Data type of ta_register_mam_channel_req_t + */ +void ta_register_mam_channel_req_free(ta_register_mam_channel_req_t** req); + +#ifdef __cplusplus +} +#endif + +#endif // REQUEST_TA_REGISTER_MAM_CHANNEL_H_ diff --git a/accelerator/core/serializer/ser_mam.c b/accelerator/core/serializer/ser_mam.c index 292b7320..5477a2a6 100644 --- a/accelerator/core/serializer/ser_mam.c +++ b/accelerator/core/serializer/ser_mam.c @@ -482,3 +482,82 @@ status_t recv_mam_message_res_serialize(ta_recv_mam_res_t* const res, char** obj cJSON_Delete(json_root); return ret; } + +status_t register_mam_channel_req_deserialize(const char* const obj, ta_register_mam_channel_req_t* req) { + if (obj == NULL || req == NULL) { + ta_log_error("%s\n", ta_error_to_string(SC_SERIALIZER_NULL)); + return SC_SERIALIZER_NULL; + } + status_t ret = SC_OK; + cJSON* json_obj = cJSON_Parse(obj); + cJSON* json_elt = NULL; + + if (json_obj == NULL) { + ret = SC_SERIALIZER_JSON_PARSE; + ta_log_error("%s\n", ta_error_to_string(ret)); + goto done; + } + + json_elt = cJSON_GetObjectItemCaseSensitive(json_obj, "seed"); + if (json_elt != NULL && json_elt->valuestring != NULL && strlen(json_elt->valuestring) == NUM_TRYTES_ADDRESS) { + strncpy(req->seed, json_elt->valuestring, NUM_TRYTES_ADDRESS); + req->seed[NUM_TRYTES_ADDRESS] = 0; + } else { + ret = SC_SERIALIZER_INVALID_REQ; + ta_log_error("%s\n", ta_error_to_string(ret)); + } + +done: + cJSON_Delete(json_obj); + return ret; +} + +status_t register_mam_channel_res_serialize(const char* const uuid, char** obj) { + if (uuid == NULL) { + ta_log_error("%s\n", ta_error_to_string(SC_SERIALIZER_NULL)); + return SC_SERIALIZER_NULL; + } + + status_t ret = SC_OK; + cJSON* json_root = cJSON_CreateObject(); + + cJSON_AddStringToObject(json_root, "user-id", uuid); + + *obj = cJSON_PrintUnformatted(json_root); + if (*obj == NULL) { + ta_log_error("%s\n", ta_error_to_string(SC_SERIALIZER_JSON_PARSE)); + ret = SC_SERIALIZER_JSON_PARSE; + } + + cJSON_Delete(json_root); + return ret; +} + +status_t register_mam_channel_res_deserialize(const char* const obj, char* user_id) { + if (obj == NULL || user_id == NULL) { + ta_log_error("%s\n", ta_error_to_string(SC_SERIALIZER_NULL)); + return SC_SERIALIZER_NULL; + } + status_t ret = SC_OK; + cJSON* json_obj = cJSON_Parse(obj); + cJSON* json_elt = NULL; + + if (json_obj == NULL) { + ret = SC_SERIALIZER_JSON_PARSE; + ta_log_error("%s\n", ta_error_to_string(ret)); + goto done; + } + + json_elt = cJSON_GetObjectItemCaseSensitive(json_obj, "user-id"); + if (json_elt != NULL && json_elt->valuestring != NULL && strlen(json_elt->valuestring) == (UUID_STR_LEN - 1)) { + strncpy(user_id, json_elt->valuestring, UUID_STR_LEN - 1); + user_id[UUID_STR_LEN - 1] = 0; + } else { + ret = SC_SERIALIZER_INVALID_REQ; + ta_log_error("%s\n", ta_error_to_string(ret)); + } + +done: + cJSON_Delete(json_obj); + return ret; +} diff --git a/accelerator/core/serializer/ser_mam.h b/accelerator/core/serializer/ser_mam.h index 03b2e645..c6f73074 100644 --- a/accelerator/core/serializer/ser_mam.h +++ b/accelerator/core/serializer/ser_mam.h @@ -93,6 +93,54 @@ status_t recv_mam_message_res_deserialize(const char* const obj, ta_recv_mam_res */ status_t recv_mam_message_res_serialize(ta_recv_mam_res_t* const res, char** obj); +/** + * @brief Deserialize JSON string to type of ta_send_mam_req_t + * + * @param[in] obj Input values in JSON + * @param[out] req Request data in type of ta_send_mam_req_t + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t send_mam_message_req_deserialize(const char* const obj, ta_send_mam_req_t* req); + +/** + * @brief Deserialize JSON string to type of ta_register_mam_channel_req_t + * + * @param[in] obj Input values in JSON + * @param[out] req Request data in type of ta_register_mam_channel_req_t + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t register_mam_channel_req_deserialize(const char* const obj, ta_register_mam_channel_req_t* req); + +/** + * @brief Serialize response of register_mam_channel + * + * @param[in] uuid Returned UUID from tangle-accelerator + * @param[out] obj Response formed in JSON + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t register_mam_channel_res_serialize(const char* const uuid, char** obj); + +/** + * @brief Deserialize JSON string to user-id + * + * @param[in] obj Input values in JSON + * @param[out] user_id User ID in string + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t register_mam_channel_res_deserialize(const char* const obj, char* user_id); + #ifdef __cplusplus } #endif diff --git a/tests/api/mam_test.c b/tests/api/mam_test.c index 74e05617..c410ec21 100644 --- a/tests/api/mam_test.c +++ b/tests/api/mam_test.c @@ -230,6 +230,18 @@ void test_encrypt_decrypt_psk(void) { send_mam_res_free(&send_res); } +void test_api_register_mam_channel(void) { + char* json_result; + const char* json = "{\"seed\":\"" TRYTES_81_1 "\"}"; + char user_id[UUID_STR_LEN], seed[NUM_TRYTES_ADDRESS + 1]; + TEST_ASSERT_EQUAL_INT32(SC_OK, api_register_mam_channel(&ta_core.cache, json, &json_result)); + + TEST_ASSERT_EQUAL_INT32(SC_OK, register_mam_channel_res_deserialize(json_result, user_id)); + TEST_ASSERT_EQUAL_INT32(SC_OK, cache_get(user_id, seed)); + TEST_ASSERT_EQUAL_INT32(SC_OK, cache_del(user_id)); + free(json_result); +} + int main(int argc, char* argv[]) { UNITY_BEGIN(); rand_trytes_init(); @@ -251,6 +263,7 @@ int main(int argc, char* argv[]) { RUN_TEST(test_write_until_next_channel); RUN_TEST(test_write_with_chid); RUN_TEST(test_encrypt_decrypt_psk); + RUN_TEST(test_api_register_mam_channel); ta_core_destroy(&ta_core); return UNITY_END(); } diff --git a/tests/unit-test/test_cache.c b/tests/unit-test/test_cache.c index 4c7e1097..3d630d4e 100644 --- a/tests/unit-test/test_cache.c +++ b/tests/unit-test/test_cache.c @@ -43,9 +43,9 @@ void test_cache_timeout(void) { } void test_generate_uuid(void) { - uuid_t binuuid; - uuid_generate_random(binuuid); - uuid_unparse(binuuid, test_uuid); + uuid_t bin_uuid; + uuid_generate_random(bin_uuid); + uuid_unparse(bin_uuid, test_uuid); TEST_ASSERT_TRUE(test_uuid[0]); } diff --git a/tests/unit-test/test_serializer.c b/tests/unit-test/test_serializer.c index c098b83f..6187f4b8 100644 --- a/tests/unit-test/test_serializer.c +++ b/tests/unit-test/test_serializer.c @@ -357,7 +357,6 @@ void test_send_mam_message_request_deserialize(void) { "\",\"message\":\"" TEST_PAYLOAD "\",\"ch_mss_depth\":" STR(TEST_CH_DEPTH) ",\"ep_mss_depth\":" STR( TEST_EP_DEPTH) "},\"key\":{\"ntru\":[\"" TEST_NTRU_PK "\"],\"psk\":[\"" TRYTES_81_2 "\",\"" TRYTES_81_3 "\"]}, \"protocol\":\"MAM_V1\"}"; - printf("json = %s\n", json); ta_send_mam_req_t* req = send_mam_req_new(); send_mam_message_req_deserialize(json, req); send_mam_data_mam_v1_t* data = (send_mam_data_mam_v1_t*)req->data; @@ -622,6 +621,23 @@ void test_fetch_txn_with_uuid_res_not_exist_serialize(void) { free(json_result); } +void test_register_mam_channel_req_deserialize(void) { + const char* json = "{\"seed\":\"" TRYTES_81_1 "\"}"; + ta_register_mam_channel_req_t* req = ta_register_mam_channel_req_new(); + + TEST_ASSERT_EQUAL_INT32(SC_OK, register_mam_channel_req_deserialize(json, req)); + TEST_ASSERT_EQUAL_STRING(TRYTES_81_1, req->seed); + ta_register_mam_channel_req_free(&req); +} + +void test_register_mam_channel_res_serialize(void) { + const char* json = "{\"user-id\":\"" TEST_UUID "\"}"; + char* json_result = NULL; + TEST_ASSERT_EQUAL_INT32(SC_OK, register_mam_channel_res_serialize(TEST_UUID, &json_result)); + TEST_ASSERT_EQUAL_STRING(json, json_result); + free(json_result); +} + int main(void) { UNITY_BEGIN(); @@ -657,6 +673,8 @@ int main(void) { RUN_TEST(test_get_node_status_res_serialize); RUN_TEST(test_fetch_txn_with_uuid_res_sent_serialize); RUN_TEST(test_fetch_txn_with_uuid_res_not_exist_serialize); + RUN_TEST(test_register_mam_channel_req_deserialize); + RUN_TEST(test_register_mam_channel_res_serialize); serializer_logger_release(); return UNITY_END(); }