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