1 /*
2 * Copyright (c) 2025 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 "nearlink_config_utils.h"
17
18 #include <unistd.h>
19
20 #include "directory_ex.h"
21
22 #include "edm_log.h"
23 #include "nearlink_protocol_utils.h"
24
25 namespace OHOS {
26 namespace EDM {
27 const std::string CONFIG_PATH = "/data/service/el1/public/edm/config/system/all/nearlink/config.json";
28 const std::string CONFIG_SYSTEM_ALL_DIR = "/data/service/el1/public/edm/config/system/all";
29 const std::string NEARLINK_DIR = "nearlink";
30 const std::string SEPARATOR = "/";
31 const char *const PROTOCOL_DENY_LIST = "ProtocolDenyList";
32 constexpr int32_t EDM_UID = 3057;
33 constexpr int32_t EDM_GID = 3057;
34
NearlinkConfigUtils()35 NearlinkConfigUtils::NearlinkConfigUtils()
36 {
37 EDMLOGI("NearlinkConfigUtils::NearlinkConfigUtils()");
38 std::vector<std::string> files;
39 OHOS::GetDirFiles(CONFIG_SYSTEM_ALL_DIR, files);
40 if (std::find(files.begin(), files.end(), NEARLINK_DIR) == files.end()) {
41 CreateNearlinkConfigDir(CONFIG_SYSTEM_ALL_DIR + SEPARATOR + NEARLINK_DIR);
42 }
43 LoadConfig();
44 }
45
~NearlinkConfigUtils()46 NearlinkConfigUtils::~NearlinkConfigUtils()
47 {
48 EDMLOGI("NearlinkConfigUtils::~NearlinkConfigUtils()");
49 if (root_) {
50 cJSON_Delete(root_);
51 }
52 }
53
UpdateProtocol(const std::string & userId,const std::string & protocol,bool isAdd)54 bool NearlinkConfigUtils::UpdateProtocol(const std::string &userId, const std::string &protocol, bool isAdd)
55 {
56 EDMLOGI("NearlinkConfigUtils::UpdateProtocol() - isAdd: %d", isAdd);
57
58 // 通用前置检查
59 if (!root_ && !LoadConfig()) {
60 EDMLOGE("Failed to load config before update protocol");
61 return false;
62 }
63 if (!CheckProtocolDenyListExists()) {
64 EDMLOGE("Failed to ensure PROTOCOL_DENY_LIST exists");
65 return false;
66 }
67
68 // 获取 denyList 和 userItem
69 cJSON *denyList = cJSON_GetObjectItem(root_, PROTOCOL_DENY_LIST);
70 if (!denyList) {
71 EDMLOGE("PROTOCOL_DENY_LIST not found in config");
72 return false;
73 }
74 cJSON *userItem = cJSON_GetObjectItem(denyList, userId.c_str());
75
76 // 调用子函数处理增删逻辑
77 if (isAdd) {
78 return AddProtocol(protocol, userId, denyList, userItem);
79 } else {
80 return RemoveProtocol(protocol, userId, denyList, userItem);
81 }
82 }
83
AddProtocol(const std::string & protocol,const std::string & userId,cJSON * denyList,cJSON * userItem)84 bool NearlinkConfigUtils::AddProtocol(
85 const std::string &protocol, const std::string &userId, cJSON *denyList, cJSON *userItem)
86 {
87 if (userItem && IsProtocolExist(protocol, userItem)) {
88 EDMLOGI("Protocol %s already exists", protocol.c_str());
89 return true; // 协议已存在,无需添加
90 }
91
92 cJSON *protocols = cJSON_CreateString(protocol.c_str());
93 if (!protocols) {
94 EDMLOGE("Failed to create protocol string item");
95 return false;
96 }
97
98 if (!userItem) {
99 // 新增用户条目
100 CJSON_CREATE_ARRAY_AND_CHECK(userItem, false);
101 CJSON_ADD_ITEM_TO_ARRAY_AND_CHECK_AND_CLEAR(protocols, userItem, false);
102 if (!cJSON_AddItemToObject(denyList, userId.c_str(), userItem)) {
103 EDMLOGE("cJSON_AddItemToObject Error");
104 cJSON_Delete(userItem);
105 return false;
106 }
107 } else {
108 // 直接添加到现有数组
109 CJSON_ADD_ITEM_TO_ARRAY_AND_CHECK_AND_CLEAR(protocols, userItem, false);
110 }
111 return SaveConfig();
112 }
113
RemoveProtocol(const std::string & protocol,const std::string & userId,cJSON * denyList,cJSON * userItem)114 bool NearlinkConfigUtils::RemoveProtocol(
115 const std::string &protocol, const std::string &userId, cJSON *denyList, cJSON *userItem)
116 {
117 if (!userItem) {
118 EDMLOGI("User entry does not exist, nothing to remove");
119 return true;
120 }
121
122 int indexToRemove = -1;
123 for (int i = 0; i < cJSON_GetArraySize(userItem); ++i) {
124 cJSON *item = cJSON_GetArrayItem(userItem, i);
125 if (item && item->valuestring && strcmp(item->valuestring, protocol.c_str()) == 0) {
126 indexToRemove = i;
127 break;
128 }
129 }
130
131 if (indexToRemove < 0) {
132 EDMLOGI("Protocol %s not found", protocol.c_str());
133 return true; // 协议不存在,无需删除
134 }
135
136 cJSON_DeleteItemFromArray(userItem, indexToRemove);
137 if (cJSON_GetArraySize(userItem) == 0) {
138 cJSON_DeleteItemFromObject(denyList, userId.c_str()); // 删除空用户条目
139 }
140 return SaveConfig();
141 }
142
IsProtocolExist(const std::string & protocol,cJSON * userItem)143 bool NearlinkConfigUtils::IsProtocolExist(const std::string &protocol, cJSON *userItem)
144 {
145 cJSON *protocolItem = nullptr;
146 cJSON_ArrayForEach(protocolItem, userItem) {
147 if (strcmp(protocolItem->valuestring, protocol.c_str()) == 0) {
148 return true;
149 }
150 }
151 return false;
152 }
153
CreateNearlinkConfigDir(const std::string & dir)154 bool NearlinkConfigUtils::CreateNearlinkConfigDir(const std::string &dir)
155 {
156 EDMLOGI("NearlinkConfigUtils::CreateNearlinkConfigDir");
157 if (!OHOS::ForceCreateDirectory(dir)) {
158 EDMLOGE("mkdir dir failed");
159 return false;
160 }
161 if (chown(dir.c_str(), EDM_UID, EDM_GID) != 0) {
162 EDMLOGE("fail to change dir ownership");
163 return false;
164 }
165 mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
166 if (!OHOS::ChangeModeFile(dir, mode)) {
167 EDMLOGE("change mode failed, temp install dir");
168 return false;
169 }
170 return true;
171 }
172
QueryProtocols(const std::string & userId,std::vector<int32_t> & protocols)173 bool NearlinkConfigUtils::QueryProtocols(const std::string &userId, std::vector<int32_t> &protocols)
174 {
175 if (!root_ && !LoadConfig()) {
176 return false;
177 }
178 cJSON *denyList = cJSON_GetObjectItem(root_, PROTOCOL_DENY_LIST);
179 if (!denyList) {
180 return true;
181 }
182 cJSON *userItem = cJSON_GetObjectItem(denyList, userId.c_str());
183 if (!userItem) {
184 return true;
185 }
186 cJSON *protocolItem = nullptr;
187 cJSON_ArrayForEach(protocolItem, userItem) {
188 int32_t protocol = 0;
189 NearlinkProtocolUtils::StrToProtocolInt(protocolItem->valuestring, protocol);
190 protocols.push_back(protocol);
191 }
192 return true;
193 }
194
RemoveUserIdItem(const std::string & userId)195 bool NearlinkConfigUtils::RemoveUserIdItem(const std::string &userId)
196 {
197 EDMLOGI("NearlinkConfigUtils::RemoveUserIdItem");
198 if (!root_ && !LoadConfig()) {
199 return false;
200 }
201 cJSON *denyList = cJSON_GetObjectItem(root_, PROTOCOL_DENY_LIST);
202 if (!denyList) {
203 return true;
204 }
205 cJSON_DeleteItemFromObject(denyList, userId.c_str());
206 return SaveConfig();
207 }
208
RemoveProtocolDenyList()209 bool NearlinkConfigUtils::RemoveProtocolDenyList()
210 {
211 EDMLOGI("NearlinkConfigUtils::RemoveProtocolDenyList");
212 if (!root_ && !LoadConfig()) {
213 return false;
214 }
215 cJSON_DeleteItemFromObject(root_, PROTOCOL_DENY_LIST);
216 return SaveConfig();
217 }
218
LoadConfig()219 bool NearlinkConfigUtils::LoadConfig()
220 {
221 EDMLOGI("NearlinkConfigUtils::LoadConfig");
222 std::ifstream inFile(CONFIG_PATH, std::ios::binary);
223 if (inFile.good()) {
224 EDMLOGI("NearlinkConfigUtils::LoadConfig inFile.good");
225 inFile.seekg(0, std::ios::end);
226 size_t size = inFile.tellg();
227 if (size == 0) {
228 inFile.close();
229 CJSON_CREATE_OBJECT_AND_CHECK(root_, false);
230 return true;
231 }
232 inFile.seekg(0, std::ios::beg);
233 std::string jsonStr(size, ' ');
234 inFile.read(&jsonStr[0], size);
235 inFile.close();
236 root_ = cJSON_Parse(jsonStr.c_str());
237 return root_ != nullptr;
238 }
239 EDMLOGI("NearlinkConfigUtils::LoadConfig inFile fail");
240 inFile.close();
241 CJSON_CREATE_OBJECT_AND_CHECK(root_, false);
242 return true;
243 }
244
SaveConfig()245 bool NearlinkConfigUtils::SaveConfig()
246 {
247 EDMLOGI("NearlinkConfigUtils::saveConfig");
248 if (!root_) {
249 return false;
250 }
251 char *jsonStr = cJSON_Print(root_);
252 if (!jsonStr) {
253 return false;
254 }
255 std::ofstream file(CONFIG_PATH);
256 if (!file.is_open()) {
257 cJSON_free(jsonStr);
258 return false;
259 }
260 file << jsonStr;
261 file.close();
262 cJSON_free(jsonStr);
263 return true;
264 }
265
CheckProtocolDenyListExists()266 bool NearlinkConfigUtils::CheckProtocolDenyListExists()
267 {
268 if (!root_) {
269 CJSON_CREATE_OBJECT_AND_CHECK(root_, false);
270 }
271 cJSON *denyList = cJSON_GetObjectItem(root_, PROTOCOL_DENY_LIST);
272 if (!denyList) {
273 cJSON *protocolDenyList = nullptr;
274 CJSON_CREATE_OBJECT_AND_CHECK(protocolDenyList, false);
275 if (!cJSON_AddItemToObject(root_, PROTOCOL_DENY_LIST, protocolDenyList)) {
276 EDMLOGE("NearlinkConfigUtils::cJSON_AddItemToObject Root Error");
277 cJSON_Delete(protocolDenyList);
278 return false;
279 }
280 }
281 return true;
282 }
283 } // namespace EDM
284 } // namespace OHOS