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
20namespace OHOS {
21namespace UDMF {
22static std::bitset<MAX_BIT_SIZE> g_ruleIntention;
23static std::bitset<MAX_BIT_SIZE> g_ruleBundleName;
24static std::bitset<MAX_BIT_SIZE> g_ruleGroupId;
25static constexpr const char *UNIFIED_KEY_SCHEMA = "udmf://";
26static constexpr const char *ALPHA_AGGREGATE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
27static constexpr const char *DIGIT_AGGREGATE = "0123456789";
28static constexpr const char *SYMBOL_AGGREGATE = ":;<=>?@[\\]_`";
29UnifiedKey::UnifiedKey(std::string key)
30{
31    this->key = std::move(key);
32}
33
34UnifiedKey::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
41std::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
54bool 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
109bool 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
127void 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