1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BusinessError } from '@ohos.base'; 17import Want from '@ohos.app.ability.Want'; 18import fileUri from '@ohos.file.fileuri'; 19import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'; 20import fs from '@ohos.file.fs'; 21import dlpPermission from '@ohos.dlpPermission'; 22import IdlDlpRpcServiceStub from './data/IIdlDlpRpcServiceTs/id_dlpRpc_service_stub'; 23import { 24 closeDlpFileCallback, 25 sandBoxLinkFileCallback, 26 fileOpenHistoryCallback, 27 linkSetCallback, 28 genDlpFileCallback, 29 openDlpFileCallback, 30 recoverDlpFileCallback, 31 replaceDlpLinkFileCallback, 32 resumeFuseLinkCallback, 33 stopFuseLinkCallback 34} from './data/IIdlDlpRpcServiceTs/i_id_dlpRpc_service'; 35import IDLDLPProperty from '../common/dlpClass'; 36import { IAuthUser } from '../common/dlpClass'; 37import Constants from '../common/constant'; 38import { HiLog } from '../common/HiLog'; 39import FileUtil from '../common/external/FileUtil'; 40import { DecryptState, OpenDlpFileManager } from '../OpenDlpFile/manager/OpenDlpFileManager'; 41import DecryptContent from '../OpenDlpFile/data/DecryptContent'; 42import FileUtils from '../common/FileUtils/FileUtils'; 43 44const TAG = 'DlpRpcServiceStub'; 45 46class DlpRpcServiceStub extends IdlDlpRpcServiceStub { 47 private dlpFileMap: Map<string, dlpPermission.DLPFile | null> = new Map<string, dlpPermission.DLPFile | null>(); 48 private inFile: fs.File | undefined = undefined; 49 private outFile: fs.File | undefined = undefined; 50 51 constructor(des: string) { 52 super(des); 53 } 54 55 async getOpeningFile(inputUri: string): Promise<dlpPermission.DLPFile | null> { 56 const manager = OpenDlpFileManager.getInstance(); 57 const getRet = manager.getHasDecryptedContent(inputUri); 58 if (getRet.errcode === Constants.ERR_CODE_SUCCESS && getRet.result) { 59 const decryptContent = getRet.result; 60 return decryptContent.dlpFile; 61 } 62 63 if (this.dlpFileMap.has(inputUri)) { 64 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(inputUri) as dlpPermission.DLPFile; 65 return dlpFile; 66 } 67 return null; 68 } 69 70 async genDlpFile(inputUri: string, outputUri: string, dlp: IDLDLPProperty, callback: genDlpFileCallback 71 ): Promise<void> { 72 HiLog.info(TAG, 'genDlpFile in service'); 73 let result: Record<string, number>; 74 try { 75 result = await this.genDlpFileFd(inputUri, outputUri); 76 } catch (error) { 77 callback(error); 78 return; 79 } 80 let dlpP: dlpPermission.DLPProperty = { 81 'ownerAccount': dlp.ownerAccount, 82 'ownerAccountID': dlp.ownerAccountID, 83 'ownerAccountType': dlp.ownerAccountType, 84 'authUserList': dlp.authUserList, 85 'contactAccount': dlp.contactAccount, 86 'offlineAccess': dlp.offlineAccess, 87 'everyoneAccessList': dlp.everyoneAccessList, 88 'expireTime': dlp.expireTime 89 } 90 try { 91 let dlpFile = await dlpPermission.generateDLPFile(result.inFileFd, result.outFileFd, dlpP); 92 if (!this.dlpFileMap.has(outputUri)) { 93 this.dlpFileMap.set(outputUri, dlpFile); 94 this.addEncryptingState(outputUri); 95 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 96 } else { 97 let rawDlpFile = this.dlpFileMap.get(outputUri) ?? null; 98 if (rawDlpFile !== null) { 99 try { 100 await rawDlpFile.closeDLPFile(); 101 } catch (err) { 102 HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`); 103 } 104 } 105 this.dlpFileMap.delete(outputUri); 106 this.dlpFileMap.set(outputUri, dlpFile); 107 this.addEncryptingState(outputUri); 108 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 109 } 110 callback(0); 111 } catch (err) { 112 HiLog.error(TAG, `genDlpFile file: ${JSON.stringify(err)}`); 113 await this.closeFile(); 114 callback((err as BusinessError).code); 115 } 116 } 117 118 async closeFile(): Promise<void> { 119 FileUtil.closeSync(this.inFile); 120 FileUtil.closeSync(this.outFile); 121 } 122 123 async genDlpFileFd(inputUri: string, outputUri: string): Promise<Record<string, number>> { 124 return new Promise(async (resolve, reject) => { 125 let inFileFd: number = -1; 126 let outFileFd: number = -1; 127 try { 128 this.inFile = await fs.open(inputUri, fs.OpenMode.READ_WRITE); 129 inFileFd = this.inFile.fd; 130 } catch (error) { 131 HiLog.error(TAG, `open: ${FileUtils.getFileNameByUri(inputUri)}, failed: ${JSON.stringify(error)}`); 132 reject((error as BusinessError).code); 133 return; 134 } 135 let uriInfo: fileUri.FileUri = new fileUri.FileUri(''); 136 try { 137 uriInfo = new fileUri.FileUri(outputUri); 138 } catch (err) { 139 HiLog.error(TAG, `fileUri fail: ${JSON.stringify(err)}`); 140 } 141 try { 142 this.outFile = await fs.open(outputUri, fs.OpenMode.READ_WRITE); 143 outFileFd = this.outFile.fd; 144 } catch (error) { 145 FileUtil.closeSync(this.inFile); 146 FileUtil.unlinkSync(uriInfo.path); 147 reject((error as BusinessError).code); 148 return; 149 } 150 let result = { 151 'inFileFd': inFileFd, 152 'outFileFd': outFileFd 153 } as Record<string, number>; 154 resolve(result); 155 }) 156 } 157 158 async openDlpFile(srcUri: string, callerAppId: string, callback: openDlpFileCallback): Promise<void> { 159 HiLog.info(TAG, `openDlpFile start: ${FileUtils.getFileNameByUri(srcUri)}`); 160 let inFile = await fs.open(srcUri, fs.OpenMode.READ_WRITE); 161 let dlpFile: dlpPermission.DLPFile; 162 let authUserListNew: IAuthUser[] = []; 163 try { 164 dlpFile = await dlpPermission.openDLPFile(inFile.fd, callerAppId); 165 dlpFile.dlpProperty.authUserList?.forEach(item => { 166 authUserListNew.push( 167 new IAuthUser( 168 item.authAccount, 169 item.authAccountType, 170 item.dlpFileAccess, 171 item.permExpiryTime 172 )) 173 }) 174 let _dlp = new IDLDLPProperty( 175 dlpFile.dlpProperty.ownerAccount, 176 dlpFile.dlpProperty.ownerAccountID, 177 dlpFile.dlpProperty.ownerAccountType, 178 authUserListNew, 179 dlpFile.dlpProperty.contactAccount, 180 dlpFile.dlpProperty.offlineAccess, 181 dlpFile.dlpProperty.everyoneAccessList ?? [], 182 dlpFile.dlpProperty.expireTime ?? 0, 183 ); 184 callback(0, _dlp, ''); 185 if (!this.dlpFileMap.has(srcUri)) { 186 this.dlpFileMap.set(srcUri, dlpFile); 187 this.addEncryptingState(srcUri); 188 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 189 } else { 190 HiLog.info(TAG, `map is overwrite`); 191 this.dlpFileMap.delete(srcUri); 192 this.dlpFileMap.set(srcUri, dlpFile); 193 this.addEncryptingState(srcUri); 194 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 195 } 196 } catch (err) { 197 let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0); 198 callback((err as BusinessError).code, _dlp, (err as BusinessError).message); 199 } finally { 200 FileUtil.closeSync(inFile); 201 } 202 } 203 204 async stopFuseLink(uri: string, callback: stopFuseLinkCallback): Promise<void> { 205 HiLog.info(TAG, `stopFuseLink start filename: ${FileUtils.getFileNameByUri(uri)}`); 206 let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(uri); 207 if (dlpFile !== null) { 208 await dlpFile.stopFuseLink(); 209 } else { 210 HiLog.error(TAG, `stopFuseLink not find filename: ${FileUtils.getFileNameByUri(uri)}`); 211 callback(-1); 212 } 213 } 214 215 async resumeFuseLink(uri: string, callback: resumeFuseLinkCallback): Promise<void> { 216 HiLog.info(TAG, `resumeFuseLink start`); 217 let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(uri); 218 if (dlpFile !== null) { 219 await dlpFile.resumeFuseLink(); 220 } else { 221 HiLog.error(TAG, `resumeFuseLink not findfilename: ${FileUtils.getFileNameByUri(uri)}`); 222 callback(-1); 223 } 224 } 225 226 async replaceDlpLinkFile(srcUri: string, linkFileName: string, callback: replaceDlpLinkFileCallback): Promise<void> { 227 if (this.dlpFileMap.has(srcUri)) { 228 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(srcUri) as dlpPermission.DLPFile; 229 const manager = OpenDlpFileManager.getInstance(); 230 const getRet = manager.getHasDecryptedContentByLinkFileName(linkFileName); 231 if (getRet.errcode === Constants.ERR_CODE_SUCCESS && getRet.result) { 232 const decryptContent = getRet.result; 233 decryptContent.dlpFile = dlpFile; 234 } 235 236 try { 237 await dlpFile.replaceDLPLinkFile(linkFileName); 238 } catch (error) { 239 HiLog.wrapError(TAG, error, 'replaceDLPLinkFile error'); 240 } 241 } else { 242 HiLog.error(TAG, `replaceDLPLinkFile not find: ${FileUtils.getFileNameByUri(srcUri)}`); 243 callback(-1); 244 } 245 } 246 247 async recoverDlpFile(srcUri: string, pathUri: string, callback: recoverDlpFileCallback): Promise<void> { 248 let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(srcUri); 249 if (dlpFile !== null) { 250 let inFile: fs.File | undefined; 251 try { 252 inFile = await fs.open(pathUri, fs.OpenMode.READ_WRITE); 253 await dlpFile.recoverDLPFile(inFile.fd); 254 } catch (err) { 255 HiLog.error(TAG, `recoverDlpFileInner4: ${JSON.stringify(err)}`); 256 callback((err as BusinessError).code); 257 } finally { 258 FileUtil.closeSync(inFile); 259 } 260 } else { 261 HiLog.error(TAG, `recoverDlpFile not find: ${FileUtils.getFileNameByUri(srcUri)}`); 262 callback(-1); 263 } 264 } 265 266 async closeDlpFile(srcUri: string, callback: closeDlpFileCallback): Promise<void> { 267 HiLog.info(TAG, `closeDlpFile start`); 268 let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(srcUri); 269 if (dlpFile !== null) { 270 try { 271 await dlpFile.closeDLPFile(); 272 if (this.dlpFileMap.has(srcUri)) { 273 this.dlpFileMap.delete(srcUri); 274 this.deleteEncryptingState(srcUri); 275 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 276 } 277 callback(0); 278 } catch (err) { 279 HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`); 280 callback((err as BusinessError).code); 281 } 282 } 283 } 284 285 async sandBoxLinkFile(linkFileName: string, callerToken: number, callback: sandBoxLinkFileCallback): Promise<void> { 286 let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0); 287 const manager = OpenDlpFileManager.getInstance(); 288 const getRet = manager.getHasDecryptedContentByLinkFileName(linkFileName); 289 if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) { 290 HiLog.error(TAG, `request from sandbox, but can not find dlp file by linkFileName: ${linkFileName}`); 291 callback(-1, _dlp, ''); 292 return; 293 } 294 const decryptContent: DecryptContent = getRet.result; 295 if (decryptContent.appInfo.tokenID !== callerToken) { 296 HiLog.error(TAG, `found file, but token invalid: ${linkFileName}`); 297 callback(-1, _dlp, ''); 298 return; 299 } 300 301 let authUserListNew: IAuthUser[] = []; 302 const dlpFile = decryptContent.dlpFile; 303 dlpFile.dlpProperty.authUserList?.forEach(item => { 304 authUserListNew.push( 305 new IAuthUser( 306 item.authAccount, 307 item.authAccountType, 308 item.dlpFileAccess, 309 item.permExpiryTime 310 )) 311 }) 312 313 _dlp = new IDLDLPProperty( 314 dlpFile.dlpProperty.ownerAccount, 315 dlpFile.dlpProperty.ownerAccountID, 316 dlpFile.dlpProperty.ownerAccountType, 317 authUserListNew, 318 dlpFile.dlpProperty.contactAccount, 319 dlpFile.dlpProperty.offlineAccess, 320 dlpFile.dlpProperty.everyoneAccessList ?? [], 321 dlpFile.dlpProperty.expireTime ?? 0 322 ); 323 let fileUri = decryptContent.openDlpFileData.uri; 324 callback(0, _dlp, fileUri.toString()); 325 } 326 327 async fileOpenHistory(uri: string, callback: fileOpenHistoryCallback): Promise<void> { 328 HiLog.info(TAG, 'fileOpenHistory start'); 329 const manager = OpenDlpFileManager.getInstance(); 330 const getRet = manager.getHasDecryptedContent(uri); 331 if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) { 332 callback(-1); 333 } else { 334 callback(0); 335 } 336 } 337 338 async linkSet(uri: string, callback: linkSetCallback): Promise<void> { 339 HiLog.info(TAG, 'linkSet start'); 340 const manager = OpenDlpFileManager.getInstance(); 341 const getRet = manager.getHasDecryptedContent(uri); 342 if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) { 343 callback(-1); 344 } else { 345 callback(0); 346 } 347 } 348 349 private async addEncryptingState(uri: string): Promise<void> { 350 const manager = OpenDlpFileManager.getInstance(); 351 const setRet = await manager.setStatus(uri, { state: DecryptState.ENCRYPTING }); 352 if (setRet.errcode !== Constants.ERR_CODE_SUCCESS) { 353 HiLog.error(TAG, `addEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} failed.`); 354 } else { 355 HiLog.info(TAG, `addEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} success.`); 356 } 357 } 358 359 private async deleteEncryptingState(uri: string): Promise<void> { 360 const manager = OpenDlpFileManager.getInstance(); 361 const deleteRet = await manager.deleteStatus(uri); 362 if (deleteRet.errcode !== Constants.ERR_CODE_SUCCESS) { 363 HiLog.error(TAG, `deleteEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} failed.`); 364 } else { 365 HiLog.info(TAG, `deleteEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} success.`); 366 } 367 } 368} 369 370export default class DlpFileProcessAbility extends ServiceExtensionAbility { 371 onCreate(want: Want) { 372 HiLog.info(TAG, `onCreate, want: ${want.abilityName}`); 373 } 374 375 onRequest(want: Want, startId: number) { 376 HiLog.info(TAG, `onRequest, want: ${want.abilityName}`); 377 } 378 379 onConnect(want: Want) { 380 HiLog.info(TAG, `service onConnect, want: ${want.abilityName}`); 381 return new DlpRpcServiceStub('dlpRpc service stub'); 382 } 383 384 onDisconnect(want: Want): void { 385 HiLog.info(TAG, `onDisconnect, want: ${want.abilityName}`); 386 } 387 388 onDestroy(): void { 389 HiLog.info(TAG, 'onDestroy'); 390 } 391}