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.ToString(), 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); 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 parameter format error!"); 214 NError(EINVAL).ThrowErr(env); 215 return false; 216 } 217 218 auto [succBundleName, bundleName, lenBundleName] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); 219 if (!succBundleName) { 220 LOGE("FileShare::GetJSArgs get bundleName parameter failed!"); 221 NError(EINVAL).ThrowErr(env); 222 return false; 223 } 224 uriPermInfo.bundleName = string(bundleName.get()); 225 226 if (NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number)) { 227 auto [succFlag, flag] = NVal(env, funcArg[NARG_POS::THIRD]).ToUint32(); 228 uriPermInfo.flag = flag; 229 uriPermInfo.mode = GetModeFromFlag(flag); 230 } else if (NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_string)) { 231 auto [succFlag, flag, lenFlag] = NVal(env, funcArg[NARG_POS::THIRD]).ToUTF8String(); 232 uriPermInfo.mode = string(flag.get()); 233 uriPermInfo.flag = GetFlagFromMode(uriPermInfo.mode); 234 } else { 235 LOGE("FileShare::GetJSArgs get flag parameter failed!"); 236 NError(EINVAL).ThrowErr(env); 237 return false; 238 } 239 240 return true; 241 } 242 Async(napi_env env,napi_callback_info info)243 napi_value GrantUriPermission::Async(napi_env env, napi_callback_info info) 244 { 245 LOGD("FileShare::GrantUriPermission begin!"); 246 if (!IsSystemApp()) { 247 LOGE("FileShare::GrantUriPermission is not System App!"); 248 NError(E_PERMISSION_SYS).ThrowErr(env); 249 return nullptr; 250 } 251 NFuncArg funcArg(env, info); 252 if (!funcArg.InitArgs(NARG_CNT::THREE, NARG_CNT::FOUR)) { 253 LOGE("FileShare::GrantUriPermission GetJSArgsForGrantUriPermission Number of arguments unmatched!"); 254 NError(EINVAL).ThrowErr(env); 255 return nullptr; 256 } 257 258 UriPermissionInfo uriPermInfo; 259 bool result = GetJSArgs(env, funcArg, uriPermInfo); 260 if (!result) { 261 LOGE("FileShare::GrantUriPermission GetJSArgs failed!"); 262 NError(EINVAL).ThrowErr(env); 263 return nullptr; 264 } 265 266 auto cbExec = [uriPermInfo, env]() -> NError { 267 int ret = DoGrantUriPermission(uriPermInfo); 268 if (ret < 0) { 269 LOGE("FileShare::GrantUriPermission DoGrantUriPermission failed with %{public}d", ret); 270 return NError(-ret); 271 } 272 LOGD("FileShare::GrantUriPermission DoGrantUriPermission successfully!"); 273 return NError(ERRNO_NOERR); 274 }; 275 276 auto cbCompl = [](napi_env env, NError err) -> NVal { 277 if (err) { 278 return { env, err.GetNapiErr(env) }; 279 } 280 return NVal::CreateUndefined(env); 281 }; 282 283 NVal thisVar(env, funcArg.GetThisVar()); 284 if (funcArg.GetArgc() == NARG_CNT::THREE) { 285 return NAsyncWorkPromise(env, thisVar).Schedule(GRANT_URI_NAME, cbExec, cbCompl).val_; 286 } else { 287 NVal cb(env, funcArg[NARG_POS::FOURTH]); 288 return NAsyncWorkCallback(env, thisVar, cb).Schedule(GRANT_URI_NAME, cbExec, cbCompl).val_; 289 } 290 } 291 } // namespace ModuleFileShare 292 } // namespace AppFileService 293 } // namespace OHOS 294