diff --git a/interfaces/kits/accesstoken/BUILD.gn b/interfaces/kits/accesstoken/BUILD.gn index 71bd9856de28d9c72e0fb57f9e2f46f7cdc1281c..c3781bc36c6943a31a6fcba7f25903a09c5372a0 100644 --- a/interfaces/kits/accesstoken/BUILD.gn +++ b/interfaces/kits/accesstoken/BUILD.gn @@ -18,6 +18,7 @@ ohos_shared_library("libabilityaccessctrl") { "//base/security/access_token/frameworks/common/include", "//base/security/access_token/interfaces/innerkits/accesstoken/include", "//base/security/access_token/interfaces/kits/accesstoken/napi/include", + "//base/security/access_token/interfaces/kits/common/include", "//foundation/arkui/napi/interfaces/inner_api", "//foundation/arkui/napi/interfaces/kits", ] @@ -26,6 +27,7 @@ ohos_shared_library("libabilityaccessctrl") { deps = [ "//base/security/access_token/interfaces/innerkits/accesstoken:libaccesstoken_sdk", + "//base/security/access_token/interfaces/kits/common:libnapi_common", "//foundation/arkui/napi:ace_napi", ] cflags_cc = [ "-DHILOG_ENABLE" ] diff --git a/interfaces/kits/accesstoken/napi/include/napi_atmanager.h b/interfaces/kits/accesstoken/napi/include/napi_atmanager.h index 167e816c95b74db111d3727f2a08908c293b7b12..0be35fe4c1051af96f993f9a9dbb23f32c9e1eea 100644 --- a/interfaces/kits/accesstoken/napi/include/napi_atmanager.h +++ b/interfaces/kits/accesstoken/napi/include/napi_atmanager.h @@ -19,23 +19,68 @@ #include #include #include +#include +#include "access_token.h" +#include "accesstoken_kit.h" +#include "napi_common.h" #include "napi/native_api.h" #include "napi/native_node_api.h" +#include "perm_state_change_callback_customize.h" namespace OHOS { namespace Security { namespace AccessToken { const int AT_PERM_OPERA_FAIL = -1; const int AT_PERM_OPERA_SUCC = 0; -const int VALUE_BUFFER_SIZE = 256; -const int ASYNC_CALL_BACK_VALUES_NUM = 2; const int VERIFY_OR_FLAG_INPUT_MAX_VALUES = 2; const int GRANT_OR_REVOKE_INPUT_MAX_VALUES = 4; +enum PermissionStateChangeType { + PERMISSION_REVOKED_OPER = 0, + PERMISSION_GRANTED_OPER = 1, +}; + static thread_local napi_ref atManagerRef_; const std::string ATMANAGER_CLASS_NAME = "atManager"; +class RegisterPermStateChangeScopePtr : public PermStateChangeCallbackCustomize { +public: + explicit RegisterPermStateChangeScopePtr(const PermStateChangeScope& subscribeInfo); + ~RegisterPermStateChangeScopePtr(); + void PermStateChangeCallback(PermStateChangeInfo& result) override; + void SetEnv(const napi_env& env); + void SetCallbackRef(const napi_ref& ref); +private: + napi_env env_ = nullptr; + napi_ref ref_ = nullptr; +}; + +struct RegisterPermStateChangeWorker { + napi_env env = nullptr; + napi_ref ref = nullptr; + PermStateChangeInfo result; + RegisterPermStateChangeScopePtr* subscriber = nullptr; +}; + +struct PermStateChangeContext { + virtual ~PermStateChangeContext(); + napi_env env = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + int32_t errCode = RET_FAILED; + std::string permStateChangeType; + PermStateChangeScope scopeInfo; + AccessTokenKit* accessTokenKit = nullptr; + std::shared_ptr subscriber = nullptr; +}; + +struct RegisterPermStateChangeInfo : public PermStateChangeContext {}; + +struct UnregisterPermStateChangeInfo : public PermStateChangeContext { + ~UnregisterPermStateChangeInfo(); +}; + struct AtManagerAsyncContext { napi_env env = nullptr; uint32_t tokenId = 0; @@ -75,6 +120,19 @@ private: static void GetPermissionFlagsExcute(napi_env env, void *data); static void GetPermissionFlagsComplete(napi_env env, napi_status status, void *data); static void SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName); + static bool ParseInputToRegister(const napi_env env, napi_callback_info cbInfo, + RegisterPermStateChangeInfo& registerPermStateChangeInfo); + static napi_value RegisterPermStateChangeCallback(napi_env env, napi_callback_info cbinfo); + static void RegisterPermStateChangeExecute(napi_env env, void* data); + static void RegisterPermStateChangeComplete(napi_env env, napi_status status, void* data); + static bool IsExistRegister(const RegisterPermStateChangeInfo* registerPermStateChangeInfo); + static bool ParseInputToUnregister(const napi_env env, napi_callback_info cbInfo, + UnregisterPermStateChangeInfo& unregisterPermStateChangeInfo); + static napi_value UnregisterPermStateChangeCallback(napi_env env, napi_callback_info cbinfo); + static void UnregisterPermStateChangeExecute(napi_env env, void* data); + static void UnregisterPermStateChangeCompleted(napi_env env, napi_status status, void* data); + static bool FindAndGetSubscriberInMap(UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo); + static void DeleteRegisterInMap(AccessTokenKit* accessTokenKit, const PermStateChangeScope& scopeInfo); }; } // namespace AccessToken } // namespace Security diff --git a/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp b/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp index a74f44ccc758463b49c647b33e686631b6922ae8..99c5f2534c43276c0928951b8f0e6bc589453ff7 100644 --- a/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp +++ b/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -27,12 +28,145 @@ namespace OHOS { namespace Security { namespace AccessToken { +std::mutex g_lockForPermStateChangeRegisters; +std::map> g_permStateChangeRegisters; namespace { static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AccessTokenAbilityAccessCtrl" }; + +static bool ConvertPermStateChangeInfo(napi_env env, napi_value value, const PermStateChangeInfo& result) +{ + napi_value element; + NAPI_CALL_BASE(env, napi_create_int32(env, result.PermStateChangeType, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "change", element), false); + element = nullptr; + NAPI_CALL_BASE(env, napi_create_int32(env, result.tokenID, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "tokenID", element), false); + element = nullptr; + NAPI_CALL_BASE(env, napi_create_string_utf8(env, result.permissionName.c_str(), + NAPI_AUTO_LENGTH, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "permissionName", element), false); + return true; +}; + +static bool CompareScopeInfo(const PermStateChangeScope& scopeInfo, + const std::vector& tokenIDs, const std::vector& permList) +{ + std::vector targetTokenIDs = scopeInfo.tokenIDs; + std::vector targetPermList = scopeInfo.permList; + if (targetTokenIDs.size() != tokenIDs.size() || targetPermList.size() != permList.size()) { + return false; + } + std::sort(targetTokenIDs.begin(), targetTokenIDs.end()); + std::sort(targetPermList.begin(), targetPermList.end()); + if (std::equal(targetTokenIDs.begin(), targetTokenIDs.end(), tokenIDs.begin()) && + std::equal(targetPermList.begin(), targetPermList.end(), permList.begin())) { + return true; + } + return false; +}; + +static void UvQueueWorkPermStateChanged(uv_work_t* work, int status) +{ + if (work == nullptr || work->data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "work == nullptr || work->data == nullptr"); + return; + } + std::unique_ptr uvWorkPtr {work}; + RegisterPermStateChangeWorker* registerPermStateChangeData = + reinterpret_cast(work->data); + std::unique_ptr workPtr {registerPermStateChangeData}; + napi_value result[ARGS_ONE] = {nullptr}; + NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env, + napi_create_array(registerPermStateChangeData->env, &result[PARAM0])); + if (!ConvertPermStateChangeInfo(registerPermStateChangeData->env, + result[PARAM0], registerPermStateChangeData->result)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertPermStateChangeInfo failed"); + return; + } + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value resultout = nullptr; + NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env, + napi_get_undefined(registerPermStateChangeData->env, &undefined)); + NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env, + napi_get_reference_value(registerPermStateChangeData->env, registerPermStateChangeData->ref, &callback)); + NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env, + napi_call_function(registerPermStateChangeData->env, + undefined, callback, ARGS_ONE, &result[PARAM0], &resultout)); + ACCESSTOKEN_LOG_DEBUG(LABEL, "UvQueueWorkPermStateChanged end"); +}; } // namespace +RegisterPermStateChangeScopePtr::RegisterPermStateChangeScopePtr(const PermStateChangeScope& subscribeInfo) + : PermStateChangeCallbackCustomize(subscribeInfo) +{} + +RegisterPermStateChangeScopePtr::~RegisterPermStateChangeScopePtr() +{} + +void RegisterPermStateChangeScopePtr::PermStateChangeCallback(PermStateChangeInfo& result) +{ + uv_loop_s* loop = nullptr; + NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop)); + if (loop == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr"); + return; + } + uv_work_t* work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!"); + return; + } + std::unique_ptr uvWorkPtr {work}; + RegisterPermStateChangeWorker* registerPermStateChangeWorker = + new (std::nothrow) RegisterPermStateChangeWorker(); + if (registerPermStateChangeWorker == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for RegisterPermStateChangeWorker!"); + return; + } + std::unique_ptr workPtr {registerPermStateChangeWorker}; + registerPermStateChangeWorker->env = env_; + registerPermStateChangeWorker->ref = ref_; + registerPermStateChangeWorker->result = result; + ACCESSTOKEN_LOG_DEBUG(LABEL, + "result PermStateChangeType = %{public}d, tokenID = %{public}d, permissionName = %{public}s", + result.PermStateChangeType, result.tokenID, result.permissionName.c_str()); + registerPermStateChangeWorker->subscriber = this; + work->data = reinterpret_cast(registerPermStateChangeWorker); + NAPI_CALL_RETURN_VOID(env_, + uv_queue_work(loop, work, [](uv_work_t* work) {}, UvQueueWorkPermStateChanged)); + uvWorkPtr.release(); + workPtr.release(); +} + +void RegisterPermStateChangeScopePtr::SetEnv(const napi_env& env) +{ + env_ = env; +} + +void RegisterPermStateChangeScopePtr::SetCallbackRef(const napi_ref& ref) +{ + ref_ = ref; +} + +PermStateChangeContext::~PermStateChangeContext() +{ + if (callbackRef != nullptr) { + napi_delete_reference(env, callbackRef); + callbackRef = nullptr; + } +} + +UnregisterPermStateChangeInfo::~UnregisterPermStateChangeInfo() +{ + if (work != nullptr) { + napi_delete_async_work(env, work); + work = nullptr; + } +} + void NapiAtManager::SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName) { napi_value prop = nullptr; @@ -54,7 +188,9 @@ napi_value NapiAtManager::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("verifyAccessTokenSync", VerifyAccessTokenSync), DECLARE_NAPI_FUNCTION("grantUserGrantedPermission", GrantUserGrantedPermission), DECLARE_NAPI_FUNCTION("revokeUserGrantedPermission", RevokeUserGrantedPermission), - DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags) + DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags), + DECLARE_NAPI_FUNCTION("on", RegisterPermStateChangeCallback), + DECLARE_NAPI_FUNCTION("off", UnregisterPermStateChangeCallback), }; napi_value cons = nullptr; @@ -70,8 +206,15 @@ napi_value NapiAtManager::Init(napi_env env, napi_value exports) SetNamedProperty(env, GrantStatus, PERMISSION_DENIED, "PERMISSION_DENIED"); SetNamedProperty(env, GrantStatus, PERMISSION_GRANTED, "PERMISSION_GRANTED"); + napi_value permStateChangeType = nullptr; + napi_create_object(env, &permStateChangeType); + + SetNamedProperty(env, permStateChangeType, PERMISSION_REVOKED_OPER, "PERMISSION_REVOKED_OPER"); + SetNamedProperty(env, permStateChangeType, PERMISSION_GRANTED_OPER, "PERMISSION_GRANTED_OPER"); + napi_property_descriptor exportFuncs[] = { DECLARE_NAPI_PROPERTY("GrantStatus", GrantStatus), + DECLARE_NAPI_PROPERTY("PermissionStateChangeType", permStateChangeType), }; napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs); @@ -85,6 +228,21 @@ napi_value NapiAtManager::JsConstructor(napi_env env, napi_callback_info cbinfo) napi_value thisVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr)); + AccessTokenKit* objectInfo = new (std::nothrow) AccessTokenKit(); + if (objectInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "objectInfo == nullptr"); + return nullptr; + } + if (napi_wrap(env, thisVar, objectInfo, [](napi_env env, void* data, void* hint) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "delete accesstoken kit"); + if (data != nullptr) { + AccessTokenKit* objectInfo = (AccessTokenKit*) data; + delete objectInfo; + } + }, nullptr, nullptr) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_wrap failed"); + return nullptr; + } return thisVar; } @@ -312,7 +470,7 @@ void NapiAtManager::GrantUserGrantedPermissionExcute(napi_env env, void *data) void NapiAtManager::GrantUserGrantedPermissionComplete(napi_env env, napi_status status, void *data) { - AtManagerAsyncContext* asyncContext = reinterpret_cast(data); + AtManagerAsyncContext* asyncContext = reinterpret_cast(data); napi_value results[ASYNC_CALL_BACK_VALUES_NUM] = {nullptr}; // for AsyncCallback // no err, results[0] remain nullptr @@ -383,9 +541,9 @@ napi_value NapiAtManager::GrantUserGrantedPermission(napi_env env, napi_callback return result; } -void NapiAtManager::RevokeUserGrantedPermissionExcute(napi_env env, void *data) +void NapiAtManager::RevokeUserGrantedPermissionExcute(napi_env env, void* data) { - AtManagerAsyncContext* asyncContext = reinterpret_cast(data); + AtManagerAsyncContext* asyncContext = reinterpret_cast(data); PermissionDef permissionDef; // struct init, can not use = { 0 } or memset otherwise program crashdump @@ -490,7 +648,7 @@ napi_value NapiAtManager::RevokeUserGrantedPermission(napi_env env, napi_callbac return result; } -void NapiAtManager::GetPermissionFlagsExcute(napi_env env, void *data) +void NapiAtManager::GetPermissionFlagsExcute(napi_env env, void* data) { AtManagerAsyncContext* asyncContext = reinterpret_cast(data); @@ -550,6 +708,320 @@ napi_value NapiAtManager::GetPermissionFlags(napi_env env, napi_callback_info in return result; } + +bool NapiAtManager::ParseInputToRegister(const napi_env env, const napi_callback_info cbInfo, + RegisterPermStateChangeInfo& registerPermStateChangeInfo) +{ + size_t argc = ARGS_FOUR; + napi_value argv[ARGS_FOUR] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed"); + return false; + } + std::string type = ParseString(env, argv[PARAM0]); + PermStateChangeScope scopeInfo; + if (!ParseAccessTokenIDArray(env, argv[PARAM1], scopeInfo.tokenIDs)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ParseAccessTokenIDArray failed"); + return false; + } + scopeInfo.permList = ParseStringArray(env, argv[PARAM2]); + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[PARAM3], &valueType); // get PRARM[3] type + if (valueType == napi_function) { + if (napi_create_reference(env, argv[PARAM3], 1, &callback) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_create_reference failed"); + return false; + } + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM3] type matching failed"); + return false; + } + registerPermStateChangeInfo.env = env; + registerPermStateChangeInfo.work = nullptr; + registerPermStateChangeInfo.callbackRef = callback; + registerPermStateChangeInfo.permStateChangeType = type; + registerPermStateChangeInfo.scopeInfo = scopeInfo; + registerPermStateChangeInfo.subscriber = std::make_shared(scopeInfo); + AccessTokenKit* accessTokenKitInfo = nullptr; + if (napi_unwrap(env, thisVar, reinterpret_cast(&accessTokenKitInfo)) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_unwrap failed"); + return false; + } + registerPermStateChangeInfo.accessTokenKit = accessTokenKitInfo; + return true; +} + +void NapiAtManager::RegisterPermStateChangeExecute(napi_env env, void* data) +{ + if (data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "data is null"); + return; + } + RegisterPermStateChangeInfo* registerPermStateChangeInfo = + reinterpret_cast(data); + (*registerPermStateChangeInfo->subscriber).SetEnv(env); + (*registerPermStateChangeInfo->subscriber).SetCallbackRef(registerPermStateChangeInfo->callbackRef); + registerPermStateChangeInfo->errCode = + AccessTokenKit::RegisterPermStateChangeCallback(registerPermStateChangeInfo->subscriber); + ACCESSTOKEN_LOG_DEBUG(LABEL, "RegisterPermStateChangeCallback ret = %{public}d", + registerPermStateChangeInfo->errCode); +} + +void NapiAtManager::RegisterPermStateChangeComplete(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "data is null"); + return; + } + RegisterPermStateChangeInfo* registerPermStateChangeInfo = + reinterpret_cast(data); + std::unique_ptr callbackPtr {registerPermStateChangeInfo}; + if (registerPermStateChangeInfo->errCode != RET_SUCCESS) { + ACCESSTOKEN_LOG_ERROR(LABEL, "errCode = %{public}d, delete register in map", + registerPermStateChangeInfo->errCode); + DeleteRegisterInMap(registerPermStateChangeInfo->accessTokenKit, registerPermStateChangeInfo->scopeInfo); + return; + } + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, registerPermStateChangeInfo->work)); + registerPermStateChangeInfo->work = nullptr; + callbackPtr.release(); +} + +napi_value NapiAtManager::RegisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + RegisterPermStateChangeInfo* registerPermStateChangeInfo = + new (std::nothrow) RegisterPermStateChangeInfo(); + if (registerPermStateChangeInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!"); + return nullptr; + } + std::unique_ptr callbackPtr {registerPermStateChangeInfo}; + if (!ParseInputToRegister(env, cbInfo, *registerPermStateChangeInfo)) { + return nullptr; + } + if (IsExistRegister(registerPermStateChangeInfo)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribe failed. The current subscriber has been existed"); + return nullptr; + } + { // add to map + std::lock_guard lock(g_lockForPermStateChangeRegisters); + g_permStateChangeRegisters[registerPermStateChangeInfo->accessTokenKit].emplace_back( + registerPermStateChangeInfo); + ACCESSTOKEN_LOG_DEBUG(LABEL, "add g_PermStateChangeRegisters->second.size = %{public}zu", + g_permStateChangeRegisters[registerPermStateChangeInfo->accessTokenKit].size()); + } + napi_value resource = nullptr; + if (napi_create_string_utf8(env, "RegisterPermStateChangeCallback", NAPI_AUTO_LENGTH, &resource) != napi_ok) { + DeleteRegisterInMap(registerPermStateChangeInfo->accessTokenKit, registerPermStateChangeInfo->scopeInfo); + return nullptr; + } + if (napi_create_async_work(env, + nullptr, + resource, + RegisterPermStateChangeExecute, + RegisterPermStateChangeComplete, + reinterpret_cast(registerPermStateChangeInfo), + ®isterPermStateChangeInfo->work) != napi_ok) { + DeleteRegisterInMap(registerPermStateChangeInfo->accessTokenKit, registerPermStateChangeInfo->scopeInfo); + return nullptr; + } + if (napi_queue_async_work(env, registerPermStateChangeInfo->work) != napi_ok) { + DeleteRegisterInMap(registerPermStateChangeInfo->accessTokenKit, registerPermStateChangeInfo->scopeInfo); + return nullptr; + } + callbackPtr.release(); + return nullptr; +} + +bool NapiAtManager::ParseInputToUnregister(const napi_env env, napi_callback_info cbInfo, + UnregisterPermStateChangeInfo& unregisterPermStateChangeInfo) +{ + size_t argc = ARGS_FOUR; + napi_value argv[ARGS_FOUR] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed"); + return false; + } + std::string type = ParseString(env, argv[PARAM0]); + PermStateChangeScope scopeInfo; + if (!ParseAccessTokenIDArray(env, argv[PARAM1], scopeInfo.tokenIDs)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ParseAccessTokenIDArray failed"); + return false; + } + scopeInfo.permList = ParseStringArray(env, argv[PARAM2]); + if (argc >= ARGS_FOUR) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[PARAM3], &valueType); // get PRARM[3] type + if (valueType == napi_function) { + if (napi_create_reference(env, argv[PARAM3], 1, &callback) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_create_reference failed"); + return false; + } + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM3] type matching failed"); + return false; + } + } + unregisterPermStateChangeInfo.env = env; + unregisterPermStateChangeInfo.callbackRef = callback; + unregisterPermStateChangeInfo.permStateChangeType = type; + unregisterPermStateChangeInfo.scopeInfo = scopeInfo; + AccessTokenKit* accessTokenKitInfo = nullptr; + if (napi_unwrap(env, thisVar, reinterpret_cast(&accessTokenKitInfo)) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_unwrap failed"); + return false; + } + unregisterPermStateChangeInfo.accessTokenKit = accessTokenKitInfo; + return true; +} + +void NapiAtManager::UnregisterPermStateChangeExecute(napi_env env, void* data) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "UnregisterPermStateChangeExecute begin"); + if (data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "data is null"); + return; + } + UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo = + reinterpret_cast(data); + auto subscriber = unregisterPermStateChangeInfo->subscriber; + unregisterPermStateChangeInfo->errCode = AccessTokenKit::UnRegisterPermStateChangeCallback(subscriber); +} + +void NapiAtManager::UnregisterPermStateChangeCompleted(napi_env env, napi_status status, void* data) +{ + if (data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "data is null"); + return; + } + UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo = + reinterpret_cast(data); + std::unique_ptr callbackPtr {unregisterPermStateChangeInfo}; + if (unregisterPermStateChangeInfo->callbackRef != nullptr) { + napi_value results[ARGS_ONE] = {nullptr}; + NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &results[PARAM0])); + napi_value undefined; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + napi_value resultout = nullptr; + napi_value callback = nullptr; + NAPI_CALL_RETURN_VOID(env, + napi_get_reference_value(env, unregisterPermStateChangeInfo->callbackRef, &callback)); + NAPI_CALL_RETURN_VOID(env, + napi_call_function(env, undefined, callback, ARGS_ONE, &results[PARAM0], &resultout)); + } + if (unregisterPermStateChangeInfo->errCode == RET_SUCCESS) { + DeleteRegisterInMap(unregisterPermStateChangeInfo->accessTokenKit, unregisterPermStateChangeInfo->scopeInfo); + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "errCode = %{public}d", unregisterPermStateChangeInfo->errCode); + } +} + +napi_value NapiAtManager::UnregisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo = + new (std::nothrow) UnregisterPermStateChangeInfo(); + if (unregisterPermStateChangeInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!"); + return nullptr; + } + std::unique_ptr callbackPtr {unregisterPermStateChangeInfo}; + if (!ParseInputToUnregister(env, cbInfo, *unregisterPermStateChangeInfo)) { + return nullptr; + } + if (!FindAndGetSubscriberInMap(unregisterPermStateChangeInfo)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Unsubscribe failed. The current subscriber does not exist"); + return nullptr; + } + ACCESSTOKEN_LOG_DEBUG(LABEL, "The current subscriber exist"); + napi_value resource = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "RegisterPermStateChangeCallback", NAPI_AUTO_LENGTH, &resource)); + NAPI_CALL(env, napi_create_async_work(env, + nullptr, + resource, + UnregisterPermStateChangeExecute, + UnregisterPermStateChangeCompleted, + reinterpret_cast(unregisterPermStateChangeInfo), + &(unregisterPermStateChangeInfo->work))); + NAPI_CALL(env, napi_queue_async_work(env, unregisterPermStateChangeInfo->work)); + callbackPtr.release(); + return nullptr; +} + +bool NapiAtManager::FindAndGetSubscriberInMap(UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo) +{ + std::lock_guard lock(g_lockForPermStateChangeRegisters); + std::vector tokenIDs = unregisterPermStateChangeInfo->scopeInfo.tokenIDs; + std::vector permList = unregisterPermStateChangeInfo->scopeInfo.permList; + std::sort(tokenIDs.begin(), tokenIDs.end()); + std::sort(permList.begin(), permList.end()); + auto registerInstance = g_permStateChangeRegisters.find(unregisterPermStateChangeInfo->accessTokenKit); + if (registerInstance != g_permStateChangeRegisters.end()) { + for (const auto& item : registerInstance->second) { + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + if (CompareScopeInfo(scopeInfo, tokenIDs, permList)) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "find subscriber in map"); + unregisterPermStateChangeInfo->subscriber = item->subscriber; + return true; + } + } + } + return false; +} + +bool NapiAtManager::IsExistRegister(const RegisterPermStateChangeInfo* registerPermStateChangeInfo) +{ + std::lock_guard lock(g_lockForPermStateChangeRegisters); + std::vector tokenIDs = registerPermStateChangeInfo->scopeInfo.tokenIDs; + std::vector permList = registerPermStateChangeInfo->scopeInfo.permList; + std::sort(tokenIDs.begin(), tokenIDs.end()); + std::sort(permList.begin(), permList.end()); + auto registerInstance = g_permStateChangeRegisters.find(registerPermStateChangeInfo->accessTokenKit); + if (registerInstance != g_permStateChangeRegisters.end()) { + for (const auto& item : registerInstance->second) { + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + if (CompareScopeInfo(scopeInfo, tokenIDs, permList)) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "find subscriber in map"); + return true; + } + } + } + ACCESSTOKEN_LOG_DEBUG(LABEL, "cannot find subscriber in map"); + return false; +} + +void NapiAtManager::DeleteRegisterInMap(AccessTokenKit* accessTokenKit, const PermStateChangeScope& scopeInfo) +{ + std::vector tokenIDs = scopeInfo.tokenIDs; + std::vector permList = scopeInfo.permList; + std::sort(tokenIDs.begin(), tokenIDs.end()); + std::sort(permList.begin(), permList.end()); + std::lock_guard lock(g_lockForPermStateChangeRegisters); + auto subscribers = g_permStateChangeRegisters.find(accessTokenKit); + if (subscribers != g_permStateChangeRegisters.end()) { + auto it = subscribers->second.begin(); + while (it != subscribers->second.end()) { + if (CompareScopeInfo((*it)->scopeInfo, tokenIDs, permList)) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "Find subscribers in map, delete"); + subscribers->second.erase(it); + delete *it; + *it =nullptr; + break; + } else { + ++it; + } + } + if (subscribers->second.empty()) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "No subscriberInfo in the vector, erase the map."); + g_permStateChangeRegisters.erase(subscribers); + } + } +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/interfaces/kits/common/BUILD.gn b/interfaces/kits/common/BUILD.gn index 7e98c3eea9f896907db387e6a96c53e136baa328..53d90c905a421cdb96105e45fa9764a0b9db9599 100644 --- a/interfaces/kits/common/BUILD.gn +++ b/interfaces/kits/common/BUILD.gn @@ -17,6 +17,7 @@ ohos_static_library("libnapi_common") { include_dirs = [ "include", "//base/security/access_token/frameworks/common/include", + "//base/security/access_token/interfaces/innerkits/accesstoken/include", "//foundation/arkui/napi/interfaces/inner_api", "//foundation/arkui/napi/interfaces/kits", ] diff --git a/interfaces/kits/common/include/napi_common.h b/interfaces/kits/common/include/napi_common.h index 22c77629348377422dec8c36bfe70c16d1810fd0..4dda17ac74b1a469d57a42f8a63537d4c603b811 100644 --- a/interfaces/kits/common/include/napi_common.h +++ b/interfaces/kits/common/include/napi_common.h @@ -16,20 +16,24 @@ #ifndef INTERFACES_PRIVACY_KITS_NAPI_COMMON_H #define INTERFACES_PRIVACY_KITS_NAPI_COMMON_H +#include "access_token.h" #include "napi/native_api.h" #include "napi/native_node_api.h" namespace OHOS { namespace Security { namespace AccessToken { +const int ARGS_ONE = 1; const int ARGS_TWO = 2; const int ARGS_THREE = 3; +const int ARGS_FOUR = 4; const int ARGS_FIVE = 5; const int ASYNC_CALL_BACK_VALUES_NUM = 2; const int PARAM0 = 0; const int PARAM1 = 1; const int PARAM2 = 2; const int PARAM3 = 3; +const int VALUE_BUFFER_SIZE = 256; bool ParseBool(const napi_env env, const napi_value value); int32_t ParseInt32(const napi_env env, const napi_value value); @@ -37,6 +41,8 @@ int64_t ParseInt64(const napi_env env, const napi_value value); uint32_t ParseUint32(const napi_env env, const napi_value value); std::string ParseString(const napi_env env, const napi_value value); std::vector ParseStringArray(const napi_env env, const napi_value value); +bool ParseAccessTokenIDArray(const napi_env& env, const napi_value& value, std::vector& res); +bool IsArray(const napi_env& env, const napi_value& value); } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/interfaces/kits/common/src/napi_common.cpp b/interfaces/kits/common/src/napi_common.cpp index 28c487953d0655b7262dd7729f88c77ab5f43b94..ff9e4c170f55f11b23e6fabb5e7587154dab7211 100644 --- a/interfaces/kits/common/src/napi_common.cpp +++ b/interfaces/kits/common/src/napi_common.cpp @@ -109,14 +109,15 @@ std::string ParseString(const napi_env env, const napi_value value) std::vector ParseStringArray(const napi_env env, const napi_value value) { std::vector res; + if (!IsArray(env, value)) { + return res; + } uint32_t length = 0; napi_valuetype valuetype = napi_undefined; - napi_get_array_length(env, value, &length); napi_value valueArray; for (uint32_t i = 0; i < length; i++) { napi_get_element(env, value, i, &valueArray); - napi_typeof(env, valueArray, &valuetype); if (valuetype == napi_string) { res.emplace_back(ParseString(env, valueArray)); @@ -124,6 +125,31 @@ std::vector ParseStringArray(const napi_env env, const napi_value v } return res; } + +bool ParseAccessTokenIDArray(const napi_env& env, const napi_value& value, std::vector& res) +{ + uint32_t length = 0; + if (!IsArray(env, value)) { + return false; + } + napi_get_array_length(env, value, &length); + napi_value valueArray; + for (uint32_t i = 0; i < length; i++) { + napi_get_element(env, value, i, &valueArray); + res.emplace_back(ParseUint32(env, valueArray)); + } + return true; +}; + +bool IsArray(const napi_env& env, const napi_value& value) +{ + bool isArray = false; + napi_status ret = napi_is_array(env, value, &isArray); + if (ret != napi_ok) { + return false; + } + return isArray; +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file