• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { BusinessError } from '@ohos.base';
17import Want from '@ohos.app.ability.Want';
18import fileUri from '@ohos.file.fileuri';
19import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
20import fs from '@ohos.file.fs';
21import dlpPermission from '@ohos.dlpPermission';
22import IdlDlpRpcServiceStub from './data/IIdlDlpRpcServiceTs/id_dlpRpc_service_stub';
23import {
24  closeDlpFileCallback,
25  sandBoxLinkFileCallback,
26  fileOpenHistoryCallback,
27  linkSetCallback,
28  genDlpFileCallback,
29  openDlpFileCallback,
30  recoverDlpFileCallback,
31  replaceDlpLinkFileCallback,
32  resumeFuseLinkCallback,
33  stopFuseLinkCallback
34} from './data/IIdlDlpRpcServiceTs/i_id_dlpRpc_service';
35import IDLDLPProperty from '../common/dlpClass';
36import { IAuthUser } from '../common/dlpClass';
37import Constants from '../common/constant';
38import { HiLog } from '../common/HiLog';
39import FileUtil from '../common/external/FileUtil';
40import { DecryptState, OpenDlpFileManager } from '../OpenDlpFile/manager/OpenDlpFileManager';
41import DecryptContent from '../OpenDlpFile/data/DecryptContent';
42import FileUtils from '../common/FileUtils/FileUtils';
43
44const TAG = 'DlpRpcServiceStub';
45
46class DlpRpcServiceStub extends IdlDlpRpcServiceStub {
47  private dlpFileMap: Map<string, dlpPermission.DLPFile | null> = new Map<string, dlpPermission.DLPFile | null>();
48  private inFile: fs.File | undefined = undefined;
49  private outFile: fs.File | undefined = undefined;
50
51  constructor(des: string) {
52    super(des);
53  }
54
55  async getOpeningFile(inputUri: string): Promise<dlpPermission.DLPFile | null> {
56    const manager = OpenDlpFileManager.getInstance();
57    const getRet = manager.getHasDecryptedContent(inputUri);
58    if (getRet.errcode === Constants.ERR_CODE_SUCCESS && getRet.result) {
59      const decryptContent = getRet.result;
60      return decryptContent.dlpFile;
61    }
62
63    if (this.dlpFileMap.has(inputUri)) {
64      let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(inputUri) as dlpPermission.DLPFile;
65      return dlpFile;
66    }
67    return null;
68  }
69
70  async genDlpFile(inputUri: string, outputUri: string, dlp: IDLDLPProperty, callback: genDlpFileCallback
71  ): Promise<void> {
72    HiLog.info(TAG, 'genDlpFile in service');
73    let result: Record<string, number>;
74    try {
75      result = await this.genDlpFileFd(inputUri, outputUri);
76    } catch (error) {
77      callback(error);
78      return;
79    }
80    let dlpP: dlpPermission.DLPProperty = {
81      'ownerAccount': dlp.ownerAccount,
82      'ownerAccountID': dlp.ownerAccountID,
83      'ownerAccountType': dlp.ownerAccountType,
84      'authUserList': dlp.authUserList,
85      'contactAccount': dlp.contactAccount,
86      'offlineAccess': dlp.offlineAccess,
87      'everyoneAccessList': dlp.everyoneAccessList,
88      'expireTime': dlp.expireTime
89    }
90    try {
91      let dlpFile = await dlpPermission.generateDLPFile(result.inFileFd, result.outFileFd, dlpP);
92      if (!this.dlpFileMap.has(outputUri)) {
93        this.dlpFileMap.set(outputUri, dlpFile);
94        this.addEncryptingState(outputUri);
95        AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap);
96      } else {
97        let rawDlpFile = this.dlpFileMap.get(outputUri) ?? null;
98        if (rawDlpFile !== null) {
99          try {
100            await rawDlpFile.closeDLPFile();
101          } catch (err) {
102            HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`);
103          }
104        }
105        this.dlpFileMap.delete(outputUri);
106        this.dlpFileMap.set(outputUri, dlpFile);
107        this.addEncryptingState(outputUri);
108        AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap);
109      }
110      callback(0);
111    } catch (err) {
112      HiLog.error(TAG, `genDlpFile file: ${JSON.stringify(err)}`);
113      await this.closeFile();
114      callback((err as BusinessError).code);
115    }
116  }
117
118  async closeFile(): Promise<void> {
119    FileUtil.closeSync(this.inFile);
120    FileUtil.closeSync(this.outFile);
121  }
122
123  async genDlpFileFd(inputUri: string, outputUri: string): Promise<Record<string, number>> {
124    return new Promise(async (resolve, reject) => {
125      let inFileFd: number = -1;
126      let outFileFd: number = -1;
127      try {
128        this.inFile = await fs.open(inputUri, fs.OpenMode.READ_WRITE);
129        inFileFd = this.inFile.fd;
130      } catch (error) {
131        HiLog.error(TAG, `open: ${FileUtils.getFileNameByUri(inputUri)}, failed: ${JSON.stringify(error)}`);
132        reject((error as BusinessError).code);
133        return;
134      }
135      let uriInfo: fileUri.FileUri = new fileUri.FileUri('');
136      try {
137        uriInfo = new fileUri.FileUri(outputUri);
138      } catch (err) {
139        HiLog.error(TAG, `fileUri fail: ${JSON.stringify(err)}`);
140      }
141      try {
142        this.outFile = await fs.open(outputUri, fs.OpenMode.READ_WRITE);
143        outFileFd = this.outFile.fd;
144      } catch (error) {
145        FileUtil.closeSync(this.inFile);
146        FileUtil.unlinkSync(uriInfo.path);
147        reject((error as BusinessError).code);
148        return;
149      }
150      let result = {
151        'inFileFd': inFileFd,
152        'outFileFd': outFileFd
153      } as Record<string, number>;
154      resolve(result);
155    })
156  }
157
158  async openDlpFile(srcUri: string, callerAppId: string, callback: openDlpFileCallback): Promise<void> {
159    HiLog.info(TAG, `openDlpFile start: ${FileUtils.getFileNameByUri(srcUri)}`);
160    let inFile = await fs.open(srcUri, fs.OpenMode.READ_WRITE);
161    let dlpFile: dlpPermission.DLPFile;
162    let authUserListNew: IAuthUser[] = [];
163    try {
164      dlpFile = await dlpPermission.openDLPFile(inFile.fd, callerAppId);
165      dlpFile.dlpProperty.authUserList?.forEach(item => {
166        authUserListNew.push(
167          new IAuthUser(
168            item.authAccount,
169            item.authAccountType,
170            item.dlpFileAccess,
171            item.permExpiryTime
172          ))
173      })
174      let _dlp = new IDLDLPProperty(
175        dlpFile.dlpProperty.ownerAccount,
176        dlpFile.dlpProperty.ownerAccountID,
177        dlpFile.dlpProperty.ownerAccountType,
178        authUserListNew,
179        dlpFile.dlpProperty.contactAccount,
180        dlpFile.dlpProperty.offlineAccess,
181        dlpFile.dlpProperty.everyoneAccessList ?? [],
182        dlpFile.dlpProperty.expireTime ?? 0,
183      );
184      callback(0, _dlp, '');
185      if (!this.dlpFileMap.has(srcUri)) {
186        this.dlpFileMap.set(srcUri, dlpFile);
187        this.addEncryptingState(srcUri);
188        AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap);
189      } else {
190        HiLog.info(TAG, `map is overwrite`);
191        this.dlpFileMap.delete(srcUri);
192        this.dlpFileMap.set(srcUri, dlpFile);
193        this.addEncryptingState(srcUri);
194        AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap);
195      }
196    } catch (err) {
197      let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0);
198      callback((err as BusinessError).code, _dlp, (err as BusinessError).message);
199    } finally {
200      FileUtil.closeSync(inFile);
201    }
202  }
203
204  async stopFuseLink(uri: string, callback: stopFuseLinkCallback): Promise<void> {
205    HiLog.info(TAG, `stopFuseLink start filename: ${FileUtils.getFileNameByUri(uri)}`);
206    let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(uri);
207    if (dlpFile !== null) {
208      await dlpFile.stopFuseLink();
209    } else {
210      HiLog.error(TAG, `stopFuseLink not find filename: ${FileUtils.getFileNameByUri(uri)}`);
211      callback(-1);
212    }
213  }
214
215  async resumeFuseLink(uri: string, callback: resumeFuseLinkCallback): Promise<void> {
216    HiLog.info(TAG, `resumeFuseLink start`);
217    let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(uri);
218    if (dlpFile !== null) {
219      await dlpFile.resumeFuseLink();
220    } else {
221      HiLog.error(TAG, `resumeFuseLink not findfilename: ${FileUtils.getFileNameByUri(uri)}`);
222      callback(-1);
223    }
224  }
225
226  async replaceDlpLinkFile(srcUri: string, linkFileName: string, callback: replaceDlpLinkFileCallback): Promise<void> {
227    if (this.dlpFileMap.has(srcUri)) {
228      let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(srcUri) as dlpPermission.DLPFile;
229      const manager = OpenDlpFileManager.getInstance();
230      const getRet = manager.getHasDecryptedContentByLinkFileName(linkFileName);
231      if (getRet.errcode === Constants.ERR_CODE_SUCCESS && getRet.result) {
232        const decryptContent = getRet.result;
233        decryptContent.dlpFile = dlpFile;
234      }
235
236      try {
237        await dlpFile.replaceDLPLinkFile(linkFileName);
238      } catch (error) {
239        HiLog.wrapError(TAG, error, 'replaceDLPLinkFile error');
240      }
241    } else {
242      HiLog.error(TAG, `replaceDLPLinkFile not find: ${FileUtils.getFileNameByUri(srcUri)}`);
243      callback(-1);
244    }
245  }
246
247  async recoverDlpFile(srcUri: string, pathUri: string, callback: recoverDlpFileCallback): Promise<void> {
248    let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(srcUri);
249    if (dlpFile !== null) {
250      let inFile: fs.File | undefined;
251      try {
252        inFile = await fs.open(pathUri, fs.OpenMode.READ_WRITE);
253        await dlpFile.recoverDLPFile(inFile.fd);
254      } catch (err) {
255        HiLog.error(TAG, `recoverDlpFileInner4: ${JSON.stringify(err)}`);
256        callback((err as BusinessError).code);
257      } finally {
258        FileUtil.closeSync(inFile);
259      }
260    } else {
261      HiLog.error(TAG, `recoverDlpFile not find: ${FileUtils.getFileNameByUri(srcUri)}`);
262      callback(-1);
263    }
264  }
265
266  async closeDlpFile(srcUri: string, callback: closeDlpFileCallback): Promise<void> {
267    HiLog.info(TAG, `closeDlpFile start`);
268    let dlpFile: dlpPermission.DLPFile | null = await this.getOpeningFile(srcUri);
269    if (dlpFile !== null) {
270      try {
271        await dlpFile.closeDLPFile();
272        if (this.dlpFileMap.has(srcUri)) {
273          this.dlpFileMap.delete(srcUri);
274          this.deleteEncryptingState(srcUri);
275          AppStorage.setOrCreate('dlpFileMap', this.dlpFileMap);
276        }
277        callback(0);
278      } catch (err) {
279        HiLog.error(TAG, `closeDlpFile file: ${JSON.stringify(err)}`);
280        callback((err as BusinessError).code);
281      }
282    }
283  }
284
285  async sandBoxLinkFile(linkFileName: string, callerToken: number, callback: sandBoxLinkFileCallback): Promise<void> {
286    let _dlp = new IDLDLPProperty('', '', 0, [], '', true, [], 0);
287    const manager = OpenDlpFileManager.getInstance();
288    const getRet = manager.getHasDecryptedContentByLinkFileName(linkFileName);
289    if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) {
290      HiLog.error(TAG, `request from sandbox, but can not find dlp file by linkFileName: ${linkFileName}`);
291      callback(-1, _dlp, '');
292      return;
293    }
294    const decryptContent: DecryptContent = getRet.result;
295    if (decryptContent.appInfo.tokenID !== callerToken) {
296      HiLog.error(TAG, `found file, but token invalid: ${linkFileName}`);
297      callback(-1, _dlp, '');
298      return;
299    }
300
301    let authUserListNew: IAuthUser[] = [];
302    const dlpFile = decryptContent.dlpFile;
303    dlpFile.dlpProperty.authUserList?.forEach(item => {
304      authUserListNew.push(
305        new IAuthUser(
306          item.authAccount,
307          item.authAccountType,
308          item.dlpFileAccess,
309          item.permExpiryTime
310        ))
311    })
312
313    _dlp = new IDLDLPProperty(
314      dlpFile.dlpProperty.ownerAccount,
315      dlpFile.dlpProperty.ownerAccountID,
316      dlpFile.dlpProperty.ownerAccountType,
317      authUserListNew,
318      dlpFile.dlpProperty.contactAccount,
319      dlpFile.dlpProperty.offlineAccess,
320      dlpFile.dlpProperty.everyoneAccessList ?? [],
321      dlpFile.dlpProperty.expireTime ?? 0
322    );
323    let fileUri = decryptContent.openDlpFileData.uri;
324    callback(0, _dlp, fileUri.toString());
325  }
326
327  async fileOpenHistory(uri: string, callback: fileOpenHistoryCallback): Promise<void> {
328    HiLog.info(TAG, 'fileOpenHistory start');
329    const manager = OpenDlpFileManager.getInstance();
330    const getRet = manager.getHasDecryptedContent(uri);
331    if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) {
332      callback(-1);
333    } else {
334      callback(0);
335    }
336  }
337
338  async linkSet(uri: string, callback: linkSetCallback): Promise<void> {
339    HiLog.info(TAG, 'linkSet start');
340    const manager = OpenDlpFileManager.getInstance();
341    const getRet = manager.getHasDecryptedContent(uri);
342    if (getRet.errcode !== Constants.ERR_CODE_SUCCESS || !getRet.result) {
343      callback(-1);
344    } else {
345      callback(0);
346    }
347  }
348
349  private async addEncryptingState(uri: string): Promise<void> {
350    const manager = OpenDlpFileManager.getInstance();
351    const setRet = await manager.setStatus(uri, { state: DecryptState.ENCRYPTING });
352    if (setRet.errcode !== Constants.ERR_CODE_SUCCESS) {
353      HiLog.error(TAG, `addEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} failed.`);
354    } else {
355      HiLog.info(TAG, `addEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} success.`);
356    }
357  }
358
359  private async deleteEncryptingState(uri: string): Promise<void> {
360    const manager = OpenDlpFileManager.getInstance();
361    const deleteRet = await manager.deleteStatus(uri);
362    if (deleteRet.errcode !== Constants.ERR_CODE_SUCCESS) {
363      HiLog.error(TAG, `deleteEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} failed.`);
364    } else {
365      HiLog.info(TAG, `deleteEncryptingState filename: ${FileUtils.getFileNameByUri(uri)} success.`);
366    }
367  }
368}
369
370export default class DlpFileProcessAbility extends ServiceExtensionAbility {
371  onCreate(want: Want) {
372    HiLog.info(TAG, `onCreate, want: ${want.abilityName}`);
373  }
374
375  onRequest(want: Want, startId: number) {
376    HiLog.info(TAG, `onRequest, want: ${want.abilityName}`);
377  }
378
379  onConnect(want: Want) {
380    HiLog.info(TAG, `service onConnect, want: ${want.abilityName}`);
381    return new DlpRpcServiceStub('dlpRpc service stub');
382  }
383
384  onDisconnect(want: Want): void {
385    HiLog.info(TAG, `onDisconnect, want: ${want.abilityName}`);
386  }
387
388  onDestroy(): void {
389    HiLog.info(TAG, 'onDestroy');
390  }
391}