1 /*
2  * Copyright (c) 2023 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 #define LOG_TAG "UtdClient"
16 #include <regex>
17 #include <thread>
18 #include "utd_client.h"
19 #include "logger.h"
20 #include "utd_graph.h"
21 #include "custom_utd_store.h"
22 #include "accesstoken_kit.h"
23 #include "ipc_skeleton.h"
24 #include "os_account_manager.h"
25 namespace OHOS {
26 namespace UDMF {
27 constexpr const int MAX_UTD_LENGTH = 256;
28 
UtdClient()29 UtdClient::UtdClient()
30 {
31     if (!Init()) {
32         LOG_WARN(UDMF_CLIENT, "construct UtdClient failed, try again.");
33         auto updateTask = []() {
34             std::this_thread::sleep_for(std::chrono::seconds(3));
35             UtdClient::GetInstance().Init();
36         };
37         std::thread(updateTask).detach();
38     }
39     LOG_INFO(UDMF_CLIENT, "construct UtdClient sucess.");
40 }
41 
~UtdClient()42 UtdClient::~UtdClient()
43 {
44 }
45 
GetInstance()46 UtdClient &UtdClient::GetInstance()
47 {
48     static auto instance = new UtdClient();
49     return *instance;
50 }
51 
Init()52 bool UtdClient::Init()
53 {
54     bool result = true;
55     std::unique_lock<std::shared_mutex> lock(utdMutex_);
56     descriptorCfgs_ = PresetTypeDescriptors::GetInstance().GetPresetTypes();
57     std::vector<TypeDescriptorCfg> customTypes;
58     if (IsHapTokenType()) {
59         customTypes = CustomUtdStore::GetInstance().GetHapTypeCfgs();
60     } else {
61         int32_t userId = DEFAULT_USER_ID;
62         if (GetCurrentActiveUserId(userId) != Status::E_OK) {
63             result = false;
64         }
65         customTypes = CustomUtdStore::GetInstance().GetTypeCfgs(userId);
66     }
67     LOG_INFO(UDMF_CLIENT, "get customUtd, size:%{public}zu", customTypes.size());
68     if (!customTypes.empty()) {
69         descriptorCfgs_.insert(descriptorCfgs_.end(), customTypes.begin(), customTypes.end());
70     }
71     UtdGraph::GetInstance().InitUtdGraph(descriptorCfgs_);
72     return result;
73 }
74 
GetTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)75 Status UtdClient::GetTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
76 {
77     {
78         std::shared_lock<std::shared_mutex> guard(utdMutex_);
79         for (const auto &utdTypeCfg : descriptorCfgs_) {
80             if (utdTypeCfg.typeId == typeId) {
81                 descriptor = std::make_shared<TypeDescriptor>(utdTypeCfg);
82                 LOG_DEBUG(UDMF_CLIENT, "get descriptor success. %{public}s ", typeId.c_str());
83                 return Status::E_OK;
84             }
85         }
86     }
87     if (typeId.find(FLEXIBLE_TYPE_FLAG) != typeId.npos) {
88         LOG_DEBUG(UDMF_CLIENT, "get flexible descriptor. %{public}s ", typeId.c_str());
89         return GetFlexibleTypeDescriptor(typeId, descriptor);
90     }
91     return Status::E_OK;
92 }
93 
IsValidFileExtension(const std::string & fileExtension)94 bool UtdClient::IsValidFileExtension(const std::string &fileExtension)
95 {
96     if (fileExtension.empty()) {
97         return false;
98     }
99     if (fileExtension[0] != '.' || fileExtension.find("?") != fileExtension.npos ||
100         fileExtension.find(":") != fileExtension.npos || fileExtension.find("=") != fileExtension.npos ||
101         fileExtension.find("\\") != fileExtension.npos) {
102             return false;
103     }
104 
105     return true;
106 }
107 
IsValidMimeType(const std::string & mimeType)108 bool UtdClient::IsValidMimeType(const std::string &mimeType)
109 {
110     if (mimeType.empty()) {
111         return false;
112     }
113     if (mimeType.find("?") != mimeType.npos || mimeType.find(":") != mimeType.npos ||
114         mimeType.find("=") != mimeType.npos ||mimeType.find("\\") != mimeType.npos) {
115             return false;
116     }
117     return true;
118 }
119 
GetFlexibleTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)120 Status UtdClient::GetFlexibleTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
121 {
122     TypeDescriptorCfg flexibleTypeDescriptorCfg;
123     if (!FlexibleType::ParseFlexibleUtd(typeId, flexibleTypeDescriptorCfg)) {
124         LOG_ERROR(UDMF_CLIENT, "ParseFlexibleUtd failed, invalid typeId: %{public}s", typeId.c_str());
125         return Status::E_ERROR;
126     }
127     descriptor = std::make_shared<TypeDescriptor>(flexibleTypeDescriptorCfg);
128     return Status::E_OK;
129 }
130 
GetUniformDataTypeByFilenameExtension(const std::string & fileExtension,std::string & typeId,std::string belongsTo)131 Status UtdClient::GetUniformDataTypeByFilenameExtension(const std::string &fileExtension, std::string &typeId,
132                                                         std::string belongsTo)
133 {
134     std::string lowerFileExtension = fileExtension;
135     std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
136     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
137         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. fileExtension:%{public}s, belongsTo:%{public}s ",
138                   fileExtension.c_str(), belongsTo.c_str());
139         return Status::E_INVALID_PARAMETERS;
140     }
141     {
142         std::shared_lock<std::shared_mutex> guard(utdMutex_);
143         bool found = false;
144         for (const auto &utdTypeCfg : descriptorCfgs_) {
145             for (auto fileEx : utdTypeCfg.filenameExtensions) {
146                 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
147                 if (fileEx == lowerFileExtension) {
148                     typeId = utdTypeCfg.typeId;
149                     found = true;
150                     break;
151                 }
152             }
153             if (found) {
154                 break;
155             }
156         }
157     }
158     // the find typeId is not belongsTo to the belongsTo.
159     if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
160         !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
161         typeId = "";
162     }
163 
164     if (typeId.empty()) {
165         if (!IsValidFileExtension(lowerFileExtension)) {
166             LOG_ERROR(UDMF_CLIENT, "invalid fileExtension. fileExtension:%{public}s, belongsTo:%{public}s ",
167                       fileExtension.c_str(), belongsTo.c_str());
168             return Status::E_INVALID_PARAMETERS;
169         }
170         typeId = FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo);
171     }
172     return Status::E_OK;
173 }
174 
GetUniformDataTypesByFilenameExtension(const std::string & fileExtension,std::vector<std::string> & typeIds,const std::string & belongsTo)175 Status UtdClient::GetUniformDataTypesByFilenameExtension(const std::string &fileExtension,
176     std::vector<std::string> &typeIds, const std::string &belongsTo)
177 {
178     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
179         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. fileExtension:%{public}s, belongsTo:%{public}s ",
180             fileExtension.c_str(), belongsTo.c_str());
181         return Status::E_INVALID_PARAMETERS;
182     }
183     if (!IsValidFileExtension(fileExtension)) {
184         LOG_ERROR(UDMF_CLIENT, "invalid fileExtension. fileExtension:%{public}s, belongsTo:%{public}s ",
185             fileExtension.c_str(), belongsTo.c_str());
186         return Status::E_INVALID_PARAMETERS;
187     }
188 
189     std::string lowerFileExtension = fileExtension;
190     std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
191     std::vector<std::string> typeIdsInCfg;
192     {
193         std::shared_lock<std::shared_mutex> guard(utdMutex_);
194         for (const auto &utdTypeCfg : descriptorCfgs_) {
195             for (auto fileEx : utdTypeCfg.filenameExtensions) {
196                 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
197                 if (fileEx == lowerFileExtension) {
198                     typeIdsInCfg.push_back(utdTypeCfg.typeId);
199                     break;
200                 }
201             }
202         }
203     }
204     typeIds.clear();
205     for (const auto &typeId : typeIdsInCfg) {
206         // the find typeId is not belongsTo to the belongsTo.
207         if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
208             !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
209             continue;
210         }
211         typeIds.emplace_back(typeId);
212     }
213     if (typeIds.empty()) {
214         typeIds.emplace_back(FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo));
215     }
216     return Status::E_OK;
217 }
218 
GetUniformDataTypeByMIMEType(const std::string & mimeType,std::string & typeId,std::string belongsTo)219 Status UtdClient::GetUniformDataTypeByMIMEType(const std::string &mimeType, std::string &typeId,
220                                                std::string belongsTo)
221 {
222     std::string lowerMimeType = mimeType;
223     std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
224     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
225         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. mimeType:%{public}s, belongsTo:%{public}s ",
226                   mimeType.c_str(), belongsTo.c_str());
227         return Status::E_INVALID_PARAMETERS;
228     }
229     typeId = GetTypeIdFromCfg(lowerMimeType);
230     // the find typeId is not belongsTo to the belongsTo.
231     if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
232         !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
233         typeId = "";
234     }
235     if (typeId.empty()) {
236         if (!IsValidMimeType(mimeType)) {
237             LOG_ERROR(UDMF_CLIENT, "invalid mimeType. mimeType:%{public}s, belongsTo:%{public}s ",
238                       mimeType.c_str(), belongsTo.c_str());
239             return Status::E_INVALID_PARAMETERS;
240         }
241         typeId = FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo);
242     }
243     return Status::E_OK;
244 }
245 
GetTypeIdFromCfg(const std::string & mimeType)246 std::string UtdClient::GetTypeIdFromCfg(const std::string &mimeType)
247 {
248     std::shared_lock<std::shared_mutex> guard(utdMutex_);
249     for (const auto &utdTypeCfg : descriptorCfgs_) {
250         for (auto mime : utdTypeCfg.mimeTypes) {
251             std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
252             if (mime == mimeType) {
253                 return utdTypeCfg.typeId;
254             }
255         }
256     }
257     if (mimeType.empty() || mimeType.back() != '*') {
258         return "";
259     }
260     std::string prefixType = mimeType.substr(0, mimeType.length() - 1);
261     for (const auto &utdTypeCfg : descriptorCfgs_) {
262         for (auto mime : utdTypeCfg.mimeTypes) {
263             std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
264             if (mime.rfind(prefixType, 0) == 0 && utdTypeCfg.belongingToTypes.size() > 0) {
265                 return utdTypeCfg.belongingToTypes[0];
266             }
267         }
268     }
269     return "";
270 }
271 
GetUniformDataTypesByMIMEType(const std::string & mimeType,std::vector<std::string> & typeIds,const std::string & belongsTo)272 Status UtdClient::GetUniformDataTypesByMIMEType(const std::string &mimeType, std::vector<std::string> &typeIds,
273     const std::string &belongsTo)
274 {
275     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
276         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. mimeType:%{public}s, belongsTo:%{public}s ",
277             mimeType.c_str(), belongsTo.c_str());
278         return Status::E_INVALID_PARAMETERS;
279     }
280     if (!IsValidMimeType(mimeType)) {
281         LOG_ERROR(UDMF_CLIENT, "invalid mimeType. mimeType:%{public}s, belongsTo:%{public}s ",
282             mimeType.c_str(), belongsTo.c_str());
283         return Status::E_INVALID_PARAMETERS;
284     }
285 
286     std::string lowerMimeType = mimeType;
287     std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
288     std::vector<std::string> typeIdsInCfg = GetTypeIdsFromCfg(lowerMimeType);
289     typeIds.clear();
290     for (const auto &typeId : typeIdsInCfg) {
291         // the find typeId is not belongsTo to the belongsTo.
292         if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
293             !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
294             continue;
295         }
296         typeIds.emplace_back(typeId);
297     }
298     if (typeIds.empty()) {
299         typeIds.emplace_back(FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo));
300     }
301     return Status::E_OK;
302 }
303 
GetTypeIdsFromCfg(const std::string & mimeType)304 std::vector<std::string> UtdClient::GetTypeIdsFromCfg(const std::string &mimeType)
305 {
306     bool prefixMatch = false;
307     std::string prefixType;
308     if (!mimeType.empty() && mimeType.back() == '*') {
309         prefixType = mimeType.substr(0, mimeType.length() - 1);
310         prefixMatch = true;
311     }
312     std::vector<std::string> typeIdsInCfg;
313 
314     std::shared_lock<std::shared_mutex> guard(utdMutex_);
315     for (const auto &utdTypeCfg : descriptorCfgs_) {
316         for (auto mime : utdTypeCfg.mimeTypes) {
317             std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
318             if ((mime == mimeType) || (prefixMatch && mime.rfind(prefixType, 0) == 0)) {
319                 typeIdsInCfg.push_back(utdTypeCfg.typeId);
320                 break;
321             }
322         }
323     }
324     return typeIdsInCfg;
325 }
326 
IsUtd(std::string typeId,bool & result)327 Status UtdClient::IsUtd(std::string typeId, bool &result)
328 {
329     try {
330         if (typeId.empty() || typeId.size() > MAX_UTD_LENGTH) {
331             result = false;
332             return Status::E_INVALID_PARAMETERS;
333         }
334         if (typeId[0] == '.' || find(typeId.begin(), typeId.end(), '/') != typeId.end()) {
335             result = false;
336             return Status::E_OK;
337         }
338         constexpr const char *preSetTypeIdRegexRule =
339             R"(^(general\.|openharmony\.|org\.|com\.|macos\.|debian\.|redhat\.|io\.|de\.|net\.)[a-z0-9-\.]+(\-[a-z0-9-]+)*$)";
340         if (std::regex_match(typeId, std::regex(preSetTypeIdRegexRule))) {
341             result = true;
342             return Status::E_OK;
343         }
344         constexpr const char *customUtdRegexRule = R"(^([A-Za-z]\w*)(\.\w+)+(\.[A-Za-z\d-]+)+)";
345         if (std::regex_match(typeId, std::regex(customUtdRegexRule))) {
346             result = true;
347             return Status::E_OK;
348         }
349         result = false;
350     } catch (...) {
351         LOG_ERROR(UDMF_CLIENT, "exception, typeId:%{public}s", typeId.c_str());
352         result = false;
353         return Status::E_ERROR;
354     }
355     LOG_ERROR(UDMF_CLIENT, "is not utd, typeId:%{public}s", typeId.c_str());
356     return Status::E_OK;
357 }
358 
IsHapTokenType()359 bool UtdClient::IsHapTokenType()
360 {
361     uint32_t tokenId = IPCSkeleton::GetSelfTokenID();
362     auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
363     LOG_DEBUG(UDMF_CLIENT, "GetTokenTypeFlag, tokenType = %{public}d.", tokenType);
364     if (tokenType == Security::AccessToken::TypeATokenTypeEnum::TOKEN_HAP) {
365         return true;
366     }
367     return false;
368 }
369 
GetCurrentActiveUserId(int32_t & userId)370 Status UtdClient::GetCurrentActiveUserId(int32_t& userId)
371 {
372     std::vector<int32_t> localIds;
373     int32_t status = OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(localIds);
374     if (status != Status::E_OK || localIds.empty()) {
375         LOG_ERROR(UDMF_CLIENT, "Get OsAccountId fail, status:%{public}d", status);
376         return Status::E_ERROR;
377     }
378     userId = localIds[0];
379     return Status::E_OK;
380 }
381 
InstallCustomUtds(const std::string & bundleName,const std::string & jsonStr,int32_t user)382 void UtdClient::InstallCustomUtds(const std::string &bundleName, const std::string &jsonStr, int32_t user)
383 {
384     if (IsHapTokenType()) {
385         return;
386     }
387     LOG_INFO(UDMF_CLIENT, "start, bundleName:%{public}s, user:%{public}d", bundleName.c_str(), user);
388     std::vector<TypeDescriptorCfg> customTyepCfgs = CustomUtdStore::GetInstance().GetTypeCfgs(user);
389     if (!CustomUtdStore::GetInstance().UninstallCustomUtds(bundleName, user, customTyepCfgs)) {
390         LOG_ERROR(UDMF_CLIENT, "custom utd installed failed. bundleName:%{public}s, user:%{public}d",
391             bundleName.c_str(), user);
392         return;
393     }
394     UpdateGraph(customTyepCfgs);
395     if (!jsonStr.empty()) {
396         if (!CustomUtdStore::GetInstance().InstallCustomUtds(bundleName, jsonStr, user, customTyepCfgs)) {
397             LOG_ERROR(UDMF_CLIENT, "no custom utd installed. bundleName:%{public}s, user:%{public}d",
398                 bundleName.c_str(), user);
399             return;
400         }
401         UpdateGraph(customTyepCfgs);
402     }
403 }
404 
UninstallCustomUtds(const std::string & bundleName,int32_t user)405 void UtdClient::UninstallCustomUtds(const std::string &bundleName, int32_t user)
406 {
407     if (IsHapTokenType()) {
408         return;
409     }
410     LOG_INFO(UDMF_CLIENT, "start, bundleName:%{public}s, user:%{public}d", bundleName.c_str(), user);
411     std::vector<TypeDescriptorCfg> customTyepCfgs = CustomUtdStore::GetInstance().GetTypeCfgs(user);
412     if (!CustomUtdStore::GetInstance().UninstallCustomUtds(bundleName, user, customTyepCfgs)) {
413         LOG_ERROR(UDMF_CLIENT, "custom utd installed failed. bundleName:%{public}s, user:%{public}d",
414             bundleName.c_str(), user);
415         return;
416     }
417     UpdateGraph(customTyepCfgs);
418 }
419 
UpdateGraph(const std::vector<TypeDescriptorCfg> & customTyepCfgs)420 void UtdClient::UpdateGraph(const std::vector<TypeDescriptorCfg> &customTyepCfgs)
421 {
422     std::vector<TypeDescriptorCfg> allTypeCfgs = PresetTypeDescriptors::GetInstance().GetPresetTypes();
423     allTypeCfgs.insert(allTypeCfgs.end(), customTyepCfgs.begin(), customTyepCfgs.end());
424     LOG_INFO(UDMF_CLIENT, "customTyepSize:%{public}zu, allTypeSize:%{public}zu",
425         customTyepCfgs.size(), allTypeCfgs.size());
426     auto graph = UtdGraph::GetInstance().ConstructNewGraph(allTypeCfgs);
427     std::unique_lock<std::shared_mutex> lock(utdMutex_);
428     UtdGraph::GetInstance().Update(std::move(graph));
429     descriptorCfgs_ = allTypeCfgs;
430 }
431 } // namespace UDMF
432 } // namespace OHOS
433