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 ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'; 17import dlpPermission from '@ohos.dlpPermission'; 18import fileio from '@ohos.fileio'; 19import Want from '@ohos.app.ability.Want'; 20import hiTraceMeter from '@ohos.hiTraceMeter'; 21import hiSysEvent from '@ohos.hiSysEvent'; 22import wantConstant from '@ohos.app.ability.wantConstant'; 23import fs from '@ohos.file.fs'; 24import fileUri from '@ohos.file.fileuri'; 25import { BusinessError } from '@ohos.base'; 26import osAccount from '@ohos.account.osAccount'; 27import uriPermissionManager from '@ohos.application.uriPermissionManager'; 28import { 29 getOsAccountInfo, 30 getUserId, 31 checkDomainAccountInfo, 32 getAuthPerm, 33 getFileFd, 34 getFileUriByPath, 35 getAppId, 36 DLPInfo, 37 getDLPInfo, 38 sendDlpFileOpenProperties, 39 isValidPath, 40 defaultDlpFile, 41 getAccountType, 42 getConnectionStatus 43} from '../common/utils'; 44import { 45 DlpFileInfo, 46 deleteSandbox2linkFileData, 47 deleteFileOpenHistoryData, 48 deleteLinkSetData, 49 deleteToken2FileData, 50 getDlpFileInfoFromSandbox2linkFileData, 51} from '../common/DataUtils'; 52import Constants from '../common/constant'; 53import GlobalContext from '../common/GlobalContext'; 54import rpc from '@ohos.rpc'; 55import { GetAlertMessage } from '../common/GetAlertMessage'; 56import { HiLog } from '../common/HiLog'; 57import { ObjectUtil } from '../common/ObjectUtil'; 58 59const TAG = 'View'; 60const SUFFIX_INDEX = 2; 61 62let opening: boolean = false; 63export default class ViewAbility extends ServiceExtensionAbility { 64 private dlpFd: number = -1; 65 private linkFileName: string = ''; 66 private linkFilePath: string = ''; 67 private appIndex: number = -1; 68 private tokenId: number = -1; 69 private dlpFile: dlpPermission.DLPFile = defaultDlpFile; 70 private authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY; 71 private sandboxBundleName: string = ''; 72 private sandboxAbilityName: string = ''; 73 private sandboxModuleName: string = ''; 74 private fileName: string = ''; 75 private uri: string = ''; 76 private stat?: fs.Stat; 77 private accountInfo?: osAccount.OsAccountInfo; 78 private uriInfo: fileUri.FileUri = new fileUri.FileUri(''); 79 private linkUri: string = ''; 80 private alreadyOpened: boolean = false; 81 private userId: number = -1; 82 private linkFileWriteable: boolean = false; 83 private callerBundleName: string = ''; 84 private accountType: number = dlpPermission.AccountType.DOMAIN_ACCOUNT; 85 private distributedInfoId: string = ''; 86 87 async onCreate(want: Want): Promise<void> { 88 if (!GlobalContext.load('sandbox2linkFile')) { 89 GlobalContext.store('sandbox2linkFile', new Map<string, (number | string | dlpPermission.DLPFile)[][]>()); 90 } 91 if (!GlobalContext.load('fileOpenHistory')) { 92 GlobalContext.store('fileOpenHistory', new Map<string, (number | string)[]>()); 93 } 94 if (!GlobalContext.load('token2File')) { 95 GlobalContext.store('token2File', new Map<number, (number | string | dlpPermission.DLPFile)[]>()); 96 } 97 if (!GlobalContext.load('linkSet')) { 98 GlobalContext.store('linkSet', new Set<string>()); 99 } 100 let dlpInfo: DLPInfo = await getDLPInfo(); 101 AppStorage.setOrCreate('hiPNameId', dlpInfo.name); 102 AppStorage.setOrCreate('hiPVersionId', dlpInfo.versionCode); 103 AppStorage.setOrCreate('viewContext', this.context); 104 } 105 106 async terminateCall(): Promise<void> { 107 return new Promise((resolve, reject) => { 108 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = 109 GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 110 HiLog.debug(TAG, `sandbox2linkFile size: ${sandbox2linkFile.size}`); 111 if (sandbox2linkFile.size === 0) { 112 this.context.terminateSelf(); 113 } 114 reject(); 115 return; 116 }); 117 } 118 119 async startDataAbility(): Promise<void> { 120 let want: Want = { 121 bundleName: Constants.DLP_MANAGER_BUNDLE_NAME, 122 abilityName: 'DataAbility' 123 }; 124 try { 125 await this.context.startAbility(want); 126 } catch { 127 HiLog.info(TAG, `startDataAbility failed`); 128 } 129 } 130 131 startAbility(want: Want, startId: number): void { 132 HiLog.info(TAG, `start sandbox begin`); 133 this.context.startAbility(want, async (err) => { 134 hiTraceMeter.finishTrace('DlpStartSandboxJs', startId); 135 if (err && err.code !== 0) { 136 HiLog.error(TAG, `startSandboxApp failed: ${JSON.stringify(err)}`); 137 try { 138 await this.dlpFile.deleteDLPLinkFile(this.linkFileName); 139 } catch (err) { 140 HiLog.error(TAG, `dlpFile deleteDLPLinkFile failed: ${JSON.stringify(err)}`); 141 } 142 try { 143 await this.dlpFile.closeDLPFile(); 144 } catch (err) { 145 HiLog.error(TAG, `dlpFile closeDLPFile failed: ${JSON.stringify(err)}`); 146 } 147 opening = false; 148 //when errCode is ERR_JS_APP_NOT_EXIST, delete info. 149 if (err.code === Constants.ERR_JS_APP_NOT_EXIST) { 150 await this.deleteData(true, false); 151 } 152 await GetAlertMessage.startAlertAbility(this.context, 153 {code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 154 await this.sendDlpFileOpenFault(Constants.DLP_START_SANDBOX_ERROR, this.sandboxBundleName, this.appIndex, 155 undefined); // 105: DLP_START_SANDBOX_ERROR 156 } else { 157 // 203: DLP_START_SANDBOX_SUCCESS 158 await this.sendDlpFileOpenEvent(Constants.DLP_START_SANDBOX_SUCCESS, this.sandboxBundleName, this.appIndex); 159 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = 160 GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 161 if (!sandbox2linkFile.has(this.sandboxBundleName + this.appIndex)) { 162 sandbox2linkFile.set(this.sandboxBundleName + this.appIndex, []); 163 } 164 if (!this.alreadyOpened) { 165 sandbox2linkFile.get(this.sandboxBundleName + this.appIndex)?.push( 166 [this.dlpFile, this.linkFileName, this.dlpFd, this.tokenId, this.uri]); 167 (GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>).set( 168 this.uri, [this.sandboxBundleName, this.appIndex, this.linkFileName, this.linkUri, this.distributedInfoId] 169 ); 170 (GlobalContext.load('token2File') as Map<number, (number | string | dlpPermission.DLPFile | 171 dlpPermission.DLPFileAccess | null)[]>).set(this.tokenId, 172 [this.dlpFile, this.sandboxBundleName, this.appIndex, this.authPerm, this.uri, null, -1]); 173 (GlobalContext.load('linkSet') as Set<string>).add(this.linkUri); 174 } 175 await this.startDataAbility(); 176 opening = false; 177 HiLog.debug(TAG, `startDataAbility success`); 178 } 179 }); 180 } 181 182 async deleteData(isNeedCloseFd: boolean, isNeedDeleteLink: boolean): Promise<void> { 183 HiLog.info(TAG, `deleteData start`); 184 if (isNeedCloseFd) { 185 try { 186 fileio.closeSync(this.dlpFd); 187 } catch (err) { 188 HiLog.error(TAG, `closeSync failed: ${JSON.stringify(err)}`); 189 } 190 } 191 try { 192 await deleteSandbox2linkFileData(this.sandboxBundleName + this.appIndex, isNeedDeleteLink); 193 await deleteToken2FileData(this.tokenId); 194 await deleteLinkSetData(this.linkUri); 195 await deleteFileOpenHistoryData(this.uri); 196 } catch (err) { 197 HiLog.error(TAG, `deleteData failed`); 198 } 199 } 200 201 startSandboxApp(startId: number, want: Want): void { 202 startId = Number(startId); 203 hiTraceMeter.startTrace('DlpStartSandboxJs', startId); 204 want.bundleName = this.sandboxBundleName; 205 want.abilityName = this.sandboxAbilityName; 206 want.moduleName = this.sandboxModuleName; 207 want.uri = this.linkUri; 208 want.flags = this.linkFileWriteable ? 209 wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION : wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION; 210 let dlpWant: Want = { 211 parameters: { 212 'linkFileName': { 213 'name': this.linkFileName 214 }, 215 'fileAsset': { 216 'displayName': this.uriInfo.name, 217 'relativePath': this.uriInfo.path, 218 'dateModified': this.stat?.ctime 219 }, 220 'uri': this.linkUri, 221 'dlpUri': { 222 'name': this.uri 223 }, 224 'linkFileWriteable': { 225 'name': this.linkFileWriteable 226 }, 227 'ohos.dlp.params.index': this.appIndex, 228 'ohos.dlp.params.moduleName': this.sandboxModuleName, 229 'ohos.dlp.params.securityFlag': this.authPerm === 230 dlpPermission.DLPFileAccess.READ_ONLY ? true : false 231 } 232 }; 233 ObjectUtil.Assign(want.parameters, dlpWant.parameters); 234 this.startAbility(want, startId); 235 } 236 237 async sendDlpFileOpenFault(code: number, sandboxName: string, appIndex: number, reason?: string): Promise<void> { 238 let event: hiSysEvent.SysEventInfo = { 239 domain: 'DLP', 240 name: 'DLP_FILE_OPEN', 241 eventType: hiSysEvent?.EventType?.FAULT, 242 params: { 243 'CODE': code, 244 'USER_ID': this.userId, 245 'SANDBOX_PKGNAME': sandboxName, 246 } as Record<string, number | string> 247 }; 248 if (appIndex !== -1 && event.params) { 249 event.params['SANDBOX_INDEX'] = appIndex; 250 } 251 if (reason !== undefined && event.params) { 252 event.params['REASON'] = reason; 253 } 254 try { 255 await hiSysEvent.write(event); 256 } catch (err) { 257 HiLog.error(TAG, `sendDlpFileOpenFault failed`); 258 } 259 } 260 261 async sendDlpFileOpenEvent(code: number, sandboxName: string, appIndex: number): Promise<void> { 262 let event: hiSysEvent.SysEventInfo = { 263 domain: 'DLP', 264 name: 'DLP_FILE_OPEN_EVENT', 265 eventType: hiSysEvent?.EventType?.BEHAVIOR, 266 params: { 267 'CODE': code, 268 'USER_ID': this.userId, 269 'SANDBOX_PKGNAME': sandboxName, 270 } as Record<string, number | string> 271 }; 272 if (appIndex !== -1 && event.params) { 273 event.params['SANDBOX_INDEX'] = appIndex; 274 } 275 try { 276 await hiSysEvent.write(event); 277 } catch (err) { 278 HiLog.error(TAG, `sendDlpFileOpenEvent failed`); 279 } 280 } 281 282 283 async closeFile(): Promise<void> { 284 try { 285 await this.dlpFile.closeDLPFile(); 286 fileio.closeSync(this.dlpFd); 287 } catch (err) { 288 HiLog.error(TAG, `closeFile failed: ${JSON.stringify(err)}`); 289 } 290 } 291 292 async startLoginAbility(): Promise<void> { 293 let accountWant: Want = { 294 bundleName: 'com.huawei.hmos.dlpcredmgr', 295 abilityName: 'DlpCredLoginAbility' 296 }; 297 if (await getConnectionStatus() === false) { 298 GetAlertMessage.startAlertAbility(this.context, { 299 code: Constants.ERR_JS_APP_NETWORK_INVALID } as BusinessError); 300 return; 301 } 302 try { 303 await this.context.startAbility(accountWant); 304 } catch (err) { 305 HiLog.info(TAG, `Failed to invoke startAbility, ${JSON.stringify(err)}`) 306 return; 307 } 308 await this.terminateCall(); 309 } 310 311 async getAccountAndOpenDLPFile(startId: number): Promise<void> { 312 hiTraceMeter.startTrace('DlpGetOsAccountJs', startId); 313 return new Promise(async (resolve, reject) => { 314 try { 315 this.accountInfo = await getOsAccountInfo(); 316 this.distributedInfoId = this.accountInfo.distributedInfo.id; 317 AppStorage.setOrCreate('accountDomain', this.accountInfo.domainInfo.domain); 318 this.userId = await getUserId(); 319 } catch (err) { 320 HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`); 321 hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId); 322 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 323 opening = false; 324 await GetAlertMessage.startAlertAbility(this.context, { 325 code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError); 326 fileio.closeSync(this.dlpFd); 327 reject(err); 328 return; 329 } 330 hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId); 331 if (this.accountType === dlpPermission.AccountType.CLOUD_ACCOUNT) { 332 if (this.accountInfo.distributedInfo.name === 'ohosAnonymousName' && 333 this.accountInfo.distributedInfo.id === 'ohosAnonymousUid') { 334 HiLog.info(TAG, 'account not login'); 335 opening = false; 336 await this.startLoginAbility(); 337 reject(); 338 return; 339 } 340 resolve(); 341 return; 342 } 343 let codeMessage = checkDomainAccountInfo(this.accountInfo); 344 if (codeMessage) { 345 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 346 opening = false; 347 await GetAlertMessage.startAlertAbility(this.context, { 348 code: codeMessage } as BusinessError); 349 fileio.closeSync(this.dlpFd); 350 reject(); 351 return; 352 } 353 resolve(); 354 }); 355 } 356 357 async callAlertAbility(errCode: BusinessError): Promise<void> { 358 await GetAlertMessage.startAlertAbility(this.context, errCode); 359 return; 360 } 361 362 async getOpenedDLPFile(startId: number): Promise<void> { 363 return new Promise(async (resolve, reject) => { 364 hiTraceMeter.startTrace('DlpOpenDlpFileJs', startId); 365 try { 366 HiLog.info(TAG, `openDLPFile: ${this.fileName}, dlpFd: ${this.dlpFd}`); 367 let callerAppId: string; 368 try { 369 callerAppId = await getAppId(this.callerBundleName); 370 HiLog.info(TAG, `get AppId success`); 371 } catch { 372 HiLog.error(TAG, `get AppId failed`); 373 await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION } as BusinessError); 374 return; 375 } 376 this.dlpFile = await dlpPermission.openDLPFile(this.dlpFd, callerAppId); 377 this.accountType = this.dlpFile.dlpProperty.ownerAccountType; 378 } catch (err) { 379 HiLog.error(TAG, `openDLPFile: ${this.fileName}, failed: ${JSON.stringify(err)}`); 380 hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId); 381 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 382 opening = false; 383 await this.sendDlpFileOpenFault( 384 Constants.DLP_FILE_PARSE_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data 385 ); // 103:DLP_FILE_PARSE_ERROR 386 387 if (err.code === Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION ) { 388 await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION} as BusinessError); 389 return; 390 } 391 let accountFlag: boolean = true; 392 if (this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT && 393 err.code === Constants.ERR_JS_USER_NO_PERMISSION) { 394 let accountName: string = err.message.split(', contact:')?.[1]; 395 accountFlag = await GetAlertMessage.checkAccountInfo(accountName); 396 } 397 if (!accountFlag) { 398 await this.callAlertAbility({code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 399 return; 400 } 401 await this.callAlertAbility(err.code === Constants.ERR_JS_APP_PERMISSION_DENY ? 402 {code: Constants.ERR_JS_RELEASE_FILE_OPEN } as BusinessError : err); 403 fileio.closeSync(this.dlpFd); 404 reject(); 405 return; 406 } 407 hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId); 408 try { 409 await this.dlpGetAuthPerm(); 410 } catch (err) { 411 reject(); 412 return; 413 } 414 resolve(); 415 }) 416 } 417 418 async dlpGetAuthPerm(): Promise<void> { 419 return new Promise(async (resolve, reject) => { 420 if (this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT) { 421 this.authPerm = getAuthPerm(this.accountInfo?.domainInfo.accountName ?? '', this.dlpFile.dlpProperty); 422 } else { 423 this.authPerm = dlpPermission.DLPFileAccess.READ_ONLY; 424 } 425 if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY || 426 this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) { 427 opening = false; 428 await GetAlertMessage.startAlertAbility(this.context, { 429 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 430 await this.closeFile(); 431 reject(); 432 return; 433 } 434 resolve(); 435 }); 436 } 437 438 async getPolicyAndInstallSandbox(startId: number): Promise<void> { 439 return new Promise(async (resolve, reject) => { 440 this.alreadyOpened = false; 441 try { 442 await this.sandboxSetData(startId); 443 } catch { 444 reject(); 445 return; 446 } 447 AppStorage.setOrCreate('hiSandboxIndex', this.appIndex); 448 hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId); 449 // 202: DLP_INSTALL_SANDBOX_SUCCESS 450 await this.sendDlpFileOpenEvent(Constants.DLP_INSTALL_SANDBOX_SUCCESS, this.sandboxBundleName, this.appIndex); 451 if (!this.alreadyOpened) { 452 try { 453 await this.getAlreadyOpen(startId); 454 } catch { 455 reject(); 456 return; 457 } 458 } 459 resolve(); 460 }); 461 } 462 463 async sandboxSetData(startId: number): Promise<void> { 464 return new Promise(async (resolve, reject) => { 465 try { 466 let fileOpenHistory: Map<string, (number | string)[]> = 467 GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>; 468 if (fileOpenHistory.has(this.uri) && this.historyOpenSame(fileOpenHistory)) { 469 HiLog.info(TAG, `file: ${this.fileName} already open`); 470 let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[]; 471 this.appIndex = value[Constants.FILE_OPEN_HISTORY_ONE] as number; 472 this.linkFileName = value[Constants.FILE_OPEN_HISTORY_TWO] as string; 473 this.linkUri = value[Constants.FILE_OPEN_HISTORY_THREE] as string; 474 fs.closeSync(this.dlpFd); 475 let dlpFileInfo = 476 await getDlpFileInfoFromSandbox2linkFileData(this.sandboxBundleName + this.appIndex, this.uri); 477 this.dlpFile = dlpFileInfo.dlpFile; 478 this.tokenId = dlpFileInfo.tokenId; 479 this.accountType = this.dlpFile.dlpProperty.ownerAccountType; 480 await this.dlpGetAuthPerm(); 481 this.alreadyOpened = true; 482 } else { 483 await this.getOpenedDLPFile(startId); 484 } 485 hiTraceMeter.startTrace('DlpInstallSandboxJs', startId); 486 let appInfo: dlpPermission.DLPSandboxInfo = await dlpPermission.installDLPSandbox( 487 this.sandboxBundleName, this.authPerm, this.userId, this.uri 488 ); 489 if (this.alreadyOpened && (this.appIndex != appInfo.appIndex || this.tokenId != appInfo.tokenID)) { 490 HiLog.info(TAG, `return:${this.appIndex} ${appInfo.appIndex} ${this.tokenId} ${appInfo.tokenID} `); 491 await this.deleteData(false, true); 492 this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE); 493 await this.getOpenedDLPFile(startId); 494 this.alreadyOpened = false; 495 } 496 this.appIndex = appInfo.appIndex; 497 this.tokenId = appInfo.tokenID; 498 resolve(); 499 } catch (err) { 500 HiLog.error(TAG, `installDLPSandbox failed: ${JSON.stringify(err)}`); 501 hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId); 502 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 503 opening = false; 504 await this.sendDlpFileOpenFault( 505 Constants.DLP_INSTALL_SANDBOX_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data 506 ); // 104:DLP_INSTALL_SANDBOX_ERROR 507 await GetAlertMessage.startAlertAbility(this.context, { 508 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 509 await this.closeFile(); 510 reject(); 511 } 512 }) 513 } 514 515 historyOpenSame(fileOpenHistory: Map<string, (number | string)[]>): boolean { 516 let historyDistributedInfoId = fileOpenHistory.get(this.uri); 517 let distributeId = historyDistributedInfoId ? historyDistributedInfoId[4] : ''; 518 if (distributeId === this.distributedInfoId) { 519 return true; 520 }; 521 return false; 522 } 523 524 async generateLinkFileName(startId: number): Promise<string> { 525 return new Promise<string>(async (resolve, reject) => { 526 let timestamp = new Date().getTime(); 527 let splitNames = this.fileName.split('.'); 528 HiLog.debug(TAG, `splitNames: ${splitNames}`); 529 if (splitNames.length <= SUFFIX_INDEX) { 530 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 531 opening = false; 532 await GetAlertMessage.startAlertAbility(this.context, { 533 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 534 await this.closeFile(); 535 reject(''); 536 return; 537 } 538 let secondarySuffix = splitNames[splitNames.length - SUFFIX_INDEX]; 539 this.linkFileName = String(this.sandboxBundleName).substring(0, Constants.BUNDLE_LEN) + '_' + this.appIndex + 540 '_' + timestamp + String(Math.random()).substring(Constants.RAND_START, Constants.RAND_END) + '.dlp.link.' + 541 secondarySuffix; 542 resolve(secondarySuffix); 543 }); 544 } 545 546 async getAlreadyOpen(startId: number): Promise<void> { 547 return new Promise(async (resolve, reject) => { 548 try { 549 await this.generateLinkFileName(startId); 550 } catch { 551 reject(); 552 return; 553 } 554 hiTraceMeter.startTrace('DlpAddLinkFileJs', startId); 555 try { 556 await this.getAddDLPLinkFile(startId); 557 } catch { 558 reject(); 559 return; 560 } 561 hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId); 562 try { 563 this.linkFilePath = Constants.FUSE_PATH + this.linkFileName; 564 let stat = fs.statSync(this.linkFilePath); 565 const WRITE_ACCESS: number = 0o0200; 566 if (stat.mode & WRITE_ACCESS) { 567 this.linkFileWriteable = true; 568 } else { 569 this.linkFileWriteable = false; 570 } 571 } catch (err) { 572 HiLog.error(TAG, `file error: ${JSON.stringify(err)}`); 573 opening = false; 574 try { 575 await this.terminateCall(); 576 } catch (err) { 577 reject(); 578 return; 579 } 580 } 581 this.linkUri = getFileUriByPath(this.linkFilePath); 582 if (this.linkUri === '') { 583 HiLog.error(TAG, `get linkUri ByPath fail`); 584 opening = false; 585 try { 586 await this.terminateCall(); 587 } catch (err) { 588 reject(); 589 return; 590 } 591 } 592 resolve(); 593 }); 594 } 595 596 async getAddDLPLinkFile(startId: number): Promise<void> { 597 return new Promise(async (resolve, reject) => { 598 try { 599 await this.dlpFile.addDLPLinkFile(this.linkFileName); 600 } catch (error) { 601 HiLog.error(TAG, `addDLPLinkFile failed: ${JSON.stringify(error)}`); 602 try { 603 await this.dlpFile.closeDLPFile(); 604 } catch (err) { 605 HiLog.error(TAG, `closeDLPFile failed: ${JSON.stringify(err)}`); 606 } 607 opening = false; 608 await GetAlertMessage.startAlertAbility(this.context, error); 609 hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId); 610 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 611 await this.closeFile(); 612 reject(); 613 return; 614 } 615 resolve(); 616 }); 617 } 618 619 async getUriInfo(startId: number): Promise<void> { 620 return new Promise(async (resolve, reject) => { 621 try { 622 this.uriInfo = new fileUri.FileUri(this.uri); 623 } catch (error) { 624 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 625 opening = false; 626 await GetAlertMessage.startAlertAbility(this.context, { 627 code: Constants.ERR_JS_APP_GET_FILE_ASSET_ERROR } as BusinessError); 628 await this.closeFile(); 629 HiLog.error(TAG, `open: ${this.uri}, failed: ${JSON.stringify(error)}`); 630 reject(); 631 return; 632 } 633 try { 634 this.stat = await fs.stat(this.uriInfo.path); 635 AppStorage.setOrCreate('hiFileSize', this.stat.size); 636 AppStorage.setOrCreate('hiPolicySizeEnc', this.stat.size); 637 } catch (err) { 638 HiLog.info(TAG, `stat fail: ${JSON.stringify(err)}`); 639 } 640 resolve(); 641 }); 642 } 643 644 onConnect(want: Want): rpc.RemoteObject { 645 return new rpc.RemoteObject(TAG); 646 } 647 648 onDisconnect(want: Want): void { 649 HiLog.info(TAG, `onDisconnect`); 650 } 651 652 dlpFileMapHistory(want: Want): Promise<void> { 653 return new Promise(async (resolve, reject) => { 654 this.callerBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string; 655 AppStorage.setOrCreate('hiSandboxPkgName', this.callerBundleName); 656 if ((AppStorage.get('dlpFileMap') as Map<string, (string | number)[]>)?.has(want.uri ?? '')) { 657 await GetAlertMessage.startAlertAbility(this.context, { 658 code: Constants.ERR_JS_APP_ENCRYPTION_REJECTED } as BusinessError); 659 reject(); 660 return; 661 } 662 if (opening) { 663 HiLog.info(TAG, `file is opening: ${this.uri}`); 664 reject(); 665 return; 666 } else { 667 opening = true; 668 HiLog.info(TAG, `file is opened: ${this.uri}`); 669 } 670 this.uri = want.uri as string; 671 if (!isValidPath(this.uri)) { 672 opening = false; 673 HiLog.error(TAG, `invalid uri in want.uri`); 674 try { 675 await this.terminateCall(); 676 } catch (err) { 677 reject(); 678 return; 679 } 680 } 681 let strArray: string[] = this.uri.split('/'); 682 let len: number = strArray.length; 683 this.fileName = strArray[len - 1]; 684 this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE); 685 HiLog.debug(TAG, `dlpFd: ${this.dlpFd}`); 686 if (this.dlpFd === -1) { 687 opening = false; 688 try { 689 await this.terminateCall(); 690 } catch (err) { 691 reject(); 692 return; 693 } 694 } 695 resolve(); 696 }) 697 } 698 699 grandUriPermission() { 700 let flag = wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | 701 wantConstant.Flags.FLAG_AUTH_PERSISTABLE_URI_PERMISSION; 702 let targetBundleName = this.sandboxBundleName; 703 uriPermissionManager.grantUriPermission(this.uri, flag, targetBundleName, (result) => { 704 HiLog.info(TAG, `grandUriPermission result: ${JSON.stringify(result)}`); 705 }); 706 } 707 708 async onRequest(want: Want, startId: number): Promise<void> { 709 HiLog.debug(TAG, `enter onRequest`); 710 try { 711 await this.dlpFileMapHistory(want); 712 this.accountType = await getAccountType(this.context, this.dlpFd); 713 } catch { 714 return; 715 } 716 startId = Number(startId); 717 hiTraceMeter.startTrace('DlpOpenFileJs', startId); 718 this.sandboxBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string; 719 this.sandboxAbilityName = want.parameters?.['ohos.dlp.params.abilityName'] as string; 720 this.sandboxModuleName = want.parameters?.['ohos.dlp.params.moduleName'] as string; 721 if (this.fileName === undefined || this.dlpFd === undefined || this.uri === undefined || 722 this.sandboxBundleName === undefined || this.sandboxAbilityName === undefined || 723 this.sandboxModuleName === undefined || !this.uri.endsWith('.dlp')) { 724 opening = false; 725 HiLog.error(TAG, `get parameters failed`); 726 try { 727 await this.terminateCall(); 728 } catch (err) { 729 return; 730 } 731 } 732 let fileOpenHistory: Map<string, (number | string)[]> = 733 GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>; 734 if (fileOpenHistory.has(this.uri)) { 735 let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[]; 736 if (this.sandboxBundleName !== value[Constants.FILE_OPEN_HISTORY_ZERO] as string) { 737 HiLog.error(TAG, `other app is opening this file`); 738 opening = false; 739 await GetAlertMessage.startAlertAbility(this.context, { 740 code: Constants.ERR_JS_OTHER_APP_OPEN_FILE } as BusinessError); 741 return; 742 } 743 } 744 try { 745 await this.getAccountAndOpenDLPFile(startId); 746 await this.getPolicyAndInstallSandbox(startId); 747 await this.getUriInfo(startId); 748 } catch { 749 return; 750 } 751 this.grandUriPermission(); 752 this.startSandboxApp(startId, want); 753 AppStorage.setOrCreate('hiCode', Constants.DLP_START_SANDBOX_SUCCESS); 754 sendDlpFileOpenProperties(); 755 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 756 } 757} 758