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