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 "UnifiedKey"
16 #include <sstream>
17 #include "unified_key.h"
18
19 #include "logger.h"
20
21 namespace OHOS {
22 namespace UDMF {
23 static std::bitset<MAX_BIT_SIZE> g_ruleIntention;
24 static std::bitset<MAX_BIT_SIZE> g_ruleBundleName;
25 static std::bitset<MAX_BIT_SIZE> g_ruleGroupId;
26 static constexpr const char *UNIFIED_KEY_SCHEMA = "udmf://";
27 static constexpr const char *ALPHA_AGGREGATE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
28 static constexpr const char *DIGIT_AGGREGATE = "0123456789";
29 static constexpr const char *SYMBOL_AGGREGATE = ":;<=>?@[\\]_`";
30 static constexpr const char SEPARATOR = '/';
31 static constexpr uint32_t PREFIX_LEN = 24;
32 static constexpr uint32_t SUFIX_LEN = 8;
33 static constexpr uint32_t INDEX_LEN = 32;
UnifiedKey(std::string key)34 UnifiedKey::UnifiedKey(std::string key)
35 {
36 this->key = std::move(key);
37 }
38
UnifiedKey(std::string intention,std::string bundle,std::string groupId)39 UnifiedKey::UnifiedKey(std::string intention, std::string bundle, std::string groupId)
40 {
41 this->intention = std::move(intention);
42 this->bundleName = std::move(bundle);
43 this->groupId = std::move(groupId);
44 }
45
GetUnifiedKey()46 std::string UnifiedKey::GetUnifiedKey()
47 {
48 if (!this->key.empty()) {
49 return this->key;
50 }
51 if (this->intention.empty() || this->groupId.empty()) {
52 return "";
53 }
54 // Uri-compliant structure, example: udmf://drag/com.ohos.test/012345679abc
55 std::ostringstream oss;
56 oss << UNIFIED_KEY_SCHEMA << this->intention << SEPARATOR <<
57 this->bundleName << SEPARATOR << this->groupId;
58 this->key = oss.str();
59 return this->key;
60 }
61
GetPropertyKey() const62 std::string UnifiedKey::GetPropertyKey() const
63 {
64 if (this->key.size() > INDEX_LEN) {
65 return this->key.substr(0, key.size() - SUFIX_LEN);
66 }
67 if (this->intention.empty() || this->groupId.size() < INDEX_LEN) {
68 LOG_ERROR(UDMF_FRAMEWORK, "Empty property key.intention:%{public}s, groupId:%{public}s",
69 intention.c_str(), groupId.c_str());
70 return "";
71 }
72 std::ostringstream oss;
73 oss << UNIFIED_KEY_SCHEMA << this->intention << SEPARATOR <<
74 this->bundleName << SEPARATOR << this->groupId.substr(0, PREFIX_LEN);
75 return oss.str();
76 }
77
IsValid()78 bool UnifiedKey::IsValid()
79 {
80 if (this->key.empty()) {
81 LOG_DEBUG(UDMF_FRAMEWORK, "empty key");
82 return false;
83 }
84 PreliminaryWork();
85
86 std::string data = this->key; // schema/intention/groupId
87 std::string separator = "://";
88 size_t pos = data.find(separator);
89 if (pos == std::string::npos) {
90 return false;
91 }
92 std::string schema = data.substr(0, pos + separator.size()); // schema
93 if (UNIFIED_KEY_SCHEMA != schema) {
94 LOG_DEBUG(UDMF_FRAMEWORK, "wrong schema");
95 return false;
96 }
97
98 data = data.substr(pos + separator.size()); // intention/bundleName/groupId
99 pos = data.find('/'); // intention
100 if (pos == std::string::npos) {
101 return false;
102 }
103 std::string intentionTmp = data.substr(0, pos);
104 if (!CheckCharacter(intentionTmp, g_ruleIntention)) {
105 return false;
106 }
107 this->intention = intentionTmp;
108
109 data = data.substr(pos + 1);
110 pos = data.find('/'); // bundleName
111 if (pos == std::string::npos) {
112 return false;
113 }
114 std::string bundle = data.substr(0, pos);
115 if (!CheckCharacter(bundle, g_ruleBundleName)) {
116 LOG_DEBUG(UDMF_FRAMEWORK, "wrong bundle");
117 return false;
118 }
119 this->bundleName = bundle;
120
121 data = data.substr(pos + 1); // groupId
122 if (data.empty()) {
123 return false;
124 }
125 if (!CheckCharacter(data, g_ruleGroupId)) {
126 LOG_DEBUG(UDMF_FRAMEWORK, "wrong groupId");
127 return false;
128 }
129 this->groupId = data;
130 return true;
131 }
132
CheckCharacter(std::string data,std::bitset<MAX_BIT_SIZE> rule)133 bool UnifiedKey::CheckCharacter(std::string data, std::bitset<MAX_BIT_SIZE> rule)
134 {
135 if (data.empty()) {
136 LOG_DEBUG(UDMF_FRAMEWORK, "empty key");
137 return false;
138 }
139 size_t dataLen = data.size();
140 for (size_t i = 0; i < dataLen; ++i) {
141 if (static_cast<int>(data[i]) >= 0 && static_cast<int>(data[i]) < 128) { // 128:ASCII Max Number
142 bool isLegal = rule.test(data[i]);
143 if (!isLegal) {
144 return false;
145 }
146 }
147 }
148 return true;
149 }
150
PreliminaryWork()151 void UnifiedKey::PreliminaryWork()
152 {
153 // All intentions are composed of uppercase and lowercase letters and underscores.
154 if (g_ruleIntention.none()) {
155 std::string intentionTmp = std::string(ALPHA_AGGREGATE) + "_";
156 for (char i : intentionTmp) {
157 g_ruleIntention.set(i);
158 }
159 }
160 // All bundle name are composed of uppercase and lowercase letters and dots.
161 if (g_ruleBundleName.none()) {
162 std::string bundleAggregate = std::string(ALPHA_AGGREGATE) + DIGIT_AGGREGATE + "._";
163 for (char i : bundleAggregate) {
164 g_ruleBundleName.set(i);
165 }
166 }
167 // Characters of groupId are taken from Ascii codes 48 to 122.
168 if (g_ruleGroupId.none()) {
169 std::string idAggregate = std::string(DIGIT_AGGREGATE) + ALPHA_AGGREGATE + SYMBOL_AGGREGATE;
170 for (char i : idAggregate) {
171 g_ruleGroupId.set(i);
172 }
173 }
174 }
175 } // namespace UDMF
176 } // namespace OHOS