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 UIAbility from '@ohos.app.ability.UIAbility'; 17import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; 18import { Permissions } from '@ohos.abilityAccessCtrl'; 19import dlpPermission from '@ohos.dlpPermission'; 20import emitter from '@ohos.events.emitter'; 21import Want from '@ohos.app.ability.Want'; 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 isPC, 32 getAppId, 33 getDLPInfo, 34 sendDlpManagerAccountLogin, 35 DLPInfo, 36 showErrorDialogAndExit, 37 isValidPath, 38 startAlertAbility 39} from '../common/utils'; 40import GlobalContext from '../common/GlobalContext'; 41import HomeFeature from '../feature/HomeFeature'; 42import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 43import { BusinessError } from '@ohos.base'; 44import window from '@ohos.window'; 45import common from '@ohos.app.ability.common'; 46import { AccountTipsConfig } from '../common/AccountTipsConfig'; 47 48const TAG = '[DLPManager_Main]'; 49let permissionList: Array<Permissions> = [ 50 'ohos.permission.READ_MEDIA', 51 'ohos.permission.WRITE_MEDIA', 52 'ohos.permission.FILE_ACCESS_MANAGER' 53]; 54 55let direction: number = -1; 56 57export default class MainAbility extends UIAbility { 58 authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY; 59 callerToken:number = 0; 60 private homeFeature!: HomeFeature; 61 62 async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> { 63 GlobalContext.store('abilityWant', want); 64 if (!GlobalContext.load('fileOpenHistoryFromMain')) { 65 GlobalContext.store('fileOpenHistoryFromMain', new Map<string, string>()); 66 } 67 if (GlobalContext.load('fileOpenHistoryFromMain').has(want.uri)) { 68 await showErrorDialogAndExit({ code: Constants.ERR_JS_APP_ENCRYPTING } as BusinessError); 69 return; 70 } 71 GlobalContext.store('context', this.context); 72 GlobalContext.store('domainAccount', !isPC() ? false : true); 73 GlobalContext.store('uri', want.uri ?? ''); 74 direction = this.context.config.direction ?? -1; 75 if (!GlobalContext.load('linkSet')) { 76 GlobalContext.store('linkSet', new Set<string>()); 77 } 78 this.homeFeature = new HomeFeature(this.context); 79 GlobalContext.store('homeFeature', this.homeFeature); 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 onDestroy(): void { 98 console.info(TAG, 'onDestroy'); 99 if (GlobalContext.load('fileOpenHistoryFromMain')) { 100 (GlobalContext.load('fileOpenHistoryFromMain') as Map<string, Object>).delete(GlobalContext.load('uri') as string) 101 } 102 } 103 104 onNewWant(want: Want) { 105 console.log(TAG, 'onNewWant', JSON.stringify(want)); 106 this.getNewWantPage(want); 107 } 108 109 async gotoPage(windowStage: window.WindowStage): Promise<void> { 110 let accountInfo: osAccount.OsAccountInfo = GlobalContext.load('accountInfo'); 111 let accountName: string = (GlobalContext.load('domainAccount') as boolean) ? accountInfo.domainInfo.accountName : accountInfo.distributedInfo.name; 112 this.authPerm = getAuthPerm(accountName, GlobalContext.load('dlpProperty')); 113 114 AppStorage.setOrCreate('authPerm', this.authPerm); 115 AppStorage.setOrCreate<string>('contactAccount', GlobalContext.load('dlpProperty').contactAccount); 116 AppStorage.setOrCreate('validity', GlobalContext.load('dlpProperty').expireTime) 117 if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY || 118 this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) { 119 await showErrorDialogAndExit({ code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError); 120 return; 121 } 122 if (this.authPerm === dlpPermission.DLPFileAccess.FULL_CONTROL) { 123 if (GlobalContext.load('domainAccount') as boolean) { 124 try { 125 await this.checkValidEnterpriseAndAccount(); 126 } catch { 127 return; 128 } 129 } 130 131 windowStage.loadContent('pages/changeEncryption', (err: BusinessError) =>{ 132 if (err.code !== 0) { 133 console.error(TAG, 'loadContent failed', err.code, err.message); 134 } 135 }); 136 } else { 137 windowStage.loadContent('pages/permissionStatus', (err: BusinessError) =>{ 138 if (err.code !== 0) { 139 console.error(TAG, 'loadContent failed', err.code, err.message); 140 } 141 }); 142 } 143 windowStage.getMainWindow().then((win: window.Window) => { 144 win.setWindowBackgroundColor('#00FFFFFF'); 145 }); 146 } 147 148 checkValidWant(want: Want): boolean { 149 let parameters = want.parameters; 150 if (parameters === undefined) { 151 console.error(TAG, 'need parameters in want'); 152 return false; 153 } 154 if (parameters.fileName === undefined) { 155 console.error(TAG, 'need fileName in want.parameters'); 156 return false; 157 } 158 if ((parameters.fileName as Record<string, string>).name === undefined) { 159 console.error(TAG, 'need name in want.parameters.fileName'); 160 return false; 161 } 162 if (want.uri === undefined) { 163 console.error(TAG, 'need uri in want'); 164 return false; 165 } 166 this.callerToken = parameters['ohos.aafwk.param.callerToken'] as number; 167 let callerBundleName: string = parameters['ohos.aafwk.param.callerBundleName'] as string; 168 if (this.callerToken === undefined || callerBundleName === undefined) { 169 console.error(TAG, 'need caller info in want.parameters'); 170 return false; 171 } 172 GlobalContext.store('hiPkgName', callerBundleName); 173 let uri = String(want.uri); 174 if ((GlobalContext.load('linkSet') as Set<string>).has(uri)) { 175 console.error(TAG, 'invalid uri for opened link uri'); 176 return false; 177 } 178 179 if (uri.indexOf(Constants.FUSE_PATH) !== -1 || !isValidPath(uri)) { 180 console.error(TAG, 'invalid uri in want.uri'); 181 return false; 182 } 183 return true; 184 } 185 186 async checkValidEnterpriseAndAccount(): Promise<void> { 187 return new Promise(async (resolve, reject) => { 188 let accountInfo: osAccount.OsAccountInfo = GlobalContext.load('accountInfo'); 189 AccountTipsConfig.getAccountInfo(accountInfo.domainInfo.accountName) 190 .then(() => { 191 resolve(); 192 }) 193 .catch(async (error: BusinessError) => { 194 await showErrorDialogAndExit(error); 195 reject(); 196 return; 197 }) 198 }) 199 } 200 201 async checkValidWantAndAccount(want: Want): Promise<void> { 202 return new Promise(async (resolve, reject) => { 203 if (!this.checkValidWant(want)) { 204 await startAlertAbility(GlobalContext.load('context') as common.UIAbilityContext, { code: Constants.ERR_JS_APP_PARAM_ERROR } as BusinessError); 205 reject(); 206 return; 207 } 208 let accountInfo: osAccount.OsAccountInfo; 209 try { 210 accountInfo = await getOsAccountInfo(); 211 GlobalContext.store('accountInfo', accountInfo); 212 resolve(); 213 } catch (err) { 214 console.error(TAG, 'getOsAccountInfo failed', (err as BusinessError).code, (err as BusinessError).message); 215 await startAlertAbility(GlobalContext.load('context') as common.UIAbilityContext, { code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError); 216 reject(); 217 return; 218 } 219 let codeMessage = checkDomainAccountInfo(accountInfo); 220 if (codeMessage) { 221 await startAlertAbility(GlobalContext.load('context') as common.UIAbilityContext, { code: codeMessage } as BusinessError); 222 reject(); 223 return; 224 } 225 }) 226 } 227 228 async getNewWantPage(want: Want): Promise<void> { 229 console.log(TAG, 'getNewWantPage start'); 230 let windowStage: window.WindowStage = GlobalContext.load('windowStage') as window.WindowStage; 231 try { 232 await this.checkValidWantAndAccount(want) 233 } catch { 234 return; 235 } 236 GlobalContext.store('abilityWant', want); 237 GlobalContext.store('uri', (GlobalContext.load('abilityWant') as Want).uri as string); 238 sendDlpManagerAccountLogin(0); 239 let requestIsFromSandBox: boolean = await judgeIsSandBox(); 240 GlobalContext.store('requestIsFromSandBox', requestIsFromSandBox); 241 console.info(TAG, 'request is from sandbox', requestIsFromSandBox); 242 if (requestIsFromSandBox) { 243 let abilityWant: Want = GlobalContext.load('abilityWant') as Want; 244 const linkFileName: string = (abilityWant.parameters?.linkFileName as Record<string, string>)?.name; 245 this.homeFeature.sandBoxLinkFileHome(linkFileName, this.callerToken, (err: number, data: dlpPermission.DLPProperty, uri: string) => { 246 if (err !== 0) { 247 return; 248 } 249 let dlpFileName: string = (abilityWant.parameters?.fileName as Record<string, string>)?.name; 250 GlobalContext.store('dlpFileName', dlpFileName); 251 GlobalContext.store('linkFileName', linkFileName); 252 GlobalContext.store('dlpProperty', data); 253 GlobalContext.store('permanent', data.expireTime === 0); 254 if (data.expireTime !== 0) { 255 GlobalContext.store('validity', new Date(data.expireTime as number)); 256 } 257 GlobalContext.store('uri', uri ?? ''); 258 this.gotoPage(windowStage); 259 }); 260 } else { 261 let fileName: string = ((GlobalContext.load('abilityWant') as Want).parameters?.fileName as Record<string, string>)?.name; 262 let isDlpSuffix: boolean = fileName.endsWith('.dlp'); 263 if (!isDlpSuffix) { 264 console.info(TAG, fileName, 'is not a dlp file'); 265 GlobalContext.store('originFileName', fileName); 266 GlobalContext.store('originFd', getFileFd(GlobalContext.load('uri') as string)); 267 windowStage.loadContent('pages/encryptionProtection', (err: BusinessError) =>{ 268 if (err.code !== 0) { 269 console.error(TAG, 'loadContent failed', err.code, err.message); 270 } 271 }); 272 windowStage.getMainWindow().then((win: window.Window) => { 273 win.setWindowBackgroundColor('#00FFFFFF'); 274 }); 275 return; 276 } else { 277 let uri: string = GlobalContext.load('uri') as string; 278 try { 279 await new Promise<void>((resolve, reject) => { 280 this.homeFeature.fileOpenHistoryHome(uri, async (err: number) => { 281 if (err === 0) { 282 await showErrorDialogAndExit({ code: Constants.ERR_JS_APP_OPEN_REJECTED } as BusinessError); 283 reject(); 284 } 285 resolve(); 286 }) 287 }) 288 } catch { 289 return; 290 } 291 let dlpFileName: string = ((GlobalContext.load('abilityWant') as Want).parameters?.fileName as Record<string, string>)?.name; 292 GlobalContext.store('dlpFileName', dlpFileName); 293 let callerAppId: string; 294 try { 295 let callerBundleName = Constants.DLP_MANAGER_BUNDLE_NAME; 296 callerAppId = await getAppId(callerBundleName); 297 console.info(TAG, 'get AppId', callerAppId); 298 } catch { 299 console.log(TAG, 'get AppId failed'); 300 return; 301 } 302 this.homeFeature.openDlpFileHome(uri, callerAppId, async (err: number, data: dlpPermission.DLPProperty, msg: string) => { 303 if (err !== 0) { 304 let ansErr: BusinessError<void> = { 305 code: err, 306 name: '', 307 message: msg, 308 } 309 await showErrorDialogAndExit(ansErr); 310 return; 311 } else { 312 GlobalContext.store('dlpProperty', data); 313 GlobalContext.store('permanent', data.expireTime === 0); 314 GlobalContext.store('fileOpenHistoryFromMain', new Map<string, string>()); 315 if (data.expireTime !== 0) { 316 GlobalContext.store('validity', new Date(data.expireTime as number)); 317 } 318 let fileOpenHistoryFromMain: Map<string, string> = GlobalContext.load('fileOpenHistoryFromMain') as Map<string, string>; 319 fileOpenHistoryFromMain.set(uri, uri); 320 console.log(TAG, 'fileOpenHistoryFromMain add', JSON.stringify(fileOpenHistoryFromMain)); 321 this.gotoPage(windowStage); 322 } 323 }) 324 } 325 } 326 } 327 328 async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> { 329 console.info(TAG, 'onWindowStageCreate'); 330 GlobalContext.store('windowStage', windowStage); 331 let dlpInfo:DLPInfo = await getDLPInfo(); 332 GlobalContext.store('hiPNameId', dlpInfo.name); 333 GlobalContext.store('hiPVersionId', dlpInfo.versionCode); 334 try { 335 let atManager = abilityAccessCtrl.createAtManager(); 336 await atManager.requestPermissionsFromUser(GlobalContext.load('context') as common.UIAbilityContext, permissionList); 337 } catch (err) { 338 console.error(TAG, 'requestPermissionsFromUser failed', (err as BusinessError).code, (err as BusinessError).message); 339 return; 340 } 341 this.homeFeature.connectServiceExtAbility(()=>{ 342 console.info(TAG, 'onWindowStageCreate callback'); 343 this.getNewWantPage(GlobalContext.load('abilityWant') as Want); 344 }); 345 console.info(TAG, 'onWindowStageCreate end'); 346 } 347 348 onWindowStageDestroy(): void { 349 console.info(TAG, 'onWindowStageDestroy'); 350 } 351 352 onForeground(): void { 353 console.info(TAG, 'onForeground'); 354 } 355 356 onBackground() { 357 console.info(TAG, 'onBackground'); 358 } 359}; 360