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 GlobalContext from '../common/GlobalContext'; 38import Constants from '../common/constant'; 39import { HiLog } from '../common/HiLog'; 40import FileUtil from '../common/external/FileUtil'; 41 42const TAG = 'DlpRpcServiceStub'; 43 44class DlpRpcServiceStub extends IdlDlpRpcServiceStub { 45 private dlpFileMap: Map<string, dlpPermission.DLPFile | null> = new Map<string, dlpPermission.DLPFile | null>(); 46 private inFile: fs.File | undefined = undefined; 47 private outFile: fs.File | undefined = undefined; 48 49 constructor(des: string) { 50 super(des); 51 } 52 53 getOpeningFile(inputUri: string) : dlpPermission.DLPFile | null { 54 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 55 if (sandbox2linkFile !== undefined) { 56 for (let key of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 57 for (let j of key) { 58 if (j[4] === inputUri) { 59 let dlpFile: dlpPermission.DLPFile = j[0] as dlpPermission.DLPFile; 60 return dlpFile; 61 } 62 } 63 } 64 } 65 66 if (this.dlpFileMap.has(inputUri)) { 67 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(inputUri) as dlpPermission.DLPFile; 68 return dlpFile; 69 } 70 return null; 71 } 72 73 async genDlpFile(inputUri: string, outputUri: string, dlp: IDLDLPProperty, callback: genDlpFileCallback 74 ): Promise<void> { 75 HiLog.info(TAG, `genDlpFile in service`); 76 let result: Record<string, number>; 77 try { 78 result = await this.genDlpFileFd(inputUri, outputUri); 79 } catch (error) { 80 callback(error); 81 return; 82 } 83 let dlpP: dlpPermission.DLPProperty = { 84 'ownerAccount' : dlp.ownerAccount, 85 'ownerAccountID' : dlp.ownerAccountID, 86 'ownerAccountType' : dlp.ownerAccountType, 87 'authUserList' : dlp.authUserList, 88 'contactAccount' : dlp.contactAccount, 89 'offlineAccess' : dlp.offlineAccess, 90 'everyoneAccessList' : dlp.everyoneAccessList, 91 'expireTime': dlp.expireTime 92 } 93 try { 94 let dlpFile = await dlpPermission.generateDLPFile(result.inFileFd, result.outFileFd, dlpP); 95 if (!this.dlpFileMap.has(outputUri)) { 96 this.dlpFileMap.set(outputUri, dlpFile); 97 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 98 } else { 99 let rawDlpFile = this.dlpFileMap.get(outputUri) ?? null; 100 if (rawDlpFile !== null) { 101 try { 102 await rawDlpFile.closeDLPFile(); 103 } catch (err) { 104 HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`); 105 } 106 } 107 this.dlpFileMap.delete(outputUri); 108 this.dlpFileMap.set(outputUri, dlpFile); 109 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 110 } 111 callback(0); 112 } catch (err) { 113 HiLog.error(TAG, `genDlpFile file: ${JSON.stringify(err)}`); 114 await this.closeFile(); 115 callback((err as BusinessError).code); 116 } 117 } 118 119 async closeFile(): Promise<void> { 120 FileUtil.closeFileSync(this.inFile); 121 FileUtil.closeFileSync(this.outFile); 122 } 123 124 async genDlpFileFd(inputUri: string, outputUri: string): Promise<Record<string, number>> { 125 return new Promise(async (resolve, reject) => { 126 let inFileFd: number = -1; 127 let outFileFd: number = -1; 128 try { 129 this.inFile = await fs.open(inputUri, fs.OpenMode.READ_WRITE); 130 inFileFd = this.inFile.fd; 131 } catch (error) { 132 HiLog.error(TAG, `open: ${inputUri}, failed: ${JSON.stringify(error)}`); 133 reject((error as BusinessError).code); 134 return; 135 } 136 let uriInfo: fileUri.FileUri = new fileUri.FileUri(''); 137 try { 138 uriInfo = new fileUri.FileUri(outputUri); 139 } catch (err) { 140 HiLog.error(TAG, `fileUri fail: ${JSON.stringify(err)}`); 141 } 142 try { 143 this.outFile = await fs.open(outputUri, fs.OpenMode.READ_WRITE); 144 outFileFd = this.outFile.fd; 145 } catch (error) { 146 FileUtil.closeFileSync(this.inFile); 147 FileUtil.unlinkSync(uriInfo.path); 148 reject((error as BusinessError).code); 149 return; 150 } 151 let result = { 152 'inFileFd': inFileFd, 153 'outFileFd': outFileFd 154 } as Record<string, number>; 155 resolve(result); 156 }) 157 } 158 159 async openDlpFile(srcUri: string, callerAppId: string, callback: openDlpFileCallback): Promise<void> { 160 HiLog.info(TAG, `openDlpFile start: ${srcUri}`); 161 let inFile = await fs.open(srcUri, fs.OpenMode.READ_WRITE); 162 let dlpFile: dlpPermission.DLPFile; 163 let authUserListNew: IAuthUser[] = []; 164 try { 165 dlpFile = await dlpPermission.openDLPFile(inFile.fd, callerAppId); 166 dlpFile.dlpProperty.authUserList?.forEach(item => { 167 authUserListNew.push( 168 new IAuthUser( 169 item.authAccount, 170 item.authAccountType, 171 item.dlpFileAccess, 172 item.permExpiryTime 173 )) 174 }) 175 let _dlp = new IDLDLPProperty( 176 dlpFile.dlpProperty.ownerAccount, 177 dlpFile.dlpProperty.ownerAccountID, 178 dlpFile.dlpProperty.ownerAccountType, 179 authUserListNew, 180 dlpFile.dlpProperty.contactAccount, 181 dlpFile.dlpProperty.offlineAccess, 182 dlpFile.dlpProperty.everyoneAccessList ?? [], 183 dlpFile.dlpProperty.expireTime ?? 0, 184 ); 185 callback(0, _dlp, ''); 186 if (!this.dlpFileMap.has(srcUri)) { 187 this.dlpFileMap.set(srcUri, dlpFile); 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 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 194 } 195 } catch (err) { 196 let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0); 197 callback((err as BusinessError).code, _dlp, (err as BusinessError).message); 198 } finally { 199 FileUtil.closeFileSync(inFile); 200 } 201 } 202 203 async stopFuseLink(uri: string, callback: stopFuseLinkCallback): Promise<void> { 204 HiLog.info(TAG, `stopFuseLink start: ${uri}`); 205 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(uri); 206 if (dlpFile !== null) { 207 await dlpFile.stopFuseLink(); 208 } else { 209 HiLog.error(TAG, `stopFuseLink not find: ${uri}`); 210 callback(-1); 211 } 212 } 213 214 async resumeFuseLink(uri: string, callback: resumeFuseLinkCallback): Promise<void> { 215 HiLog.info(TAG, `resumeFuseLink start`); 216 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(uri); 217 if (dlpFile !== null) { 218 await dlpFile.resumeFuseLink(); 219 } else { 220 HiLog.error(TAG, `resumeFuseLink not find: ${uri}`); 221 callback(-1); 222 } 223 } 224 225 async replaceDlpLinkFile(srcUri: string, linkFileName: string, callback: replaceDlpLinkFileCallback): Promise<void> { 226 GlobalContext.load('sandbox2linkFile'); 227 if (this.dlpFileMap.has(srcUri)) { 228 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(srcUri) as dlpPermission.DLPFile; 229 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 230 for (let key of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 231 for (let j of key) { 232 if (j[1] === linkFileName) { 233 j[0] = dlpFile; 234 } 235 } 236 } 237 await dlpFile.replaceDLPLinkFile(linkFileName); 238 } else { 239 HiLog.error(TAG, `replaceDLPLinkFile not find: ${srcUri}`); 240 callback(-1); 241 } 242 } 243 244 async recoverDlpFile(srcUri: string, pathUri: string, callback: recoverDlpFileCallback): Promise<void> { 245 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(srcUri); 246 if (dlpFile !== null) { 247 let inFile: fs.File | undefined; 248 try { 249 inFile = await fs.open(pathUri, fs.OpenMode.READ_WRITE); 250 await dlpFile.recoverDLPFile(inFile.fd); 251 } catch (err) { 252 HiLog.error(TAG, `recoverDlpFileInner4: ${JSON.stringify(err)}`); 253 callback((err as BusinessError).code); 254 } finally { 255 FileUtil.closeFileSync(inFile); 256 } 257 } else { 258 HiLog.error(TAG, `recoverDlpFile not find: ${srcUri}`); 259 callback(-1); 260 } 261 } 262 263 async closeDlpFile(srcUri: string, callback: closeDlpFileCallback): Promise<void> { 264 HiLog.info(TAG, `closeDlpFile start`); 265 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(srcUri); 266 if (dlpFile !== null) { 267 try { 268 await dlpFile.closeDLPFile(); 269 if (this.dlpFileMap.has(srcUri)) { 270 this.dlpFileMap.delete(srcUri); 271 AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap); 272 } 273 callback(0); 274 } catch (err) { 275 HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`); 276 callback((err as BusinessError).code); 277 } 278 } 279 } 280 281 async sandBoxLinkFile(linkFileName: string, callerToken: number, callback: sandBoxLinkFileCallback): Promise<void> { 282 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 283 for (let value of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 284 for (let linkFile of value) { 285 let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0); 286 if (linkFile[Constants.FILE_OPEN_HISTORY_ONE] === linkFileName) { 287 let authUserListNew: IAuthUser[] = []; 288 if (callerToken !== linkFile[Constants.FILE_OPEN_HISTORY_THREE]) { 289 HiLog.error(TAG, `found file, but token invalid: ${linkFileName}`); 290 callback(-1, _dlp, ''); 291 } else { 292 let linkFileInfo: Record<number, number | string | dlpPermission.DLPFile> = 293 linkFile[0] as Record<number, number | string | dlpPermission.DLPFile>; 294 linkFileInfo['dlpProperty'].authUserList.forEach((item: IAuthUser)=> { 295 authUserListNew.push( 296 new IAuthUser( 297 item.authAccount, 298 item.authAccountType, 299 item.dlpFileAccess, 300 item.permExpiryTime 301 )) 302 }) 303 _dlp = new IDLDLPProperty( 304 linkFileInfo['dlpProperty'].ownerAccount, 305 linkFileInfo['dlpProperty'].ownerAccountID, 306 linkFileInfo['dlpProperty'].ownerAccountType, 307 authUserListNew, 308 linkFileInfo['dlpProperty'].contactAccount, 309 linkFileInfo['dlpProperty'].offlineAccess, 310 linkFileInfo['dlpProperty'].everyoneAccessList ?? [], 311 linkFileInfo['dlpProperty'].expireTime ?? 0 312 ); 313 let fileUri = linkFile[4]; 314 callback(0, _dlp, fileUri.toString()); 315 } 316 } else { 317 HiLog.error(TAG, `request from sandbox, but can not find dlp file by linkFileName: ${linkFileName}`); 318 callback(-1, _dlp, ''); 319 } 320 } 321 } 322 } 323 324 async fileOpenHistory(uri: string, callback: fileOpenHistoryCallback): Promise<void> { 325 HiLog.info(TAG, `fileOpenHistory start`); 326 if ((GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>)?.has(uri)) { 327 callback(0); 328 } else { 329 callback(-1); 330 } 331 } 332 333 async linkSet(uri: string, callback: linkSetCallback): Promise<void> { 334 HiLog.info(TAG, `linkSet start`); 335 if ((GlobalContext.load('linkSet') as Map<string, (number | string)[]>)?.has(uri)) { 336 callback(0); 337 } else { 338 callback(-1); 339 } 340 } 341} 342 343export default class DlpFileProcessAbility extends ServiceExtensionAbility { 344 onCreate(want: Want) { 345 HiLog.info(TAG, `onCreate, want: ${want.abilityName}`); 346 } 347 348 onRequest(want: Want, startId: number) { 349 HiLog.info(TAG, `onRequest, want: ${want.abilityName}`); 350 } 351 352 onConnect(want: Want) { 353 HiLog.info(TAG, `service onConnect, want: ${want.abilityName}`); 354 return new DlpRpcServiceStub('dlpRpc service stub'); 355 } 356 357 onDisconnect(want: Want): void { 358 HiLog.info(TAG, `onDisconnect, want: ${want.abilityName}`); 359 } 360 361 onDestroy(): void { 362 HiLog.info(TAG, `onDestroy`); 363 } 364}