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