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; 61const APPID_FOR_HOPE: string = '5765880207854533797'; 62const BUNDLE_NAME_FOR_HOPE: string = 'com.huawei.it.welink'; 63 64interface DlpConnectionPluginIdObj { 65 id: string 66} 67 68let opening: boolean = false; 69export default class ViewAbility extends ServiceExtensionAbility { 70 private dlpFd: number = -1; 71 private linkFileName: string = ''; 72 private linkFilePath: string = ''; 73 private appIndex: number = -1; 74 private tokenId: number = -1; 75 private dlpFile: dlpPermission.DLPFile = defaultDlpFile; 76 private authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY; 77 private needCallAccount: boolean = true; 78 private needCheckAccountType: boolean = false; 79 private sandboxBundleName: string = ''; 80 private sandboxAbilityName: string = ''; 81 private sandboxModuleName: string = ''; 82 private fileName: string = ''; 83 private uri: string = ''; 84 private stat?: fs.Stat; 85 private accountInfo?: osAccount.OsAccountInfo; 86 private uriInfo: fileUri.FileUri = new fileUri.FileUri(''); 87 private linkUri: string = ''; 88 private alreadyOpened: boolean = false; 89 private userId: number = -1; 90 private linkFileWriteable: boolean = false; 91 private callerBundleName: string = ''; 92 private accountType: number = dlpPermission.AccountType.DOMAIN_ACCOUNT; 93 private distributedInfoId: string = ''; 94 95 async onCreate(want: Want): Promise<void> { 96 if (!GlobalContext.load('sandbox2linkFile')) { 97 GlobalContext.store('sandbox2linkFile', new Map<string, (number | string | dlpPermission.DLPFile)[][]>()); 98 } 99 if (!GlobalContext.load('fileOpenHistory')) { 100 GlobalContext.store('fileOpenHistory', new Map<string, (number | string)[]>()); 101 } 102 if (!GlobalContext.load('token2File')) { 103 GlobalContext.store('token2File', new Map<number, (number | string | dlpPermission.DLPFile)[]>()); 104 } 105 if (!GlobalContext.load('linkSet')) { 106 GlobalContext.store('linkSet', new Set<string>()); 107 } 108 let dlpInfo: DLPInfo = await getDLPInfo(); 109 AppStorage.setOrCreate('hiPNameId', dlpInfo.name); 110 AppStorage.setOrCreate('hiPVersionId', dlpInfo.versionCode); 111 AppStorage.setOrCreate('viewContext', 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.startAlertAbility(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 if (await getConnectionStatus() === false) { 306 GetAlertMessage.startAlertAbility(this.context, { 307 code: Constants.ERR_JS_APP_NETWORK_INVALID } as BusinessError); 308 return; 309 } 310 try { 311 await this.context.startAbility(accountWant); 312 } catch (err) { 313 HiLog.info(TAG, `Failed to invoke startAbility, ${JSON.stringify(err)}`) 314 return; 315 } 316 await this.terminateCall(); 317 } 318 319 async getAccountAndOpenDLPFile(startId: number): Promise<void> { 320 hiTraceMeter.startTrace('DlpGetOsAccountJs', startId); 321 return new Promise(async (resolve, reject) => { 322 try { 323 this.accountInfo = await getOsAccountInfo(); 324 this.distributedInfoId = this.accountInfo.distributedInfo.id; 325 AppStorage.setOrCreate('accountDomain', this.accountInfo.domainInfo.domain); 326 this.userId = await getUserId(); 327 } catch (err) { 328 HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`); 329 hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId); 330 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 331 opening = false; 332 await GetAlertMessage.startAlertAbility(this.context, { 333 code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError); 334 fileio.closeSync(this.dlpFd); 335 reject(err); 336 return; 337 } 338 hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId); 339 if (this.accountType === dlpPermission.AccountType.CLOUD_ACCOUNT) { 340 if (this.accountInfo.distributedInfo.name === 'ohosAnonymousName' && 341 this.accountInfo.distributedInfo.id === 'ohosAnonymousUid') { 342 HiLog.info(TAG, 'account not login'); 343 opening = false; 344 await this.startLoginAbility(); 345 reject(); 346 return; 347 } 348 resolve(); 349 return; 350 } 351 let codeMessage = checkDomainAccountInfo(this.accountInfo); 352 if (codeMessage) { 353 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 354 opening = false; 355 await GetAlertMessage.startAlertAbility(this.context, { 356 code: codeMessage } as BusinessError); 357 fileio.closeSync(this.dlpFd); 358 reject(); 359 return; 360 } 361 resolve(); 362 }); 363 } 364 365 async callAlertAbility(errCode: BusinessError): Promise<void> { 366 await GetAlertMessage.startAlertAbility(this.context, errCode); 367 return; 368 } 369 370 async getOpenedDLPFile(startId: number): Promise<void> { 371 return new Promise(async (resolve, reject) => { 372 hiTraceMeter.startTrace('DlpOpenDlpFileJs', startId); 373 try { 374 HiLog.info(TAG, `openDLPFile: ${this.fileName}, dlpFd: ${this.dlpFd}`); 375 let callerAppId: string; 376 try { 377 callerAppId = await getAppId(this.callerBundleName); 378 HiLog.info(TAG, `get AppId success`); 379 } catch { 380 HiLog.error(TAG, `get AppId failed`); 381 await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION } as BusinessError); 382 return; 383 } 384 this.dlpFile = await dlpPermission.openDLPFile(this.dlpFd, callerAppId); 385 this.accountType = this.dlpFile.dlpProperty.ownerAccountType; 386 } catch (err) { 387 HiLog.error(TAG, `openDLPFile: ${this.fileName}, failed: ${JSON.stringify(err)}`); 388 hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId); 389 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 390 opening = false; 391 await this.sendDlpFileOpenFault( 392 Constants.DLP_FILE_PARSE_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data 393 ); // 103:DLP_FILE_PARSE_ERROR 394 395 if (err.code === Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION ) { 396 await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION} as BusinessError); 397 return; 398 } 399 let accountFlag: boolean = true; 400 if (this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT && 401 err.code === Constants.ERR_JS_USER_NO_PERMISSION) { 402 let accountName: string = err.message.split(', contact:')?.[1]; 403 accountFlag = await GetAlertMessage.checkAccountInfo(accountName); 404 } 405 if (!accountFlag) { 406 await this.callAlertAbility({code: Constants.ERR_JS_USER_NO_PERMISSION} as BusinessError); 407 return; 408 } 409 await this.callAlertAbility(err.code === Constants.ERR_JS_APP_PERMISSION_DENY ? 410 {code: Constants.ERR_JS_RELEASE_FILE_OPEN } as BusinessError : err); 411 fileio.closeSync(this.dlpFd); 412 reject(); 413 return; 414 } 415 hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId); 416 try { 417 await this.dlpGetAuthPerm(); 418 } catch (err) { 419 reject(); 420 return; 421 } 422 resolve(); 423 }) 424 } 425 426 async dlpGetAuthPerm(): Promise<void> { 427 return new Promise(async (resolve, reject) => { 428 if (this.needCallAccount && this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT) { 429 this.authPerm = getAuthPerm(this.accountInfo?.domainInfo.accountName ?? '', this.dlpFile.dlpProperty); 430 } else { 431 this.authPerm = dlpPermission.DLPFileAccess.READ_ONLY; 432 } 433 if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY || 434 this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) { 435 opening = false; 436 await GetAlertMessage.startAlertAbility(this.context, { 437 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 438 await this.closeFile(); 439 reject(); 440 return; 441 } 442 resolve(); 443 }); 444 } 445 446 async getPolicyAndInstallSandbox(startId: number): Promise<void> { 447 return new Promise(async (resolve, reject) => { 448 this.alreadyOpened = false; 449 try { 450 await this.sandboxSetData(startId); 451 } catch { 452 reject(); 453 return; 454 } 455 AppStorage.setOrCreate('hiSandboxIndex', this.appIndex); 456 hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId); 457 // 202: DLP_INSTALL_SANDBOX_SUCCESS 458 await this.sendDlpFileOpenEvent(Constants.DLP_INSTALL_SANDBOX_SUCCESS, this.sandboxBundleName, this.appIndex); 459 if (!this.alreadyOpened) { 460 try { 461 await this.getAlreadyOpen(startId); 462 } catch { 463 reject(); 464 return; 465 } 466 } 467 resolve(); 468 }); 469 } 470 471 async sandboxSetData(startId: number): Promise<void> { 472 return new Promise(async (resolve, reject) => { 473 try { 474 let fileOpenHistory: Map<string, (number | string)[]> = 475 GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>; 476 if (fileOpenHistory.has(this.uri) && this.historyOpenSame(fileOpenHistory)) { 477 HiLog.info(TAG, `file: ${this.fileName} already open`); 478 let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[]; 479 this.appIndex = value[Constants.FILE_OPEN_HISTORY_ONE] as number; 480 this.linkFileName = value[Constants.FILE_OPEN_HISTORY_TWO] as string; 481 this.linkUri = value[Constants.FILE_OPEN_HISTORY_THREE] as string; 482 fs.closeSync(this.dlpFd); 483 let dlpFileInfo = 484 await getDlpFileInfoFromSandbox2linkFileData(this.sandboxBundleName + this.appIndex, this.uri); 485 this.dlpFile = dlpFileInfo.dlpFile; 486 this.tokenId = dlpFileInfo.tokenId; 487 this.accountType = this.dlpFile.dlpProperty.ownerAccountType; 488 await this.dlpGetAuthPerm(); 489 this.alreadyOpened = true; 490 } else { 491 await this.getOpenedDLPFile(startId); 492 } 493 hiTraceMeter.startTrace('DlpInstallSandboxJs', startId); 494 let appInfo: dlpPermission.DLPSandboxInfo = await dlpPermission.installDLPSandbox( 495 this.sandboxBundleName, this.authPerm, this.userId, this.uri 496 ); 497 if (this.alreadyOpened && (this.appIndex != appInfo.appIndex || this.tokenId != appInfo.tokenID)) { 498 HiLog.info(TAG, `return:${this.appIndex} ${appInfo.appIndex} ${this.tokenId} ${appInfo.tokenID} `); 499 await this.deleteData(false, true); 500 this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE); 501 await this.getOpenedDLPFile(startId); 502 this.alreadyOpened = false; 503 } 504 this.appIndex = appInfo.appIndex; 505 this.tokenId = appInfo.tokenID; 506 resolve(); 507 } catch (err) { 508 HiLog.error(TAG, `installDLPSandbox failed: ${JSON.stringify(err)}`); 509 hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId); 510 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 511 opening = false; 512 await this.sendDlpFileOpenFault( 513 Constants.DLP_INSTALL_SANDBOX_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data 514 ); // 104:DLP_INSTALL_SANDBOX_ERROR 515 await GetAlertMessage.startAlertAbility(this.context, { 516 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 517 await this.closeFile(); 518 reject(); 519 } 520 }) 521 } 522 523 historyOpenSame(fileOpenHistory: Map<string, (number | string)[]>): boolean { 524 let historyDistributedInfoId = fileOpenHistory.get(this.uri); 525 let distributeId = historyDistributedInfoId ? historyDistributedInfoId[4] : ''; 526 if (distributeId === this.distributedInfoId) { 527 return true; 528 }; 529 return false; 530 } 531 532 async generateLinkFileName(startId: number): Promise<string> { 533 return new Promise<string>(async (resolve, reject) => { 534 let timestamp = new Date().getTime(); 535 let splitNames = this.fileName.split('.'); 536 HiLog.debug(TAG, `splitNames: ${splitNames}`); 537 if (splitNames.length <= SUFFIX_INDEX) { 538 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 539 opening = false; 540 await GetAlertMessage.startAlertAbility(this.context, { 541 code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 542 await this.closeFile(); 543 reject(''); 544 return; 545 } 546 let secondarySuffix = splitNames[splitNames.length - SUFFIX_INDEX]; 547 this.linkFileName = String(this.sandboxBundleName).substring(0, Constants.BUNDLE_LEN) + '_' + this.appIndex + 548 '_' + timestamp + String(Math.random()).substring(Constants.RAND_START, Constants.RAND_END) + '.dlp.link.' + 549 secondarySuffix; 550 resolve(secondarySuffix); 551 }); 552 } 553 554 async getAlreadyOpen(startId: number): Promise<void> { 555 return new Promise(async (resolve, reject) => { 556 try { 557 await this.generateLinkFileName(startId); 558 } catch { 559 reject(); 560 return; 561 } 562 hiTraceMeter.startTrace('DlpAddLinkFileJs', startId); 563 try { 564 await this.getAddDLPLinkFile(startId); 565 } catch { 566 reject(); 567 return; 568 } 569 hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId); 570 try { 571 this.linkFilePath = Constants.FUSE_PATH + this.linkFileName; 572 let stat = fs.statSync(this.linkFilePath); 573 const WRITE_ACCESS: number = 0o0200; 574 if (stat.mode & WRITE_ACCESS) { 575 this.linkFileWriteable = true; 576 } else { 577 this.linkFileWriteable = false; 578 } 579 } catch (err) { 580 HiLog.error(TAG, `file error: ${JSON.stringify(err)}`); 581 opening = false; 582 try { 583 await this.terminateCall(); 584 } catch (err) { 585 reject(); 586 return; 587 } 588 } 589 this.linkUri = getFileUriByPath(this.linkFilePath); 590 if (this.linkUri === '') { 591 HiLog.error(TAG, `get linkUri ByPath fail`); 592 opening = false; 593 try { 594 await this.terminateCall(); 595 } catch (err) { 596 reject(); 597 return; 598 } 599 } 600 resolve(); 601 }); 602 } 603 604 async getAddDLPLinkFile(startId: number): Promise<void> { 605 return new Promise(async (resolve, reject) => { 606 try { 607 await this.dlpFile.addDLPLinkFile(this.linkFileName); 608 } catch (error) { 609 HiLog.error(TAG, `addDLPLinkFile failed: ${JSON.stringify(error)}`); 610 try { 611 await this.dlpFile.closeDLPFile(); 612 } catch (err) { 613 HiLog.error(TAG, `closeDLPFile failed: ${JSON.stringify(err)}`); 614 } 615 opening = false; 616 await GetAlertMessage.startAlertAbility(this.context, error); 617 hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId); 618 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 619 await this.closeFile(); 620 reject(); 621 return; 622 } 623 resolve(); 624 }); 625 } 626 627 async getUriInfo(startId: number): Promise<void> { 628 return new Promise(async (resolve, reject) => { 629 try { 630 this.uriInfo = new fileUri.FileUri(this.uri); 631 } catch (error) { 632 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 633 opening = false; 634 await GetAlertMessage.startAlertAbility(this.context, { 635 code: Constants.ERR_JS_APP_GET_FILE_ASSET_ERROR } as BusinessError); 636 await this.closeFile(); 637 HiLog.error(TAG, `open: ${this.uri}, failed: ${JSON.stringify(error)}`); 638 reject(); 639 return; 640 } 641 try { 642 this.stat = await fs.stat(this.uriInfo.path); 643 AppStorage.setOrCreate('hiFileSize', this.stat.size); 644 AppStorage.setOrCreate('hiPolicySizeEnc', this.stat.size); 645 } catch (err) { 646 HiLog.info(TAG, `stat fail: ${JSON.stringify(err)}`); 647 } 648 resolve(); 649 }); 650 } 651 652 onConnect(want: Want): rpc.RemoteObject { 653 return new rpc.RemoteObject(TAG); 654 } 655 656 onDisconnect(want: Want): void { 657 HiLog.info(TAG, `onDisconnect`); 658 } 659 660 dlpFileMapHistory(want: Want): Promise<void> { 661 return new Promise(async (resolve, reject) => { 662 this.callerBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string; 663 AppStorage.setOrCreate('hiSandboxPkgName', this.callerBundleName); 664 if ((AppStorage.get('dlpFileMap') as Map<string, (string | number)[]>)?.has(want.uri ?? '')) { 665 await GetAlertMessage.startAlertAbility(this.context, { 666 code: Constants.ERR_JS_APP_ENCRYPTION_REJECTED } as BusinessError); 667 reject(); 668 return; 669 } 670 if (opening) { 671 HiLog.info(TAG, `file is opening: ${this.uri}`); 672 reject(); 673 return; 674 } else { 675 opening = true; 676 HiLog.info(TAG, `file is opened: ${this.uri}`); 677 } 678 this.uri = want.uri as string; 679 if (!isValidPath(this.uri)) { 680 opening = false; 681 HiLog.error(TAG, `invalid uri in want.uri`); 682 try { 683 await this.terminateCall(); 684 } catch (err) { 685 reject(); 686 return; 687 } 688 } 689 let strArray: string[] = this.uri.split('/'); 690 let len: number = strArray.length; 691 this.fileName = strArray[len - 1]; 692 this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE); 693 HiLog.debug(TAG, `dlpFd: ${this.dlpFd}`); 694 if (this.dlpFd === -1) { 695 opening = false; 696 try { 697 await this.terminateCall(); 698 } catch (err) { 699 reject(); 700 return; 701 } 702 } 703 resolve(); 704 }) 705 } 706 707 async checkNeedCallAccount(): Promise<boolean> { 708 switch (this.accountType) { 709 case dlpPermission.AccountType.CLOUD_ACCOUNT: { 710 return true; 711 } 712 case dlpPermission.AccountType.DOMAIN_ACCOUNT: { 713 try { 714 this.accountInfo = await getOsAccountInfo(); 715 this.userId = await getUserId(); 716 } catch (err) { 717 HiLog.error(TAG, 'getOsAccountInfo failed: ${JSON.stringify(err)}'); 718 return true; 719 } 720 if (this.accountInfo.domainInfo.accountName === '') { 721 HiLog.debug(TAG, 'not need check call account'); 722 return false; 723 } 724 } 725 defalut: { 726 break; 727 } 728 } 729 return true; 730 } 731 732 grandUriPermission() { 733 let flag = wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | 734 wantConstant.Flags.FLAG_AUTH_PERSISTABLE_URI_PERMISSION; 735 let targetBundleName = this.sandboxBundleName; 736 uriPermissionManager.grantUriPermission(this.uri, flag, targetBundleName, (result) => { 737 HiLog.info(TAG, `grandUriPermission result: ${JSON.stringify(result)}`); 738 }); 739 } 740 741 async checkPermissionWithPluginId(want: Want): Promise<boolean> { 742 let paramCallerBundleName = want.parameters?.['ohos.aafwk.param.callerBundleName'] as string; 743 AppStorage.setOrCreate('paramCallerBundleName', paramCallerBundleName); 744 745 let pluginId: string = (want.parameters?.['dlpConnectionPluginId'] as DlpConnectionPluginIdObj)?.id; 746 if (pluginId === null || pluginId === undefined) { 747 return true; 748 } 749 750 let callerAppId = want.parameters?.['ohos.aafwk.param.callerAppIdentifier'] as string; 751 if (callerAppId !== APPID_FOR_HOPE || paramCallerBundleName !== BUNDLE_NAME_FOR_HOPE) { 752 HiLog.error(TAG, `callerAppId or callerBundleNameis error.`); 753 await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION} as BusinessError); 754 return false; 755 } 756 757 this.needCheckAccountType = true; 758 return true; 759 } 760 761 async onRequest(want: Want, startId: number): Promise<void> { 762 HiLog.debug(TAG, `enter onRequest`); 763 if (!this.checkPermissionWithPluginId(want)) { 764 return; 765 } 766 try { 767 await this.dlpFileMapHistory(want); 768 this.accountType = await getAccountType(this.context, this.dlpFd); 769 } catch { 770 return; 771 } 772 startId = Number(startId); 773 hiTraceMeter.startTrace('DlpOpenFileJs', startId); 774 this.sandboxBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string; 775 this.sandboxAbilityName = want.parameters?.['ohos.dlp.params.abilityName'] as string; 776 this.sandboxModuleName = want.parameters?.['ohos.dlp.params.moduleName'] as string; 777 if (this.needCheckAccountType) { 778 this.needCallAccount = await this.checkNeedCallAccount(); 779 } 780 if (this.fileName === undefined || this.dlpFd === undefined || this.uri === undefined || 781 this.sandboxBundleName === undefined || this.sandboxAbilityName === undefined || 782 this.sandboxModuleName === undefined || !this.uri.endsWith('.dlp')) { 783 opening = false; 784 HiLog.error(TAG, `get parameters failed`); 785 try { 786 await this.terminateCall(); 787 } catch (err) { 788 return; 789 } 790 } 791 let fileOpenHistory: Map<string, (number | string)[]> = 792 GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>; 793 if (fileOpenHistory.has(this.uri)) { 794 let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[]; 795 if (this.sandboxBundleName !== value[Constants.FILE_OPEN_HISTORY_ZERO] as string) { 796 HiLog.error(TAG, `other app is opening this file`); 797 opening = false; 798 await GetAlertMessage.startAlertAbility(this.context, { 799 code: Constants.ERR_JS_OTHER_APP_OPEN_FILE } as BusinessError); 800 return; 801 } 802 } 803 try { 804 if (this.needCallAccount) { 805 await this.getAccountAndOpenDLPFile(startId); 806 } 807 await this.getPolicyAndInstallSandbox(startId); 808 await this.getUriInfo(startId); 809 } catch { 810 return; 811 } 812 this.grandUriPermission(); 813 this.startSandboxApp(startId, want); 814 AppStorage.setOrCreate('hiCode', Constants.DLP_START_SANDBOX_SUCCESS); 815 sendDlpFileOpenProperties(); 816 hiTraceMeter.finishTrace('DlpOpenFileJs', startId); 817 } 818} 819