• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023-2024 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 UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
17import UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility';
18import dlpPermission from '@ohos.dlpPermission';
19import emitter from '@ohos.events.emitter';
20import Want from '@ohos.app.ability.Want';
21import { BusinessError } from '@ohos.base';
22import osAccount from '@ohos.account.osAccount';
23import { Configuration } from '@ohos.app.ability.Configuration';
24import Constants from '../common/constant';
25import {
26  getAuthPerm,
27  checkDomainAccountInfo,
28  getOsAccountInfo,
29  judgeIsSandBox,
30  getFileFd,
31  getAppId,
32  DLPInfo,
33  getDLPInfo,
34  sendDlpManagerAccountLogin,
35  isValidPath,
36  getAccountType
37} from '../common/utils';
38import GlobalContext from '../common/GlobalContext';
39import { GetAlertMessage } from '../common/GetAlertMessage';
40import { HiLog } from '../common/HiLog';
41import FileUtils from '../common/FileUtils';
42import AccountManager from '../manager/AccountManager';
43import IdDlpRpcServiceProxy from './data/IIdlDlpRpcServiceTs/id_dlpRpc_service_proxy';
44import common from '@ohos.app.ability.common';
45
46const TAG = 'MainEx';
47
48let direction: number = -1;
49const DLP_FILE_PROCESS_ABILITY_NAME = 'DlpFileProcessAbility';
50
51export default class MainAbility extends UIExtensionAbility {
52  private authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY;
53  private callerToken: number = 0;
54  private dlpRpcProxy?: IdDlpRpcServiceProxy;
55  private connectionNum: number = -1;
56
57  connectDlpFileProcessAbility(want: Want, session: UIExtensionContentSession) {
58    HiLog.info(TAG, `connectDlpFileProcessAbility`);
59    if (this.dlpRpcProxy !== undefined) {
60      return;
61    }
62
63    let newWant = {
64      'bundleName': Constants.DLP_MANAGER_BUNDLE_NAME,
65      'abilityName': DLP_FILE_PROCESS_ABILITY_NAME
66    } as Record<string, string>;
67
68    let options: common.ConnectOptions = {
69      onConnect: (elementName, proxy) => {
70        HiLog.info(TAG, `${DLP_FILE_PROCESS_ABILITY_NAME}: onConnect success`);
71        this.dlpRpcProxy = new IdDlpRpcServiceProxy(proxy);
72        GlobalContext.store('dlpRpcProxy', this.dlpRpcProxy);
73        HiLog.info(TAG, `DLPManager IDL onConnect success: ${JSON.stringify(this.dlpRpcProxy)}`);
74        this.getNewWantPage(want, session);
75      },
76      onDisconnect: () => {
77        HiLog.info(TAG, `${DLP_FILE_PROCESS_ABILITY_NAME}: onDisconnect`);
78      },
79      onFailed: () => {
80        HiLog.info(TAG, `${DLP_FILE_PROCESS_ABILITY_NAME}: onFailed`);
81      }
82    }
83
84    if (this.dlpRpcProxy === undefined) {
85      HiLog.info(TAG, `try connect`);
86      try {
87        this.connectionNum = this.context.connectServiceExtensionAbility(newWant, options);
88      } catch (err) {
89        HiLog.error(TAG, `connectDlpFileProcessAbility failed: ${JSON.stringify(err)}`);
90      }
91    }
92    HiLog.info(TAG, `connectDlpFileProcessAbility result: ${this.connectionNum}`);
93  }
94
95  async onSessionCreate(want: Want, session: UIExtensionContentSession): Promise<void> {
96    HiLog.info(TAG, `onSessionCreate start`);
97    if (GlobalContext.load('session')) {
98      this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_ENCRYPTING,
99          data: GlobalContext.load('abilityWant').parameters?.displayName
100        } as BusinessError);
101      return;
102    }
103    GlobalContext.store('session', session);
104    let dlpInfo:DLPInfo = await getDLPInfo();
105    AppStorage.setOrCreate('hiPNameId', dlpInfo.name);
106    AppStorage.setOrCreate('hiPVersionId', dlpInfo.versionCode);
107    GlobalContext.store('abilityWant', want);
108    GlobalContext.store('uri', want.uri ?? '');
109    direction = this.context.config.direction ?? -1;
110
111    this.connectDlpFileProcessAbility(want, session);
112
113    AccountManager.connectAbility(this.context);
114  }
115
116  onConfigurationUpdate(newConfig: Configuration): void {
117    if (direction !== newConfig.direction) {
118      direction = newConfig.direction ?? -1;
119    }
120    let eventData: emitter.EventData = {
121      data: {
122        'direction': direction,
123      }};
124    let innerEvent: emitter.InnerEvent = {
125      eventId: Constants.ENCRYPTION_EMIT_DIRECTION_STATUS,
126      priority: emitter.EventPriority.HIGH
127    };
128    emitter.emit(innerEvent, eventData);
129  }
130
131  onSessionDestroy(session: UIExtensionContentSession): void {
132    HiLog.info(TAG, `onSessionDestroy`);
133    if (session !== GlobalContext.load('session')) {
134      return;
135    }
136    if (!(GlobalContext.load('requestIsFromSandBox') as boolean)) {
137      this.dlpRpcProxy?.closeDlpFile(GlobalContext.load('uri'), (err: number) => {
138        if (err !== 0) {
139          HiLog.error(TAG, `closeDLPFile failed: ${err}`);
140        }
141      });
142    }
143    GlobalContext.store('session', '');
144  }
145
146  async gotoPage(session: UIExtensionContentSession): Promise<void> {
147    let accountInfo: osAccount.OsAccountInfo = GlobalContext.load('accountInfo');
148    let accountName: string = accountInfo.domainInfo.accountName;
149    this.authPerm = getAuthPerm(accountName, GlobalContext.load('dlpProperty'));
150
151    AppStorage.setOrCreate('authPerm', this.authPerm);
152    AppStorage.setOrCreate<string>('contactAccount', GlobalContext.load('dlpProperty').contactAccount);
153    AppStorage.setOrCreate('validity', GlobalContext.load('dlpProperty').expireTime)
154    if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY ||
155      this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) {
156      this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
157      return;
158    }
159    if (this.authPerm === dlpPermission.DLPFileAccess.FULL_CONTROL) {
160      let accountInfo: osAccount.OsAccountInfo = GlobalContext.load('accountInfo');
161      let checkFlag = await AccountManager.checkAccountInfo(accountInfo?.domainInfo?.accountName);
162      if (!checkFlag) {
163        this.gotoAlertPage(session, { code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError);
164        return;
165      }
166
167      let storage: LocalStorage = new LocalStorage({
168        'session': session,
169      } as Record<string, UIExtensionContentSession | string>);
170      try {
171        session.loadContent('pages/changeEncryption', storage);
172        session.setWindowBackgroundColor(Constants.TRANSPARENT_BACKGROUND_COLOR);
173      } catch (exception) {
174        HiLog.error(TAG, `Failed to set the background color. Cause: ${JSON.stringify(exception)}`);
175      }
176    } else {
177      let storage: LocalStorage = new LocalStorage({
178        'session': session,
179      } as Record<string, UIExtensionContentSession | string>);
180      try {
181        session.loadContent('pages/permissionStatus', storage);
182        session.setWindowBackgroundColor(Constants.TRANSPARENT_BACKGROUND_COLOR);
183      } catch (exception) {
184        HiLog.error(TAG, `Failed to set the background color. Cause: ${JSON.stringify(exception)}`);
185      }
186    }
187  }
188
189  async checkValidWant(want: Want): Promise<boolean> {
190    let parameters = want.parameters;
191    if (parameters === undefined) {
192      HiLog.error(TAG, `need parameters in want`);
193      return false;
194    }
195    if (parameters.fileName === undefined) {
196      HiLog.error(TAG, `need fileName in want.parameters`);
197      return false;
198    }
199    if ((parameters.fileName as Record<string, string>).name === undefined) {
200      HiLog.error(TAG, `need name in want.parameters.fileName`);
201      return false;
202    }
203    if (want.uri === undefined) {
204      HiLog.error(TAG, `need uri in want`);
205      return false;
206    }
207    this.callerToken = parameters['ohos.aafwk.param.callerToken'] as number;
208    let callerBundleName: string = parameters['ohos.aafwk.param.callerBundleName'] as string;
209    if (this.callerToken === undefined || callerBundleName === undefined) {
210      HiLog.error(TAG, `need caller info in want.parameters`);
211      return false;
212    }
213    AppStorage.setOrCreate('hiPkgName', callerBundleName);
214    let uri = String(want.uri);
215    if (!isValidPath(uri)) {
216      HiLog.error(TAG, `invalid uri in want.uri`);
217      return false;
218    }
219    try {
220      await new Promise<void>((resolve, reject) => {
221        this.dlpRpcProxy?.linkSet(uri, (err: number) => {
222          if (err === 0) {
223            HiLog.error(TAG, `invalid uri for opened link uri`);
224            reject();
225          }
226          resolve();
227        })
228      })
229    } catch {
230      return false;
231    }
232
233    if (uri.indexOf(Constants.FUSE_PATH) !== -1) {
234      HiLog.error(TAG, `invalid uri in want.uri`);
235      return false;
236    }
237    return true;
238  }
239
240  async checkValidWantAndAccount(session: UIExtensionContentSession, want: Want): Promise<void> {
241    return new Promise(async (resolve, reject) => {
242      if (!this.checkValidWant(want)) {
243        this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_PARAM_ERROR } as BusinessError);
244        reject();
245        return;
246      }
247      let accountInfo: osAccount.OsAccountInfo;
248      try {
249        accountInfo = await getOsAccountInfo();
250        GlobalContext.store('accountInfo', accountInfo);
251        AppStorage.setOrCreate('accountDomain', accountInfo.domainInfo.domain);
252        resolve();
253      } catch (err) {
254        HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`);
255        this.gotoAlertPage(session, { code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError);
256        reject();
257        return;
258      }
259    })
260  }
261
262  async getNewWantPage(want: Want, session: UIExtensionContentSession): Promise<void> {
263    HiLog.info(TAG, `getNewWantPage start`);
264    try {
265      await this.checkValidWantAndAccount(session, want)
266    } catch {
267      return;
268    }
269    let codeMessage = checkDomainAccountInfo(GlobalContext.load('accountInfo'));
270    sendDlpManagerAccountLogin(0);
271    if (codeMessage) {
272      this.gotoAlertPage(session, { code: codeMessage } as BusinessError);
273      return;
274    }
275    let requestIsFromSandBox: boolean = await judgeIsSandBox(want);
276    GlobalContext.store('requestIsFromSandBox', requestIsFromSandBox);
277    HiLog.info(TAG, `request is from sandbox: ${requestIsFromSandBox}`);
278    if (requestIsFromSandBox) {
279      this.requestIsFromSandBox(session, want);
280    } else {
281      this.requestIsNotFromSandBox(session, want);
282    }
283  }
284
285  requestIsFromSandBox(session: UIExtensionContentSession, want: Want): void {
286    const linkFileName: string = (want.parameters?.linkFileName as Record<string, string>)?.name;
287    this.dlpRpcProxy?.sandBoxLinkFile(linkFileName, this.callerToken,
288      (err: number, data: dlpPermission.DLPProperty, uri: string) => {
289      if (err !== 0) {
290        return;
291      }
292      let dlpFileName: string = (want.parameters?.fileName as Record<string, string>)?.name;
293      GlobalContext.store('dlpFileName', dlpFileName);
294      GlobalContext.store('linkFileName', linkFileName);
295      GlobalContext.store('dlpProperty', data);
296      GlobalContext.store('uri', uri ?? '');
297      AppStorage.setOrCreate('permanent', data.expireTime === 0);
298      if (data.expireTime !== 0) {
299        AppStorage.setOrCreate('validity', new Date(data.expireTime as number));
300      }
301      this.gotoPage(session);
302    });
303  }
304
305  async requestIsNotFromSandBox(session: UIExtensionContentSession, want: Want): Promise<void> {
306    let fileName: string = (want.parameters?.fileName as Record<string, string>)?.name;
307    let isDlpSuffix: boolean = false;
308    try {
309      isDlpSuffix = await FileUtils.isDLPFile(GlobalContext.load('uri'));
310    } catch {
311      this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
312      return;
313    }
314    HiLog.info(TAG, `isDlpSuffix: ${isDlpSuffix}`);
315    if (!isDlpSuffix) {
316      HiLog.error(TAG, `${fileName} is not a dlp file`);
317      GlobalContext.store('originFileName', fileName);
318      GlobalContext.store('originFd', getFileFd(GlobalContext.load('uri') as string));
319      let storage: LocalStorage = new LocalStorage({
320        'session': session,
321      } as Record<string, UIExtensionContentSession | string>);
322      try {
323        session.loadContent('pages/encryptionProtection', storage);
324        session.setWindowBackgroundColor(Constants.TRANSPARENT_BACKGROUND_COLOR);
325      } catch (exception) {
326        HiLog.error(TAG, `Failed to set the background color. Cause: ${JSON.stringify(exception)}`);
327      }
328      return;
329    } else {
330      try {
331        let dlpFd = getFileFd(String(want.uri));
332        let accountType = await getAccountType(this.context, dlpFd);
333        if (accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT) {
334          this.dlpFilesToEncrypt(session, want);
335        } else {
336          await GetAlertMessage.phoneHandle(this.context, {
337            code: Constants.ERR_JS_APP_CANNOT_OPEN } as BusinessError);
338        }
339      } catch {
340        return;
341      }
342    }
343  }
344
345  async dlpFilesToEncrypt(session: UIExtensionContentSession, want: Want): Promise<void> {
346    let uri: string = GlobalContext.load('uri') as string;
347    try {
348      await this.findFileOpenHistoryHome(uri, session);
349    } catch {
350      return;
351    }
352    let dlpFileName: string = (want.parameters?.fileName as Record<string, string>)?.name;
353    GlobalContext.store('dlpFileName', dlpFileName);
354    let callerAppId: string;
355    try {
356      let callerBundleName = Constants.DLP_MANAGER_BUNDLE_NAME;
357      callerAppId = await getAppId(callerBundleName);
358      HiLog.info(TAG, `get AppId: ${callerAppId}`);
359    } catch {
360      HiLog.error(TAG, `get AppId failed`);
361      return;
362    }
363    this.dlpRpcProxy?.openDlpFile(uri, callerAppId,
364      async (err: number, data: dlpPermission.DLPProperty, msg: string) => {
365      if (err !== 0) {
366        let ansErr: BusinessError<void> = {
367          code: err,
368          name: '',
369          message: msg,
370        }
371        let accountFlag: boolean = true;
372        if (err === Constants.ERR_JS_USER_NO_PERMISSION) {
373          let accountName: string = msg.split(', contact:')?.[1];
374          accountFlag = await AccountManager.checkAccountInfo(accountName);
375        }
376        if (!accountFlag) {
377          this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
378          return;
379        }
380        this.gotoAlertPage(session, ansErr as BusinessError);
381        return;
382      } else {
383        this.getOwnerAccountTypeInfo(data, session);
384      }
385    })
386  }
387
388  async getOwnerAccountTypeInfo(data: dlpPermission.DLPProperty, session: UIExtensionContentSession) {
389    GlobalContext.store('dlpProperty', data);
390    AppStorage.setOrCreate('permanent', data.expireTime === 0);
391    if (data.expireTime !== 0) {
392      AppStorage.setOrCreate('validity', new Date(data.expireTime as number));
393    }
394    if (data.ownerAccountType === dlpPermission.AccountType.DOMAIN_ACCOUNT) {
395      this.gotoPage(session);
396    } else {
397      this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
398    }
399  }
400
401  findFileOpenHistoryHome(uri: string, session: UIExtensionContentSession): Promise<void> {
402    return new Promise<void>((resolve, reject) => {
403      this.dlpRpcProxy?.fileOpenHistory(uri, async (err: number) => {
404        if (err === 0) {
405          this.gotoAlertPage(session, { code: Constants.ERR_JS_APP_OPEN_REJECTED } as BusinessError);
406          reject();
407        }
408        resolve();
409      })
410    })
411  }
412
413  gotoAlertPage(session: UIExtensionContentSession, error: BusinessError) {
414    let storage: LocalStorage = new LocalStorage({
415      'session': session,
416      'error': error
417    } as Record<string, UIExtensionContentSession | string | object>);
418    try {
419      session.loadContent('pages/alert', storage);
420      session.setWindowBackgroundColor(Constants.TRANSPARENT_BACKGROUND_COLOR);
421    } catch (exception) {
422      HiLog.error(TAG, `Failed to set the background color. Cause: ${JSON.stringify(exception)}`);
423    }
424  }
425
426  onWindowStageDestroy(): void {
427    HiLog.info(TAG, `onWindowStageDestroy`);
428  }
429
430  onForeground(): void {
431    HiLog.info(TAG, `onForeground`);
432  }
433
434  onBackground() {
435    HiLog.info(TAG, `onBackground`);
436  }
437};
438