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()