* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "napi_geolocation_permission.h"
#include <cstdint>
#include <vector>
#include "business_error.h"
#include "nweb_napi_scope.h"
#include "napi/native_common.h"
#include "nweb_data_base.h"
#include "nweb_helper.h"
#include "web_errors.h"
#include "securec.h"
namespace {
constexpr int32_t PARAMZERO = 0;
constexpr int32_t PARAMONE = 1;
constexpr int32_t PARAMTWO = 2;
constexpr int32_t PARAMTHREE = 3;
constexpr int32_t RESULT_COUNT = 2;
constexpr int32_t INTERFACE_OK = 0;
constexpr int32_t INTERFACE_ERROR = -1;
constexpr int32_t ALLOW_PERMISSION_OPERATION = 1;
constexpr int32_t DELETE_PERMISSION_OPERATION = 2;
struct GetPermissionOriginsParam {
std::vector<std::string> origins;
napi_env env;
napi_async_work asyncWork;
napi_deferred deferred;
napi_ref callbackRef;
napi_status status;
int errCode;
bool incognitoMode;
};
struct GetOriginPermissionStateParam {
bool retValue;
bool incognitoMode;
std::string origin;
napi_env env;
napi_async_work asyncWork;
napi_deferred deferred;
napi_ref jsStringRef;
napi_ref callbackRef;
napi_status status;
int errCode;
};
}
namespace OHOS {
namespace NWeb {
napi_value NapiGeolocationPermission::Init(napi_env env, napi_value exports)
{
const std::string GEOLOCATION_PERMISSION_CLASS_NAME = "GeolocationPermissions";
napi_property_descriptor properties[] = {
DECLARE_NAPI_STATIC_FUNCTION("allowGeolocation", NapiGeolocationPermission::JsAllowGeolocation),
DECLARE_NAPI_STATIC_FUNCTION("deleteGeolocation", NapiGeolocationPermission::JsDeleteGeolocation),
DECLARE_NAPI_STATIC_FUNCTION("deleteAllGeolocation", NapiGeolocationPermission::JsDeleteAllGeolocation),
DECLARE_NAPI_STATIC_FUNCTION("getStoredGeolocation", NapiGeolocationPermission::JsGetStoredGeolocation),
DECLARE_NAPI_STATIC_FUNCTION("getAccessibleGeolocation",
NapiGeolocationPermission::JsGetAccessibleGeolocation),
};
napi_value constructor = nullptr;
napi_define_class(env, GEOLOCATION_PERMISSION_CLASS_NAME.c_str(), GEOLOCATION_PERMISSION_CLASS_NAME.length(),
JsConstructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);
NAPI_ASSERT(env, constructor != nullptr, "NapiGeolocationPermission define js class failed");
napi_status status = napi_set_named_property(env, exports, "GeolocationPermissions", constructor);
NAPI_ASSERT(env, status == napi_ok, "NapiGeolocationPermission set property failed");
return exports;
}
bool NapiGeolocationPermission::GetStringPara(napi_env env, napi_value argv, std::string& outValue)
{
constexpr int32_t MAX_STRING_LENGTH = 40960;
size_t bufferSize = 0;
napi_valuetype valueType = napi_null;
napi_typeof(env, argv, &valueType);
if (valueType != napi_string) {
return false;
}
napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize);
if (bufferSize > MAX_STRING_LENGTH) {
return false;
}
char stringValue[bufferSize + 1];
size_t jsStringLength = 0;
napi_get_value_string_utf8(env, argv, stringValue, bufferSize + 1, &jsStringLength);
if (jsStringLength != bufferSize) {
return false;
}
outValue = stringValue;
return true;
}
bool NapiGeolocationPermission::GetBooleanPara(napi_env env, napi_value argv, bool& outValue)
{
napi_valuetype valueType = napi_null;
napi_typeof(env, argv, &valueType);
if (valueType != napi_boolean) {
return false;
}
bool boolValue;
napi_get_value_bool(env, argv, &boolValue);
outValue = boolValue;
return true;
}
napi_value NapiGeolocationPermission::ProcessActionByType(napi_env env, napi_callback_info info,
int32_t operationType)
{
napi_value retValue = nullptr;
size_t argc = PARAMTWO;
size_t argcForOld = PARAMONE;
napi_value argv[PARAMTWO] = { 0 };
napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
if (argc != PARAMTWO && argc != argcForOld) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_TWO, "one", "two"));
return nullptr;
}
std::string origin;
if (!GetStringPara(env, argv[PARAMZERO], origin)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "origin", "string"));
return nullptr;
}
bool incognitoMode = false;
if (argc == PARAMTWO) {
napi_get_value_bool(env, argv[PARAMONE], &incognitoMode);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
std::shared_ptr<OHOS::NWeb::NWebDataBase> dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
if (!dataBase) {
return result;
}
if (operationType == ALLOW_PERMISSION_OPERATION) {
if (dataBase->SetPermissionByOrigin(origin, OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE, true,
incognitoMode) == NWebError::INVALID_ORIGIN) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_ORIGIN);
return result;
}
} else if (operationType == DELETE_PERMISSION_OPERATION) {
if (dataBase->ClearPermissionByOrigin(origin, OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE,
incognitoMode) == NWebError::INVALID_ORIGIN) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_ORIGIN);
return result;
}
}
return result;
}
napi_value NapiGeolocationPermission::JsAllowGeolocation(napi_env env, napi_callback_info info)
{
return ProcessActionByType(env, info, ALLOW_PERMISSION_OPERATION);
}
napi_value NapiGeolocationPermission::JsDeleteGeolocation(napi_env env, napi_callback_info info)
{
return ProcessActionByType(env, info, DELETE_PERMISSION_OPERATION);
}
napi_value NapiGeolocationPermission::JsDeleteAllGeolocation(napi_env env, napi_callback_info info)
{
napi_value retValue = nullptr;
size_t argc = PARAMONE;
size_t argcForOld = 0;
napi_value argv[PARAMONE] = { 0 };
napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
if (argc != PARAMONE && argc != argcForOld) {
return nullptr;
}
bool incognitoMode = false;
if (argc == PARAMONE) {
napi_get_value_bool(env, argv[PARAMZERO], &incognitoMode);
}
std::shared_ptr<OHOS::NWeb::NWebDataBase> dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
if (dataBase != nullptr) {
dataBase->ClearAllPermission(OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE, incognitoMode);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
return result;
}
void NapiGeolocationPermission::GetPermissionStateComplete(napi_env env, napi_status status, void *data)
{
GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
NApiScope scope(env);
if (!scope.IsVaild()) {
delete param;
param = nullptr;
return;
}
napi_value setResult[RESULT_COUNT] = {0};
if (param->status) {
setResult[PARAMZERO] = NWebError::BusinessError::CreateError(env, param->errCode);
napi_get_undefined(env, &setResult[PARAMONE]);
} else {
napi_get_undefined(env, &setResult[PARAMZERO]);
napi_get_boolean(env, param->retValue, &setResult[PARAMONE]);
}
napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
napi_value callback = nullptr;
napi_get_reference_value(env, param->callbackRef, &callback);
napi_value returnVal = nullptr;
napi_call_function(env, nullptr, callback, RESULT_COUNT, args, &returnVal);
napi_delete_reference(env, param->jsStringRef);
napi_delete_reference(env, param->callbackRef);
napi_delete_async_work(env, param->asyncWork);
delete param;
param = nullptr;
}
void NapiGeolocationPermission::GetPermissionStatePromiseComplete(napi_env env, napi_status status, void *data)
{
GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
NApiScope scope(env);
if (!scope.IsVaild()) {
delete param;
param = nullptr;
return;
}
napi_value setResult[RESULT_COUNT] = {0};
setResult[PARAMZERO] = NWebError::BusinessError::CreateError(env, param->errCode);
napi_get_boolean(env, param->retValue, &setResult[PARAMONE]);
napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
if (param->status == napi_ok) {
napi_resolve_deferred(env, param->deferred, args[1]);
} else {
napi_reject_deferred(env, param->deferred, args[0]);
}
napi_delete_reference(env, param->jsStringRef);
napi_delete_async_work(env, param->asyncWork);
delete param;
param = nullptr;
}
void NapiGeolocationPermission::ExecuteGetPermissionState(napi_env env, void *data)
{
GetOriginPermissionStateParam *param = static_cast<GetOriginPermissionStateParam *>(data);
std::shared_ptr<OHOS::NWeb::NWebDataBase> dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
if (!dataBase) {
param->errCode = INTERFACE_ERROR;
param->status = napi_generic_failure;
return;
}
if (dataBase->GetPermissionResultByOrigin(param->origin,
OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE, param->retValue, param->incognitoMode)) {
param->errCode = INTERFACE_OK;
param->status = napi_ok;
} else {
param->errCode = NWebError::INVALID_ORIGIN;
param->status = napi_generic_failure;
}
}
napi_value NapiGeolocationPermission::GetPermissionStateAsync(napi_env env,
napi_value *argv, const std::string& origin, bool incognitoMode)
{
napi_value result = nullptr;
napi_value resourceName = nullptr;
GetOriginPermissionStateParam *param = new (std::nothrow) GetOriginPermissionStateParam {
.retValue = false,
.incognitoMode = incognitoMode,
.origin = origin,
.env = env,
.asyncWork = nullptr,
.deferred = nullptr,
.jsStringRef = nullptr,
.callbackRef = nullptr,
};
if (param == nullptr) {
return nullptr;
}
napi_create_reference(env, argv[0], 1, ¶m->jsStringRef);
napi_create_reference(env, argv[1], 1, ¶m->callbackRef);
NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetPermissionState,
GetPermissionStateComplete, static_cast<void *>(param), ¶m->asyncWork));
NAPI_CALL(env, napi_queue_async_work_with_qos(env, param->asyncWork, napi_qos_user_initiated));
napi_get_undefined(env, &result);
return result;
}
napi_value NapiGeolocationPermission::GetPermissionStatePromise(napi_env env, napi_value *argv,
const std::string& origin, bool incognitoMode)
{
napi_deferred deferred = nullptr;
napi_value promise = nullptr;
napi_create_promise(env, &deferred, &promise);
GetOriginPermissionStateParam *param = new (std::nothrow) GetOriginPermissionStateParam {
.retValue = false,
.incognitoMode = incognitoMode,
.origin = origin,
.env = env,
.asyncWork = nullptr,
.deferred = deferred,
.jsStringRef = nullptr,
.callbackRef = nullptr,
};
if (param == nullptr) {
return nullptr;
}
napi_create_reference(env, argv[0], 1, ¶m->jsStringRef);
napi_value resourceName = nullptr;
NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetPermissionState,
GetPermissionStatePromiseComplete, static_cast<void *>(param), ¶m->asyncWork));
NAPI_CALL(env, napi_queue_async_work_with_qos(env, param->asyncWork, napi_qos_user_initiated));
return promise;
}
napi_value NapiGeolocationPermission::JsGetAccessibleGeolocation(napi_env env, napi_callback_info info)
{
napi_value retValue = nullptr;
size_t argc = PARAMTHREE;
size_t argcPromiseForOld = PARAMONE;
size_t argcPromise = PARAMTWO;
size_t argcCallback = PARAMTHREE;
napi_value argv[PARAMTHREE] = { 0 };
napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
if (argc != argcPromise && argc != argcCallback && argc != argcPromiseForOld) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_THREE, "one", "two", "three"));
return nullptr;
}
std::string origin;
if (!GetStringPara(env, argv[PARAMZERO], origin)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "origin", "string"));
return nullptr;
}
bool incognitoMode = false;
napi_value result = nullptr;
if (argc == argcCallback) {
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[PARAMONE], &valueType);
if (valueType != napi_function) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "callback", "function"));
return nullptr;
}
if (!GetBooleanPara(env, argv[PARAMTWO], incognitoMode)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "incognito", "boolean"));
return nullptr;
}
GetPermissionStateAsync(env, argv, origin, incognitoMode);
napi_get_undefined(env, &result);
return result;
}
if (argc == PARAMTWO) {
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[PARAMONE], &valueType);
if (valueType != napi_function) {
if (!GetBooleanPara(env, argv[PARAMONE], incognitoMode)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "incognito", "boolean"));
return nullptr;
}
return GetPermissionStatePromise(env, argv, origin, incognitoMode);
}
GetPermissionStateAsync(env, argv, origin, incognitoMode);
napi_get_undefined(env, &result);
return result;
}
return GetPermissionStatePromise(env, argv, origin, incognitoMode);
}
void NapiGeolocationPermission::GetOriginComplete(napi_env env, napi_status status, void *data)
{
GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
NApiScope scope(env);
if (!scope.IsVaild()) {
delete param;
param = nullptr;
return;
}
napi_value setResult[RESULT_COUNT] = {0};
if (param->status) {
napi_get_undefined(env, &setResult[PARAMZERO]);
napi_get_undefined(env, &setResult[PARAMONE]);
} else {
napi_get_undefined(env, &setResult[PARAMZERO]);
napi_create_array(env, &setResult[PARAMONE]);
for (uint32_t i = 0; i < param->origins.size(); i++) {
std::string str = param->origins[i];
napi_value val = nullptr;
napi_create_string_utf8(env, str.c_str(), str.length(), &val);
napi_set_element(env, setResult[PARAMONE], i, val);
}
}
napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
napi_value callback = nullptr;
napi_get_reference_value(env, param->callbackRef, &callback);
napi_value returnVal = nullptr;
napi_call_function(env, nullptr, callback, RESULT_COUNT, args, &returnVal);
napi_delete_reference(env, param->callbackRef);
napi_delete_async_work(env, param->asyncWork);
delete param;
param = nullptr;
}
void NapiGeolocationPermission::GetOriginsPromiseComplete(napi_env env, napi_status status, void *data)
{
GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
NApiScope scope(env);
if (!scope.IsVaild()) {
delete param;
param = nullptr;
return;
}
napi_value setResult[RESULT_COUNT] = {0};
napi_get_undefined(env, &setResult[PARAMZERO]);
napi_create_array(env, &setResult[PARAMONE]);
for (uint32_t i = 0; i < param->origins.size(); i++) {
std::string str = param->origins[i];
napi_value val = nullptr;
napi_create_string_utf8(env, str.c_str(), str.length(), &val);
napi_set_element(env, setResult[PARAMONE], i, val);
}
napi_value args[RESULT_COUNT] = {setResult[PARAMZERO], setResult[PARAMONE]};
if (param->status == napi_ok) {
napi_resolve_deferred(env, param->deferred, args[1]);
} else {
napi_reject_deferred(env, param->deferred, args[0]);
}
napi_delete_async_work(env, param->asyncWork);
delete param;
param = nullptr;
}
void NapiGeolocationPermission::ExecuteGetOrigins(napi_env env, void *data)
{
GetPermissionOriginsParam *param = static_cast<GetPermissionOriginsParam *>(data);
std::shared_ptr<OHOS::NWeb::NWebDataBase> dataBase = OHOS::NWeb::NWebHelper::Instance().GetDataBase();
if (!dataBase) {
param->errCode = INTERFACE_ERROR;
param->status = napi_generic_failure;
return;
}
param->origins = dataBase->GetOriginsByPermission(
OHOS::NWeb::NWebDataBase::WebPermissionType::GEOLOCATION_TYPE, param->incognitoMode);
param->errCode = INTERFACE_OK;
param->status = napi_ok;
}
napi_value NapiGeolocationPermission::GetOriginsAsync(napi_env env,
napi_value *argv,
bool incognitoMode)
{
napi_value result = nullptr;
napi_value resourceName = nullptr;
GetPermissionOriginsParam *param = new (std::nothrow) GetPermissionOriginsParam {
.env = env,
.asyncWork = nullptr,
.deferred = nullptr,
.callbackRef = nullptr,
.incognitoMode = incognitoMode,
};
if (param == nullptr) {
return nullptr;
}
napi_create_reference(env, *argv, 1, ¶m->callbackRef);
NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetOrigins,
GetOriginComplete, static_cast<void *>(param), ¶m->asyncWork));
NAPI_CALL(env, napi_queue_async_work_with_qos(env, param->asyncWork, napi_qos_user_initiated));
napi_get_undefined(env, &result);
return result;
}
napi_value NapiGeolocationPermission::GetOriginsPromise(napi_env env,
bool incognitoMode)
{
napi_deferred deferred = nullptr;
napi_value promise = nullptr;
napi_create_promise(env, &deferred, &promise);
napi_value resourceName = nullptr;
NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
GetPermissionOriginsParam *param = new (std::nothrow) GetPermissionOriginsParam {
.env = env,
.asyncWork = nullptr,
.deferred = deferred,
.callbackRef = nullptr,
.incognitoMode = incognitoMode,
};
if (param == nullptr) {
return nullptr;
}
NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteGetOrigins,
GetOriginsPromiseComplete, static_cast<void *>(param), ¶m->asyncWork));
NAPI_CALL(env, napi_queue_async_work_with_qos(env, param->asyncWork, napi_qos_user_initiated));
return promise;
}
napi_value NapiGeolocationPermission::JsGetStoredGeolocation(napi_env env, napi_callback_info info)
{
napi_value retValue = nullptr;
size_t argc = PARAMTWO;
size_t argcForZero = PARAMZERO;
size_t argcPromise = PARAMONE;
size_t argcCallback = PARAMTWO;
napi_value argv[PARAMTWO] = { 0 };
napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
if (argc != argcPromise && argc != argcCallback && argc != argcForZero) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_THREE, "one", "two", "three"));
return nullptr;
}
bool incognitoMode = false;
if (argc == argcCallback) {
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[PARAMZERO], &valueType);
if (valueType != napi_function) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "callback", "function"));
return nullptr;
}
if (!GetBooleanPara(env, argv[PARAMONE], incognitoMode)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "incognito", "boolean"));
return nullptr;
}
GetOriginsAsync(env, argv, incognitoMode);
napi_value result = nullptr;
napi_get_undefined(env, &result);
return result;
}
if (argc == PARAMONE) {
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[PARAMZERO], &valueType);
if (valueType != napi_function) {
if (!GetBooleanPara(env, argv[PARAMZERO], incognitoMode)) {
NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "incognito", "boolean"));
return nullptr;
}
return GetOriginsPromise(env, incognitoMode);
}
GetOriginsAsync(env, argv, incognitoMode);
napi_value result = nullptr;
napi_get_undefined(env, &result);
return result;
}
return GetOriginsPromise(env, incognitoMode);
}
napi_value NapiGeolocationPermission::JsConstructor(napi_env env, napi_callback_info info)
{
napi_value thisVar = nullptr;
size_t argc = PARAMTWO;
napi_value argv[PARAMTWO] = { 0 };
napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
return thisVar;
}
}
}