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, ¶m->jsStringRef);
260 napi_create_reference(env, argv[1], 1, ¶m->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), ¶m->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, ¶m->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), ¶m->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, ¶m->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), ¶m->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), ¶m->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