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  #include "check_common.h"
16  
17  #include <algorithm>
18  #include <climits>
19  
20  #include "doc_errno.h"
21  #include "grd_base/grd_db_api.h"
22  #include "rd_log_print.h"
23  #include "securec.h"
24  
25  using namespace DocumentDB;
26  namespace DocumentDB {
27  namespace {
28  constexpr const char *KEY_ID = "_id";
29  constexpr const char *COLLECTION_PREFIX_GRD = "GRD_";
30  constexpr const char *COLLECTION_PREFIX_GM_SYS = "GM_SYS";
31  const int MAX_COLLECTION_NAME = 512;
32  const int MAX_ID_LENS = 900;
33  const int JSON_DEEP_MAX = 4;
34  
CheckCollectionNamePrefix(const std::string & name,const std::string & prefix)35  bool CheckCollectionNamePrefix(const std::string &name, const std::string &prefix)
36  {
37      if (name.length() < prefix.length()) {
38          return false;
39      }
40  
41      return (strncasecmp(name.c_str(), prefix.c_str(), prefix.length()) == 0);
42  }
43  
ReplaceAll(std::string & inout,const std::string & what,const std::string & with)44  void ReplaceAll(std::string &inout, const std::string &what, const std::string &with)
45  {
46      std::string::size_type pos{};
47      while ((pos = inout.find(what.data(), pos, what.length())) != std::string::npos) {
48          inout.replace(pos, what.length(), with.data(), with.length());
49          pos += with.length();
50      }
51  }
52  } // namespace
53  
CheckCollectionName(const std::string & collectionName,std::string & formattedName,int & errCode)54  bool CheckCommon::CheckCollectionName(const std::string &collectionName, std::string &formattedName, int &errCode)
55  {
56      if (collectionName.empty()) {
57          errCode = -E_INVALID_ARGS;
58          return false;
59      }
60      if (collectionName.length() + 1 > MAX_COLLECTION_NAME) { // with '\0'
61          errCode = -E_OVER_LIMIT;
62          return false;
63      }
64      if (CheckCollectionNamePrefix(collectionName, COLLECTION_PREFIX_GRD) ||
65          CheckCollectionNamePrefix(collectionName, COLLECTION_PREFIX_GM_SYS)) {
66          GLOGE("Collection name is illegal");
67          errCode = -E_INVALID_COLL_NAME_FORMAT;
68          return false;
69      }
70  
71      formattedName = collectionName;
72      std::transform(formattedName.begin(), formattedName.end(), formattedName.begin(), [](unsigned char c) {
73          return std::tolower(c);
74      });
75  
76      ReplaceAll(formattedName, "'", R"('')");
77      return true;
78  }
79  
CheckSingleFilterPath(std::vector<std::string> & singleFilterPath)80  static int CheckSingleFilterPath(std::vector<std::string> &singleFilterPath)
81  {
82      if (singleFilterPath.empty()) {
83          return -E_INVALID_JSON_FORMAT;
84      }
85      for (size_t j = 0; j < singleFilterPath.size(); j++) {
86          if (singleFilterPath[j].empty()) {
87              return -E_INVALID_ARGS;
88          }
89          for (auto oneChar : singleFilterPath[j]) {
90              if (!((isalpha(oneChar)) || (isdigit(oneChar)) || (oneChar == '_'))) {
91                  return -E_INVALID_ARGS;
92              }
93          }
94      }
95      if (!singleFilterPath.empty() && !singleFilterPath[0].empty() && isdigit(singleFilterPath[0][0])) {
96          return -E_INVALID_ARGS;
97      }
98      return E_OK;
99  }
100  
CheckFilter(JsonObject & filterObj,std::vector<std::vector<std::string>> & filterPath,bool & isIdExist)101  int CheckCommon::CheckFilter(JsonObject &filterObj, std::vector<std::vector<std::string>> &filterPath, bool &isIdExist)
102  {
103      for (size_t i = 0; i < filterPath.size(); i++) {
104          if (filterPath[i].size() > JSON_DEEP_MAX) {
105              GLOGE("filter's json deep is deeper than JSON_DEEP_MAX");
106              return -E_INVALID_ARGS;
107          }
108      }
109      int ret = E_OK;
110      for (size_t i = 0; i < filterPath.size(); i++) {
111          ret = CheckSingleFilterPath(filterPath[i]);
112          if (ret != E_OK) {
113              return ret;
114          }
115      }
116      ret = CheckIdFormat(filterObj, isIdExist);
117      if (ret != E_OK) {
118          GLOGE("Filter Id format is illegal");
119          return ret;
120      }
121      return ret;
122  }
123  
CheckIdFormat(JsonObject & idObj,bool & isIdExisit)124  int CheckCommon::CheckIdFormat(JsonObject &idObj, bool &isIdExisit)
125  {
126      JsonObject idObjChild = idObj.GetChild();
127      ValueObject idValue = JsonCommon::GetValueInSameLevel(idObjChild, KEY_ID, isIdExisit);
128      if ((idValue.GetValueType() == ValueObject::ValueType::VALUE_NULL) && isIdExisit == false) {
129          return E_OK;
130      }
131      if (idValue.GetValueType() != ValueObject::ValueType::VALUE_STRING) {
132          return -E_INVALID_ARGS;
133      }
134      if (idValue.GetStringValue().length() + 1 > MAX_ID_LENS) { // with '\0'
135          return -E_OVER_LIMIT;
136      }
137      return E_OK;
138  }
139  
CheckDocument(JsonObject & documentObj,bool & isIdExist)140  int CheckCommon::CheckDocument(JsonObject &documentObj, bool &isIdExist)
141  {
142      if (documentObj.GetDeep() > JSON_DEEP_MAX) {
143          GLOGE("documentObj's json deep is deeper than JSON_DEEP_MAX");
144          return -E_INVALID_ARGS;
145      }
146      int ret = CheckIdFormat(documentObj, isIdExist);
147      if (ret != E_OK) {
148          return ret;
149      }
150      JsonObject documentObjChild = documentObj.GetChild();
151      if (!JsonCommon::CheckJsonField(documentObjChild)) {
152          GLOGE("Document json field format is illegal");
153          return -E_INVALID_ARGS;
154      }
155      return E_OK;
156  }
157  
SplitFieldName(const std::string & fieldName,std::vector<std::string> & allFieldsName)158  int SplitFieldName(const std::string &fieldName, std::vector<std::string> &allFieldsName)
159  {
160      std::string tempParseName;
161      std::string priFieldName = fieldName;
162      for (size_t j = 0; j < priFieldName.size(); j++) {
163          if (priFieldName[j] != '.') {
164              tempParseName += priFieldName[j];
165          }
166          if (priFieldName[j] == '.' || j == priFieldName.size() - 1) {
167              if ((j > 0 && priFieldName[j] == '.' && priFieldName[j - 1] == '.') ||
168                  (priFieldName[j] == '.' && j == priFieldName.size() - 1)) {
169                  return -E_INVALID_ARGS;
170              }
171              allFieldsName.emplace_back(tempParseName);
172              tempParseName.clear();
173          }
174      }
175      return E_OK;
176  }
177  
CheckSingleUpdataDocPath(std::vector<std::string> & singleUpdataPath)178  static int CheckSingleUpdataDocPath(std::vector<std::string> &singleUpdataPath)
179  {
180      for (const auto &fieldName : singleUpdataPath) {
181          for (auto oneChar : fieldName) {
182              if (!((isalpha(oneChar)) || (isdigit(oneChar)) || (oneChar == '_'))) {
183                  GLOGE("updata fieldName is illegal");
184                  return -E_INVALID_ARGS;
185              }
186          }
187      }
188      return E_OK;
189  }
190  
CheckUpdata(JsonObject & updataObj)191  int CheckCommon::CheckUpdata(JsonObject &updataObj)
192  {
193      JsonObject jsonTemp = updataObj.GetChild();
194      size_t maxDeep = 0;
195      while (!jsonTemp.IsNull()) {
196          std::vector<std::string> allFieldsName;
197          int errCode = SplitFieldName(jsonTemp.GetItemField(), allFieldsName);
198          if (errCode != E_OK) {
199              return errCode;
200          }
201          errCode = CheckSingleUpdataDocPath(allFieldsName);
202          if (errCode != E_OK) {
203              return errCode;
204          }
205          maxDeep = std::max(allFieldsName.size() + jsonTemp.GetDeep(), maxDeep);
206          if (maxDeep > JSON_DEEP_MAX) {
207              GLOGE("document's json deep is deeper than JSON_DEEP_MAX");
208              return -E_INVALID_ARGS;
209          }
210          jsonTemp = jsonTemp.GetNext();
211      }
212      bool isIdExist = true;
213      CheckIdFormat(updataObj, isIdExist);
214      if (isIdExist) {
215          return -E_INVALID_ARGS;
216      }
217      return E_OK;
218  }
219  
CheckSingleProjectionDocPath(std::vector<std::string> & singleProjectionPath)220  static int CheckSingleProjectionDocPath(std::vector<std::string> &singleProjectionPath)
221  {
222      for (const auto &fieldName : singleProjectionPath) {
223          if (fieldName.empty()) {
224              return -E_INVALID_ARGS;
225          }
226          for (size_t j = 0; j < fieldName.size(); j++) {
227              if (!((isalpha(fieldName[j])) || (isdigit(fieldName[j])) || (fieldName[j] == '_'))) {
228                  return -E_INVALID_ARGS;
229              }
230              if (j == 0 && (isdigit(fieldName[j]))) {
231                  return -E_INVALID_ARGS;
232              }
233          }
234      }
235      return E_OK;
236  }
237  
CheckProjection(JsonObject & projectionObj,std::vector<std::vector<std::string>> & path)238  int CheckCommon::CheckProjection(JsonObject &projectionObj, std::vector<std::vector<std::string>> &path)
239  {
240      if (projectionObj.GetDeep() > JSON_DEEP_MAX) {
241          GLOGE("projectionObj's json deep is deeper than JSON_DEEP_MAX");
242          return -E_INVALID_ARGS;
243      }
244      int errCode = E_OK;
245      if (!projectionObj.GetChild().IsNull()) {
246          JsonObject projectionObjChild = projectionObj.GetChild();
247          if (!JsonCommon::CheckProjectionField(projectionObjChild, errCode)) {
248              GLOGE("projection json field format is illegal");
249              return errCode;
250          }
251      }
252      for (size_t i = 0; i < path.size(); i++) {
253          if (path[i].empty()) {
254              return -E_INVALID_JSON_FORMAT;
255          }
256          errCode = CheckSingleProjectionDocPath(path[i]);
257          if (errCode != E_OK) {
258              return errCode;
259          }
260      }
261      return E_OK;
262  }
263  } // namespace DocumentDB