• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * @file Describe the file
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import { isEmptyStr, isUninterrupted } from '@ohos/common/src/main/ets/utils/TextUtils';
18import { getQueries } from '@ohos/common/src/main/ets/utils/UrlUtils';
19import { Log } from "@ohos/common/src/main/ets/utils/Log";
20
21const KEY_RANGE_BEGIN = 'begin';
22
23const KEY_RANGE_END = 'end';
24
25const KEY_SEARCH_TEXT = 'searchText';
26
27const KEY_ORDER_BY_ASC = 'orderByAsc';
28
29const KEY_ORDER_BY_DESC = 'orderByDesc';
30
31const TAG = 'InstancesQueryParams';
32
33// max length (16 chinese) of search text, The excess part will be discarded.
34const MAX_SEARCH_LENGTH = 32;
35
36/**
37 * the class contains Instances query Params
38 *
39 * @since 2022-09-02
40 */
41export class InstancesQueryParams {
42  begin?: number
43  end?: number
44  searchText?: string
45  orderByAsc?: string
46  orderByDesc?: string
47
48  constructor() {
49  }
50
51  /**
52   * judge is valid begin&end params:
53   * 1.has valid begin&end value
54   * 2.begin&end >0
55   * 3.begin<end
56   *
57   * @param begin the begin params
58   * @param end the end params
59   */
60  public isValidBeginEnd(): boolean {
61    const begin = this.getBegin();
62    const end = this.getEnd();
63    if (begin === null || begin === undefined) {
64      return false;
65    }
66    if (end === null || end === undefined) {
67      return false;
68    }
69    return end >= 0 && end >= 0 && begin < end;
70  }
71
72  public getBegin(): number {
73    return this.begin as number;
74  }
75
76  public setBegin(begin: number): void {
77    this.begin = begin;
78  }
79
80  public getEnd(): number {
81    return this.end as number;
82  }
83
84  public setEnd(end: number): void {
85    this.end = end;
86  }
87
88  public getSearchText(): string {
89    return this.searchText as string;
90  }
91
92  public setSearchText(searchText: string): void {
93    this.searchText = searchText;
94  }
95
96  public getOrderByAsc(): string {
97    return this.orderByAsc as string;
98  }
99
100  public setOrderByAsc(orderByAsc: string): void {
101    this.orderByAsc = orderByAsc;
102  }
103
104  public getOrderByDesc(): string {
105    return this.orderByDesc as string;
106  }
107
108  public setOrderByDesc(orderByDesc: string): void {
109    this.orderByDesc = orderByDesc;
110  }
111}
112
113/**
114 * judge is valid params or not:
115 * 1.invalid object -> false
116 * 2.valid searchText -> true
117 * 3.valid begin and end -> true
118 * 4.or else -> false
119 *
120 * @param params object of InstancesQueryParams
121 */
122export function isValidQueryParams(params: InstancesQueryParams): boolean {
123  if (params === null || params === undefined) {
124    return false;
125  }
126  const isValidSearchText = !isEmptyStr(params.getSearchText());
127  if (isValidSearchText) {
128    return true;
129  }
130  return params.isValidBeginEnd();
131}
132
133/**
134 * parse all params from uri
135 *
136 * @param uri uri from caller
137 * @return result of InstancesQueryParams after parsed
138 */
139export function parseParamsFromUri(uri: string): InstancesQueryParams | undefined {
140  const queryMap = getQueries(uri);
141  if (queryMap === null || queryMap === undefined || queryMap.size <= 0) {
142    Log.warn(TAG, 'parseBeginEndFromUri get invalid queryMap');
143    return undefined;
144  }
145  const paramsResult = new InstancesQueryParams();
146
147  parseBeginEndFromQueryMap(queryMap, paramsResult);
148
149  parseSearchTextFromQueryMap(queryMap, paramsResult);
150
151  parseOrderByFromQueryMap(queryMap, paramsResult);
152
153  return paramsResult;
154}
155
156/**
157 * try parse begin and end params from queryMap
158 *
159 * @param queryMap params map parsed from uri
160 * @param params the object to save parse result
161 */
162function parseBeginEndFromQueryMap(queryMap: Map<string, string>, params: InstancesQueryParams): void {
163  const beginStr = queryMap.get(KEY_RANGE_BEGIN) as string;
164  const endStr = queryMap.get(KEY_RANGE_END) as string;
165  if (isEmptyStr(beginStr) || isEmptyStr(endStr)) {
166    Log.warn(TAG, 'parseBeginEndFromUri get invalid begin end str');
167    return;
168  }
169  try {
170    const beginTime = Number.parseInt(beginStr);
171    const endTime = Number.parseInt(endStr);
172    Log.debug(TAG, `parseBeginEndFromUri ${beginTime}/${endTime}`);
173    params.setBegin(beginTime);
174    params.setEnd(endTime);
175  } catch (err) {
176    Log.error(TAG, `parseBeginEndFromUri get err ${err}`);
177  }
178}
179
180/**
181 * try parse search params from queryMap
182 *
183 * @param queryMap params map parsed from uri
184 * @param params the object to save parse result
185 */
186function parseSearchTextFromQueryMap(queryMap: Map<string, string>, params: InstancesQueryParams): void {
187  let searchText = queryMap.get(KEY_SEARCH_TEXT) as string;
188  if (isEmptyStr(searchText)) {
189    return;
190  }
191
192  // decode for chinese search
193  searchText = decodeURI(searchText);
194  if (isEmptyStr(searchText)) {
195    Log.warn(TAG, `the searchText is empty after decode`);
196    return;
197  }
198  const originalText = searchText;
199
200  // Crop the character string to the maximum length supported by the query.
201  if (searchText.length > MAX_SEARCH_LENGTH) {
202    searchText = searchText.substring(0, MAX_SEARCH_LENGTH);
203  }
204
205  // Replace characters to prevent SQL injection.
206  searchText = getSecuritySearchText(searchText);
207
208  params.setSearchText(searchText);
209
210  if (originalText != searchText) {
211    Log.info(TAG, `the searchText is converted from ${originalText} to ${searchText}`);
212  }
213}
214
215/**
216 * To prevent SQL injection, replace sql's separator characters to double characters.
217 * And you need to add the ' symbol before and after searchText when splicing SQL statements.
218 *
219 * @param searchText search text before replace
220 */
221function getSecuritySearchText(searchText: string): string {
222  /*
223   * Separator characters of sql:
224   * MySQL -> `
225   * MS-SQL -> ]
226   * PostgreSQL -> "
227   * String separator -> '
228   */
229  return searchText.replace(RegExp("/(?<matchedText>[\`\]\"\'])/gm"), '$<matchedText>$<matchedText>');
230}
231
232/**
233 * try parse orderBy params from queryMap
234 *
235 * @param queryMap params map parsed from uri
236 * @param params the object to save parse result
237 */
238function parseOrderByFromQueryMap(queryMap: Map<string, string>, params: InstancesQueryParams): void {
239  const orderByAsc = queryMap.get(KEY_ORDER_BY_ASC) as string;
240  if (isUninterrupted(orderByAsc)) {
241    params.setOrderByAsc(orderByAsc);
242  }
243  const orderByDesc = queryMap.get(KEY_ORDER_BY_DESC) as string;
244  if (isUninterrupted(orderByDesc)) {
245    params.setOrderByDesc(orderByDesc);
246  }
247}