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