• 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 
16 #include "napi_geolocation_permission.h"
17 
18 #include <cstdint>
19 #include <vector>
20 
21 #include "business_error.h"
22 #include "napi/native_common.h"
23 #include "nweb_data_base.h"
24 #include "nweb_helper.h"
25 #include "web_errors.h"
26 #include "securec.h"
27 
28 namespace {
29 constexpr int32_t PARAMZERO = 0;
30 constexpr int32_t PARAMONE = 1;
31 constexpr int32_t PARAMTWO = 2;
32 constexpr int32_t RESULT_COUNT = 2;
33 constexpr int32_t INTERFACE_OK = 0;
34 constexpr int32_t INTERFACE_ERROR = -1;
35 constexpr int32_t ALLOW_PERMISSION_OPERATION = 1;
36 constexpr int32_t DELETE_PERMISSION_OPERATION = 2;
37 
38 struct GetPermissionOriginsParam {
39     std::vector<std::string> origins;
40     napi_env env;
41     napi_async_work asyncWork;
42     napi_deferred deferred;
43     napi_ref callbackRef;
44     napi_status status;
45     int errCode;
46 };
47 
48 struct GetOriginPermissionStateParam {
49     bool retValue;
50     std::string origin;
51     napi_env env;
52     napi_async_work asyncWork;
53     napi_deferred deferred;
54     napi_ref jsStringRef;
55     napi_ref callbackRef;
56     napi_status status;
57     int errCode;
58 };
59 }
60 
61 namespace OHOS {
62 namespace NWeb {
Init(napi_env env,napi_value exports)63 napi_value NapiGeolocationPermission::Init(napi_env env, napi_value exports)
64 {
65     const std::string GEOLOCATION_PERMISSION_CLASS_NAME = "GeolocationPermissions";
66     napi_property_descriptor properties[] = {
67         DECLARE_NAPI_STATIC_FUNCTION("allowGeolocation", NapiGeolocationPermission::JsAllowGeolocation),
68         DECLARE_NAPI_STATIC_FUNCTION("deleteGeolocation", NapiGeolocationPermission::JsDeleteGeolocation),
69         DECLARE_NAPI_STATIC_FUNCTION("deleteAllGeolocation", NapiGeolocationPermission::JsDeleteAllGeolocation),
70         DECLARE_NAPI_STATIC_FUNCTION("getStoredGeolocation", NapiGeolocationPermission::JsGetStoredGeolocation),
71         DECLARE_NAPI_STATIC_FUNCTION("getAccessibleGeolocation",
72             NapiGeolocationPermission::JsGetAccessibleGeolocation),
73     };
74     napi_value constructor = nullptr;
75     napi_define_class(env, GEOLOCATION_PERMISSION_CLASS_NAME.c_str(), GEOLOCATION_PERMISSION_CLASS_NAME.length(),
76         JsConstructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);
77     NAPI_ASSERT(env, constructor != nullptr, "NapiGeolocationPermission define js class failed");
78     napi_status status = napi_set_named_property(env, exports, "GeolocationPermissions", constructor);
79     NAPI_ASSERT(env, status == napi_ok, "NapiGeolocationPermission set property failed");
80     return exports;
81 }
82 
GetStringPara(napi_env env,napi_value argv,std::string & outValue)83 bool NapiGeolocationPermission::GetStringPara(napi_env env, napi_value argv, std::string& outValue)
84 {
85     constexpr int32_t MAX_STRING_LENGTH = 40960;
86     size_t bufferSize = 0;
87     napi_valuetype valueType = napi_null;
88 
89     napi_typeof(env, argv, &valueType);
90     if (valueType != napi_string) {
91         return false;
92     }
93     napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize);
94     if (bufferSize > MAX_STRING_LENGTH) {
95         return false;
96     }
97     char stringValue[bufferSize + 1];
98     size_t jsStringLength = 0;
99     napi_get_value_string_utf8(env, argv, stringValue, bufferSize + 1, &jsStringLength);
100     if (jsStringLength != bufferSize) {
101         return false;
102     }
103     outValue = stringValue;
104     return true;
105 }
106 
ProcessActionByType(napi_env env,napi_callback_info info,int32_t operationType)107 napi_value NapiGeolocationPermission::ProcessActionByType(napi_env env, napi_callback_info info,
108     int32_t operationType)
109 {
110     napi_value retValue = nullptr;
111     size_t argc = PARAMONE;
112     napi_value argv[PARAMONE] = { 0 };
113     napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
114     if (argc != PARAMONE) {
115         NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
116         return nullptr;
117     }
118 
119     std::string origin;
120     if (!GetStringPara(env, argv[PARAMZERO], origin)) {
121         NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
122         return nullptr;
123     }
124 
125     napi_value result = nullptr;
126     napi_get_undefined(env, &result);
127     OHOS::NWeb::NWebDataBase *dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
128     if (!dataBase) {
129         return result;
130     }
131     if (operationType == ALLOW_PERMISSION_OPERATION) {
132         if (dataBase->SetPermissionByOrigin(origin, OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE,
133             true) == NWebError::INVALID_ORIGIN) {
134             NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_ORIGIN);
135             return result;
136         }
137     } else if (operationType == DELETE_PERMISSION_OPERATION) {
138         if (dataBase->ClearPermissionByOrigin(origin, OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE)
139             == NWebError::INVALID_ORIGIN) {
140             NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_ORIGIN);
141             return result;
142         }
143     }
144     return result;
145 }
146 
JsAllowGeolocation(napi_env env,napi_callback_info info)147 napi_value NapiGeolocationPermission::JsAllowGeolocation(napi_env env, napi_callback_info info)
148 {
149     return ProcessActionByType(env, info, ALLOW_PERMISSION_OPERATION);
150 }
151 
JsDeleteGeolocation(napi_env env,napi_callback_info info)152 napi_value NapiGeolocationPermission::JsDeleteGeolocation(napi_env env, napi_callback_info info)
153 {
154     return ProcessActionByType(env, info, DELETE_PERMISSION_OPERATION);
155 }
156 
JsDeleteAllGeolocation(napi_env env,napi_callback_info info)157 napi_value NapiGeolocationPermission::JsDeleteAllGeolocation(napi_env env, napi_callback_info info)
158 {
159     OHOS::NWeb::NWebDataBase *dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
160     if (dataBase != nullptr) {
161         dataBase->ClearAllPermission(OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE);
162     }
163 
164     napi_value result = nullptr;
165     napi_get_undefined(env, &result);
166     return result;
167 }
168 
GetPermissionStateComplete(napi_env env,napi_status status,void * data)169 void NapiGeolocationPermission::GetPermissionStateComplete(napi_env env, napi_status status, void *data)
170 {
171     GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
172     napi_handle_scope scope = nullptr;
173     napi_open_handle_scope(env, &scope);
174     if (scope == nullptr) {
175         return;
176     }
177     napi_value setResult[RESULT_COUNT] = {0};
178     if (param->status) {
179         setResult[PARAMZERO] = NWebError::BusinessError::CreateError(env, param->errCode);
180         napi_get_undefined(env, &setResult[PARAMONE]);
181     } else {
182         napi_get_undefined(env, &setResult[PARAMZERO]);
183         napi_get_boolean(env, param->retValue, &setResult[PARAMONE]);
184     }
185     napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
186     napi_value callback = nullptr;
187     napi_get_reference_value(env, param->callbackRef, &callback);
188     napi_value returnVal = nullptr;
189     napi_call_function(env, nullptr, callback, RESULT_COUNT, args, &returnVal);
190     napi_delete_reference(env, param->jsStringRef);
191     napi_delete_reference(env, param->callbackRef);
192     napi_delete_async_work(env, param->asyncWork);
193     napi_close_handle_scope(env, scope);
194     delete param;
195     param = nullptr;
196 }
197 
GetPermissionStatePromiseComplete(napi_env env,napi_status status,void * data)198 void NapiGeolocationPermission::GetPermissionStatePromiseComplete(napi_env env, napi_status status, void *data)
199 {
200     GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
201     napi_handle_scope scope = nullptr;
202     napi_open_handle_scope(env, &scope);
203     if (scope == nullptr) {
204         return;
205     }
206     napi_value setResult[RESULT_COUNT] = {0};
207     setResult[PARAMZERO] = NWebError::BusinessError::CreateError(env, param->errCode);
208     napi_get_boolean(env, param->retValue, &setResult[PARAMONE]);
209     napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
210     if (param->status == napi_ok) {
211         napi_resolve_deferred(env, param->deferred, args[1]);
212     } else {
213         napi_reject_deferred(env, param->deferred, args[0]);
214     }
215     napi_delete_reference(env, param->jsStringRef);
216     napi_delete_async_work(env, param->asyncWork);
217     napi_close_handle_scope(env, scope);
218     delete param;
219     param = nullptr;
220 }
221 
ExecuteGetPermissionState(napi_env env,void * data)222 void NapiGeolocationPermission::ExecuteGetPermissionState(napi_env env, void *data)
223 {
224     GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
225     OHOS::NWeb::NWebDataBase* dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
226     if (!dataBase) {
227         param->errCode = INTERFACE_ERROR;
228         param->status = napi_generic_failure;
229         return;
230     }
231     if (dataBase->GetPermissionResultByOrigin(param->origin,
232         OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE, param->retValue)) {
233         param->errCode = INTERFACE_OK;
234         param->status = napi_ok;
235     } else {
236         param->errCode = NWebError::INVALID_ORIGIN;
237         param->status = napi_generic_failure;
238     }
239 }
240 
GetPermissionStateAsync(napi_env env,napi_value * argv,const std::string & origin)241 napi_value NapiGeolocationPermission::GetPermissionStateAsync(napi_env env, napi_value *argv,
242     const std::string& origin)
243 {
244     napi_value result = nullptr;
245     napi_value resourceName = nullptr;
246 
247     GetOriginPermissionStateParam *param = new (std::nothrow) GetOriginPermissionStateParam {
248         .retValue = false,
249         .origin = origin,
250         .env = env,
251         .asyncWork = nullptr,
252         .deferred = nullptr,
253         .jsStringRef = nullptr,
254         .callbackRef = nullptr,
255     };
256     if (param == nullptr) {
257         return nullptr;
258     }
259     napi_create_reference(env, argv[0], 1, &param->jsStringRef);
260     napi_create_reference(env, argv[1], 1, &param->callbackRef);
261     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
262     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetPermissionState,
263         GetPermissionStateComplete, static_cast<void *>(param), &param->asyncWork));
264     NAPI_CALL(env, napi_queue_async_work(env, param->asyncWork));
265     napi_get_undefined(env, &result);
266     return result;
267 }
268 
GetPermissionStatePromise(napi_env env,napi_value * argv,const std::string & origin)269 napi_value NapiGeolocationPermission::GetPermissionStatePromise(napi_env env, napi_value *argv,
270     const std::string& origin)
271 {
272     napi_deferred deferred = nullptr;
273     napi_value promise = nullptr;
274     napi_create_promise(env, &deferred, &promise);
275 
276     GetOriginPermissionStateParam *param = new (std::nothrow) GetOriginPermissionStateParam {
277         .retValue = false,
278         .origin = origin,
279         .env = env,
280         .asyncWork = nullptr,
281         .deferred = deferred,
282         .jsStringRef = nullptr,
283         .callbackRef = nullptr,
284     };
285     if (param == nullptr) {
286         return nullptr;
287     }
288     napi_create_reference(env, argv[0], 1, &param->jsStringRef);
289     napi_value resourceName = nullptr;
290     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
291     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetPermissionState,
292         GetPermissionStatePromiseComplete, static_cast<void *>(param), &param->asyncWork));
293     NAPI_CALL(env, napi_queue_async_work(env, param->asyncWork));
294     return promise;
295 }
296 
JsGetAccessibleGeolocation(napi_env env,napi_callback_info info)297 napi_value NapiGeolocationPermission::JsGetAccessibleGeolocation(napi_env env, napi_callback_info info)
298 {
299     napi_value retValue = nullptr;
300     size_t argc = PARAMTWO;
301     size_t argcPromise = PARAMONE;
302     size_t argcCallback = PARAMTWO;
303     napi_value argv[PARAMTWO] = { 0 };
304     napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
305     if (argc != argcPromise && argc != argcCallback) {
306         NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
307         return nullptr;
308     }
309     std::string origin;
310 
311     if (!GetStringPara(env, argv[PARAMZERO], origin)) {
312         NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
313         return nullptr;
314     }
315 
316     if (argc == argcCallback) {
317         napi_valuetype valueType = napi_undefined;
318         napi_typeof(env, argv[PARAMONE], &valueType);
319         if (valueType != napi_function) {
320             NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
321             return nullptr;
322         }
323         GetPermissionStateAsync(env, argv, origin);
324         napi_value result = nullptr;
325         napi_get_undefined(env, &result);
326         return result;
327     }
328     return GetPermissionStatePromise(env, argv, origin);
329 }
330 
GetOriginComplete(napi_env env,napi_status status,void * data)331 void NapiGeolocationPermission::GetOriginComplete(napi_env env, napi_status status, void *data)
332 {
333     GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
334     napi_handle_scope scope = nullptr;
335     napi_open_handle_scope(env, &scope);
336     if (scope == nullptr) {
337         return;
338     }
339     napi_value setResult[RESULT_COUNT] = {0};
340     if (param->status) {
341         napi_get_undefined(env, &setResult[PARAMZERO]);
342         napi_get_undefined(env, &setResult[PARAMONE]);
343     } else {
344         napi_get_undefined(env, &setResult[PARAMZERO]);
345         napi_create_array(env, &setResult[PARAMONE]);
346         for (uint32_t i = 0; i < param->origins.size(); i++) {
347             std::string str = param->origins[i];
348             napi_value val = nullptr;
349             napi_create_string_utf8(env, str.c_str(), str.length(), &val);
350             napi_set_element(env, setResult[PARAMONE], i, val);
351         }
352     }
353     napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
354     napi_value callback = nullptr;
355     napi_get_reference_value(env, param->callbackRef, &callback);
356     napi_value returnVal = nullptr;
357     napi_call_function(env, nullptr, callback, RESULT_COUNT, args, &returnVal);
358     napi_delete_reference(env, param->callbackRef);
359     napi_delete_async_work(env, param->asyncWork);
360     napi_close_handle_scope(env, scope);
361     delete param;
362     param = nullptr;
363 }
364 
GetOriginsPromiseComplete(napi_env env,napi_status status,void * data)365 void NapiGeolocationPermission::GetOriginsPromiseComplete(napi_env env, napi_status status, void *data)
366 {
367     GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
368     napi_handle_scope scope = nullptr;
369     napi_open_handle_scope(env, &scope);
370     if (scope == nullptr) {
371         return;
372     }
373     napi_value setResult[RESULT_COUNT] = {0};
374     napi_get_undefined(env, &setResult[PARAMZERO]);
375     napi_create_array(env, &setResult[PARAMONE]);
376     for (uint32_t i = 0; i < param->origins.size(); i++) {
377         std::string str = param->origins[i];
378         napi_value val = nullptr;
379         napi_create_string_utf8(env, str.c_str(), str.length(), &val);
380         napi_set_element(env, setResult[PARAMONE], i, val);
381     }
382     napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
383     if (param->status == napi_ok) {
384         napi_resolve_deferred(env, param->deferred, args[1]);
385     } else {
386         napi_reject_deferred(env, param->deferred, args[0]);
387     }
388     napi_delete_async_work(env, param->asyncWork);
389     napi_close_handle_scope(env, scope);
390     delete param;
391     param = nullptr;
392 }
393 
ExecuteGetOrigins(napi_env env,void * data)394 void NapiGeolocationPermission::ExecuteGetOrigins(napi_env env, void *data)
395 {
396     GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
397     OHOS::NWeb::NWebDataBase *dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
398     if (!dataBase) {
399         param->errCode = INTERFACE_ERROR;
400         param->status = napi_generic_failure;
401         return;
402     }
403     param->origins = dataBase->GetOriginsByPermission(OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE);
404     param->errCode = INTERFACE_OK;
405     param->status = napi_ok;
406 }
407 
GetOriginsAsync(napi_env env,napi_value * argv)408 napi_value NapiGeolocationPermission::GetOriginsAsync(napi_env env, napi_value *argv)
409 {
410     napi_value result = nullptr;
411     napi_value resourceName = nullptr;
412 
413     GetPermissionOriginsParam *param = new (std::nothrow) GetPermissionOriginsParam {
414         .env = env,
415         .asyncWork = nullptr,
416         .deferred = nullptr,
417         .callbackRef = nullptr,
418     };
419     if (param == nullptr) {
420         return nullptr;
421     }
422     napi_create_reference(env, *argv, 1, &param->callbackRef);
423     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
424     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetOrigins,
425         GetOriginComplete, static_cast<void *>(param), &param->asyncWork));
426     NAPI_CALL(env, napi_queue_async_work(env, param->asyncWork));
427     napi_get_undefined(env, &result);
428     return result;
429 }
430 
GetOriginsPromise(napi_env env)431 napi_value NapiGeolocationPermission::GetOriginsPromise(napi_env env)
432 {
433     napi_deferred deferred = nullptr;
434     napi_value promise = nullptr;
435     napi_create_promise(env, &deferred, &promise);
436 
437     GetPermissionOriginsParam *param = new (std::nothrow) GetPermissionOriginsParam {
438         .env = env,
439         .asyncWork = nullptr,
440         .deferred = deferred,
441         .callbackRef = nullptr,
442     };
443     if (param == nullptr) {
444         return nullptr;
445     }
446     napi_value resourceName = nullptr;
447     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
448     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetOrigins,
449         GetOriginsPromiseComplete, static_cast<void *>(param), &param->asyncWork));
450     NAPI_CALL(env, napi_queue_async_work(env, param->asyncWork));
451     return promise;
452 }
453 
JsGetStoredGeolocation(napi_env env,napi_callback_info info)454 napi_value NapiGeolocationPermission::JsGetStoredGeolocation(napi_env env, napi_callback_info info)
455 {
456     napi_value retValue = nullptr;
457     size_t argc = PARAMONE;
458     size_t argcPromise = PARAMZERO;
459     size_t argcCallback = PARAMONE;
460     napi_value argv = nullptr;
461     napi_get_cb_info(env, info, &argc, &argv, &retValue, nullptr);
462     if (argc != argcPromise && argc != argcCallback) {
463         NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
464         return nullptr;
465     }
466     if (argc == argcCallback) {
467         napi_valuetype valueType = napi_undefined;
468         napi_typeof(env, argv, &valueType);
469         if (valueType != napi_function) {
470             NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
471             return nullptr;
472         }
473         GetOriginsAsync(env, &argv);
474         napi_value result = nullptr;
475         napi_get_undefined(env, &result);
476         return result;
477     }
478     return GetOriginsPromise(env);
479 }
480 
JsConstructor(napi_env env,napi_callback_info info)481 napi_value NapiGeolocationPermission::JsConstructor(napi_env env, napi_callback_info info)
482 {
483     napi_value thisVar = nullptr;
484     size_t argc = PARAMTWO;
485     napi_value argv[PARAMTWO] = { 0 };
486     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
487     return thisVar;
488 }
489 } // namespace NWeb
490 } // namespace OHOS
491