1 /*
2 * Copyright (c) 2022-2024 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
16 #include "js_uri_perm_mgr.h"
17
18 #include "ability_business_error.h"
19 #include "ability_manager_errors.h"
20 #include "ability_runtime_error_util.h"
21 #include "hilog_tag_wrapper.h"
22 #include "ipc_skeleton.h"
23 #include "js_error_utils.h"
24 #include "napi_common_util.h"
25 #include "parameters.h"
26 #include "tokenid_kit.h"
27 #include "uri.h"
28 #include "uri_permission_manager_client.h"
29
30 namespace OHOS {
31 namespace AbilityRuntime {
32 namespace {
33 constexpr int32_t ERR_OK = 0;
34 constexpr int32_t argCountFour = 4;
35 constexpr int32_t argCountThree = 3;
36 constexpr int32_t argCountTwo = 2;
37
38 struct UriPermissionParam {
39 std::string uriStr;
40 int32_t flag = 0;
41 std::string bundleName;
42 int32_t appIndex = 0;
43 bool hasAppIndex = false;
44 };
45
ResolveGrantUriPermissionTask(napi_env env,NapiAsyncTask & task,int32_t errCode)46 static void ResolveGrantUriPermissionTask(napi_env env, NapiAsyncTask &task, int32_t errCode)
47 {
48 TAG_LOGI(AAFwkTag::URIPERMMGR, "ResolveGrantUriPermissionTask");
49 if (errCode == ERR_OK) {
50 task.ResolveWithNoError(env, CreateJsUndefined(env));
51 return;
52 }
53 if (errCode == AAFwk::CHECK_PERMISSION_FAILED || errCode == AAFwk::ERR_CODE_INVALID_URI_FLAG ||
54 errCode == AAFwk::ERR_CODE_INVALID_URI_TYPE || errCode == AAFwk::ERR_CODE_GRANT_URI_PERMISSION) {
55 task.Reject(env, CreateJsErrorByNativeErr(env, errCode, "ohos.permission.PROXY_AUTHORIZATION_URI"));
56 return;
57 }
58 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
59 return;
60 }
61
ResolveGrantUriPermissionWithAppIndexTask(napi_env env,NapiAsyncTask & task,int32_t errCode)62 static void ResolveGrantUriPermissionWithAppIndexTask(napi_env env, NapiAsyncTask &task, int32_t errCode)
63 {
64 TAG_LOGI(AAFwkTag::URIPERMMGR, "ResolveGrantUriPermissionWithAppIndexTask");
65 if (errCode == ERR_OK) {
66 task.ResolveWithNoError(env, CreateJsUndefined(env));
67 return;
68 }
69 if (errCode == AAFwk::CHECK_PERMISSION_FAILED || errCode == AAFwk::ERR_CODE_INVALID_URI_FLAG ||
70 errCode == AAFwk::ERR_CODE_INVALID_URI_TYPE || errCode == AAFwk::ERR_CODE_GRANT_URI_PERMISSION ||
71 errCode == AAFwk::ERR_GET_TARGET_BUNDLE_INFO_FAILED) {
72 task.Reject(env, CreateJsErrorByNativeErr(env, errCode, "ohos.permission.PROXY_AUTHORIZATION_URI"));
73 return;
74 }
75 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
76 return;
77 }
78
ResolveRevokeUriPermissionTask(napi_env env,NapiAsyncTask & task,int32_t errCode)79 static void ResolveRevokeUriPermissionTask(napi_env env, NapiAsyncTask &task, int32_t errCode)
80 {
81 TAG_LOGI(AAFwkTag::URIPERMMGR, "ResolveRevokeUriPermissionTask");
82 if (errCode == ERR_OK) {
83 task.ResolveWithNoError(env, CreateJsUndefined(env));
84 return;
85 }
86 if (errCode == AAFwk::ERR_CODE_INVALID_URI_TYPE || errCode == AAFwk::ERR_CODE_GRANT_URI_PERMISSION) {
87 task.Reject(env, CreateJsErrorByNativeErr(env, errCode));
88 return;
89 }
90 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
91 return;
92 }
93
ResolveRevokeUriPermissionWithAppIndexTask(napi_env env,NapiAsyncTask & task,int32_t errCode)94 static void ResolveRevokeUriPermissionWithAppIndexTask(napi_env env, NapiAsyncTask &task, int32_t errCode)
95 {
96 TAG_LOGI(AAFwkTag::URIPERMMGR, "ResolveRevokeUriPermissionWithAppIndexTask");
97 if (errCode == ERR_OK) {
98 task.ResolveWithNoError(env, CreateJsUndefined(env));
99 return;
100 }
101 if (errCode == AAFwk::ERR_CODE_INVALID_URI_TYPE || errCode == AAFwk::ERR_CODE_GRANT_URI_PERMISSION ||
102 errCode == AAFwk::ERR_GET_TARGET_BUNDLE_INFO_FAILED) {
103 task.Reject(env, CreateJsErrorByNativeErr(env, errCode));
104 return;
105 }
106 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
107 return;
108 }
109
ParseGrantUriPermissionParams(napi_env env,NapiCallbackInfo & info,UriPermissionParam & param)110 static bool ParseGrantUriPermissionParams(napi_env env, NapiCallbackInfo &info, UriPermissionParam ¶m)
111 {
112 // only support 3 or 4 params
113 if (info.argc < argCountThree) {
114 TAG_LOGE(AAFwkTag::URIPERMMGR, "param number invalid");
115 ThrowTooFewParametersError(env);
116 return false;
117 }
118 if (!OHOS::AppExecFwk::UnwrapStringFromJS2(env, info.argv[0], param.uriStr)) {
119 TAG_LOGE(AAFwkTag::URIPERMMGR, "invalid uriStr");
120 ThrowInvalidParamError(env, "Parse param uri failed, uri must be string.");
121 return false;
122 }
123 if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(env, info.argv[1], param.flag)) {
124 TAG_LOGE(AAFwkTag::URIPERMMGR, "flag invalid.");
125 ThrowInvalidParamError(env, "Parse param flag failed, flag must be number.");
126 return false;
127 }
128 if (!OHOS::AppExecFwk::UnwrapStringFromJS2(env, info.argv[argCountTwo], param.bundleName)) {
129 TAG_LOGE(AAFwkTag::URIPERMMGR, "targetBundleName invalid");
130 ThrowInvalidParamError(env, "Parse param targetBundleName failed, targetBundleName must be string.");
131 return false;
132 }
133 if (info.argc >= argCountFour) {
134 // process param index or callback
135 if (CheckTypeForNapiValue(env, info.argv[argCountThree], napi_function)) {
136 return true;
137 }
138 if (!CheckTypeForNapiValue(env, info.argv[argCountThree], napi_number) ||
139 !OHOS::AppExecFwk::UnwrapInt32FromJS2(env, info.argv[argCountThree], param.appIndex)) {
140 TAG_LOGE(AAFwkTag::URIPERMMGR, "appIndex invalid");
141 ThrowInvalidParamError(env, "Parse param appCloneIndex failed, appCloneIndex must be number.");
142 return false;
143 }
144 if (param.appIndex < 0) {
145 ThrowInvalidParamError(env, "Param appCloneIndex is invalid, the value less than 0.");
146 return false;
147 }
148 param.hasAppIndex = true;
149 }
150 return true;
151 }
152
ParseRevokeUriPermissionParams(napi_env env,NapiCallbackInfo & info,UriPermissionParam & param)153 static bool ParseRevokeUriPermissionParams(napi_env env, NapiCallbackInfo &info, UriPermissionParam ¶m)
154 {
155 // only support 2 or 3 params
156 if (info.argc < argCountTwo) {
157 TAG_LOGE(AAFwkTag::URIPERMMGR, "Invalid args");
158 ThrowTooFewParametersError(env);
159 return false;
160 }
161 if (!OHOS::AppExecFwk::UnwrapStringFromJS2(env, info.argv[0], param.uriStr)) {
162 TAG_LOGE(AAFwkTag::URIPERMMGR, "invalid uriStr");
163 ThrowInvalidParamError(env, "Parse param uri failed, uri must be string.");
164 return false;
165 }
166 if (!OHOS::AppExecFwk::UnwrapStringFromJS2(env, info.argv[1], param.bundleName)) {
167 TAG_LOGE(AAFwkTag::URIPERMMGR, "bundleName invalid");
168 ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
169 return false;
170 }
171 if (info.argc >= argCountThree) {
172 // process param index or callback
173 if (CheckTypeForNapiValue(env, info.argv[argCountTwo], napi_function)) {
174 return true;
175 }
176 if (!CheckTypeForNapiValue(env, info.argv[argCountTwo], napi_number) ||
177 !OHOS::AppExecFwk::UnwrapInt32FromJS2(env, info.argv[argCountTwo], param.appIndex)) {
178 TAG_LOGE(AAFwkTag::URIPERMMGR, "appCloneIndex invalid");
179 ThrowInvalidParamError(env, "Parse param appCloneIndex failed, appCloneIndex must be number.");
180 return false;
181 }
182 if (param.appIndex < 0) {
183 ThrowInvalidParamError(env, "Param appCloneIndex is invalid, the value less than 0.");
184 return false;
185 }
186 param.hasAppIndex = true;
187 }
188 return true;
189 }
190 }
191 class JsUriPermMgr {
192 public:
193 JsUriPermMgr() = default;
194 ~JsUriPermMgr() = default;
195
Finalizer(napi_env env,void * data,void * hint)196 static void Finalizer(napi_env env, void* data, void* hint)
197 {
198 TAG_LOGI(AAFwkTag::URIPERMMGR, "call");
199 std::unique_ptr<JsUriPermMgr>(static_cast<JsUriPermMgr*>(data));
200 }
201
GrantUriPermission(napi_env env,napi_callback_info info)202 static napi_value GrantUriPermission(napi_env env, napi_callback_info info)
203 {
204 GET_NAPI_INFO_AND_CALL(env, info, JsUriPermMgr, OnGrantUriPermission);
205 }
206
RevokeUriPermission(napi_env env,napi_callback_info info)207 static napi_value RevokeUriPermission(napi_env env, napi_callback_info info)
208 {
209 GET_NAPI_INFO_AND_CALL(env, info, JsUriPermMgr, OnRevokeUriPermission);
210 }
211
212 private:
OnGrantUriPermission(napi_env env,NapiCallbackInfo & info)213 napi_value OnGrantUriPermission(napi_env env, NapiCallbackInfo& info)
214 {
215 TAG_LOGD(AAFwkTag::URIPERMMGR, "start");
216 UriPermissionParam param;
217 if (!ParseGrantUriPermissionParams(env, info, param)) {
218 return CreateJsUndefined(env);
219 }
220 auto selfToken = IPCSkeleton::GetSelfTokenID();
221 if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
222 TAG_LOGE(AAFwkTag::URIPERMMGR, "app not system-app");
223 ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
224 return CreateJsUndefined(env);
225 }
226 NapiAsyncTask::CompleteCallback complete =
227 [param](napi_env env, NapiAsyncTask& task, int32_t status) {
228 Uri uri(param.uriStr);
229 int errCode = AAFwk::UriPermissionManagerClient::GetInstance().GrantUriPermission(uri,
230 param.flag, param.bundleName, param.appIndex);
231 TAG_LOGI(AAFwkTag::URIPERMMGR, "GrantUriPermission, errCode is %{public}d", errCode);
232 if (param.hasAppIndex) {
233 return ResolveGrantUriPermissionWithAppIndexTask(env, task, errCode);
234 }
235 return ResolveGrantUriPermissionTask(env, task, errCode);
236 };
237 napi_value lastParam = (info.argc >= argCountFour && !param.hasAppIndex) ? info.argv[argCountThree] : nullptr;
238 napi_value result = nullptr;
239 NapiAsyncTask::ScheduleHighQos("JsUriPermMgr::OnGrantUriPermission",
240 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
241 return result;
242 }
243
OnRevokeUriPermission(napi_env env,NapiCallbackInfo & info)244 napi_value OnRevokeUriPermission(napi_env env, NapiCallbackInfo& info)
245 {
246 TAG_LOGD(AAFwkTag::URIPERMMGR, "start");
247 UriPermissionParam param;
248 if (!ParseRevokeUriPermissionParams(env, info, param)) {
249 return CreateJsUndefined(env);
250 }
251 auto selfToken = IPCSkeleton::GetSelfTokenID();
252 if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
253 TAG_LOGE(AAFwkTag::URIPERMMGR, "app not system-app");
254 ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
255 return CreateJsUndefined(env);
256 }
257 NapiAsyncTask::CompleteCallback complete =
258 [param](napi_env env, NapiAsyncTask& task, int32_t status) {
259 Uri uri(param.uriStr);
260 auto errCode = AAFwk::UriPermissionManagerClient::GetInstance().RevokeUriPermissionManually(uri,
261 param.bundleName, param.appIndex);
262 TAG_LOGD(AAFwkTag::URIPERMMGR, "errCode: %{public}d", errCode);
263 if (param.hasAppIndex) {
264 return ResolveRevokeUriPermissionWithAppIndexTask(env, task, errCode);
265 }
266 return ResolveRevokeUriPermissionTask(env, task, errCode);
267 };
268 napi_value lastParam = (info.argc >= argCountThree && !param.hasAppIndex) ? info.argv[argCountTwo] : nullptr;
269 napi_value result = nullptr;
270 NapiAsyncTask::ScheduleHighQos("JsUriPermMgr::OnRevokeUriPermission",
271 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
272 return result;
273 }
274 };
275
CreateJsUriPermMgr(napi_env env,napi_value exportObj)276 napi_value CreateJsUriPermMgr(napi_env env, napi_value exportObj)
277 {
278 TAG_LOGD(AAFwkTag::URIPERMMGR, "call");
279 if (env == nullptr || exportObj == nullptr) {
280 TAG_LOGI(AAFwkTag::URIPERMMGR, "Invalid param");
281 return nullptr;
282 }
283
284 std::unique_ptr<JsUriPermMgr> jsUriPermMgr = std::make_unique<JsUriPermMgr>();
285 napi_wrap(env, exportObj, jsUriPermMgr.release(), JsUriPermMgr::Finalizer, nullptr, nullptr);
286
287 const char *moduleName = "JsUriPermMgr";
288 BindNativeFunction(env, exportObj, "grantUriPermission", moduleName, JsUriPermMgr::GrantUriPermission);
289 BindNativeFunction(env, exportObj, "revokeUriPermission", moduleName, JsUriPermMgr::RevokeUriPermission);
290 return CreateJsUndefined(env);
291 }
292 } // namespace AbilityRuntime
293 } // namespace OHOS
294