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 #include "grant_permissions.h"
16
17 #include <string>
18 #include <vector>
19
20 #include "access_token.h"
21 #include "accesstoken_kit.h"
22 #include "ipc_skeleton.h"
23 #include "js_native_api.h"
24 #include "log.h"
25 #include "n_napi.h"
26 #include "parameter.h"
27 #include "tokenid_kit.h"
28
29 namespace OHOS {
30 namespace AppFileService {
31 namespace ModuleFileShare {
32 using namespace OHOS::FileManagement::LibN;
33 using namespace std;
34
35 namespace {
36 const std::string FILE_ACCESS_PERMISSION = "ohos.permission.FILE_ACCESS_PERSIST";
37 const std::string FULL_MOUNT_ENABLE_PARAMETER = "const.filemanager.full_mount.enable";
38
CheckPermission(const string & permission)39 static bool CheckPermission(const string &permission)
40 {
41 Security::AccessToken::AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID();
42 return Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenCaller, permission) ==
43 Security::AccessToken::PermissionState::PERMISSION_GRANTED;
44 }
45
CheckFileManagerFullMountEnable()46 static bool CheckFileManagerFullMountEnable()
47 {
48 char value[] = "false";
49 int retSystem = GetParameter(FULL_MOUNT_ENABLE_PARAMETER.c_str(), "false", value, sizeof(value));
50 if (retSystem > 0 && !strcmp(value, "true")) {
51 LOGE("The full mount enable parameter is true");
52 return true;
53 }
54 LOGD("The full mount enable parameter is false");
55 return false;
56 }
57 } // namespace
58
GetErrData(napi_env env,deque<struct PolicyErrorResult> & errorResults)59 static napi_value GetErrData(napi_env env, deque<struct PolicyErrorResult> &errorResults)
60 {
61 napi_value res = nullptr;
62 napi_status status = napi_create_array(env, &res);
63 if (status != napi_ok) {
64 LOGE("Failed to create array");
65 return nullptr;
66 }
67 size_t index = 0;
68 for (auto &iter : errorResults) {
69 NVal obj = NVal::CreateObject(env);
70 obj.AddProp("uri", NVal::CreateUTF8String(env, iter.uri).val_);
71 obj.AddProp("code", NVal::CreateInt32(env, iter.code).val_);
72 obj.AddProp("message", NVal::CreateUTF8String(env, iter.message).val_);
73 status = napi_set_element(env, res, index++, obj.val_);
74 if (status != napi_ok) {
75 LOGE("Failed to set element on data");
76 return nullptr;
77 }
78 }
79 return res;
80 }
81
GetResultData(napi_env env,const vector<bool> & results)82 static napi_value GetResultData(napi_env env, const vector<bool> &results)
83 {
84 napi_value res = nullptr;
85 napi_status status = napi_create_array(env, &res);
86 if (status != napi_ok) {
87 LOGE("Failed to create array");
88 return nullptr;
89 }
90 size_t index = 0;
91 for (const auto &iter : results) {
92 napi_value value;
93 napi_get_boolean(env, iter, &value);
94 status = napi_set_element(env, res, index++, value);
95 if (status != napi_ok) {
96 LOGE("Failed to set element on data");
97 return nullptr;
98 }
99 }
100 return res;
101 }
102
GetUriPoliciesArg(napi_env env,napi_value agrv,std::vector<UriPolicyInfo> & uriPolicies)103 static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector<UriPolicyInfo> &uriPolicies)
104 {
105 uint32_t count;
106 napi_status status = napi_get_array_length(env, agrv, &count);
107 if (status != napi_ok) {
108 LOGE("get array length failed");
109 return status;
110 }
111 if (count > MAX_ARRAY_SIZE) {
112 LOGE("The length of the array is extra-long");
113 return napi_invalid_arg;
114 }
115 for (uint32_t i = 0; i < count; i++) {
116 napi_handle_scope scope;
117 status = napi_open_handle_scope(env, &scope);
118 if (status != napi_ok) {
119 return status;
120 }
121 napi_value object;
122 status = napi_get_element(env, agrv, i, &object);
123 if (status != napi_ok) {
124 LOGE("get element failed");
125 return status;
126 }
127 napi_value uriValue;
128 napi_value modeValue;
129 status = napi_get_named_property(env, object, "uri", &uriValue);
130 if (status != napi_ok) {
131 LOGE("get named property failed");
132 return status;
133 }
134 status = napi_get_named_property(env, object, "operationMode", &modeValue);
135 if (status != napi_ok) {
136 LOGE("get named property failed");
137 return status;
138 }
139 auto [succStr, str, ignore] = NVal(env, uriValue).ToUTF8String();
140 auto [succMode, mode] = NVal(env, modeValue).ToUint32();
141 if (!succStr || !succMode) {
142 LOGE("the argument error");
143 return napi_invalid_arg;
144 }
145 UriPolicyInfo uriPolicy {.uri = str.get(), .mode = mode};
146 uriPolicies.emplace_back(uriPolicy);
147 status = napi_close_handle_scope(env, scope);
148 if (status != napi_ok) {
149 return status;
150 }
151 }
152 return napi_ok;
153 }
154
PersistPermission(napi_env env,napi_callback_info info)155 napi_value PersistPermission(napi_env env, napi_callback_info info)
156 {
157 if (!CheckFileManagerFullMountEnable()) {
158 LOGE("The device doesn't support this api");
159 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
160 return nullptr;
161 }
162 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
163 LOGE("PersistPermission has not ohos permission!");
164 NError(E_PERMISSION).ThrowErr(env);
165 return nullptr;
166 }
167 NFuncArg funcArg(env, info);
168 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
169 LOGE("PersistPermission Number of arguments unmatched");
170 NError(E_PARAMS).ThrowErr(env);
171 return nullptr;
172 }
173 std::vector<UriPolicyInfo> uriPolicies;
174 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
175 NError(E_PARAMS).ThrowErr(env);
176 return nullptr;
177 }
178 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
179 auto cbExec = [uriPolicies, arg]() -> NError {
180 arg->errNo = FilePermission::PersistPermission(uriPolicies, arg->errorResults);
181 return NError(arg->errNo);
182 };
183 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
184 if (err) {
185 if (arg->errNo == EPERM) {
186 napi_value data = err.GetNapiErr(env);
187 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
188 return NVal(env, data);
189 }
190 return {env, err.GetNapiErr(env)};
191 }
192 return NVal::CreateUndefined(env);
193 };
194 const string procedureName = "persist_permission";
195 NVal thisVar(env, funcArg.GetThisVar());
196 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
197 }
198
RevokePermission(napi_env env,napi_callback_info info)199 napi_value RevokePermission(napi_env env, napi_callback_info info)
200 {
201 if (!CheckFileManagerFullMountEnable()) {
202 LOGE("The device doesn't support this api");
203 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
204 return nullptr;
205 }
206 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
207 LOGE("RevokePermission has not ohos permission!");
208 NError(E_PERMISSION).ThrowErr(env);
209 return nullptr;
210 }
211 NFuncArg funcArg(env, info);
212 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
213 LOGE("RevokePermission Number of arguments unmatched");
214 NError(E_PARAMS).ThrowErr(env);
215 return nullptr;
216 }
217 std::vector<UriPolicyInfo> uriPolicies;
218 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
219 NError(E_PARAMS).ThrowErr(env);
220 return nullptr;
221 }
222 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
223 auto cbExec = [uriPolicies, arg]() -> NError {
224 arg->errNo = FilePermission::RevokePermission(uriPolicies, arg->errorResults);
225 return NError(arg->errNo);
226 };
227 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
228 if (err) {
229 if (arg->errNo == EPERM) {
230 napi_value data = err.GetNapiErr(env);
231 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
232 return NVal(env, data);
233 }
234 return {env, err.GetNapiErr(env)};
235 }
236 return NVal::CreateUndefined(env);
237 };
238 const string procedureName = "revoke_permission";
239 NVal thisVar(env, funcArg.GetThisVar());
240 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
241 }
242
ActivatePermission(napi_env env,napi_callback_info info)243 napi_value ActivatePermission(napi_env env, napi_callback_info info)
244 {
245 if (!CheckFileManagerFullMountEnable()) {
246 LOGE("The device doesn't support this api");
247 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
248 return nullptr;
249 }
250 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
251 LOGE("PersistPermission has not ohos permission!");
252 NError(E_PERMISSION).ThrowErr(env);
253 return nullptr;
254 }
255 NFuncArg funcArg(env, info);
256 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
257 LOGE("ActivatePermission Number of arguments unmatched");
258 NError(E_PARAMS).ThrowErr(env);
259 return nullptr;
260 }
261 std::vector<UriPolicyInfo> uriPolicies;
262 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
263 NError(E_PARAMS).ThrowErr(env);
264 return nullptr;
265 }
266 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
267 auto cbExec = [uriPolicies, arg]() -> NError {
268 arg->errNo = FilePermission::ActivatePermission(uriPolicies, arg->errorResults);
269 return NError(arg->errNo);
270 };
271 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
272 if (err) {
273 if (arg->errNo == EPERM) {
274 napi_value data = err.GetNapiErr(env);
275 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
276 return NVal(env, data);
277 }
278 return {env, err.GetNapiErr(env)};
279 }
280 return NVal::CreateUndefined(env);
281 };
282 const string procedureName = "activate_permission";
283 NVal thisVar(env, funcArg.GetThisVar());
284 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
285 }
286
DeactivatePermission(napi_env env,napi_callback_info info)287 napi_value DeactivatePermission(napi_env env, napi_callback_info info)
288 {
289 if (!CheckFileManagerFullMountEnable()) {
290 LOGE("The device doesn't support this api");
291 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
292 return nullptr;
293 }
294 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
295 LOGE("PersistPermission has not ohos permission!");
296 NError(E_PERMISSION).ThrowErr(env);
297 return nullptr;
298 }
299 NFuncArg funcArg(env, info);
300 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
301 LOGE("DeactivatePermission Number of arguments unmatched");
302 NError(E_PARAMS).ThrowErr(env);
303 return nullptr;
304 }
305 std::vector<UriPolicyInfo> uriPolicies;
306 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
307 NError(E_PARAMS).ThrowErr(env);
308 return nullptr;
309 }
310 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
311 auto cbExec = [uriPolicies, arg]() -> NError {
312 arg->errNo = FilePermission::DeactivatePermission(uriPolicies, arg->errorResults);
313 return NError(arg->errNo);
314 };
315 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
316 if (err) {
317 if (arg->errNo == EPERM) {
318 napi_value data = err.GetNapiErr(env);
319 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
320 return NVal(env, data);
321 }
322 return {env, err.GetNapiErr(env)};
323 }
324 return NVal::CreateUndefined(env);
325 };
326 const string procedureName = "deactivate_permission";
327 NVal thisVar(env, funcArg.GetThisVar());
328 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
329 }
330
CheckPersistentPermission(napi_env env,napi_callback_info info)331 napi_value CheckPersistentPermission(napi_env env, napi_callback_info info)
332 {
333 if (!CheckFileManagerFullMountEnable()) {
334 LOGE("The device doesn't support this api");
335 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
336 return nullptr;
337 }
338 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
339 LOGE("PersistPermission has not ohos permission!");
340 NError(E_PERMISSION).ThrowErr(env);
341 return nullptr;
342 }
343 NFuncArg funcArg(env, info);
344 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
345 LOGE("ActivatePermission Number of arguments unmatched");
346 NError(E_PARAMS).ThrowErr(env);
347 return nullptr;
348 }
349 std::vector<UriPolicyInfo> uriPolicies;
350 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
351 NError(E_PARAMS).ThrowErr(env);
352 return nullptr;
353 }
354 shared_ptr<PolicyInfoResultArgs> arg = make_shared<PolicyInfoResultArgs>();
355 auto cbExec = [uriPolicies, arg]() -> NError {
356 arg->errNo = FilePermission::CheckPersistentPermission(uriPolicies, arg->resultData);
357 return NError(arg->errNo);
358 };
359 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
360 if (arg->errNo != 0) {
361 return {env, err.GetNapiErr(env)};
362 }
363 return {env, GetResultData(env, arg->resultData)};
364 };
365 const string procedureName = "check_persist_permission";
366 NVal thisVar(env, funcArg.GetThisVar());
367 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
368 }
369
370 } // namespace ModuleFileShare
371 } // namespace AppFileService
372 } // namespace OHOS
373