• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}