• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "grant_uri_permission.h"
16 
17 #include "ability.h"
18 #include "datashare_helper.h"
19 #include "datashare_values_bucket.h"
20 #include "ipc_skeleton.h"
21 #include "log.h"
22 #include "remote_uri.h"
23 #include "tokenid_kit.h"
24 #include "uri_permission_manager_client.h"
25 #include "want.h"
26 
27 using namespace OHOS::DataShare;
28 using namespace OHOS::FileManagement::LibN;
29 using namespace OHOS::DistributedFS::ModuleRemoteUri;
30 
31 namespace OHOS {
32 namespace AppFileService {
33 namespace ModuleFileShare {
34     enum MediaFileTable {
35         FILE_TABLE = 0,
36         PHOTO_TABLE = 1,
37         AUDIO_TABLE = 2,
38     };
39 
40     struct UriPermissionInfo {
41         unsigned int flag;
42         string mode;
43         string bundleName;
44         string uri;
45     };
46 
IsSystemApp()47     static bool IsSystemApp()
48     {
49         uint64_t fullTokenId = OHOS::IPCSkeleton::GetCallingFullTokenID();
50         return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
51     }
52 
GetIdFromUri(string uri)53     static int32_t GetIdFromUri(string uri)
54     {
55         std::replace(uri.begin(), uri.end(), '/', ' ');
56         stringstream ss(uri);
57         string tmp;
58         int fileId = -1;
59         ss >> tmp >> tmp >> tmp >> fileId;
60         return fileId;
61     }
62 
GetModeFromFlag(unsigned int flag)63     static string GetModeFromFlag(unsigned int flag)
64     {
65         string mode = "";
66         if (flag & OHOS::AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION) {
67             mode += "r";
68         }
69         if (flag & OHOS::AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION) {
70             mode += "w";
71         }
72         return mode;
73     }
74 
GetFlagFromMode(const string & mode)75     static unsigned int GetFlagFromMode(const string &mode)
76     {
77         unsigned int flag = AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION;
78         if (mode.find("w") != string::npos) {
79             flag = AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION;
80         }
81         return flag;
82     }
83 
GetMediaTypeAndApiFromUri(const std::string & uri,bool & isApi10)84     static int32_t GetMediaTypeAndApiFromUri(const std::string &uri, bool &isApi10)
85     {
86         if (uri.find(MEDIA_FILE_URI_PHOTO_PREFEX) == 0) {
87             isApi10 = true;
88             return MediaFileTable::PHOTO_TABLE;
89         } else if (uri.find(MEDIA_FILE_URI_VIDEO_PREFEX) == 0 ||
90             uri.find(MEDIA_FILE_URI_IMAGE_PREFEX) == 0) {
91             return MediaFileTable::PHOTO_TABLE;
92         } else if (uri.find(MEDIA_FILE_URI_AUDIO_PREFEX) == 0) {
93             isApi10 = true;
94             return MediaFileTable::AUDIO_TABLE;
95         } else if (uri.find(MEDIA_FILE_URI_Audio_PREFEX) == 0) {
96             return MediaFileTable::AUDIO_TABLE;
97         } else if (uri.find(MEDIA_FILE_URI_FILE_PREFEX) == 0) {
98             return MediaFileTable::FILE_TABLE;
99         }
100 
101         return MediaFileTable::FILE_TABLE;
102     }
103 
InsertByDatashare(const DataShareValuesBucket & valuesBucket,bool isApi10)104     static int InsertByDatashare(const DataShareValuesBucket &valuesBucket, bool isApi10)
105     {
106         int ret = -1;
107         std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
108         sptr<FileShareGrantToken> remote = new IRemoteStub<FileShareGrantToken>();
109         if (remote == nullptr) {
110             LOGE("FileShare::InsertByDatashare get remoteObject failed!");
111             return -ENOMEM;
112         }
113 
114         dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
115         if (!dataShareHelper) {
116             LOGE("FileShare::InsertByDatashare connect to datashare failed!");
117             return -E_PERMISSION;
118         }
119         string uriStr = MEDIA_GRANT_URI_PERMISSION;
120         if (isApi10) {
121             uriStr +=  MEDIA_API_VERSION_10;
122         }
123 
124         Uri uri(uriStr);
125         ret = dataShareHelper->Insert(uri, valuesBucket);
126         if (ret < 0) {
127             LOGE("FileShare::InsertByDatashare insert failed with error code %{public}d!", ret);
128             return ret;
129         }
130         return ret;
131     }
132 
InitValuesBucket(const UriPermissionInfo & uriPermInfo,Uri & uri,bool & isApi10,DataShareValuesBucket & valuesBucket)133     static int InitValuesBucket(const UriPermissionInfo &uriPermInfo, Uri &uri, bool &isApi10,
134                                 DataShareValuesBucket &valuesBucket)
135     {
136         int32_t fileId = GetIdFromUri(uriPermInfo.uri);
137         if (fileId == -1) {
138             LOGE("FileShare::InitValuesBucket get fileId parameter failed!");
139             return -EINVAL;
140         }
141 
142         int32_t filesType = GetMediaTypeAndApiFromUri(uri.GetPath(), isApi10);
143         valuesBucket.Put(PERMISSION_FILE_ID, fileId);
144         valuesBucket.Put(PERMISSION_BUNDLE_NAME, uriPermInfo.bundleName);
145         valuesBucket.Put(PERMISSION_MODE, uriPermInfo.mode);
146         valuesBucket.Put(PERMISSION_TABLE_TYPE, filesType);
147         return 0;
148     }
149 
GrantInMediaLibrary(const UriPermissionInfo & uriPermInfo,Uri & uri)150     static int GrantInMediaLibrary(const UriPermissionInfo &uriPermInfo, Uri &uri)
151     {
152         bool isApi10 = false;
153         DataShareValuesBucket valuesBucket;
154         int ret = InitValuesBucket(uriPermInfo, uri, isApi10, valuesBucket);
155         if (ret < 0) {
156             return ret;
157         }
158 
159         ret = InsertByDatashare(valuesBucket, isApi10);
160         if (ret < 0) {
161             return ret;
162         }
163         return 0;
164     }
165 
DoGrantUriPermission(const UriPermissionInfo & uriPermInfo)166     static int DoGrantUriPermission(const UriPermissionInfo &uriPermInfo)
167     {
168         Uri uri(uriPermInfo.uri);
169         string authority = uri.GetAuthority();
170         string path = uri.GetPath();
171         if (authority == MEDIA_AUTHORITY && path.find(".") == string::npos) {
172             return GrantInMediaLibrary(uriPermInfo, uri);
173         } else {
174             auto& uriPermissionClient = AAFwk::UriPermissionManagerClient::GetInstance();
175             int ret =  uriPermissionClient.GrantUriPermission(uri, uriPermInfo.flag,
176                                                               uriPermInfo.bundleName, 1);
177             if (ret != 0) {
178                 LOGD("uriPermissionClient.GrantUriPermission by uri permission client failed!");
179                 return GrantInMediaLibrary(uriPermInfo, uri);
180             }
181         }
182 
183         return 0;
184     }
185 
CheckValidPublicUri(const string & inputUri)186     static bool CheckValidPublicUri(const string &inputUri)
187     {
188         Uri uri(inputUri);
189         string scheme = uri.GetScheme();
190         if (scheme != FILE_SCHEME) {
191             return false;
192         }
193 
194         string authority = uri.GetAuthority();
195         if (authority != MEDIA_AUTHORITY && authority != FILE_MANAGER_AUTHORITY) {
196             return false;
197         }
198 
199         return true;
200     }
201 
GetJSArgs(napi_env env,const NFuncArg & funcArg,UriPermissionInfo & uriPermInfo)202     static bool GetJSArgs(napi_env env, const NFuncArg &funcArg, UriPermissionInfo &uriPermInfo)
203     {
204         auto [succUri, uri, lenUri] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
205         if (!succUri) {
206             LOGE("FileShare::GetJSArgs get uri parameter failed!");
207             NError(EINVAL).ThrowErr(env);
208             return false;
209         }
210 
211         uriPermInfo.uri = string(uri.get());
212         if (!CheckValidPublicUri(uriPermInfo.uri)) {
213             LOGE("FileShare::GetJSArgs uri = %{private}s parameter format error!", uriPermInfo.uri.c_str());
214             NError(EINVAL).ThrowErr(env);
215             return false;
216         }
217 
218         LOGD("FileShare::GetJSArgs uri = %{private}s", uriPermInfo.uri.c_str());
219 
220         auto [succBundleName, bundleName, lenBundleName] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String();
221         if (!succBundleName) {
222             LOGE("FileShare::GetJSArgs get bundleName parameter failed!");
223             NError(EINVAL).ThrowErr(env);
224             return false;
225         }
226         uriPermInfo.bundleName = string(bundleName.get());
227 
228         if (NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number)) {
229             auto [succFlag, flag] = NVal(env, funcArg[NARG_POS::THIRD]).ToUint32();
230             uriPermInfo.flag = flag;
231             uriPermInfo.mode = GetModeFromFlag(flag);
232         } else if (NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_string)) {
233             auto [succFlag, flag, lenFlag] = NVal(env, funcArg[NARG_POS::THIRD]).ToUTF8String();
234             uriPermInfo.mode = string(flag.get());
235             uriPermInfo.flag = GetFlagFromMode(uriPermInfo.mode);
236         } else {
237             LOGE("FileShare::GetJSArgs get flag parameter failed!");
238             NError(EINVAL).ThrowErr(env);
239             return false;
240         }
241 
242         return true;
243     }
244 
Async(napi_env env,napi_callback_info info)245     napi_value GrantUriPermission::Async(napi_env env, napi_callback_info info)
246     {
247         LOGD("FileShare::GrantUriPermission begin!");
248         if (!IsSystemApp()) {
249             LOGE("FileShare::GrantUriPermission is not System App!");
250             NError(E_PERMISSION_SYS).ThrowErr(env);
251             return nullptr;
252         }
253         NFuncArg funcArg(env, info);
254         if (!funcArg.InitArgs(NARG_CNT::THREE, NARG_CNT::FOUR)) {
255             LOGE("FileShare::GrantUriPermission GetJSArgsForGrantUriPermission Number of arguments unmatched!");
256             NError(EINVAL).ThrowErr(env);
257             return nullptr;
258         }
259 
260         UriPermissionInfo uriPermInfo;
261         bool result = GetJSArgs(env, funcArg, uriPermInfo);
262         if (!result) {
263             LOGE("FileShare::GrantUriPermission GetJSArgs failed!");
264             NError(EINVAL).ThrowErr(env);
265             return nullptr;
266         }
267 
268         auto cbExec = [uriPermInfo, env]() -> NError {
269             int ret = DoGrantUriPermission(uriPermInfo);
270             if (ret < 0) {
271                 LOGE("FileShare::GrantUriPermission DoGrantUriPermission failed with %{public}d", ret);
272                 return NError(-ret);
273             }
274             LOGD("FileShare::GrantUriPermission DoGrantUriPermission successfully!");
275             return NError(ERRNO_NOERR);
276         };
277 
278         auto cbCompl = [](napi_env env, NError err) -> NVal {
279             if (err) {
280                 return { env, err.GetNapiErr(env) };
281             }
282             return NVal::CreateUndefined(env);
283         };
284 
285         NVal thisVar(env, funcArg.GetThisVar());
286         if (funcArg.GetArgc() == NARG_CNT::THREE) {
287             return NAsyncWorkPromise(env, thisVar).Schedule(GRANT_URI_NAME, cbExec, cbCompl).val_;
288         } else {
289             NVal cb(env, funcArg[NARG_POS::FOURTH]);
290             return NAsyncWorkCallback(env, thisVar, cb).Schedule(GRANT_URI_NAME, cbExec, cbCompl).val_;
291         }
292     }
293 } // namespace ModuleFileShare
294 } // namespace AppFileService
295 } // namespace OHOS
296