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