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}