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