• 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 { HiLog } from '../../common/HiLog';
17import Result from '../../common/Result';
18import { ResultMsg } from '../../common/ResultMsg';
19import DecryptContent from '../data/DecryptContent';
20import { ArkTSUtils } from '@kit.ArkTS';
21import Constants from '../../common/constant';
22import FileUtils from '../../common/FileUtils/FileUtils';
23
24const TAG: string = 'OpenDlpFileManager';
25
26export enum DecryptState {
27  NOT_STARTED = 1,
28  DECRYPTING = 2,
29  DECRYPTED = 3,
30  ENCRYPTING = 4,
31}
32
33export interface DecryptStatus {
34  state: DecryptState;
35  startTime?: number;
36}
37
38export class OpenDlpFileManager {
39  private static instance: OpenDlpFileManager;
40  private statusMap: Map<string, DecryptStatus>;
41  private contentMap: Map<string, DecryptContent>;
42  private lock: ArkTSUtils.locks.AsyncLock;
43
44  private constructor() {
45    this.statusMap = new Map<string, DecryptStatus>();
46    this.contentMap = new Map<string, DecryptContent>();
47    this.lock = new ArkTSUtils.locks.AsyncLock();
48  }
49
50  static getInstance(): OpenDlpFileManager {
51    if (!OpenDlpFileManager.instance) {
52      OpenDlpFileManager.instance = new OpenDlpFileManager();
53    }
54    return OpenDlpFileManager.instance;
55  }
56
57  public async setStatus(uri: string, status: DecryptStatus): Promise<Result<void>> {
58    HiLog.info(TAG, `setStatus: filename: ${FileUtils.getFileNameByUri(uri)}, status = ${status.state}`);
59    try {
60      await this.lock.lockAsync(() => {
61        this.statusMap.set(uri, status);
62      });
63      return ResultMsg.buildSuccess();
64    } catch (error) {
65      HiLog.wrapError(TAG, error, 'setStatus lockAsync error');
66      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
67    }
68  }
69
70  public getStatus(uri: string): Result<DecryptStatus> {
71    let status: DecryptStatus | undefined;
72    status = this.statusMap.get(uri) || { state: DecryptState.NOT_STARTED };
73    HiLog.info(TAG, `getStatus: filename: ${FileUtils.getFileNameByUri(uri)}, status = ${status.state}`);
74    return ResultMsg.buildSuccess(status);
75  }
76
77  public async deleteStatus(uri: string): Promise<Result<void>> {
78    HiLog.info(TAG, `deleteStatus: filename: ${FileUtils.getFileNameByUri(uri)}`);
79    try {
80      await this.lock.lockAsync(() => {
81        this.statusMap.delete(uri);
82      });
83      return ResultMsg.buildSuccess();
84    } catch (error) {
85      HiLog.wrapError(TAG, error, 'deleteStatus lockAsync error');
86      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
87    }
88  }
89
90  public async deleteStatusButNotHasDecrypted(uri: string): Promise<Result<void>> {
91    HiLog.info(TAG, `deleteStatusButNotHasDecrypted: filename: ${FileUtils.getFileNameByUri(uri)}`);
92    try {
93      const status = this.statusMap.get(uri) || { state: DecryptState.NOT_STARTED };
94      if (status.state !== DecryptState.DECRYPTED) {
95        await this.lock.lockAsync(() => {
96          HiLog.info(TAG, `delete filename: ${FileUtils.getFileNameByUri(uri)}`);
97          this.statusMap.delete(uri);
98        });
99      }
100      return ResultMsg.buildSuccess();
101    } catch (error) {
102      HiLog.wrapError(TAG, error, 'deleteStatus lockAsync error');
103      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
104    }
105  }
106
107  public async addDecryptContent(uri: string, content: DecryptContent): Promise<Result<void>> {
108    HiLog.info(TAG, `addDecryptContent filename: ${FileUtils.getFileNameByUri(uri)}`);
109    try {
110      await this.lock.lockAsync(() => {
111        this.contentMap.set(uri, content);
112        this.statusMap.set(uri, { state: DecryptState.DECRYPTED });
113      });
114      return ResultMsg.buildSuccess();
115    } catch (error) {
116      HiLog.wrapError(TAG, error, 'setContent lockAsync error');
117      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
118    }
119  }
120
121  public getHasDecryptedContent(uri: string): Result<DecryptContent> {
122    let content = this.contentMap.get(uri);
123    if (!content) {
124      HiLog.error(TAG, 'getHasDecryptedContent error');
125      return ResultMsg.getErrMsg(Constants.ERR_CODE_PARAMS_CHECK_ERROR);
126    }
127    return ResultMsg.buildSuccess(content);
128  }
129
130  private getContentByLinkFileName(linkFileName: string): DecryptContent | undefined {
131    for (const entry of this.contentMap) {
132      if (entry[1].linkFileName === linkFileName) {
133        HiLog.info(TAG, 'getContentByLinkFileName found');
134        return entry[1];
135      }
136    }
137    HiLog.info(TAG, 'getContentByLinkFileName not found');
138    return undefined;
139  }
140
141  public getHasDecryptedContentByLinkFileName(linkFileName: string): Result<DecryptContent> {
142    const content = this.getContentByLinkFileName(linkFileName);
143    return ResultMsg.buildSuccess(content);
144  }
145
146  private getContentByTokenId(tokenId: number): DecryptContent | undefined {
147    for (const entry of this.contentMap) {
148      if (entry[1].appInfo.tokenID === tokenId) {
149        HiLog.info(TAG, 'getContentByTokenId found');
150        return entry[1];
151      }
152    }
153    HiLog.info(TAG, 'getContentByTokenId not found');
154    return undefined;
155  }
156
157  public getHasDecryptedContentByTokenId(tokenId: number): Result<DecryptContent> {
158    const content = this.getContentByTokenId(tokenId);
159    return ResultMsg.buildSuccess(content);
160  }
161
162  private removeMatchingEntries(bundleName: string, sandboxAppIndex: number): Set<DecryptContent> {
163    let decryptContents = new Set<DecryptContent>();
164    const entries = Array.from(this.contentMap.entries());
165    entries.forEach(entry => {
166      const key = entry[0];
167      const value = entry[1];
168      if (value.openDlpFileData.sandboxBundleName === bundleName &&
169        value.appInfo.appIndex === sandboxAppIndex) {
170        decryptContents.add(value);
171        this.contentMap.delete(key);
172        this.statusMap.delete(key);
173      }
174    });
175    return decryptContents;
176  }
177
178  public async removeByBundleNameAndAppIndex(bundleName: string, sandboxAppIndex: number):
179    Promise<Result<Set<DecryptContent>>> {
180    try {
181      let decryptContents: Set<DecryptContent> = new Set<DecryptContent>();
182      await this.lock.lockAsync(() => {
183        decryptContents = this.removeMatchingEntries(bundleName, sandboxAppIndex);
184      });
185      return ResultMsg.buildSuccess(decryptContents);
186    } catch (error) {
187      HiLog.wrapError(TAG, error, 'removeByBundleNameAndAppIndex lockAsync error');
188      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
189    }
190  }
191
192  public getHasDecryptedSize(): Result<number> {
193    const size = this.contentMap.size;
194    return ResultMsg.buildSuccess(size);
195  }
196
197  public async removeAllByUri(uri: string): Promise<Result<void>> {
198    try {
199      await this.lock.lockAsync(() => {
200        this.statusMap.delete(uri);
201        this.contentMap.delete(uri);
202      });
203      return ResultMsg.buildSuccess();
204    } catch (error) {
205      HiLog.wrapError(TAG, error, 'removeContentByUri lockAsync error');
206      return ResultMsg.getErrMsg(Constants.ERR_CODE_GET_LOCK_ASYNC_ERROR);
207    }
208  }
209}