• 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 */
15import UIAbility from '@ohos.app.ability.UIAbility';
16import datafile from '@ohos.file.fileAccess';
17import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
18import { Permissions } from '@ohos.abilityAccessCtrl';
19import dlpPermission from '@ohos.dlpPermission';
20import emitter from '@ohos.events.emitter';
21import deviceInfo from '@ohos.deviceInfo';
22import Constants from '../common/constant';
23import {
24  getAuthPerm,
25  checkAccountLogin,
26  getOsAccountInfo,
27  judgeIsSandBox,
28  getFileFd,
29  isValidPath
30} from '../common/utils';
31import GlobalContext from '../common/GlobalContext'
32import { Configuration } from '@ohos.app.ability.Configuration';
33import Want from '@ohos.app.ability.Want';
34import AbilityConstant from '@ohos.app.ability.AbilityConstant';
35import { BusinessError } from '@ohos.base';
36import window from '@ohos.window';
37import osAccount from '@ohos.account.osAccount';
38import common from '@ohos.app.ability.common';
39
40const PHONE = 'phone';
41const TAG = '[DLPManager_Main]';
42let permissionList: Array<Permissions> = [
43  'ohos.permission.READ_MEDIA',
44  'ohos.permission.WRITE_MEDIA',
45  'ohos.permission.FILE_ACCESS_MANAGER'
46];
47
48let direction: number = -1;
49let languageValue: string = 'zh';
50
51export default class MainAbility extends UIAbility {
52  authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY;
53  callerToken:number = 0;
54
55  async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
56    console.info(TAG, 'onCreate');
57    GlobalContext.store('abilityWant', want);
58    GlobalContext.store('context', this.context);
59    GlobalContext.store('domainAccount', deviceInfo.deviceType === PHONE ? false : true);
60    GlobalContext.store('uri', want.uri ?? '');
61
62    GlobalContext.store('dsHelper', datafile.createFileAccessHelper(this.context));
63    direction = this.context.config.direction ?? -1;
64    languageValue = this.context.config.language ?? 'zh';
65    if (!GlobalContext.load('fileOpenHistoryFromMain')) {
66      GlobalContext.store('fileOpenHistoryFromMain', new Map<string, (string | number)[]>());
67    }
68    if (!GlobalContext.load('linkSet')) {
69      GlobalContext.store('linkSet', new Set<string>());
70    }
71  }
72  onConfigurationUpdate(newConfig: Configuration): void {
73    if (direction !== newConfig.direction) {
74      direction = newConfig.direction ?? -1;
75    }
76    if (languageValue !== newConfig.language) {
77      languageValue = newConfig.language ?? 'zh';
78    }
79    let eventData: emitter.EventData = {
80      data: {
81        'direction': direction,
82      }};
83    let innerEvent: emitter.InnerEvent = {
84      eventId: Constants.ENCRYPTION_EMIT_DIRECTION_STATUS,
85      priority: emitter.EventPriority.HIGH
86    };
87    emitter.emit(innerEvent, eventData);
88
89    let languageData: emitter.EventData = {
90      data: {
91        'languageValue': languageValue,
92      }};
93    let languageEvent: emitter.InnerEvent = {
94      eventId: Constants.ENCRYPTION_EMIT_LANGUAGE_VALUE,
95      priority: emitter.EventPriority.HIGH
96    };
97    emitter.emit(languageEvent, languageData);
98  }
99
100  onDestroy(): void {
101    console.info(TAG, 'onDestroy');
102    if (GlobalContext.load('fileOpenHistoryFromMain')) {
103      (GlobalContext.load('fileOpenHistoryFromMain') as Map<string, Object>).delete(GlobalContext.load('uri') as string)
104    }
105  }
106
107  onNewWant(want: Want) {
108    console.log(TAG, 'onNewWant', JSON.stringify(want));
109    GlobalContext.store('abilityWant', want);
110    GlobalContext.store('uri', (GlobalContext.load('abilityWant') as Want).uri as string);
111
112    this.getNewWantPage();
113  }
114
115  async showErrorDialogAndExit(error: BusinessError): Promise<void> {
116    let abilityWant = GlobalContext.load('abilityWant') as Want;
117    if (abilityWant.parameters) {
118      abilityWant.parameters.error = error;
119    }
120    let context: common.UIAbilityContext = GlobalContext.load('context') as common.UIAbilityContext;
121    GlobalContext.store('alertContext', context);
122    (GlobalContext.load('windowStage') as window.WindowStage).loadContent('pages/alert', (err: BusinessError) => {
123      if (err.code !== 0) {
124        console.error(TAG, 'loadContent failed', err.code, err.message);
125      }
126    });
127  }
128
129  async gotoPage(windowStage: window.WindowStage, accountInfo: osAccount.OsAccountInfo): Promise<void> {
130    let accountName: string = (GlobalContext.load('domainAccount') as boolean) ? accountInfo.domainInfo.accountName : accountInfo.distributedInfo.name;
131    this.authPerm = getAuthPerm(accountName, (GlobalContext.load('dlpFile') as dlpPermission.DLPFile).dlpProperty);
132    console.info(TAG, accountName, 'has dlp access', JSON.stringify(this.authPerm));
133
134    AppStorage.SetOrCreate('authPerm', this.authPerm);
135    AppStorage.SetOrCreate<string>('contactAccount', (GlobalContext.load('dlpFile') as dlpPermission.DLPFile).dlpProperty.contactAccount);
136    if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY ||
137      this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) {
138      await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
139      return;
140    }
141    if (this.authPerm === dlpPermission.DLPFileAccess.FULL_CONTROL) {
142      windowStage.loadContent('pages/changeEncryption', (err: BusinessError) =>{
143        if (err.code !== 0) {
144          console.error(TAG, 'loadContent failed', err.code, err.message);
145        }
146      });
147    } else {
148      windowStage.loadContent('pages/permissionStatus', (err: BusinessError) =>{
149        if (err.code !== 0) {
150          console.error(TAG, 'loadContent failed', err.code, err.message);
151        }
152      });
153    }
154    windowStage.getMainWindow().then((win: window.Window) => {
155      win.setBackgroundColor('#00FFFFFF');
156    });
157  }
158
159  async findDlpFile(): Promise<void> {
160    return new Promise(async (resolve, reject) => {
161      let abilityWant: Want = GlobalContext.load('abilityWant') as Want;
162      const linkFileName: string = (abilityWant.parameters?.linkFileName as Record<string, string>)?.name;
163      let sandbox2linkFile:Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>;
164      for (let value of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) {
165        for (let linkFile of value) {
166          if (linkFile[Constants.FILE_OPEN_HISTORY_ONE] === linkFileName) {
167            if (this.callerToken !== linkFile[Constants.FILE_OPEN_HISTORY_THREE]) {
168              console.error(TAG, 'found file, buf token invalid', linkFileName);
169              await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
170              reject();
171              return;
172            }
173            GlobalContext.store('dlpFile', linkFile[Constants.FILE_OPEN_HISTORY_ZERO]);
174            GlobalContext.store('dlpFd', linkFile[Constants.FILE_OPEN_HISTORY_TWO]);
175            let dlpFileName: string = (abilityWant.parameters?.fileName as Record<string, string>)?.name;
176            GlobalContext.store('dlpFileName', dlpFileName);
177            GlobalContext.store('linkFileName', linkFileName);
178            console.info(TAG, 'find dlp file', dlpFileName, GlobalContext.load('dlpFd'));
179            resolve();
180            return;
181          }
182        }
183      }
184      console.error(TAG, 'request from sandbox, but can not find dlp file by linkFileName', linkFileName);
185      await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
186      reject();
187    });
188  }
189
190  async openDlpFile(): Promise<void> {
191    return new Promise(async (resolve, reject) => {
192      try {
193        let dlpFileName: string = ((GlobalContext.load('abilityWant')as Want).parameters?.fileName as Record<string, string>)?.name;
194        GlobalContext.store('dlpFileName', dlpFileName);
195        let dlpFd: number = getFileFd(GlobalContext.load('uri') as string);
196        GlobalContext.store('dlpFd', dlpFd);
197        console.info(TAG, 'openDLPFile', dlpFileName, dlpFd);
198        GlobalContext.store('dlpFile', await dlpPermission.openDLPFile(dlpFd));
199        resolve();
200      } catch (err) {
201        console.error(TAG, 'openDLPFile', GlobalContext.load('dlpFileName') as string, 'failed', (err as BusinessError).code, (err as BusinessError).message);
202        await this.showErrorDialogAndExit(err as BusinessError);
203        reject(err);
204      }
205    });
206  }
207
208  checkValidWant(): boolean {
209    let parameters = (GlobalContext.load('abilityWant') as Want).parameters;
210    if (parameters === undefined) {
211      console.error(TAG, 'need parameters in want');
212      return false;
213    }
214    if (parameters.fileName === undefined) {
215      console.error(TAG, 'need fileName in want.parameters');
216      return false;
217    }
218    if ((parameters.fileName as Record<string, string>).name === undefined) {
219      console.error(TAG, 'need name in want.parameters.fileName');
220      return false;
221    }
222    if ((GlobalContext.load('abilityWant') as Want).uri === undefined) {
223      console.error(TAG, 'need uri in want');
224      return false;
225    }
226    this.callerToken = parameters['ohos.aafwk.param.callerToken'] as number;
227    let callerBundleName: string = parameters['ohos.aafwk.param.callerBundleName'] as string;
228    if (this.callerToken === undefined || callerBundleName === undefined) {
229      console.error(TAG, 'need caller info in want.parameters');
230      return false;
231    }
232    let uri = String((GlobalContext.load('abilityWant') as Want).uri);
233    if ((GlobalContext.load('linkSet') as Set<string>).has(uri)) {
234      console.error(TAG, 'invalid uri for opened link uri');
235      return false;
236    }
237
238    if (uri.indexOf(Constants.FUSE_PATH) !== -1 || !isValidPath(uri)) {
239      console.error(TAG, 'invalid uri in want.uri');
240      return false;
241    }
242    return true;
243  }
244
245  async getNewWantPage(): Promise<void> {
246    console.log(TAG, 'getNewWantPage start');
247    let windowStage: window.WindowStage = GlobalContext.load('windowStage') as window.WindowStage;
248    if (!this.checkValidWant()) {
249      await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_PARAM_ERROR } as BusinessError);
250      return;
251    }
252    let accountInfo: osAccount.OsAccountInfo;
253    try {
254      accountInfo = await getOsAccountInfo();
255    } catch (err) {
256      console.error(TAG, 'getOsAccountInfo failed', (err as BusinessError).code, (err as BusinessError).message);
257      await this.showErrorDialogAndExit({ code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError);
258      return;
259    }
260    if (!checkAccountLogin(accountInfo)) {
261      await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_NO_ACCOUNT_ERROR } as BusinessError);
262      return;
263    }
264    let requestIsFromSandBox: boolean = await judgeIsSandBox();
265    GlobalContext.store('requestIsFromSandBox', requestIsFromSandBox);
266    console.info(TAG, 'request is from sandbox', requestIsFromSandBox);
267    if (requestIsFromSandBox) {
268      try {
269        await this.findDlpFile();
270      } catch {
271        return;
272      }
273    } else {
274      let fileName: string = ((GlobalContext.load('abilityWant') as Want).parameters?.fileName as Record<string, string>)?.name;
275      let isDlpSuffix: boolean = fileName.endsWith('.dlp');
276      if (!isDlpSuffix) {
277        console.info(TAG, fileName, 'is not a dlp file');
278        GlobalContext.store('originFileName', fileName);
279        GlobalContext.store('originFd', getFileFd(GlobalContext.load('uri') as string));
280        windowStage.loadContent('pages/encryptionProtection', (err: BusinessError) =>{
281          if (err.code !== 0) {
282            console.error(TAG, 'loadContent failed', err.code, err.message);
283          }
284        });
285        windowStage.getMainWindow().then((win: window.Window) => {
286          win.setBackgroundColor('#00FFFFFF');
287        });
288        return;
289      } else {
290        let uri: string = GlobalContext.load('uri') as string;
291        if ((GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>)?.has(uri)) {
292          await this.showErrorDialogAndExit({ code: Constants.ERR_JS_APP_OPEN_REJECTED } as BusinessError);
293          return;
294        }
295        try {
296          await this.openDlpFile();
297        } catch {
298          return;
299        }
300        GlobalContext.store('fileOpenHistoryFromMain', new Map<string, (string | number)[]>());
301        let fileOpenHistoryFromMain: Map<string, (string | number)[]> = GlobalContext.load('fileOpenHistoryFromMain') as Map<string, (string | number)[]>;
302        fileOpenHistoryFromMain.set(uri, [uri, GlobalContext.load('dlpFileName') as string, GlobalContext.load('dlpFd') as number]);
303        console.log(TAG, 'fileOpenHistoryFromMain add', JSON.stringify(fileOpenHistoryFromMain));
304      }
305    }
306    this.gotoPage(windowStage, accountInfo);
307}
308
309  async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
310    console.info(TAG, 'onWindowStageCreate');
311    GlobalContext.store('windowStage', windowStage);
312    try {
313      let atManager = abilityAccessCtrl.createAtManager();
314      await atManager.requestPermissionsFromUser(GlobalContext.load('context') as common.UIAbilityContext, permissionList);
315    } catch (err) {
316      console.error(TAG, 'requestPermissionsFromUser failed', err.code, err.message);
317      return;
318    }
319    this.getNewWantPage();
320  }
321
322  onWindowStageDestroy(): void {
323    console.info(TAG, 'onWindowStageDestroy');
324  }
325
326  onForeground(): void {
327    console.info(TAG, 'onForeground');
328  }
329
330  onBackground() {
331    console.info(TAG, 'onBackground');
332  }
333};
334