1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "mine_hichain_connector.h"
17 
18 #include <cstdlib>
19 #include <chrono>
20 #include <unistd.h>
21 #include <securec.h>
22 
23 #include "device_auth.h"
24 #include "device_auth_defines.h"
25 #include "dm_constants.h"
26 #include "dm_log.h"
27 #include "nlohmann/json.hpp"
28 #include "parameter.h"
29 
30 
31 namespace OHOS {
32 namespace DistributedHardware {
33 constexpr int32_t DEVICE_UDID_LENGTH = 65;
34 constexpr int64_t CREATE_GROUP_REQUESTID = 159357462;
35 constexpr int32_t MAX_HICHAIN_DELAY_TIME = 10;
36 
37 std::mutex g_createGroupMutex;
38 std::condition_variable g_createGroupNotify;
39 
40 bool g_mineCreateGroupFlag = false;
41 
42 const DeviceGroupManager *g_deviceGroupManager = nullptr;
43 DeviceAuthCallback g_deviceAuthCallback = {
44     .onTransmit = nullptr,
45     .onFinish = MineHiChainConnector::onFinish,
46     .onError = MineHiChainConnector::onError,
47     .onRequest = nullptr
48 };
MineHiChainConnector()49 MineHiChainConnector::MineHiChainConnector()
50 {
51     Init();
52     LOGI("HiChainConnector::constructor success.");
53 }
54 
~MineHiChainConnector()55 MineHiChainConnector::~MineHiChainConnector()
56 {
57     UnInit();
58     LOGI("HiChainConnector::destructor.");
59 }
60 
onFinish(int64_t requestId,int operationCode,const char * returnData)61 void MineHiChainConnector::onFinish(int64_t requestId, int operationCode, const char *returnData)
62 {
63     (void)returnData;
64     LOGD("start to notify the asynchronous operation group of the successful result.");
65     if (requestId == CREATE_GROUP_REQUESTID) {
66         std::unique_lock<std::mutex> locker(g_createGroupMutex);
67         g_mineCreateGroupFlag = true;
68         g_createGroupNotify.notify_one();
69         LOGI("Create group success");
70     }
71     LOGI("OnFinish callback complete with requestId: %{public}" PRId64 ", operation: %{public}d.", requestId,
72         operationCode);
73 }
74 
onError(int64_t requestId,int operationCode,int errorCode,const char * errorReturn)75 void MineHiChainConnector::onError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn)
76 {
77     (void)errorReturn;
78     LOGD("start to notify the asynchronous operation group of the successful result.");
79     if (requestId == CREATE_GROUP_REQUESTID) {
80         std::unique_lock<std::mutex> locker(g_createGroupMutex);
81         g_mineCreateGroupFlag = false;
82         g_createGroupNotify.notify_one();
83         LOGI("failed to create group");
84     }
85     LOGI("OnError callback complete with requestId: %{public}" PRId64 ", operation: %{public}d, errorCode: %{public}d.",
86         requestId, operationCode, errorCode);
87 }
88 
Init(void)89 int32_t MineHiChainConnector::Init(void)
90 {
91     int retValue = InitDeviceAuthService();
92     if (retValue != HC_SUCCESS) {
93         LOGE("failed to init device auth service with ret:%{public}d.", retValue);
94         return ERR_DM_FAILED;
95     }
96     g_deviceGroupManager = GetGmInstance();
97     if (g_deviceGroupManager == nullptr) {
98         LOGE("failed to get Gm instance from hichain");
99         return ERR_DM_FAILED;
100     }
101 #if (defined(MINE_HARMONY))
102     retValue = g_deviceGroupManager->unRegCallback(DM_PKG_NAME);
103     if (retValue != HC_SUCCESS) {
104         LOGE("failed to register callback function to hichain with ret:%{public}d.", retValue);
105     }
106     retValue = g_deviceGroupManager->regCallback(DM_PKG_NAME, &g_deviceAuthCallback);
107     if (retValue != HC_SUCCESS) {
108         LOGE("failed to register callback function to hichain with ret:%{public}d.", retValue);
109         return ERR_DM_FAILED;
110     }
111 #endif
112     LOGI("init hichain modle successfully.");
113     return DM_OK;
114 }
115 
116 
UnInit(void)117 int32_t MineHiChainConnector::UnInit(void)
118 {
119     if (g_deviceGroupManager == nullptr) {
120         LOGE("g_deviceGroupManager os nullptr");
121         return ERR_DM_POINT_NULL;
122     }
123 #if (defined(MINE_HARMONY))
124     if (g_deviceGroupManager->unRegCallback(DM_PKG_NAME) != HC_SUCCESS) {
125         LOGE("failed to unregister callback to hichain");
126         return ERR_DM_HICHAIN_UNREGISTER_CALLBACK;
127     }
128     DestroyDeviceAuthService();
129 #endif
130     LOGI("uninit hichain modle successfully");
131     return DM_OK;
132 }
133 
DeleteCredentialAndGroup(void)134 int32_t MineHiChainConnector::DeleteCredentialAndGroup(void)
135 {
136     nlohmann::json jsonObj;
137     jsonObj[FIELD_IS_DELETE_ALL] = true;
138     std::string params = jsonObj.dump();
139 #if (defined(MINE_HARMONY))
140     char *returnInfo = nullptr;
141     int32_t retValue = g_deviceGroupManager->processCredential(DELETE_SELF_CREDENTIAL, params.c_str(), &returnInfo);
142     if (retValue != HC_SUCCESS) {
143         LOGE("failed to delete hichain credential and group with ret:%{public}d.", retValue);
144         return ERR_DM_FAILED;
145     }
146 #endif
147     return DM_OK;
148 }
149 
CreateGroup(const std::string & reqJsonStr)150 int32_t MineHiChainConnector::CreateGroup(const std::string &reqJsonStr)
151 {
152     int64_t requestId = CREATE_GROUP_REQUESTID;
153     char deviceUdid[DEVICE_UDID_LENGTH + 1] = {0};
154 
155     nlohmann::json jsonObject = nlohmann::json::parse(reqJsonStr, nullptr, false);
156     if (jsonObject.is_discarded()) {
157         LOGE("reqJsonStr string not a json type.");
158         return ERR_DM_FAILED;
159     }
160     if (!jsonObject.contains(FIELD_USER_ID) || !jsonObject[FIELD_USER_ID].is_string()) {
161         LOGE("userId key is not exist in reqJsonStr.");
162         return ERR_DM_FAILED;
163     }
164     int32_t retValue = GetDevUdid(deviceUdid, DEVICE_UDID_LENGTH);
165     if (retValue != 0) {
166         LOGE("failed to local device Udid with ret: %{public}d", retValue);
167         return ERR_DM_FAILED;
168     }
169 
170     nlohmann::json jsonObj;
171     jsonObj[FIELD_USER_ID] = jsonObject[FIELD_USER_ID];
172     jsonObj[FIELD_GROUP_NAME] = DEVICE_MANAGER_GROUPNAME;
173     jsonObj[FIELD_DEVICE_ID] = std::string(deviceUdid);
174     jsonObj[FIELD_GROUP_TYPE] = IDENTICAL_ACCOUNT_GROUP;
175     std::string createParams = jsonObj.dump();
176     retValue = g_deviceGroupManager->createGroup(DEFAULT_OS_ACCOUNT, requestId, DM_PKG_NAME, createParams.c_str());
177     if (retValue != HC_SUCCESS) {
178         LOGE("failed to create group with ret:%{public}d.", retValue);
179         return ERR_DM_FAILED;
180     }
181 
182     std::chrono::seconds timeout = std::chrono::seconds(MAX_HICHAIN_DELAY_TIME);
183     std::unique_lock<std::mutex> locker(g_createGroupMutex);
184     if (g_createGroupNotify.wait_for(locker, timeout, [] { return g_mineCreateGroupFlag; })) {
185         g_mineCreateGroupFlag = false;
186         return DM_OK;
187     }
188     g_mineCreateGroupFlag = false;
189     return ERR_DM_FAILED;
190 }
191 
RequestCredential(std::string & returnJsonStr)192 int MineHiChainConnector::RequestCredential(std::string &returnJsonStr)
193 {
194     if (g_deviceGroupManager == nullptr) {
195         LOGE("HiChainConnector::g_deviceGroupManager is nullptr.");
196         return ERR_DM_INPUT_PARA_INVALID;
197     }
198 
199     LOGI("start to request device credential.");
200 #if (defined(MINE_HARMONY))
201     char *returnInfo = nullptr;
202     int32_t retValue = g_deviceGroupManager->getRegisterInfo(&returnInfo);
203     if (retValue != HC_SUCCESS || returnInfo == nullptr) {
204         LOGE("failed to request hichain credential with ret:%{public}d.", retValue);
205         return ERR_DM_HICHAIN_GET_REGISTER_INFO;
206     }
207     returnJsonStr = returnInfo;
208     g_deviceGroupManager->destroyInfo(&returnInfo);
209 #endif
210     LOGI("request hichain device credential successfully with JsonStrLen:%{public}zu", returnJsonStr.size());
211     return DM_OK;
212 }
213 
CheckCredential(std::string reqJsonStr,std::string & returnJsonStr)214 int MineHiChainConnector::CheckCredential(std::string reqJsonStr, std::string &returnJsonStr)
215 {
216     if (reqJsonStr.empty() || g_deviceGroupManager == nullptr) {
217         LOGE("HiChainConnector::g_deviceGroupManager is nullptr.");
218         return ERR_DM_INPUT_PARA_INVALID;
219     }
220     LOGI("start to check device credential.");
221 #if (defined(MINE_HARMONY))
222     char *returnInfo = nullptr;
223     int32_t retValue = g_deviceGroupManager->processCredential(QUERY_SELF_CREDENTIAL_INFO,
224         reqJsonStr.c_str(), &returnInfo);
225     if (retValue != HC_SUCCESS) {
226         LOGE("failed to check device credential info with ret:%{public}d.", retValue);
227         return ERR_DM_HICHAIN_GET_REGISTER_INFO;
228     }
229     returnJsonStr = returnInfo;
230     g_deviceGroupManager->destroyInfo(&returnInfo);
231 #endif
232     LOGI("check device credential info successfully with JsonStrLen:%{public}zu", returnJsonStr.size());
233     return DM_OK;
234 }
235 
ImportCredential(std::string reqJsonStr,std::string & returnJsonStr)236 int MineHiChainConnector::ImportCredential(std::string reqJsonStr, std::string &returnJsonStr)
237 {
238     if (reqJsonStr.empty() || g_deviceGroupManager == nullptr) {
239         LOGE("reqJsonStr is empty or g_deviceGroupManager is nullptr.");
240         return ERR_DM_INPUT_PARA_INVALID;
241     }
242     nlohmann::json jsonObject = nlohmann::json::parse(reqJsonStr, nullptr, false);
243     if (jsonObject.is_discarded()) {
244         LOGE("import credenfial input reqJsonStr string not a json string type.");
245         return ERR_DM_INPUT_PARA_INVALID;
246     }
247     if (IsCredentialExist()) {
248         LOGE("the device has already exists credential.");
249         return ERR_DM_HICHAIN_CREDENTIAL_EXISTS;
250     }
251     int32_t retValue = g_deviceGroupManager->regCallback(DM_PKG_NAME, &g_deviceAuthCallback);
252     if (retValue != HC_SUCCESS) {
253         LOGE("failed to register callback function to hichain with ret:%{public}d.", retValue);
254         return ERR_DM_HICHAIN_REGISTER_CALLBACK;
255     }
256     LOGI("start to import device credential info to hichain.");
257 #if (defined(MINE_HARMONY))
258     char *returnInfo = nullptr;
259     retValue = g_deviceGroupManager->processCredential(IMPORT_SELF_CREDENTIAL, reqJsonStr.c_str(), &returnInfo);
260     if (retValue != HC_SUCCESS) {
261         LOGE("failed to import hichain credential with ret:%{public}d.", retValue);
262         return ERR_DM_HICHAIN_GROUP_CREATE_FAILED;
263     }
264     if (CreateGroup(reqJsonStr) != DM_OK) {
265         DeleteCredentialAndGroup();
266         LOGE("fail to import hichain credential bacause create group unsuccessfully.");
267         return ERR_DM_HICHAIN_GROUP_CREATE_FAILED;
268     }
269 #endif
270     LOGI("import device credential info successfully.");
271     return DM_OK;
272 }
273 
DeleteCredential(std::string reqJsonStr,std::string & returnJsonStr)274 int MineHiChainConnector::DeleteCredential(std::string reqJsonStr, std::string &returnJsonStr)
275 {
276     if (reqJsonStr.empty() || g_deviceGroupManager == nullptr) {
277         LOGE("reqJsonStr is empty or g_deviceGroupManager is nullptr.");
278         return ERR_DM_INPUT_PARA_INVALID;
279     }
280 
281     LOGI("start to delete device credential from hichain.");
282     if (DeleteCredentialAndGroup() != DM_OK) {
283         LOGE("failed to delete hichain credential.");
284         return ERR_DM_HICHAIN_CREDENTIAL_DELETE_FAILED;
285     }
286     LOGI("delete device credential info from hichain successfully.");
287     return DM_OK;
288 }
289 
IsCredentialExist(void)290 bool MineHiChainConnector::IsCredentialExist(void)
291 {
292     bool resultFlag = false;
293     std::string reqJsonStr = "{\n}";
294 
295     if (g_deviceGroupManager == nullptr) {
296         LOGE("g_deviceGroupManager is nullptr.");
297         return resultFlag;
298     }
299 #if (defined(MINE_HARMONY))
300     char *returnInfo = nullptr;
301     int32_t retValue = g_deviceGroupManager->processCredential(QUERY_SELF_CREDENTIAL_INFO,
302         reqJsonStr.c_str(), &returnInfo);
303     if (retValue != HC_SUCCESS || returnInfo == nullptr) {
304         LOGE("failed to check device credential info with ret:%{public}d.", retValue);
305         return resultFlag;
306     }
307 
308     do {
309         nlohmann::json jsonObject = nlohmann::json::parse(returnInfo, nullptr, false);
310         if (jsonObject.is_discarded()) {
311             LOGE("reqJsonStr is not a json string type.");
312             break;
313         }
314         if (!jsonObject.contains(FIELD_CREDENTIAL_EXISTS) || !jsonObject[FIELD_CREDENTIAL_EXISTS].is_boolean()) {
315             LOGE("failed to get key:%{public}s from import json object.", FIELD_CREDENTIAL_EXISTS);
316             break;
317         }
318         if (!jsonObject[FIELD_CREDENTIAL_EXISTS]) {
319             LOGI("credential information does not exist on the current device.");
320             break;
321         }
322         LOGI("credential information exist on the current device.");
323         resultFlag = true;
324     } while (false);
325 
326     g_deviceGroupManager->destroyInfo(&returnInfo);
327 #endif
328     return resultFlag;
329 }
330 } // namespace DistributedHardware
331 } // namespace OHOS