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