1/* 2 * Copyright (c) 2025 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 Result from '../../common/Result'; 17import { ResultMsg } from '../../common/ResultMsg'; 18import { FileParseFactory } from '../handler/FileParseHandler'; 19import OpenDlpFileData from '../data/OpenDlpFileData'; 20import common from '@ohos.app.ability.common'; 21import Constants from '../../common/constant'; 22import DecryptContent from '../data/DecryptContent'; 23import { AccountHandlerFactory } from '../handler/AccountHandler'; 24import DecryptHandler from '../handler/DecryptHandler'; 25import { DecryptState, OpenDlpFileManager } from '../manager/OpenDlpFileManager'; 26import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'; 27import { HiLog } from '../../common/HiLog'; 28import { clearDlpInfoByError } from '../common/DataUtils/DataUtils'; 29import CredConnectService from '../../rpc/CredConnectService'; 30import OpeningDialogManager from '../manager/OpeningDialogManager'; 31import { BusinessError } from '@ohos.base'; 32import { DlpFileOpenReport } from '../common/DlpFileOpenReport'; 33import ErrorManager from '../handler/ErrorHandler'; 34import StartSandboxHandler from '../handler/StartSandboxHandler'; 35 36const TAG: string = 'OpenDlpFileProcessor'; 37 38export class OpenDlpFileProcessor { 39 public async process(want: Want, startId: number, context: common.ServiceExtensionContext): Promise<Result<void>> { 40 this.batchRefresh(context); 41 const proRet = await this.processOpenDlpFile(want, startId, context); 42 if (proRet.errcode !== Constants.ERR_CODE_SUCCESS) { 43 HiLog.error(TAG, 'processOpenDlpFile error'); 44 const err = { code: proRet.errcode, message: proRet.errmsg ? proRet.errmsg : '' } as BusinessError; 45 return await this.processErrcode(err, proRet.result); 46 } 47 HiLog.debug(TAG, 'processOpenDlpFile success'); 48 return ResultMsg.buildSuccess(); 49 } 50 51 private async processOpenDlpFile(want: Want, startId: number, context: common.ServiceExtensionContext): 52 Promise<Result<DecryptContent>> { 53 HiLog.info(TAG, 'enter processOpenDlpFile'); 54 55 // 1. Params check 56 const openDlpFileData = new OpenDlpFileData(want, startId); 57 if (!openDlpFileData.checkAndSetWantParams()) { 58 HiLog.error(TAG, 'checkAndSetWantParams error'); 59 return ResultMsg.getErrMsg(Constants.ERR_CODE_PARAMS_CHECK_ERROR); 60 } 61 62 // 2. Check if uri in decrypting or encrypting 63 const checkRet = await this.checkAndGetState(openDlpFileData); 64 if (checkRet.errcode !== Constants.ERR_CODE_SUCCESS || !checkRet.result) { 65 HiLog.error(TAG, 'checkAndSetState error'); 66 return ResultMsg.buildMsg(checkRet.errcode, checkRet.errmsg); 67 } 68 69 // 3. Parse dlp file 70 const fileParseResult = await this.parseFile(openDlpFileData, context, checkRet.result); 71 if (fileParseResult.errcode !== Constants.ERR_CODE_SUCCESS || !fileParseResult.result) { 72 HiLog.error(TAG, 'parseFile error'); 73 await OpeningDialogManager.getInstance().hideOpeningDialogByFailed(openDlpFileData.requestId); 74 return ResultMsg.buildMsg(fileParseResult.errcode, fileParseResult.errmsg); 75 } 76 let decryptContent = fileParseResult.result; 77 78 // 4. Handle account 79 const accountHandleResult = await this.handleAccount(decryptContent, context); 80 if (accountHandleResult.errcode !== Constants.ERR_CODE_SUCCESS) { 81 HiLog.error(TAG, 'handleAccount error'); 82 return ResultMsg.buildResult(accountHandleResult.errcode, accountHandleResult.errmsg, decryptContent); 83 } 84 85 // 5. decrypt and install sandbox 86 const decryptResult = await this.decryptAndInstall(decryptContent, context, startId); 87 if (decryptResult.errcode !== Constants.ERR_CODE_SUCCESS) { 88 HiLog.error(TAG, 'decryptAndInstall error'); 89 return ResultMsg.buildResult(decryptResult.errcode, decryptResult.errmsg, decryptContent); 90 } 91 92 // 6. start sandbox 93 const startSandboxRet = await StartSandboxHandler.getInstance().startSandbox(decryptContent, context); 94 if (startSandboxRet.errcode !== Constants.ERR_CODE_SUCCESS) { 95 HiLog.error(TAG, 'startSandbox error'); 96 await OpeningDialogManager.getInstance().hideOpeningDialogByFailed(decryptContent.openDlpFileData.requestId); 97 return ResultMsg.buildResult(startSandboxRet.errcode, startSandboxRet.errmsg, decryptContent); 98 } 99 100 return ResultMsg.buildSuccess(decryptContent); 101 } 102 103 private async parseFile(openDlpFileData: OpenDlpFileData, context: common.ServiceExtensionContext, 104 state: DecryptState): Promise<Result<DecryptContent>> { 105 const fileParseRet = await FileParseFactory.createFileParse(openDlpFileData); 106 if (fileParseRet.errcode !== Constants.ERR_CODE_SUCCESS || !fileParseRet.result) { 107 HiLog.error(TAG, 'createFileParse error'); 108 return ResultMsg.buildMsg(fileParseRet.errcode, fileParseRet.errmsg); 109 } 110 111 OpeningDialogManager.getInstance().loadOpeningDialog(context, fileParseRet.result.fileSize, 112 openDlpFileData, state, fileParseRet.result?.parseType); 113 114 const fileMetaInfoRet = await fileParseRet.result.parse(openDlpFileData.uri, context.filesDir); 115 if (fileMetaInfoRet.errcode !== Constants.ERR_CODE_SUCCESS) { 116 HiLog.error(TAG, 'parse error'); 117 OpeningDialogManager.getInstance().hideOpeningDialogByFailed(openDlpFileData.requestId); 118 return ResultMsg.buildMsg(fileMetaInfoRet.errcode, fileMetaInfoRet.errmsg); 119 } 120 const decryptContent = new DecryptContent(fileMetaInfoRet.result!, openDlpFileData); 121 return ResultMsg.buildSuccess(decryptContent); 122 } 123 124 private async handleAccount(decryptContent: DecryptContent, context: common.ServiceExtensionContext): 125 Promise<Result<DecryptContent>> { 126 const accountHandlerRet = AccountHandlerFactory.createAccountHandler(decryptContent); 127 if (accountHandlerRet.errcode !== Constants.ERR_CODE_SUCCESS || !accountHandlerRet.result) { 128 HiLog.error(TAG, 'createAccountHandler error'); 129 OpeningDialogManager.getInstance().hideOpeningDialogByFailed(decryptContent.openDlpFileData.requestId); 130 return ResultMsg.buildResult(accountHandlerRet.errcode, accountHandlerRet.errmsg, decryptContent); 131 } 132 133 const handleLoginRet = await accountHandlerRet.result.handle(decryptContent, context); 134 if (handleLoginRet.errcode !== Constants.ERR_CODE_SUCCESS) { 135 HiLog.error(TAG, 'handleLogin error'); 136 OpeningDialogManager.getInstance().hideOpeningDialogByFailed(decryptContent.openDlpFileData.requestId); 137 return ResultMsg.buildResult(handleLoginRet.errcode, handleLoginRet.errmsg, decryptContent); 138 } 139 return ResultMsg.buildSuccess(decryptContent); 140 } 141 142 private async decryptAndInstall(decryptContent: DecryptContent, context: common.ServiceExtensionContext, 143 startId: number): Promise<Result<DecryptContent>> { 144 hiTraceMeter.startTrace('DlpInstallSandboxJs', startId); 145 const decryptHandler = new DecryptHandler(); 146 const getDecryptDataRet = await decryptHandler.getDecryptData(decryptContent, context); 147 hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId); 148 if (getDecryptDataRet.errcode !== Constants.ERR_CODE_SUCCESS) { 149 HiLog.error(TAG, 'getDecryptData error'); 150 await OpenDlpFileManager.getInstance().deleteStatusButNotHasDecrypted(decryptContent.openDlpFileData.uri); 151 OpeningDialogManager.getInstance().hideOpeningDialogByFailed(decryptContent.openDlpFileData.requestId); 152 return ResultMsg.buildResult(getDecryptDataRet.errcode, getDecryptDataRet.errmsg, decryptContent); 153 } 154 return ResultMsg.buildSuccess(decryptContent); 155 } 156 157 private checkIfContinue(state: DecryptState): Result<void> { 158 HiLog.info(TAG, `checkIfContinue state is ${state}`); 159 const isDecrypting = OpeningDialogManager.getInstance().getIsDecrypting(); 160 if (state === DecryptState.DECRYPTING || isDecrypting) { 161 HiLog.info(TAG, `in decrypting, state ${state}, isDecrypting ${isDecrypting}`); 162 return ResultMsg.getErrMsg(Constants.ERR_CODE_FILE_IS_DECRYPTING_ERROR); 163 } 164 if (state === DecryptState.ENCRYPTING) { 165 HiLog.info(TAG, 'in encrypting'); 166 return ResultMsg.getErrMsg(Constants.ERR_JS_APP_ENCRYPTION_REJECTED); 167 } 168 return ResultMsg.buildSuccess(); 169 } 170 171 private async checkAndGetState(openDlpFileData: OpenDlpFileData): Promise<Result<DecryptState>> { 172 const manager = OpenDlpFileManager.getInstance(); 173 const getStatusRet = manager.getStatus(openDlpFileData.uri); 174 if (getStatusRet.errcode !== Constants.ERR_CODE_SUCCESS || !getStatusRet.result) { 175 HiLog.error(TAG, 'checkAndGetState getStatus error'); 176 return ResultMsg.buildMsg(getStatusRet.errcode, getStatusRet.errmsg); 177 } 178 179 const checkRet = this.checkIfContinue(getStatusRet.result.state); 180 if (checkRet.errcode !== Constants.ERR_CODE_SUCCESS) { 181 HiLog.error(TAG, 'checkIfContinue not continue'); 182 return ResultMsg.buildMsg(checkRet.errcode, checkRet.errmsg); 183 } 184 return ResultMsg.buildSuccess(getStatusRet.result.state); 185 } 186 187 public async processErrcode(error: BusinessError, decryptContent?: DecryptContent): Promise<Result<void>> { 188 await ErrorManager.getInstance().startHandleError(decryptContent?.openDlpFileData?.requestId ?? '', error); 189 if (decryptContent) { 190 clearDlpInfoByError(decryptContent); 191 this.sendDlpFileOpenFault(error, decryptContent); 192 } 193 return ResultMsg.buildSuccess(); 194 } 195 196 private batchRefresh(context: common.ServiceExtensionContext) { 197 HiLog.info(TAG, 'begin batchRefresh'); 198 const connectService: CredConnectService = new CredConnectService(context); 199 connectService.connectServiceShareAbility(Constants.COMMAND_BATCH_REFRESH); 200 } 201 202 private sendDlpFileOpenFault(error: BusinessError, decryptContent: DecryptContent): void { 203 let err: BusinessError = { code: error.code, message: error.message, name: '' }; 204 if (err.code === Constants.ERR_JS_USER_NO_PERMISSION_2B || 205 err.code === Constants.ERR_JS_USER_NO_PERMISSION_2C || 206 err.code === Constants.ERR_JS_FILE_EXPIRATION) { 207 err.message = Constants.NO_PERMISSION_OR_EXPIRATION; 208 } 209 DlpFileOpenReport.sendDlpFileOpenFault(err.code, decryptContent, err); 210 } 211}