• 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 privacyManager, { Permissions } from '@ohos.privacyManager';
18import { Log } from '@ohos/common/src/main/ets/utils/Log';
19import { hasNoError } from '@ohos/common/src/main/ets/utils/ErrorUtils';
20import {
21  BundleNameAndTokenIdFromUri,
22  getBundleNameAndTokenIDByUri
23} from '@ohos/common/src/main/ets/utils/UrlUtils';
24
25import { ErrorCode } from '@ohos/datamanager/src/main/ets/constants/ErrorCode';
26import delegate from './DataShareAbilityDelegate'
27import data_rdb from '@ohos.data.relationalStore';
28import dataSharePredicates from '@ohos.data.dataSharePredicates';
29import { BusinessError } from '@ohos.base';
30
31const TAG = "DataShareAbilityAuthenticateProxy";
32
33const INSERT_BY_PROXY_OPERATION_NAME: string = 'insert';
34const UPDATE_BY_PROXY_OPERATION_NAME: string = 'update';
35const DELETE_BY_PROXY_OPERATION_NAME: string = 'delete';
36const QUERY_BY_PROXY_OPERATION_NAME: string = 'query';
37
38const PERMISSIONS_FLAG_HIGH: number = 2;
39const PERMISSIONS_FLAG_LOW: number = 1;
40const PERMISSIONS_FLAG_UNAUTHORIZED: number = -1;
41
42const PERMISSIONS_WRITE_WHOLE_CALENDAR: Permissions = "ohos.permission.WRITE_WHOLE_CALENDAR"
43const PERMISSIONS_WRITE_CALENDAR: Permissions = "ohos.permission.WRITE_CALENDAR"
44const PERMISSIONS_READ_WHOLE_CALENDAR: Permissions = "ohos.permission.READ_WHOLE_CALENDAR"
45const PERMISSIONS_READ_CALENDAR: Permissions = "ohos.permission.READ_CALENDAR"
46
47const SUCCESS_COUNT: number = 1;
48const FAIL_COUNT: number = 1;
49
50/**
51 * the proxy of CalendarData's DataShareAbilityDelegate, identify the high and low permissions of the app
52 *
53 * @since 2022-10-17
54 */
55class DataShareAbilityAuthenticateProxy {
56  async init(): Promise<boolean> {
57    Log.log(TAG, 'init start');
58    let isDatabaseInitComplete = await delegate.init();
59    Log.log(TAG, 'init end');
60    return isDatabaseInitComplete;
61  }
62
63  async insertByProxy(uri: string, value: data_rdb.ValuesBucket, permission: Permissions, callback: Function) {
64    let insertDataParameter = new InsertDataParameter(value);
65    insertDataParameter.operationName = INSERT_BY_PROXY_OPERATION_NAME;
66    let verifyFlag = await verifyByUri(uri, insertDataParameter, PERMISSIONS_WRITE_WHOLE_CALENDAR,
67      PERMISSIONS_WRITE_CALENDAR, permission, callback);
68    dataOperateAfterVerify(uri, verifyFlag, insertDataParameter);
69  }
70
71  async deleteByProxy(uri: string, predicates: dataSharePredicates.DataSharePredicates, permission: Permissions, callback: Function) {
72    let deleteDataParameter = new DeleteDataParameter(predicates);
73    deleteDataParameter.operationName = DELETE_BY_PROXY_OPERATION_NAME;
74    let verifyFlag = await verifyByUri(uri, deleteDataParameter, PERMISSIONS_WRITE_WHOLE_CALENDAR,
75      PERMISSIONS_WRITE_CALENDAR, permission, callback);
76    dataOperateAfterVerify(uri, verifyFlag, deleteDataParameter);
77  }
78
79  async updateByProxy(uri: string, value: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, permission: Permissions, callback: Function) {
80    let updateDataParameter = new UpdateDataParameter(value, predicates);
81    updateDataParameter.operationName = UPDATE_BY_PROXY_OPERATION_NAME;
82    let verifyFlag = await verifyByUri(uri, updateDataParameter, PERMISSIONS_WRITE_WHOLE_CALENDAR,
83      PERMISSIONS_WRITE_CALENDAR, permission, callback);
84    dataOperateAfterVerify(uri, verifyFlag, updateDataParameter);
85  }
86
87  async queryByProxy(uri: string, columns: Array<string>, predicates: dataSharePredicates.DataSharePredicates, permission: Permissions, callback: Function) {
88    let queryDataParameter = new QueryDataParameter(columns, predicates);
89    queryDataParameter.operationName = QUERY_BY_PROXY_OPERATION_NAME;
90    let verifyFlag = await verifyByUri(uri, queryDataParameter, PERMISSIONS_READ_WHOLE_CALENDAR,
91      PERMISSIONS_READ_CALENDAR, permission, callback);
92    dataOperateAfterVerify(uri, verifyFlag, queryDataParameter);
93  }
94}
95
96/**
97 * Verify corresponding to permissions
98 *
99 * @Param uri indicates user's input uri
100 * @Param dataParameter indicates database operation information to be performed
101 * @Param highPermission indicates high-level permission to be verified
102 * @Param lowPermission indicates low-level permission to be verified
103 */
104async function verifyByUri(uri: string, dataParameter: DataParameter, highPermission: Permissions,
105                           lowPermission: Permissions, permission: Permissions, callback: Function): Promise<number> {
106  let bundleNameAndTokenIdFromUri: BundleNameAndTokenIdFromUri = getBundleNameAndTokenIDByUri(uri);
107
108  // Verify whether tokenId has HIGH-level to use database.
109  if (permission === PERMISSIONS_READ_WHOLE_CALENDAR || permission === PERMISSIONS_WRITE_WHOLE_CALENDAR) {
110    // Encapsulate the callback function of an object to add Permission Used Record
111    dataParameter.callback = (err: BusinessError, rowId: number) => {
112      callback(err, rowId);
113      addPermissionUsedRecordInCallBack(err, bundleNameAndTokenIdFromUri.tokenId, highPermission);
114    }
115    // return high-level
116    return PERMISSIONS_FLAG_HIGH;
117  }
118
119  // Verify whether tokenId has LOW-level to use database.
120  if (permission === PERMISSIONS_READ_CALENDAR || permission === PERMISSIONS_WRITE_CALENDAR) {
121    // Encapsulate the callback function of an object to add Permission Used Record
122    dataParameter.callback = (err: BusinessError, rowId: number) => {
123      callback(err, rowId);
124      addPermissionUsedRecordInCallBack(err, bundleNameAndTokenIdFromUri.tokenId, lowPermission);
125    }
126    // return low-level
127    return PERMISSIONS_FLAG_LOW;
128  }
129  return PERMISSIONS_FLAG_UNAUTHORIZED;
130}
131
132/**
133 * Perform database operations corresponding to permissions
134 *
135 * @Param uri indicates user's input uri
136 * @Param verifyFlag indicates the Check flag returned by permission check
137 * @Param dataParameter indicates database operation information to be performed
138 */
139function dataOperateAfterVerify(uri: string, verifyFlag: number, dataParameter: DataParameter) {
140  if (verifyFlag === PERMISSIONS_FLAG_HIGH) {
141    dataOperateSelectorByHighAuthority(uri, dataParameter);
142  } else if (verifyFlag === PERMISSIONS_FLAG_LOW) {
143    dataOperateSelectorByLowAuthority(uri, dataParameter);
144  } else {
145    // callback error with information
146    const err: BusinessError = {
147      code: ErrorCode.ILLEGAL_ARGUMENT_ERROR,
148      name: 'AuthenticateException',
149      message: 'Caller App does not have permission to read'
150    };
151    dataParameter.callback(err, PERMISSIONS_FLAG_UNAUTHORIZED);
152  }
153  return;
154}
155
156/**
157 * Perform database operations corresponding to permissions
158 *
159 * @param err Error object
160 * @Param tokenId
161 * @Param permission indicates permission to be verified
162 */
163function addPermissionUsedRecordInCallBack(err: BusinessError, tokenId: string, permission: Permissions) {
164  // add Permission Used Record
165  if (hasNoError(err)) {
166    try {
167      privacyManager.addPermissionUsedRecord(Number(tokenId), permission, SUCCESS_COUNT, 0)
168        .then(() => {
169          console.log('addPermissionUsedRecord success Permission is ' + permission);
170        })
171        .catch((err: BusinessError) => {
172          console.log(`addPermissionUsedRecord fail, err->${JSON.stringify(err)}`);
173        });
174    } catch (err) {
175      console.log(`catch err->${JSON.stringify(err)}`);
176    }
177  } else {
178    try {
179      privacyManager.addPermissionUsedRecord(Number(tokenId), permission, 0, FAIL_COUNT)
180        .then(() => {
181          console.log('addPermissionUsedRecord success Permission is ' + permission);
182        })
183        .catch((err: BusinessError) => {
184          console.log(`addPermissionUsedRecord fail, err->${JSON.stringify(err)}`);
185        });
186    } catch (err) {
187      console.log(`catch err->${JSON.stringify(err)}`);
188    }
189  }
190  return;
191}
192
193/**
194 * Perform database operations corresponding to high-level permissions
195 *
196 * @Param uri indicates user's input uri
197 * @Param dataParameter indicates database operation information to be performed
198 */
199async function dataOperateSelectorByHighAuthority(uri: string, dataParameter: DataParameter) {
200  let operationName = dataParameter.operationName;
201  let columns = dataParameter.columns;
202  let predicates = dataParameter.predicates;
203  let value = dataParameter.value;
204  let callback = dataParameter.callback;
205  switch (operationName) {
206    case INSERT_BY_PROXY_OPERATION_NAME:
207      delegate.insertByHighAuthority(uri, value, callback);
208      break;
209    case UPDATE_BY_PROXY_OPERATION_NAME:
210      delegate.updateByHighAuthority(uri, value, predicates, callback);
211      break;
212    case DELETE_BY_PROXY_OPERATION_NAME:
213      delegate.deleteByHighAuthority(uri, predicates, callback);
214      break;
215    case QUERY_BY_PROXY_OPERATION_NAME:
216      delegate.queryByHighAuthority(uri, columns, predicates, callback);
217      break;
218    default:
219      break;
220  }
221}
222
223/**
224 * Perform database operations corresponding to low-level permissions
225 *
226 * @Param uri indicates user's input uri
227 * @Param dataParameter indicates database operation information to be performed
228 */
229async function dataOperateSelectorByLowAuthority(uri: string, dataParameter: DataParameter) {
230  let operationName = dataParameter.operationName;
231  let columns = dataParameter.columns;
232  let predicates = dataParameter.predicates;
233  let value = dataParameter.value;
234  let callback = dataParameter.callback;
235  switch (operationName) {
236    case INSERT_BY_PROXY_OPERATION_NAME:
237      delegate.insertByLowAuthority(uri, value, callback);
238      break;
239    case UPDATE_BY_PROXY_OPERATION_NAME:
240      delegate.updateByLowAuthority(uri, value, predicates, callback);
241      break;
242    case DELETE_BY_PROXY_OPERATION_NAME:
243      delegate.deleteByLowAuthority(uri, predicates, callback);
244      break;
245    case QUERY_BY_PROXY_OPERATION_NAME:
246      delegate.queryByLowAuthority(uri, columns, predicates, callback);
247      break;
248    default:
249      break;
250  }
251}
252
253/**
254 * List of operation parameters for database operation
255 *
256 * @since 2022-12-28
257 */
258abstract class DataParameter {
259  operationName: string = '';
260
261  value: data_rdb.ValuesBucket = {} as data_rdb.ValuesBucket;
262
263  columns: Array<string> = [];
264
265  predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
266
267  callback: Function = (err: BusinessError, count: number) => {
268  };
269}
270
271/**
272 * List of operation parameters for insert operation
273 *
274 * @since 2022-12-28
275 */
276class InsertDataParameter extends DataParameter {
277  constructor(value: data_rdb.ValuesBucket) {
278    super();
279    this.value = value;
280  }
281}
282
283/**
284 * List of operation parameters for delete operation
285 *
286 * @since 2022-12-28
287 */
288class DeleteDataParameter extends DataParameter {
289  constructor(predicates: dataSharePredicates.DataSharePredicates) {
290    super();
291    this.predicates = predicates;
292  }
293}
294
295/**
296 * List of operation parameters for update operation
297 *
298 * @since 2022-12-28
299 */
300class UpdateDataParameter extends DataParameter {
301  constructor(value: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates) {
302    super();
303    this.value = value;
304    this.predicates = predicates;
305  }
306}
307
308/**
309 * List of operation parameters for query operation
310 *
311 * @since 2022-10-28
312 */
313class QueryDataParameter extends DataParameter {
314  constructor(columns: Array<string>, predicates: dataSharePredicates.DataSharePredicates) {
315    super();
316    this.columns = columns;
317    this.predicates = predicates;
318  }
319}
320
321export default new DataShareAbilityAuthenticateProxy()