1 /*
2  * Copyright (c) 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 "relationship_sync_mgr.h"
17 
18 #include <cstdint>
19 #include <vector>
20 #include "dm_crypto.h"
21 #include "dm_log.h"
22 
23 namespace OHOS {
24 namespace DistributedHardware {
25     DM_IMPLEMENT_SINGLE_INSTANCE(ReleationShipSyncMgr);
26 namespace {
27     /**
28      * @brief account logout payload length 8
29      * |      2 bytes         |         6 bytes          |
30      * | userid lower 2 bytes | account id first 6 bytes |
31      */
32     const int32_t ACCOUNT_LOGOUT_PAYLOAD_LEN = 8;
33     /**
34      * @brief device unbind payload length 2
35      * |      2 bytes         |
36      * | userid lower 2 bytes |
37      */
38     const int32_t DEVICE_UNBIND_PAYLOAD_LEN = 2;
39     /**
40      * @brief app unbind payload length 6
41      * |      2 bytes         |         4 bytes          |
42      * | userid lower 2 bytes |  token id lower 4 bytes  |
43      */
44     const int32_t APP_UNBIND_PAYLOAD_LEN = 6;
45     const int32_t USERID_PAYLOAD_LEN = 2;
46     const int32_t ACCOUNTID_PAYLOAD_LEN = 6;
47     const int32_t BIT_PER_BYTES = 8;
48     const int32_t INVALIED_PAYLOAD_SIZE = 12;
49 
50     const char * const MSG_TYPE = "TYPE";
51     const char * const MSG_VALUE = "VALUE";
52     const char * const MSG_PEER_UDID = "PEER_UDID";
53     const char * const MSG_ACCOUNTID = "ACCOUNTID";
54 }
55 
RelationShipChangeMsg()56 RelationShipChangeMsg::RelationShipChangeMsg() : type(RelationShipChangeType::TYPE_MAX),
57     userId(UINT32_MAX), accountId(""), tokenId(UINT64_MAX), peerUdid("")
58 {
59 }
60 
ToBroadcastPayLoad(uint8_t *&msg, uint32_t &len) const61 bool RelationShipChangeMsg::ToBroadcastPayLoad(uint8_t *&msg, uint32_t &len) const
62 {
63     if (!IsValid()) {
64         LOGE("invalid");
65         return false;
66     }
67 
68     bool ret = false;
69     switch (type) {
70         case RelationShipChangeType::ACCOUNT_LOGOUT:
71             ToAccountLogoutPayLoad(msg, len);
72             ret = true;
73             break;
74         case RelationShipChangeType::DEVICE_UNBIND:
75             ToDeviceUnbindPayLoad(msg, len);
76             ret = true;
77             break;
78         case RelationShipChangeType::APP_UNBIND:
79             ToAppUnbindPayLoad(msg, len);
80             ret = true;
81             break;
82         default:
83             LOGE("RelationShipChange type invalid");
84             break;
85     }
86     return ret;
87 }
88 
FromBroadcastPayLoad(const cJSON *payloadJson, RelationShipChangeType type)89 bool RelationShipChangeMsg::FromBroadcastPayLoad(const cJSON *payloadJson, RelationShipChangeType type)
90 {
91     LOGI("FromBroadcastPayLoad type %{public}d.", type);
92     if (type == RelationShipChangeType::TYPE_MAX) {
93         LOGE("ChangeType invalid, type: %{public}d", type);
94         return false;
95     }
96     bool ret = false;
97     switch (type) {
98         case RelationShipChangeType::ACCOUNT_LOGOUT:
99             ret = FromAccountLogoutPayLoad(payloadJson);
100             break;
101         case RelationShipChangeType::DEVICE_UNBIND:
102             ret = FromDeviceUnbindPayLoad(payloadJson);
103             break;
104         case RelationShipChangeType::APP_UNBIND:
105             ret = FromAppUnbindPayLoad(payloadJson);
106             break;
107         default:
108             LOGE("RelationShipChange type invalid");
109             break;
110     }
111     return ret;
112 }
113 
IsValid() const114 bool RelationShipChangeMsg::IsValid() const
115 {
116     bool ret = false;
117     switch (type) {
118         case RelationShipChangeType::ACCOUNT_LOGOUT:
119             ret = (userId != UINT32_MAX && accountId.length() >= ACCOUNTID_PAYLOAD_LEN);
120             break;
121         case RelationShipChangeType::DEVICE_UNBIND:
122             ret = (userId != UINT32_MAX);
123             break;
124         case RelationShipChangeType::APP_UNBIND:
125             ret = (userId != UINT32_MAX && tokenId != UINT64_MAX);
126             break;
127         case RelationShipChangeType::SERVICE_UNBIND:
128         case RelationShipChangeType::DEL_USER:
129         case RelationShipChangeType::APP_UNINSTALL:
130             // current NOT support
131             ret = false;
132             break;
133         case RelationShipChangeType::TYPE_MAX:
134             ret = false;
135             break;
136         default:
137             ret = false;
138             break;
139     }
140     return ret;
141 }
142 
IsChangeTypeValid()143 bool RelationShipChangeMsg::IsChangeTypeValid()
144 {
145     return (type == RelationShipChangeType::ACCOUNT_LOGOUT) || (type == RelationShipChangeType::DEVICE_UNBIND) ||
146         (type == RelationShipChangeType::APP_UNBIND);
147 }
148 
IsChangeTypeValid(uint32_t type)149 bool RelationShipChangeMsg::IsChangeTypeValid(uint32_t type)
150 {
151     return (type == (uint32_t)RelationShipChangeType::ACCOUNT_LOGOUT) ||
152         (type == (uint32_t)RelationShipChangeType::DEVICE_UNBIND) ||
153         (type == (uint32_t)RelationShipChangeType::APP_UNBIND);
154 }
155 
ToAccountLogoutPayLoad(uint8_t *&msg, uint32_t &len) const156 void RelationShipChangeMsg::ToAccountLogoutPayLoad(uint8_t *&msg, uint32_t &len) const
157 {
158     msg = new uint8_t[ACCOUNT_LOGOUT_PAYLOAD_LEN]();
159     for (int i = 0; i < USERID_PAYLOAD_LEN; i++) {
160         msg[i] |= (userId >> (i * BIT_PER_BYTES)) & 0xFF;
161     }
162 
163     for (int j = USERID_PAYLOAD_LEN; j < ACCOUNT_LOGOUT_PAYLOAD_LEN; j++) {
164         msg[j] = accountId[j - USERID_PAYLOAD_LEN];
165     }
166     len = ACCOUNT_LOGOUT_PAYLOAD_LEN;
167 }
168 
ToDeviceUnbindPayLoad(uint8_t *&msg, uint32_t &len) const169 void RelationShipChangeMsg::ToDeviceUnbindPayLoad(uint8_t *&msg, uint32_t &len) const
170 {
171     msg = new uint8_t[DEVICE_UNBIND_PAYLOAD_LEN]();
172     for (int i = 0; i < USERID_PAYLOAD_LEN; i++) {
173         msg[i] |= (userId >> (i * BIT_PER_BYTES)) & 0xFF;
174     }
175     len = DEVICE_UNBIND_PAYLOAD_LEN;
176 }
177 
ToAppUnbindPayLoad(uint8_t *&msg, uint32_t &len) const178 void RelationShipChangeMsg::ToAppUnbindPayLoad(uint8_t *&msg, uint32_t &len) const
179 {
180     msg = new uint8_t[APP_UNBIND_PAYLOAD_LEN]();
181     for (int i = 0; i < USERID_PAYLOAD_LEN; i++) {
182         msg[i] |= (userId >> (i * BIT_PER_BYTES)) & 0xFF;
183     }
184 
185     for (int i = USERID_PAYLOAD_LEN; i < APP_UNBIND_PAYLOAD_LEN; i++) {
186         msg[i] |= (tokenId >> ((i - USERID_PAYLOAD_LEN) * BIT_PER_BYTES)) & 0xFF;
187     }
188 
189     len = APP_UNBIND_PAYLOAD_LEN;
190 }
191 
FromAccountLogoutPayLoad(const cJSON *payloadJson)192 bool RelationShipChangeMsg::FromAccountLogoutPayLoad(const cJSON *payloadJson)
193 {
194     if (payloadJson == NULL) {
195         LOGE("Account logout payloadJson is null.");
196         return false;
197     }
198     int32_t arraySize = cJSON_GetArraySize(payloadJson);
199     if (arraySize < ACCOUNT_LOGOUT_PAYLOAD_LEN || arraySize > INVALIED_PAYLOAD_SIZE) {
200         LOGE("Payload invalied,the size is %{public}d.", arraySize);
201         return false;
202     }
203     userId = 0;
204     for (uint32_t i = 0; i < USERID_PAYLOAD_LEN; i++) {
205         cJSON *payloadItem = cJSON_GetArrayItem(payloadJson, i);
206         CHECK_NULL_RETURN(payloadItem, false);
207         if (cJSON_IsNumber(payloadItem)) {
208             userId |= (static_cast<uint8_t>(payloadItem->valueint)) << (i * BIT_PER_BYTES);
209         }
210     }
211     accountId = "";
212     for (uint32_t j = USERID_PAYLOAD_LEN; j < ACCOUNT_LOGOUT_PAYLOAD_LEN; j++) {
213         cJSON *payloadItem = cJSON_GetArrayItem(payloadJson, j);
214         CHECK_NULL_RETURN(payloadItem, false);
215         if (cJSON_IsNumber(payloadItem)) {
216             accountId += static_cast<char>(payloadItem->valueint);
217         }
218     }
219     return true;
220 }
221 
FromDeviceUnbindPayLoad(const cJSON *payloadJson)222 bool RelationShipChangeMsg::FromDeviceUnbindPayLoad(const cJSON *payloadJson)
223 {
224     if (payloadJson == NULL) {
225         LOGE("Device unbind payloadJson is null.");
226         return false;
227     }
228     int32_t arraySize = cJSON_GetArraySize(payloadJson);
229     if (arraySize < ACCOUNT_LOGOUT_PAYLOAD_LEN || arraySize > INVALIED_PAYLOAD_SIZE) {
230         LOGE("Payload invalied,the size is %{public}d.", arraySize);
231         return false;
232     }
233     userId = 0;
234     for (uint32_t i = 0; i < USERID_PAYLOAD_LEN; i++) {
235         cJSON *payloadItem = cJSON_GetArrayItem(payloadJson, i);
236         CHECK_NULL_RETURN(payloadItem, false);
237         if (cJSON_IsNumber(payloadItem)) {
238             userId |= (static_cast<uint8_t>(payloadItem->valueint)) << (i * BIT_PER_BYTES);
239         }
240     }
241     return true;
242 }
243 
FromAppUnbindPayLoad(const cJSON *payloadJson)244 bool RelationShipChangeMsg::FromAppUnbindPayLoad(const cJSON *payloadJson)
245 {
246     if (payloadJson == NULL) {
247         LOGE("App unbind payloadJson is null.");
248         return false;
249     }
250     int32_t arraySize = cJSON_GetArraySize(payloadJson);
251     if (arraySize < ACCOUNT_LOGOUT_PAYLOAD_LEN || arraySize > INVALIED_PAYLOAD_SIZE) {
252         LOGE("Payload invalied,the size is %{public}d.", arraySize);
253         return false;
254     }
255     userId = 0;
256     for (uint32_t i = 0; i < USERID_PAYLOAD_LEN; i++) {
257         cJSON *payloadItem = cJSON_GetArrayItem(payloadJson, i);
258         CHECK_NULL_RETURN(payloadItem, false);
259         if (cJSON_IsNumber(payloadItem)) {
260             userId |= (static_cast<uint8_t>(payloadItem->valueint)) << (i * BIT_PER_BYTES);
261         }
262     }
263     tokenId = 0;
264     for (uint32_t j = USERID_PAYLOAD_LEN; j < APP_UNBIND_PAYLOAD_LEN; j++) {
265         cJSON *payloadItem = cJSON_GetArrayItem(payloadJson, j);
266         CHECK_NULL_RETURN(payloadItem, false);
267         if (cJSON_IsNumber(payloadItem)) {
268             tokenId |= (static_cast<uint8_t>(payloadItem->valueint)) <<  ((j - USERID_PAYLOAD_LEN) * BIT_PER_BYTES);
269         }
270     }
271     return true;
272 }
273 
ToArrayJson() const274 cJSON *RelationShipChangeMsg::ToArrayJson() const
275 {
276     uint8_t *payload = nullptr;
277     uint32_t len = 0;
278     if (!this->ToBroadcastPayLoad(payload, len)) {
279         LOGE("Get broadcast payload failed");
280         return nullptr;
281     }
282     cJSON *arrayObj = cJSON_CreateArray();
283     if (arrayObj == nullptr) {
284         LOGE("cJSON_CreateArray failed");
285         if (payload != nullptr) {
286             delete[] payload;
287         }
288         return nullptr;
289     }
290     for (uint32_t index = 0; index < len; index++) {
291         cJSON_AddItemToArray(arrayObj, cJSON_CreateNumber(payload[index]));
292     }
293     if (payload != nullptr) {
294         delete[] payload;
295     }
296     return arrayObj;
297 }
298 
ToJson() const299 std::string RelationShipChangeMsg::ToJson() const
300 {
301     cJSON *msg = cJSON_CreateObject();
302     if (msg == NULL) {
303         LOGE("failed to create cjson object");
304         return "";
305     }
306     cJSON_AddNumberToObject(msg, MSG_TYPE, (uint32_t)type);
307     cJSON *arrayObj = ToArrayJson();
308     if (arrayObj == nullptr) {
309         LOGE("ArrayObj is nullptr.");
310         cJSON_Delete(msg);
311         return "";
312     }
313     cJSON_AddItemToObject(msg, MSG_VALUE, arrayObj);
314 
315     cJSON *udidArrayObj = cJSON_CreateArray();
316     if (udidArrayObj == nullptr) {
317         LOGE("cJSON_CreateArray failed");
318         cJSON_Delete(msg);
319         return "";
320     }
321     for (uint32_t index = 0; index < peerUdids.size(); index++) {
322         cJSON_AddItemToArray(udidArrayObj, cJSON_CreateString(peerUdids[index].c_str()));
323     }
324     cJSON_AddItemToObject(msg, MSG_PEER_UDID, udidArrayObj);
325     cJSON_AddStringToObject(msg, MSG_ACCOUNTID, accountName.c_str());
326     char *retStr = cJSON_PrintUnformatted(msg);
327     if (retStr == nullptr) {
328         LOGE("to json is nullptr.");
329         cJSON_Delete(msg);
330         return "";
331     }
332     std::string ret = std::string(retStr);
333     cJSON_Delete(msg);
334     cJSON_free(retStr);
335     return ret;
336 }
337 
FromJson(const std::string &msgJson)338 bool RelationShipChangeMsg::FromJson(const std::string &msgJson)
339 {
340     cJSON *msgObj = cJSON_Parse(msgJson.c_str());
341     if (msgObj == NULL) {
342         LOGE("parse msg failed");
343         return false;
344     }
345 
346     cJSON *typeJson = cJSON_GetObjectItem(msgObj, MSG_TYPE);
347     if (typeJson == NULL || !cJSON_IsNumber(typeJson) || !IsChangeTypeValid(typeJson->valueint)) {
348         LOGE("parse type failed.");
349         cJSON_Delete(msgObj);
350         return false;
351     }
352     this->type = (RelationShipChangeType)typeJson->valueint;
353 
354     cJSON *payloadJson = cJSON_GetObjectItem(msgObj, MSG_VALUE);
355     if (payloadJson == NULL || !cJSON_IsArray(payloadJson)) {
356         LOGE("parse payload failed.");
357         cJSON_Delete(msgObj);
358         return false;
359     }
360     if (!this->FromBroadcastPayLoad(payloadJson, type)) {
361         LOGE("parse payload error.");
362         cJSON_Delete(msgObj);
363         return false;
364     }
365 
366     cJSON *peerUdidJson = cJSON_GetObjectItem(msgObj, MSG_PEER_UDID);
367     if (peerUdidJson == NULL || !cJSON_IsString(peerUdidJson)) {
368         LOGE("parse peer udid failed.");
369         cJSON_Delete(msgObj);
370         return false;
371     }
372     this->peerUdid = std::string(peerUdidJson->valuestring);
373     cJSON_Delete(msgObj);
374     return true;
375 }
376 
SyncTrustRelationShip(const RelationShipChangeMsg &msg)377 std::string ReleationShipSyncMgr::SyncTrustRelationShip(const RelationShipChangeMsg &msg)
378 {
379     return msg.ToJson();
380 }
381 
ParseTrustRelationShipChange(const std::string &msgJson)382 RelationShipChangeMsg ReleationShipSyncMgr::ParseTrustRelationShipChange(const std::string &msgJson)
383 {
384     RelationShipChangeMsg msgObj;
385     if (!msgObj.FromJson(msgJson)) {
386         LOGE("Parse json failed");
387     }
388     return msgObj;
389 }
390 } // DistributedHardware
391 } // OHOS