1 /*
2  * Copyright (c) 2021-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 "white_list_util.h"
17 
18 #include <algorithm>
19 #include <cstring>
20 
21 #include "config_policy_utils.h"
22 
23 #include "dinput_errcode.h"
24 #include "dinput_log.h"
25 #include "dinput_utils_tool.h"
26 
27 namespace OHOS {
28 namespace DistributedHardware {
29 namespace DistributedInput {
30 namespace {
31     const char * const SPLIT_LINE = "|";
32     const char * const SPLIT_COMMA = ",";
33     const char * const WHITELIST_FILE_PATH = "etc/distributedhardware/dinput_business_event_whitelist.cfg";
34     const int32_t COMB_KEY_VEC_MIN_LEN = 2;
35     const int32_t LAST_KEY_ACTION_LEN = 1;
36     const int32_t LAST_KEY_LEN = 1;
37     const int32_t MAX_LINE_NUM = 100;
38     const int32_t MAX_CHAR_PER_LINE_NUM = 100;
39     const int32_t MAX_SPLIT_COMMA_NUM = 4;
40     const int32_t MAX_SPLIT_LINE_NUM = 12;
41     const int32_t MAX_KEY_CODE_NUM = 4;
42 }
43 
WhiteListUtil()44 WhiteListUtil::WhiteListUtil()
45 {
46     DHLOGI("Ctor WhiteListUtil.");
47     Init();
48 }
49 
~WhiteListUtil()50 WhiteListUtil::~WhiteListUtil()
51 {
52     DHLOGI("Dtor WhiteListUtil.");
53 }
54 
GetInstance(void)55 WhiteListUtil &WhiteListUtil::GetInstance(void)
56 {
57     static WhiteListUtil instance;
58     return instance;
59 }
60 
GetWhiteListCfgFile(std::ifstream & ifs)61 bool WhiteListUtil::GetWhiteListCfgFile(std::ifstream &ifs)
62 {
63     char buf[MAX_PATH_LEN] = {0};
64     char path[PATH_MAX + 1] = {0x00};
65     char *whiteListFilePath = GetOneCfgFile(WHITELIST_FILE_PATH, buf, MAX_PATH_LEN);
66     if (whiteListFilePath == nullptr) {
67         DHLOGE("whiteListFilePath is null.");
68         return false;
69     }
70 
71     if (strlen(whiteListFilePath) == 0 || strlen(whiteListFilePath) > PATH_MAX ||
72         realpath(whiteListFilePath, path) == nullptr) {
73         DHLOGE("File connicailization failed.");
74         return false;
75     }
76 
77     ifs.open(path, std::ios::in | std::ios::binary);
78     if (!ifs.is_open()) {
79         DHLOGE("WhiteListUtil Init error, file open fail path=%{public}s", path);
80         return false;
81     }
82     return true;
83 }
84 
Init()85 int32_t WhiteListUtil::Init()
86 {
87     std::ifstream ifs;
88     if (!GetWhiteListCfgFile(ifs)) {
89         return ERR_DH_INPUT_WHILTELIST_INIT_FAIL;
90     }
91 
92     TYPE_KEY_CODE_VEC vecKeyCode;
93     TYPE_COMBINATION_KEY_VEC vecCombinationKey;
94     TYPE_WHITE_LIST_VEC vecWhiteList;
95     std::string line;
96     std::size_t lineNum = 0;
97     while (getline(ifs, line)) {
98         if ((++lineNum > MAX_LINE_NUM) || !IsValidLine(line)) {
99             DHLOGE("whitelist cfg file has too many lines or too complicated. lineNum is %{public}zu", lineNum);
100             break;
101         }
102         vecKeyCode.clear();
103         vecCombinationKey.clear();
104         SplitCombinationKey(line, vecKeyCode, vecCombinationKey);
105 
106         if (CheckIsNumber(line)) {
107             int32_t keyCode = std::stoi(line);
108             if (keyCode != 0) {
109                 vecKeyCode.push_back(keyCode);
110             }
111             if (!vecKeyCode.empty()) {
112                 vecCombinationKey.push_back(vecKeyCode);
113                 vecKeyCode.clear();
114             }
115         }
116 
117         if (!vecCombinationKey.empty()) {
118             vecWhiteList.push_back(vecCombinationKey);
119             vecCombinationKey.clear();
120         }
121     }
122     ifs.close();
123     std::string localNetworkId = GetLocalDeviceInfo().networkId;
124     if (!localNetworkId.empty()) {
125         SyncWhiteList(localNetworkId, vecWhiteList);
126     }
127     return DH_SUCCESS;
128 }
129 
IsValidLine(const std::string & line) const130 bool WhiteListUtil::IsValidLine(const std::string &line) const
131 {
132     if (line.size() > MAX_CHAR_PER_LINE_NUM) {
133         DHLOGE("This line is too long, size is %{public}zu", line.size());
134         return false;
135     }
136     if (std::count(line.begin(), line.end(), SPLIT_COMMA[0]) > MAX_SPLIT_COMMA_NUM) {
137         DHLOGE("This line %{public}s has too many SPLIT_COMMA", line.c_str());
138         return false;
139     }
140     if (std::count(line.begin(), line.end(), SPLIT_LINE[0]) > MAX_SPLIT_LINE_NUM) {
141         DHLOGE("This line %{public}s has too many SPLIT_LINE", line.c_str());
142         return false;
143     }
144     return true;
145 }
146 
CheckIsNumber(const std::string & str) const147 bool WhiteListUtil::CheckIsNumber(const std::string &str) const
148 {
149     if (str.empty() || str.size() > MAX_KEY_CODE_NUM) {
150         DHLOGE("KeyCode size %{public}zu, is zero or too long.", str.size());
151         return false;
152     }
153     for (char const &c : str) {
154         if (std::isdigit(c) == 0) {
155             DHLOGE("Check KeyCode format fail, %{public}s.", str.c_str());
156             return false;
157         }
158     }
159     return true;
160 }
161 
ReadLineDataStepOne(std::string & column,TYPE_KEY_CODE_VEC & vecKeyCode,TYPE_COMBINATION_KEY_VEC & vecCombinationKey) const162 void WhiteListUtil::ReadLineDataStepOne(std::string &column, TYPE_KEY_CODE_VEC &vecKeyCode,
163     TYPE_COMBINATION_KEY_VEC &vecCombinationKey) const
164 {
165     std::size_t pos2 = column.find(SPLIT_LINE);
166     while (pos2 != std::string::npos) {
167         std::string single = column.substr(0, pos2);
168         column = column.substr(pos2 + 1, column.size());
169         pos2 = column.find(SPLIT_LINE);
170 
171         if (CheckIsNumber(single)) {
172             int32_t keyCode = std::stoi(single);
173             if (keyCode != 0) {
174                 vecKeyCode.push_back(keyCode);
175             }
176         }
177     }
178 
179     if (CheckIsNumber(column)) {
180         int32_t keyCode = std::stoi(column);
181         if (keyCode != 0) {
182             vecKeyCode.push_back(keyCode);
183         }
184     }
185 
186     if (!vecKeyCode.empty()) {
187         vecCombinationKey.push_back(vecKeyCode);
188         vecKeyCode.clear();
189     }
190 }
191 
SplitCombinationKey(std::string & line,TYPE_KEY_CODE_VEC & vecKeyCode,TYPE_COMBINATION_KEY_VEC & vecCombinationKey) const192 void WhiteListUtil::SplitCombinationKey(std::string &line, TYPE_KEY_CODE_VEC &vecKeyCode,
193     TYPE_COMBINATION_KEY_VEC &vecCombinationKey) const
194 {
195     std::size_t pos1 = line.find(SPLIT_COMMA);
196     while (pos1 != std::string::npos) {
197         std::string column = line.substr(0, pos1);
198         line = line.substr(pos1 + 1, line.size());
199         pos1 = line.find(SPLIT_COMMA);
200         vecKeyCode.clear();
201         ReadLineDataStepOne(column, vecKeyCode, vecCombinationKey);
202     }
203 }
204 
SyncWhiteList(const std::string & deviceId,const TYPE_WHITE_LIST_VEC & vecWhiteList)205 int32_t WhiteListUtil::SyncWhiteList(const std::string &deviceId, const TYPE_WHITE_LIST_VEC &vecWhiteList)
206 {
207     DHLOGI("deviceId=%{public}s", GetAnonyString(deviceId).c_str());
208 
209     std::lock_guard<std::mutex> lock(mutex_);
210     mapDeviceWhiteList_[deviceId] = vecWhiteList;
211     for (auto combKeys : vecWhiteList) {
212         GetCombKeysHash(combKeys, combKeysHashMap_[deviceId]);
213     }
214 
215     return DH_SUCCESS;
216 }
217 
GetCombKeysHash(TYPE_COMBINATION_KEY_VEC combKeys,std::unordered_set<std::string> & targetSet)218 void WhiteListUtil::GetCombKeysHash(TYPE_COMBINATION_KEY_VEC combKeys, std::unordered_set<std::string> &targetSet)
219 {
220     if (combKeys.size() < COMB_KEY_VEC_MIN_LEN) {
221         DHLOGE("white list item length invalid");
222         return;
223     }
224 
225     TYPE_KEY_CODE_VEC lastKeyAction = combKeys.back();
226     if (lastKeyAction.size() != LAST_KEY_ACTION_LEN) {
227         DHLOGE("last key action invalid");
228         return;
229     }
230     combKeys.pop_back();
231     TYPE_KEY_CODE_VEC lastKey = combKeys.back();
232     if (lastKey.size() != LAST_KEY_LEN) {
233         DHLOGE("last key invalid");
234         return;
235     }
236     combKeys.pop_back();
237 
238     std::unordered_set<std::string> hashSets;
239     WhiteListItemHash hash;
240     GetAllComb(combKeys, hash, combKeys.size(), hashSets);
241 
242     for (const auto &hashSet : hashSets) {
243         targetSet.insert(hashSet + std::to_string(lastKey[0]) + std::to_string(lastKeyAction[0]));
244     }
245 }
246 
GetAllComb(TYPE_COMBINATION_KEY_VEC vecs,WhiteListItemHash hash,int32_t targetLen,std::unordered_set<std::string> & hashSets)247 void WhiteListUtil::GetAllComb(TYPE_COMBINATION_KEY_VEC vecs, WhiteListItemHash hash,
248     int32_t targetLen, std::unordered_set<std::string> &hashSets)
249 {
250     for (size_t i = 0; i < vecs.size(); i++) {
251         TYPE_KEY_CODE_VEC nowVec = vecs[i];
252         for (int32_t code : nowVec) {
253             std::string hashStr = hash.hash + std::to_string(code);
254             WhiteListItemHash newHash(hashStr, hash.len + 1);
255             TYPE_COMBINATION_KEY_VEC leftVecs = vecs;
256             leftVecs.erase(leftVecs.begin() + i);
257             GetAllComb(leftVecs, newHash, targetLen, hashSets);
258         }
259     }
260 
261     if (hash.len == targetLen) {
262         hashSets.insert(hash.hash);
263     }
264 }
265 
ClearWhiteList(const std::string & deviceId)266 int32_t WhiteListUtil::ClearWhiteList(const std::string &deviceId)
267 {
268     DHLOGI("deviceId=%{public}s", GetAnonyString(deviceId).c_str());
269 
270     std::lock_guard<std::mutex> lock(mutex_);
271     mapDeviceWhiteList_.erase(deviceId);
272     return DH_SUCCESS;
273 }
274 
ClearWhiteList(void)275 int32_t WhiteListUtil::ClearWhiteList(void)
276 {
277     std::lock_guard<std::mutex> lock(mutex_);
278     TYPE_DEVICE_WHITE_LIST_MAP().swap(mapDeviceWhiteList_);
279     return DH_SUCCESS;
280 }
281 
GetWhiteList(const std::string & deviceId,TYPE_WHITE_LIST_VEC & vecWhiteList)282 int32_t WhiteListUtil::GetWhiteList(const std::string &deviceId, TYPE_WHITE_LIST_VEC &vecWhiteList)
283 {
284     DHLOGI("GetWhiteList start, deviceId=%{public}s", GetAnonyString(deviceId).c_str());
285 
286     std::lock_guard<std::mutex> lock(mutex_);
287     TYPE_DEVICE_WHITE_LIST_MAP::const_iterator iter = mapDeviceWhiteList_.find(deviceId);
288     if (iter != mapDeviceWhiteList_.end()) {
289         vecWhiteList = iter->second;
290         DHLOGI("GetWhiteList success, deviceId=%{public}s", GetAnonyString(deviceId).c_str());
291         return DH_SUCCESS;
292     }
293 
294     DHLOGI("GetWhiteList fail, deviceId=%{public}s", GetAnonyString(deviceId).c_str());
295     return ERR_DH_INPUT_WHILTELIST_GET_WHILTELIST_FAIL;
296 }
297 
GetBusinessEventHash(const BusinessEvent & event)298 std::string WhiteListUtil::GetBusinessEventHash(const BusinessEvent &event)
299 {
300     std::string hash = "";
301     for (const auto &p : event.pressedKeys) {
302         hash += std::to_string(p);
303     }
304     hash += std::to_string(event.keyCode);
305     hash += std::to_string(event.keyAction);
306 
307     return hash;
308 }
309 
IsNeedFilterOut(const std::string & deviceId,const BusinessEvent & event)310 bool WhiteListUtil::IsNeedFilterOut(const std::string &deviceId, const BusinessEvent &event)
311 {
312     DHLOGI("IsNeedFilterOut start, deviceId=%{public}s", GetAnonyString(deviceId).c_str());
313 
314     std::lock_guard<std::mutex> lock(mutex_);
315     if (combKeysHashMap_.empty()) {
316         DHLOGE("IsNeedFilterOut error, white list is empty!");
317         return false;
318     }
319 
320     auto iter = combKeysHashMap_.find(deviceId);
321     if (iter == combKeysHashMap_.end()) {
322         DHLOGE("IsNeedFilterOut error, not find by deviceId!");
323         return false;
324     }
325 
326     std::string hash = GetBusinessEventHash(event);
327     DHLOGI("Searched business event hash: %{public}s", hash.c_str());
328 
329     return combKeysHashMap_[deviceId].find(hash) != combKeysHashMap_[deviceId].end();
330 }
331 } // namespace DistributedInput
332 } // namespace DistributedHardware
333 } // namespace OHOS
334