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