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 { BusinessError } from '@ohos.base'; 17import Want from '@ohos.app.ability.Want'; 18import fileUri from '@ohos.file.fileuri'; 19import ServiceExtension from '@ohos.app.ability.ServiceExtensionAbility'; 20import fs from '@ohos.file.fs'; 21import dlpPermission from '@ohos.dlpPermission'; 22import IdlDlpRpcServiceStub from '../MainAbility/data/IIdlDlpRpcServiceTs/id_dlpRpc_service_stub'; 23import { 24 closeDlpFileCallback, 25 sandBoxLinkFileCallback, 26 fileOpenHistoryCallback, 27 linkSetCallback, 28 genDlpFileCallback, 29 openDlpFileCallback, 30 recoverDlpFileCallback, 31 replaceDlpLinkFileCallback, 32 resumeFuseLinkCallback, 33 stopFuseLinkCallback 34} from '../MainAbility/data/IIdlDlpRpcServiceTs/i_id_dlpRpc_service'; 35import IDLDLPProperty from './sequenceable/dlpClass'; 36import { IAuthUser } from './sequenceable/dlpClass'; 37import GlobalContext from '../common/GlobalContext'; 38import Constants from '../common/constant'; 39 40const TAG = '[DLPManager_service_extability]'; 41 42class DlpRpcServiceStub extends IdlDlpRpcServiceStub { 43 dlpFileMap: Map<string, dlpPermission.DLPFile | null> = new Map<string, dlpPermission.DLPFile | null>(); 44 45 constructor(des: string) { 46 super(des); 47 } 48 49 getOpeningFile(inputUri: string) : dlpPermission.DLPFile | null { 50 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 51 if (sandbox2linkFile !== undefined) { 52 for (let key of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 53 for (let j of key) { 54 if (j[4] === inputUri) { 55 let dlpFile: dlpPermission.DLPFile = j[0] as dlpPermission.DLPFile; 56 return dlpFile; 57 } 58 } 59 } 60 } 61 62 if (this.dlpFileMap.has(inputUri)) { 63 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(inputUri) as dlpPermission.DLPFile; 64 return dlpFile; 65 } 66 return null; 67 } 68 69 async genDlpFile(inputUri: string, outputUri: string, dlp: IDLDLPProperty, callback: genDlpFileCallback): Promise<void> { 70 console.log(TAG, 'genDlpFile in service +++++++++++'); 71 let inFile: fs.File; 72 let outFile: fs.File; 73 74 try { 75 inFile = await fs.open(inputUri, fs.OpenMode.READ_WRITE); 76 } catch (error) { 77 console.error(TAG, 'open', inputUri, 'failed', (error as BusinessError).code, (error as BusinessError).message); 78 return; 79 } 80 let uriInfo: fileUri.FileUri = new fileUri.FileUri(''); 81 try { 82 uriInfo = new fileUri.FileUri(outputUri); 83 } catch (err) { 84 console.error(TAG, 'fileUri fail', (err as BusinessError).code, (err as BusinessError).message); 85 } 86 try { 87 outFile = await fs.open(outputUri, fs.OpenMode.READ_WRITE); 88 } catch (err) { 89 try { 90 await fs.unlink(uriInfo.path); 91 } catch (err) { 92 console.error(TAG, 'unlink fail', (err as BusinessError).code, (err as BusinessError).message); 93 } 94 callback(100); 95 return; 96 } 97 98 let dlpP: dlpPermission.DLPProperty = { 99 "ownerAccount" : dlp.ownerAccount, 100 "ownerAccountID" : dlp.ownerAccountID, 101 "ownerAccountType" : dlp.ownerAccountType, 102 "authUserList" : dlp.authUserList, 103 "contactAccount" : dlp.contactAccount, 104 "offlineAccess" : dlp.offlineAccess, 105 "everyoneAccessList" : dlp.everyoneAccessList, 106 "expireTime": dlp.expireTime 107 } 108 try { 109 let dlpFile = await dlpPermission.generateDLPFile( inFile.fd, outFile.fd, dlpP); 110 111 if (!this.dlpFileMap.has(outputUri)) { 112 this.dlpFileMap.set(outputUri, dlpFile); 113 GlobalContext.store('dlpFileMap', this.dlpFileMap); 114 } else { 115 console.log(TAG, "map is overwrite", outputUri); 116 let rawDlpFile = this.dlpFileMap.get(outputUri) ?? null; 117 if (rawDlpFile !== null) { 118 try { 119 console.log(TAG, 'closeDLPFile start'); 120 await rawDlpFile.closeDLPFile(); 121 } catch (err) { 122 console.error(TAG, 'closeDlpFile file', (err as BusinessError).code, (err as BusinessError).message); 123 } 124 } 125 this.dlpFileMap.delete(outputUri); 126 this.dlpFileMap.set(outputUri, dlpFile); 127 GlobalContext.store('dlpFileMap', this.dlpFileMap); 128 } 129 callback(0); 130 } catch (err) { 131 console.log(TAG, 'genDlpFile file', JSON.stringify(err)); 132 try { 133 await fs.close(outFile); 134 } catch (err) { 135 console.log(TAG, 'close fail', (err as BusinessError).code, (err as BusinessError).message); 136 } 137 callback((err as BusinessError).code); 138 } 139 } 140 141 async openDlpFile(srcUri: string, callerAppId: string, callback: openDlpFileCallback): Promise<void> { 142 console.log(TAG, "openDlpFile start", srcUri); 143 let inFile = await fs.open(srcUri, fs.OpenMode.READ_WRITE); 144 let dlpFile: dlpPermission.DLPFile; 145 let authUserListNew: IAuthUser[] = []; 146 try { 147 dlpFile = await dlpPermission.openDLPFile(inFile.fd, callerAppId); 148 dlpFile.dlpProperty.authUserList?.forEach(item => { 149 authUserListNew.push( 150 new IAuthUser( 151 item.authAccount, 152 item.authAccountType, 153 item.dlpFileAccess, 154 item.permExpiryTime 155 )) 156 }) 157 let _dlp = new IDLDLPProperty( 158 dlpFile.dlpProperty.ownerAccount, 159 dlpFile.dlpProperty.ownerAccountID, 160 dlpFile.dlpProperty.ownerAccountType, 161 authUserListNew, 162 dlpFile.dlpProperty.contactAccount, 163 dlpFile.dlpProperty.offlineAccess, 164 dlpFile.dlpProperty.everyoneAccessList ?? [], 165 dlpFile.dlpProperty.expireTime ?? 0, 166 ); 167 callback(0, _dlp, ''); 168 if (!this.dlpFileMap.has(srcUri)) { 169 this.dlpFileMap.set(srcUri, dlpFile); 170 GlobalContext.store('dlpFileMap', this.dlpFileMap); 171 } else { 172 console.log(TAG, 'map is overwrite'); 173 this.dlpFileMap.delete(srcUri); 174 this.dlpFileMap.set(srcUri, dlpFile); 175 GlobalContext.store('dlpFileMap', this.dlpFileMap); 176 } 177 } catch(err) { 178 let _dlp = new IDLDLPProperty("", "", 0, [], "", true, [], 0); 179 callback((err as BusinessError).code, _dlp, (err as BusinessError).message); 180 } 181 } 182 183 async stopFuseLink(uri: string, callback: stopFuseLinkCallback): Promise<void> { 184 console.log(TAG, 'stopFuseLink start', uri); 185 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(uri); 186 if (dlpFile !== null) { 187 await dlpFile.stopFuseLink(); 188 } else { 189 console.log(TAG, 'stopFuseLink not find', uri); 190 callback(-1); 191 } 192 } 193 194 async resumeFuseLink(uri: string, callback: resumeFuseLinkCallback): Promise<void> { 195 console.log(TAG, 'resumeFuseLink start'); 196 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(uri); 197 if (dlpFile !== null) { 198 await dlpFile.resumeFuseLink(); 199 } else { 200 console.log(TAG, 'resumeFuseLink not find', uri); 201 callback(-1); 202 } 203 } 204 205 async replaceDlpLinkFile(srcUri: string, linkFileName: string, callback: replaceDlpLinkFileCallback): Promise<void> { 206 GlobalContext.load('sandbox2linkFile'); 207 if (this.dlpFileMap.has(srcUri)) { 208 let dlpFile: dlpPermission.DLPFile = this.dlpFileMap.get(srcUri) as dlpPermission.DLPFile; 209 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 210 for (let key of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 211 for (let j of key) { 212 if (j[1] === linkFileName) { 213 j[0] = dlpFile; 214 } 215 } 216 } 217 await dlpFile.replaceDLPLinkFile(linkFileName); 218 } else { 219 console.log(TAG, 'replaceDLPLinkFile not find', srcUri); 220 callback(-1); 221 } 222 } 223 224 async recoverDlpFile(srcUri: string, pathUri: string, callback: recoverDlpFileCallback): Promise<void> { 225 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(srcUri); 226 if (dlpFile !== null) { 227 let inFile = await fs.open(pathUri, fs.OpenMode.READ_WRITE); 228 try { 229 await dlpFile.recoverDLPFile(inFile.fd); 230 } catch (err) { 231 console.error(TAG, 'recoverDlpFileInner4', (err as BusinessError).code, (err as BusinessError).message); 232 callback((err as BusinessError).code); 233 } 234 } else { 235 console.log(TAG, 'recoverDlpFile not find', srcUri); 236 callback(-1); 237 } 238 } 239 240 async closeDlpFile(srcUri: string, callback: closeDlpFileCallback): Promise<void> { 241 console.log(TAG, 'closeDlpFile start'); 242 let dlpFile: dlpPermission.DLPFile | null = this.getOpeningFile(srcUri); 243 if (dlpFile !== null) { 244 try { 245 await dlpFile.closeDLPFile(); 246 if (this.dlpFileMap.has(srcUri)) { 247 this.dlpFileMap.delete(srcUri); 248 GlobalContext.store('dlpFileMap', this.dlpFileMap); 249 } 250 callback(0); 251 } catch (err) { 252 console.error(TAG, 'closeDlpFile file', (err as BusinessError).code, (err as BusinessError).message); 253 callback((err as BusinessError).code); 254 } 255 } 256 } 257 258 async sandBoxLinkFile(linkFileName: string, callerToken: number, callback: sandBoxLinkFileCallback): Promise<void> { 259 let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> = GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>; 260 for (let value of Array.from<(number | string | dlpPermission.DLPFile)[][]>(sandbox2linkFile.values())) { 261 for (let linkFile of value) { 262 let _dlp = new IDLDLPProperty("", "", 0, [], "", true, [], 0); 263 if (linkFile[Constants.FILE_OPEN_HISTORY_ONE] === linkFileName) { 264 let authUserListNew: IAuthUser[] = []; 265 if (callerToken !== linkFile[Constants.FILE_OPEN_HISTORY_THREE]) { 266 console.error(TAG, 'found file, but token invalid', linkFileName); 267 callback(-1, _dlp, ''); 268 } else { 269 let linkFileInfo: Record<number, number | string | dlpPermission.DLPFile> = linkFile[0] as Record<number, number | string | dlpPermission.DLPFile>; 270 linkFileInfo['dlpProperty'].authUserList.forEach((item: IAuthUser)=> { 271 authUserListNew.push( 272 new IAuthUser( 273 item.authAccount, 274 item.authAccountType, 275 item.dlpFileAccess, 276 item.permExpiryTime 277 )) 278 }) 279 _dlp = new IDLDLPProperty( 280 linkFileInfo['dlpProperty'].ownerAccount, 281 linkFileInfo['dlpProperty'].ownerAccountID, 282 linkFileInfo['dlpProperty'].ownerAccountType, 283 authUserListNew, 284 linkFileInfo['dlpProperty'].contactAccount, 285 linkFileInfo['dlpProperty'].offlineAccess, 286 linkFileInfo['dlpProperty'].everyoneAccessList ?? [], 287 linkFileInfo['dlpProperty'].expireTime ?? 0 288 ); 289 let fileUri = linkFile[4]; 290 callback(0, _dlp, fileUri.toString()); 291 } 292 } else { 293 console.error(TAG, 'request from sandbox, but can not find dlp file by linkFileName', linkFileName); 294 callback(-1, _dlp, ''); 295 } 296 } 297 } 298 } 299 300 async fileOpenHistory(uri: string, callback: fileOpenHistoryCallback): Promise<void> { 301 console.log(TAG, 'fileOpenHistory start'); 302 if ((GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>)?.has(uri)) { 303 callback(0); 304 } else { 305 callback(-1); 306 } 307 } 308 309 async linkSet(uri: string, callback: linkSetCallback): Promise<void> { 310 console.log(TAG, 'linkSet start'); 311 if ((GlobalContext.load('linkSet') as Map<string, (number | string)[]>)?.has(uri)) { 312 callback(0); 313 } else { 314 callback(-1); 315 } 316 } 317} 318 319export default class ServiceExtAbility extends ServiceExtension { 320 onCreate(want: Want) { 321 console.info(TAG, 'onCreate, want: ${want.abilityName}', want.abilityName); 322 } 323 324 onRequest(want: Want, startId: number) { 325 console.info(TAG, 'onRequest, want: ${want.abilityName}', want.abilityName); 326 } 327 328 onConnect(want: Want) { 329 console.info(TAG, 'service onConnect, want: ${want.abilityName}', want.abilityName); 330 return new DlpRpcServiceStub('dlpRpc service stub'); 331 } 332 333 onDisconnect(want: Want): void { 334 console.info(TAG, 'onDisconnect, want: ${want.abilityName}', want.abilityName); 335 } 336 337 onDestroy(): void { 338 console.info('onDestroy'); 339 } 340}