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" 25namespace OHOS { 26namespace UDMF { 27constexpr const int MAX_UTD_LENGTH = 256; 28 29UtdClient::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 42UtdClient::~UtdClient() 43{ 44} 45 46UtdClient &UtdClient::GetInstance() 47{ 48 static auto instance = new UtdClient(); 49 return *instance; 50} 51 52bool 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 75Status 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 94bool 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 108bool 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 120Status 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 131Status 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 175Status 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 219Status 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 246std::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 272Status 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 304std::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 327Status 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 359bool 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 370Status 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 382void 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 405void 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 420void 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