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