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