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