From 8e10a70bc099747db184c6b2991efc49d83266e6 Mon Sep 17 00:00:00 2001 From: bigtea Date: Tue, 12 Aug 2025 14:50:43 +0800 Subject: [PATCH] Add MANUAL_SETTING type v2 Signed-off-by: bigtea --- frameworks/common/include/permission_map.h | 1 + .../common/permission_definition_parser.py | 16 ++ frameworks/common/src/permission_map.cpp | 9 + .../common/src/permission_validator.cpp | 3 +- .../ets/@ohos.abilityAccessCtrl.ets | 35 ++++ .../src/ani_ability_access_ctrl.cpp | 87 +++++++-- .../src/ani_request_permission_on_setting.cpp | 25 +++ frameworks/ets/ani/common/include/ani_error.h | 1 + frameworks/ets/ani/common/src/ani_error.cpp | 1 + frameworks/js/napi/accesstoken/BUILD.gn | 1 + .../napi/accesstoken/src/napi_atmanager.cpp | 168 +++++++++++++++++- .../accesstoken/src/napi_context_common.cpp | 3 + .../napi_request_permission_on_setting.cpp | 26 ++- frameworks/js/napi/common/src/napi_error.cpp | 1 + .../accesstoken/include/access_token.h | 21 +++ .../accesstoken/include/access_token_error.h | 3 +- .../accesstoken/include/accesstoken_kit.h | 8 +- .../accesstoken/libaccesstoken_sdk.map | 4 +- .../accesstoken/src/accesstoken_kit.cpp | 10 +- .../src/accesstoken_manager_client.cpp | 10 +- .../src/accesstoken_manager_client.h | 6 +- .../HapTokenTest/init_hap_token_test.cpp | 36 ++++ .../HapTokenTest/update_hap_token_test.cpp | 101 +++++++++++ .../get_self_permission_state_test.cpp | 47 +++++ .../get_self_permission_status_test.cpp | 48 +++++ .../PermissionsTest/grant_permission_test.cpp | 36 ++++ .../revoke_permission_test.cpp | 40 +++++ .../test/unittest/common/test_common.cpp | 19 ++ .../test/unittest/common/test_common.h | 1 + .../napi/accesstoken/include/napi_atmanager.h | 8 +- .../napi_request_permission_on_setting.h | 1 + .../kits/js/napi/common/include/napi_error.h | 1 + .../idl/IAccessTokenManager.idl | 4 +- .../include/permission/permission_manager.h | 6 +- .../service/accesstoken_manager_service.h | 6 +- .../cpp/src/permission/permission_manager.cpp | 34 +++- .../service/accesstoken_manager_service.cpp | 15 +- .../permission_manager_coverage_test.cpp | 5 + .../accesstoken_info_manager_test.cpp | 3 +- .../test/unittest/permission_manager_test.cpp | 46 +++++ .../grantpermissionstub_fuzzer.cpp | 5 +- .../revokepermissionstub_fuzzer.cpp | 3 +- tools/accesstoken/src/to_string.cpp | 11 +- 43 files changed, 860 insertions(+), 55 deletions(-) diff --git a/frameworks/common/include/permission_map.h b/frameworks/common/include/permission_map.h index 0cf805865..f17c7fd87 100644 --- a/frameworks/common/include/permission_map.h +++ b/frameworks/common/include/permission_map.h @@ -40,6 +40,7 @@ struct PermissionBriefDef { bool TransferPermissionToOpcode(const std::string& permissionName, uint32_t& opCode); bool TransferOpcodeToPermission(uint32_t opCode, std::string& permissionName); bool IsUserGrantPermission(const std::string& permission); +bool IsOperablePermission(const std::string& permission); bool IsDefinedPermission(const std::string& permission); bool GetPermissionBriefDef(const std::string& permission, PermissionBriefDef &permissionBriefDef); void GetPermissionBriefDef(uint32_t code, PermissionBriefDef &permissionBriefDef); diff --git a/frameworks/common/permission_definition_parser.py b/frameworks/common/permission_definition_parser.py index abc9f75d3..314179d96 100755 --- a/frameworks/common/permission_definition_parser.py +++ b/frameworks/common/permission_definition_parser.py @@ -82,6 +82,7 @@ PERMISSION_BRIEF_DEFINE_PATTERN = ''' JSON_VALUE_CONVERT_TO_CPP_DICT = { "user_grant": "USER_GRANT", "system_grant": "SYSTEM_GRANT", + "manual_settings": "MANUAL_SETTINGS", "normal": "APL_NORMAL", "system_basic": "APL_SYSTEM_BASIC", "system_core": "APL_SYSTEM_CORE", @@ -177,6 +178,19 @@ def parse_json(path, platform): 'hasValue' : True } + manual_perm = { + 'name' : 'ohos.permission.MANUAL_ATM_SELF_USE', + 'grantMode' : 'manual_settings', + 'availableLevel' : 'normal', + 'availableType' : 'NORMAL', + 'since' : 19, + 'deprecated' : '', + 'provisionEnable' : True, + 'distributedSceneEnable' : False, + 'isKernelEffect' : False, + 'hasValue' : False + } + def_list = [] with open(path, "r", encoding="utf-8") as f: data = json.load(f) @@ -188,6 +202,8 @@ def parse_json(path, platform): def_list.append(perm_def) index += 1 def_list.append(PermissionDef(extend_perm, index)) + index += 1 + def_list.append(PermissionDef(manual_perm, index)) return def_list diff --git a/frameworks/common/src/permission_map.cpp b/frameworks/common/src/permission_map.cpp index 8b49b5d29..6f3cc27f9 100644 --- a/frameworks/common/src/permission_map.cpp +++ b/frameworks/common/src/permission_map.cpp @@ -84,6 +84,15 @@ bool IsUserGrantPermission(const std::string& permission) return g_permList[opCode].grantMode == USER_GRANT; } +bool IsOperablePermission(const std::string& permission) +{ + uint32_t opCode; + if (!TransferPermissionToOpcode(permission, opCode)) { + return false; // default is false + } + return g_permList[opCode].grantMode == USER_GRANT || g_permList[opCode].grantMode == MANUAL_SETTINGS; +} + bool IsDefinedPermission(const std::string& permission) { if (!g_initedPermMap) { diff --git a/frameworks/common/src/permission_validator.cpp b/frameworks/common/src/permission_validator.cpp index 814f474da..46d1a54fa 100644 --- a/frameworks/common/src/permission_validator.cpp +++ b/frameworks/common/src/permission_validator.cpp @@ -27,7 +27,8 @@ namespace AccessToken { bool PermissionValidator::IsGrantModeValid(int grantMode) { - return grantMode == GrantMode::SYSTEM_GRANT || grantMode == GrantMode::USER_GRANT; + return grantMode == GrantMode::SYSTEM_GRANT || grantMode == GrantMode::USER_GRANT || + grantMode == GrantMode::MANUAL_SETTINGS; } bool PermissionValidator::IsGrantStatusValid(int grantStatus) diff --git a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets index 8de915f7f..6cef02475 100644 --- a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets +++ b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets @@ -151,6 +151,10 @@ export default namespace abilityAccessCtrl { revokeUserGrantedPermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise; revokeUserGrantedPermission( tokenID: int, permissionName: Permissions, permissionFlags: int, callback: AsyncCallback): void; + + grantPermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise; + revokePermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise; + getVersion(): Promise; getPermissionsStatus(tokenID: int, permissionList: Array): Promise>; getPermissionFlags(tokenID: int, permissionName: Permissions): Promise; @@ -179,6 +183,9 @@ export default namespace abilityAccessCtrl { native grantUserGrantedPermissionExecute(tokenID: int, permissionName: Permissions, permissionFlags: int): void; native revokeUserGrantedPermissionExecute( tokenID: int, permissionName: Permissions, permissionFlags: int): void; + native grantPermissionExecute(tokenID: int, permissionName: Permissions, permissionFlags: int): void; + native revokePermissionExecute( + tokenID: int, permissionName: Permissions, permissionFlags: int): void; native getPermissionsStatusExecute(tokenID: int, permissionList: Array): Array; native getVersionExecute(): int; native getPermissionFlagsExecute(tokenID: int, permissionName: Permissions): int; @@ -360,6 +367,34 @@ export default namespace abilityAccessCtrl { }); } + grantPermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise { + return new Promise( + (resolve: (v: undefined) => void, reject: (error: BusinessError) => void) : void => { + let p = taskpool.execute(() : void => { + new AtManagerInner().grantPermissionExecute(tokenID, permissionName, permissionFlags); + }); + p.then((e: NullishType) : void => { + resolve(undefined); + }).catch((err: Error) : void => { + reject(err as BusinessError); + }); + }); + } + + revokePermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise { + return new Promise( + (resolve: (v: undefined) => void, reject: (error: BusinessError) => void): void => { + let p = taskpool.execute((): void => { + new AtManagerInner().revokePermissionExecute(tokenID, permissionName, permissionFlags); + }); + p.then((e: NullishType): void => { + resolve(undefined); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + } + getVersion(): Promise { let p = new Promise(( resolve: (v: int) => void, reject: (error: BusinessError) => void) => { diff --git a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp index e016d5e53..848a59400 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp @@ -302,8 +302,8 @@ static ani_int CheckAccessTokenExecute([[maybe_unused]] ani_env* env, [[maybe_un return static_cast(asyncContext->grantStatus); } -static void GrantUserGrantedPermissionExecute([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, - ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +static void GrantPermissionInner([[maybe_unused]] ani_env *env, + ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags, UpdatePermissionFlag updateFlag) { if (env == nullptr) { LOGE(ATM_DOMAIN, ATM_TAG, "Env is null."); @@ -312,33 +312,49 @@ static void GrantUserGrantedPermissionExecute([[maybe_unused]] ani_env *env, [[m AccessTokenID tokenID = static_cast(aniTokenID); std::string permissionName = ParseAniString(env, static_cast(aniPermission)); uint32_t permissionFlags = static_cast(aniFlags); + LOGI(ATM_DOMAIN, ATM_TAG, "tokenID = %{public}d, permissionName = %{public}s, flag = %{public}d.", + tokenID, permissionName.c_str(), permissionFlags); + if ((!BusinessErrorAni::ValidateTokenIDWithThrowError(env, tokenID)) || (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) || (!BusinessErrorAni::ValidatePermissionFlagWithThrowError(env, permissionFlags))) { - LOGE(ATM_DOMAIN, ATM_TAG, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", + LOGE(ATM_DOMAIN, ATM_TAG, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", tokenID, permissionName.c_str(), permissionFlags); return; } PermissionBriefDef def; - if (!GetPermissionBriefDef(permissionName, def) || def.grantMode != USER_GRANT) { + if (!GetPermissionBriefDef(permissionName, def)) { + std::string errMsg = GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST, + "The specified permission does not exist."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PERMISSION_NOT_EXIST, errMsg); + return; + } + + if (updateFlag == USER_GRANTED_PERM && def.grantMode != USER_GRANT) { std::string errMsg = GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST, - "The specified permission does not exist or is not a user_grant permission."); + "The specified permission is not a user_grant permission."); BusinessErrorAni::ThrowError(env, STS_ERROR_PERMISSION_NOT_EXIST, errMsg); return; } - int32_t res = AccessTokenKit::GrantPermission(tokenID, permissionName, permissionFlags); + if (updateFlag == OPERABLE_PERM && def.grantMode != USER_GRANT && def.grantMode != MANUAL_SETTINGS) { + std::string errMsg = GetErrorMessage(STS_ERROR_EXPECTED_PERMISSION_TYPE, + "The specified permission is not a user_grant or manual_settings permission."); + BusinessErrorAni::ThrowError(env, STS_ERROR_EXPECTED_PERMISSION_TYPE, errMsg); + return; + } + + int32_t res = AccessTokenKit::GrantPermission(tokenID, permissionName, permissionFlags, updateFlag); if (res != RET_SUCCESS) { int32_t stsCode = BusinessErrorAni::GetStsErrorCode(res); BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); } } -static void RevokeUserGrantedPermissionExecute([[maybe_unused]] ani_env* env, - [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +static void RevokePermissionInner(ani_env *env, + ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags, UpdatePermissionFlag updateFlag) { - LOGI(ATM_DOMAIN, ATM_TAG, "RevokeUserGrantedPermission begin."); if (env == nullptr) { LOGE(ATM_DOMAIN, ATM_TAG, "Env is null."); return; @@ -346,29 +362,70 @@ static void RevokeUserGrantedPermissionExecute([[maybe_unused]] ani_env* env, AccessTokenID tokenID = static_cast(aniTokenID); std::string permissionName = ParseAniString(env, static_cast(aniPermission)); uint32_t permissionFlags = static_cast(aniFlags); + LOGI(ATM_DOMAIN, ATM_TAG, "tokenID = %{public}d, permissionName = %{public}s, flag = %{public}d.", + tokenID, permissionName.c_str(), permissionFlags); + if ((!BusinessErrorAni::ValidateTokenIDWithThrowError(env, tokenID)) || (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) || (!BusinessErrorAni::ValidatePermissionFlagWithThrowError(env, permissionFlags))) { - LOGE(ATM_DOMAIN, ATM_TAG, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", + LOGE(ATM_DOMAIN, ATM_TAG, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", tokenID, permissionName.c_str(), permissionFlags); return; } PermissionBriefDef def; - if (!GetPermissionBriefDef(permissionName, def) || def.grantMode != USER_GRANT) { + if (!GetPermissionBriefDef(permissionName, def)) { + std::string errMsg = GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST, + "The specified permission does not exist."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PERMISSION_NOT_EXIST, errMsg); + return; + } + + if (updateFlag == USER_GRANTED_PERM && def.grantMode != USER_GRANT) { std::string errMsg = GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST, - "The specified permission does not exist or is not a user_grant permission."); + "The specified permission is not a user_grant permission."); BusinessErrorAni::ThrowError(env, STS_ERROR_PERMISSION_NOT_EXIST, errMsg); return; } - int32_t ret = AccessTokenKit::RevokePermission(tokenID, permissionName, permissionFlags); + if (updateFlag == OPERABLE_PERM && def.grantMode != USER_GRANT && def.grantMode != MANUAL_SETTINGS) { + std::string errMsg = GetErrorMessage(STS_ERROR_EXPECTED_PERMISSION_TYPE, + "The specified permission is not a user_grant or manual_settings permission."); + BusinessErrorAni::ThrowError(env, STS_ERROR_EXPECTED_PERMISSION_TYPE, errMsg); + return; + } + + int32_t ret = AccessTokenKit::RevokePermission(tokenID, permissionName, permissionFlags, updateFlag); if (ret != RET_SUCCESS) { int32_t stsCode = BusinessErrorAni::GetStsErrorCode(ret); BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); } } +static void GrantUserGrantedPermissionExecute([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, + ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +{ + GrantPermissionInner(env, aniTokenID, aniPermission, aniFlags, USER_GRANTED_PERM); +} + +static void RevokeUserGrantedPermissionExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +{ + RevokePermissionInner(env, aniTokenID, aniPermission, aniFlags, USER_GRANTED_PERM); +} + +static void GrantPermissionExecute([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, + ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +{ + GrantPermissionInner(env, aniTokenID, aniPermission, aniFlags, OPERABLE_PERM); +} + +static void RevokePermissionExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) +{ + RevokePermissionInner(env, aniTokenID, aniPermission, aniFlags, OPERABLE_PERM); +} + static ani_int GetVersionExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object) { LOGI(ATM_DOMAIN, ATM_TAG, "GetVersionExecute begin."); @@ -837,6 +894,10 @@ static ani_status AtManagerBindNativeFunction(ani_env* env, ani_class& cls) reinterpret_cast(GrantUserGrantedPermissionExecute) }, ani_native_function { "revokeUserGrantedPermissionExecute", nullptr, reinterpret_cast(RevokeUserGrantedPermissionExecute) }, + ani_native_function { "grantPermissionExecute", nullptr, + reinterpret_cast(GrantPermissionExecute) }, + ani_native_function { "revokePermissionExecute", + nullptr, reinterpret_cast(RevokePermissionExecute) }, ani_native_function { "getVersionExecute", nullptr, reinterpret_cast(GetVersionExecute) }, ani_native_function { "getPermissionsStatusExecute", nullptr, reinterpret_cast(GetPermissionsStatusExecute) }, diff --git a/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp b/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp index d06444f2d..03ffbbe78 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp @@ -16,6 +16,7 @@ #include "accesstoken_kit.h" #include "accesstoken_common_log.h" #include "ani_common.h" +#include "permission_map.h" #include "token_setproc.h" #include "want.h" @@ -246,6 +247,20 @@ static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext return true; } +static bool CheckManualSettingPerm(const std::vector& permissionList, std::string& permission) +{ + for (const auto& perm : permissionList) { + PermissionBriefDef permissionBriefDef; + if (GetPermissionBriefDef(perm, permissionBriefDef)) { + if (permissionBriefDef.grantMode == MANUAL_SETTINGS) { + permission = perm; + return true; + } + } + } + return false; +} + void RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList, ani_object callback) { @@ -269,6 +284,16 @@ void RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env, ani_ref nullRef = nullptr; env->GetNull(&nullRef); ani_object result = reinterpret_cast(nullRef); + + std::string permission; + if (CheckManualSettingPerm(asyncContext->permissionList, permission)) { + ani_object error = BusinessErrorAni::CreateError(env, STS_ERROR_EXPECTED_PERMISSION_TYPE, + GetErrorMessage(STS_ERROR_EXPECTED_PERMISSION_TYPE, + "The specified permission " + permission + " cannot be requested from the user.")); + ExecuteAsyncCallback(env, callback, error, result); + return; + } + static AccessTokenID selfTokenID = static_cast(GetSelfTokenID()); if (selfTokenID != asyncContext->tokenId) { LOGE(ATM_DOMAIN, ATM_TAG, "The context tokenID %{public}d is not same with selfTokenID %{public}d.", diff --git a/frameworks/ets/ani/common/include/ani_error.h b/frameworks/ets/ani/common/include/ani_error.h index 4e1f1b60b..6222286cc 100644 --- a/frameworks/ets/ani/common/include/ani_error.h +++ b/frameworks/ets/ani/common/include/ani_error.h @@ -45,6 +45,7 @@ typedef enum { STS_ERROR_ALL_PERM_GRANTED = 12100011, STS_ERROR_PERM_NOT_REVOKE_BY_USER = 12100012, STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN = 12100013, + STS_ERROR_EXPECTED_PERMISSION_TYPE = 12100014, } STSErrorCode; struct AtmResult { diff --git a/frameworks/ets/ani/common/src/ani_error.cpp b/frameworks/ets/ani/common/src/ani_error.cpp index d01e6bbbe..056e72653 100644 --- a/frameworks/ets/ani/common/src/ani_error.cpp +++ b/frameworks/ets/ani/common/src/ani_error.cpp @@ -45,6 +45,7 @@ static const std::unordered_map g_errorStringMap = { { STS_ERROR_PERM_NOT_REVOKE_BY_USER, "The permission list contains the permission that has not been revoked by the user." }, { STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN, "The specific global switch is already open." }, + { STS_ERROR_EXPECTED_PERMISSION_TYPE, "Unexpected permission."}, }; void BusinessErrorAni::ThrowError(ani_env* env, int32_t err, const std::string& errMsg) diff --git a/frameworks/js/napi/accesstoken/BUILD.gn b/frameworks/js/napi/accesstoken/BUILD.gn index 6cebe5c4c..3c484cffc 100644 --- a/frameworks/js/napi/accesstoken/BUILD.gn +++ b/frameworks/js/napi/accesstoken/BUILD.gn @@ -39,6 +39,7 @@ ohos_shared_library("libabilityaccessctrl") { ] deps = [ + "${access_token_path}/frameworks/common:accesstoken_common_cxx", "${access_token_path}/interfaces/innerkits/accesstoken:libaccesstoken_sdk", "${access_token_path}/interfaces/innerkits/token_callback:libtoken_callback_sdk", "${access_token_path}/interfaces/innerkits/token_setproc:libtokensetproc_shared", diff --git a/frameworks/js/napi/accesstoken/src/napi_atmanager.cpp b/frameworks/js/napi/accesstoken/src/napi_atmanager.cpp index fb9699a2e..57083343b 100644 --- a/frameworks/js/napi/accesstoken/src/napi_atmanager.cpp +++ b/frameworks/js/napi/accesstoken/src/napi_atmanager.cpp @@ -21,6 +21,7 @@ #include "napi_request_permission.h" #include "napi_request_permission_on_setting.h" #include "parameter.h" +#include "permission_map.h" #include "token_setproc.h" #include "want.h" #include "accesstoken_common_log.h" @@ -229,6 +230,8 @@ 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("grantPermission", GrantPermission), + DECLARE_NAPI_FUNCTION("revokePermission", RevokePermission), DECLARE_NAPI_FUNCTION("checkAccessToken", CheckAccessToken), DECLARE_NAPI_FUNCTION("checkAccessTokenSync", VerifyAccessTokenSync), DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags), @@ -650,7 +653,7 @@ napi_value NapiAtManager::VerifyAccessTokenSync(napi_env env, napi_callback_info } bool NapiAtManager::ParseInputGrantOrRevokePermission(const napi_env env, const napi_callback_info info, - AtManagerAsyncContext& asyncContext) + AtManagerAsyncContext& asyncContext, UpdatePermissionFlag updateFlag) { size_t argc = MAX_PARAMS_FOUR; napi_value argv[MAX_PARAMS_FOUR] = { nullptr }; @@ -690,7 +693,7 @@ bool NapiAtManager::ParseInputGrantOrRevokePermission(const napi_env env, const return false; } - if (argc == MAX_PARAMS_FOUR) { + if (updateFlag < UpdatePermissionFlag::OPERABLE_PERM && argc == MAX_PARAMS_FOUR) { // 3: the fourth parameter of argv if ((!IsUndefinedOrNull(env, argv[3])) && (!ParseCallback(env, argv[3], asyncContext.callbackRef))) { NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, @@ -731,7 +734,8 @@ void NapiAtManager::GrantUserGrantedPermissionExecute(napi_env env, void* data) if (!IsPermissionFlagValid(asyncContext->flag)) { asyncContext->errorCode = ERR_PARAM_INVALID; } - // only user_grant permission can use innerkit class method to grant permission, system_grant return failed + // only user_grant permission can use innerkit class method to grant permission + // system_grant or manual_settings return failed if (permissionDef.grantMode == USER_GRANT) { asyncContext->errorCode = AccessTokenKit::GrantPermission(asyncContext->tokenId, asyncContext->permissionName, asyncContext->flag); @@ -882,7 +886,8 @@ void NapiAtManager::RevokeUserGrantedPermissionExecute(napi_env env, void* data) if (!IsPermissionFlagValid(asyncContext->flag)) { asyncContext->errorCode = ERR_PARAM_INVALID; } - // only user_grant permission can use innerkit class method to grant permission, system_grant return failed + // only user_grant permission can use innerkit class method to grant permission + // system_grant or manual_settings return failed if (permissionDef.grantMode == USER_GRANT) { asyncContext->errorCode = AccessTokenKit::RevokePermission(asyncContext->tokenId, asyncContext->permissionName, asyncContext->flag); @@ -943,6 +948,161 @@ napi_value NapiAtManager::RevokeUserGrantedPermission(napi_env env, napi_callbac return result; } +void NapiAtManager::GrantPermissionExecute(napi_env env, void *data) +{ + AtManagerAsyncContext* asyncContext = reinterpret_cast(data); + if (asyncContext == nullptr) { + return; + } + + LOGI(ATM_DOMAIN, ATM_TAG, + "tokenId = %{public}d, permissionName = %{public}s, flag = %{public}d.", + asyncContext->tokenId, asyncContext->permissionName.c_str(), asyncContext->flag); + + PermissionBriefDef permissionDef; + if (!GetPermissionBriefDef(asyncContext->permissionName, permissionDef)) { + asyncContext->errorCode = ERR_PERMISSION_NOT_EXIST; + return; + } + + LOGD(ATM_DOMAIN, ATM_TAG, "PermissionName = %{public}s, grantmode = %{public}d.", + asyncContext->permissionName.c_str(), permissionDef.grantMode); + + if (!IsPermissionFlagValid(asyncContext->flag)) { + asyncContext->errorCode = ERR_PARAM_INVALID; + return; + } + // only user_grant or manual_settings permission can use innerkit class method to grant permission + // system_grant return failed + if (permissionDef.grantMode == USER_GRANT || permissionDef.grantMode == MANUAL_SETTINGS) { + asyncContext->errorCode = AccessTokenKit::GrantPermission(asyncContext->tokenId, + asyncContext->permissionName, asyncContext->flag, UpdatePermissionFlag::OPERABLE_PERM); + } else { + asyncContext->errorCode = ERR_EXPECTED_PERMISSION_TYPE; + asyncContext->extErrorMsg = "The specified permission is not a user_grant or manual_settings permission."; + } + LOGI(ATM_DOMAIN, ATM_TAG, "grant result = %{public}d.", asyncContext->errorCode); +} + +void NapiAtManager::GrantPermissionComplete(napi_env env, napi_status status, void *data) +{ + AtManagerAsyncContext* context = reinterpret_cast(data); + if (context == nullptr) { + LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null."); + return; + } + std::unique_ptr callbackPtr {context}; + napi_value result = GetNapiNull(env); + + ReturnPromiseResult(env, *context, result); +} + +napi_value NapiAtManager::GrantPermission(napi_env env, napi_callback_info info) +{ + auto* context = new (std::nothrow) AtManagerAsyncContext(env); // for async work deliver data + if (context == nullptr) { + LOGE(ATM_DOMAIN, ATM_TAG, "New struct fail."); + return nullptr; + } + + std::unique_ptr contextPtr {context}; + if (!ParseInputGrantOrRevokePermission(env, info, *context, OPERABLE_PERM)) { + return nullptr; + } + + napi_value result = nullptr; + + NAPI_CALL(env, napi_create_promise(env, &(context->deferred), &result)); + + napi_value resource = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "GrantPermission", NAPI_AUTO_LENGTH, &resource)); + + NAPI_CALL(env, napi_create_async_work( + env, nullptr, resource, + GrantPermissionExecute, GrantPermissionComplete, + reinterpret_cast(context), &(context->work))); + + NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default)); + + contextPtr.release(); + return result; +} + +void NapiAtManager::RevokePermissionExecute(napi_env env, void *data) +{ + AtManagerAsyncContext* asyncContext = reinterpret_cast(data); + if (asyncContext == nullptr) { + return; + } + + LOGI(ATM_DOMAIN, ATM_TAG, + "tokenId = %{public}d, permissionName = %{public}s, flag = %{public}d.", + asyncContext->tokenId, asyncContext->permissionName.c_str(), asyncContext->flag); + + PermissionBriefDef permissionDef; + if (!GetPermissionBriefDef(asyncContext->permissionName, permissionDef)) { + asyncContext->errorCode = ERR_PERMISSION_NOT_EXIST; + return; + } + + LOGD(ATM_DOMAIN, ATM_TAG, "PermissionName = %{public}s, grantmode = %{public}d.", + asyncContext->permissionName.c_str(), permissionDef.grantMode); + + if (!IsPermissionFlagValid(asyncContext->flag)) { + asyncContext->errorCode = ERR_PARAM_INVALID; + return; + } + // only user_grant or manual_settings permission can use innerkit class method to grant permission + // system_grant return failed + if (permissionDef.grantMode == USER_GRANT || permissionDef.grantMode == MANUAL_SETTINGS) { + asyncContext->errorCode = AccessTokenKit::RevokePermission(asyncContext->tokenId, + asyncContext->permissionName, asyncContext->flag, UpdatePermissionFlag::OPERABLE_PERM); + } else { + asyncContext->errorCode = ERR_EXPECTED_PERMISSION_TYPE; + asyncContext->extErrorMsg = "The specified permission is not a user_grant or manual_settings permission."; + } + LOGI(ATM_DOMAIN, ATM_TAG, "revoke result = %{public}d.", asyncContext->errorCode); +} + +void NapiAtManager::RevokePermissionComplete(napi_env env, napi_status status, void *data) +{ + AtManagerAsyncContext* asyncContext = reinterpret_cast(data); + std::unique_ptr callbackPtr {asyncContext}; + + napi_value result = GetNapiNull(env); + ReturnPromiseResult(env, *asyncContext, result); +} + +napi_value NapiAtManager::RevokePermission(napi_env env, napi_callback_info info) +{ + auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env); // for async work deliver data + if (asyncContext == nullptr) { + LOGE(ATM_DOMAIN, ATM_TAG, "New struct fail."); + return nullptr; + } + + std::unique_ptr context {asyncContext}; + if (!ParseInputGrantOrRevokePermission(env, info, *asyncContext, OPERABLE_PERM)) { + return nullptr; + } + + napi_value result = nullptr; + NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result)); + + napi_value resource = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "RevokePermission", NAPI_AUTO_LENGTH, &resource)); + + NAPI_CALL(env, napi_create_async_work( + env, nullptr, resource, + RevokePermissionExecute, RevokePermissionComplete, + reinterpret_cast(asyncContext), &(asyncContext->work))); + + NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default)); + + context.release(); + return result; +} + void NapiAtManager::GetPermissionFlagsExecute(napi_env env, void* data) { AtManagerAsyncContext* asyncContext = reinterpret_cast(data); diff --git a/frameworks/js/napi/accesstoken/src/napi_context_common.cpp b/frameworks/js/napi/accesstoken/src/napi_context_common.cpp index 69886d726..b91bbe7ab 100644 --- a/frameworks/js/napi/accesstoken/src/napi_context_common.cpp +++ b/frameworks/js/napi/accesstoken/src/napi_context_common.cpp @@ -60,6 +60,9 @@ int32_t GetJsErrorCode(int32_t errCode) case ERR_MALLOC_FAILED: jsCode = JS_ERROR_OUT_OF_MEMORY; break; + case ERR_EXPECTED_PERMISSION_TYPE: + jsCode = JS_ERROR_EXPECTED_PERMISSION_TYPE; + break; default: jsCode = JS_ERROR_INNER; break; diff --git a/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp b/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp index 20c944f7a..04f99a7e1 100644 --- a/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp +++ b/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp @@ -18,6 +18,7 @@ #include "accesstoken_kit.h" #include "accesstoken_common_log.h" #include "napi_base_context.h" +#include "permission_map.h" #include "token_setproc.h" #include "want.h" @@ -617,6 +618,21 @@ bool NapiRequestPermissionOnSetting::ParseRequestPermissionOnSetting(const napi_ return true; } +bool NapiRequestPermissionOnSetting::CheckManualSettingPerm( + const std::vector& permissionList, std::string& permission) +{ + for (const auto& perm : permissionList) { + PermissionBriefDef permissionBriefDef; + if (GetPermissionBriefDef(perm, permissionBriefDef)) { + if (permissionBriefDef.grantMode == MANUAL_SETTINGS) { + permission = perm; + return true; + } + } + } + return false; +} + void NapiRequestPermissionOnSetting::RequestPermissionOnSettingExecute(napi_env env, void* data) { // asyncContext release in complete @@ -625,6 +641,13 @@ void NapiRequestPermissionOnSetting::RequestPermissionOnSettingExecute(napi_env if ((asyncContextHandle == nullptr) || (asyncContextHandle->asyncContextPtr == nullptr)) { return; } + std::string permission; + if (CheckManualSettingPerm(asyncContextHandle->asyncContextPtr->permissionList, permission)) { + asyncContextHandle->asyncContextPtr->result.errorCode = ERR_EXPECTED_PERMISSION_TYPE; + asyncContextHandle->asyncContextPtr->result.errorMsg = + "The specified permission " + permission + " cannot be requested from the user."; + return; + } if (asyncContextHandle->asyncContextPtr->uiAbilityFlag) { if ((asyncContextHandle->asyncContextPtr->abilityContext == nullptr) || (asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo() == nullptr)) { @@ -677,7 +700,8 @@ void NapiRequestPermissionOnSetting::RequestPermissionOnSettingComplete(napi_env // return error if (asyncContextHandle->asyncContextPtr->deferred != nullptr) { int32_t jsCode = GetJsErrorCode(asyncContextHandle->asyncContextPtr->result.errorCode); - napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode)); + napi_value businessError = GenerateBusinessError(env, jsCode, + GetErrorMessage(jsCode, asyncContextHandle->asyncContextPtr->result.errorMsg)); NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncContextHandle->asyncContextPtr->deferred, businessError)); } diff --git a/frameworks/js/napi/common/src/napi_error.cpp b/frameworks/js/napi/common/src/napi_error.cpp index 6b3ae3d67..d1ee4cf8a 100644 --- a/frameworks/js/napi/common/src/napi_error.cpp +++ b/frameworks/js/napi/common/src/napi_error.cpp @@ -39,6 +39,7 @@ static const std::map g_errorStringMap = { {JS_ERROR_PERM_REVOKE_BY_USER, "The permission list contains the permission that has not been revoked by the user."}, {JS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN, "The specific global switch is already open."}, + {JS_ERROR_EXPECTED_PERMISSION_TYPE, "Unexpected permission."}, }; std::string GetParamErrorMsg(const std::string& param, const std::string& type) diff --git a/interfaces/innerkits/accesstoken/include/access_token.h b/interfaces/innerkits/accesstoken/include/access_token.h index ed73df16a..33710406e 100644 --- a/interfaces/innerkits/accesstoken/include/access_token.h +++ b/interfaces/innerkits/accesstoken/include/access_token.h @@ -170,8 +170,27 @@ typedef enum TypeGrantMode { * the permission is decleared and app is installed */ SYSTEM_GRANT = 1, + /** + * manual setting permission + * can only be set by the user in the settings + */ + MANUAL_SETTINGS = 2, } GrantMode; +/** + * @brief Update permission flag + */ +typedef enum TypeUpdatePermissionFlag { + /** + * the flag can update USER_GRANT permission + */ + USER_GRANTED_PERM = 0, + /** + * the flag can update USER_GRANT & MANUAL_SETTINGS permission + */ + OPERABLE_PERM = 1, +} UpdatePermissionFlag; + /** * @brief Permission flag */ @@ -261,6 +280,8 @@ typedef enum TypePermissionErrorReason { UNABLE_POP_UP = 5, /** The permission is fixed by policy */ FIXED_BY_POLICY = 6, + /* The permission is manual setting */ + MANUAL_SETTING_PERM = 7, /** The service is abnormal */ SERVICE_ABNORMAL = 12, } PermissionErrorReason; diff --git a/interfaces/innerkits/accesstoken/include/access_token_error.h b/interfaces/innerkits/accesstoken/include/access_token_error.h index 695883703..a0c2bf63b 100644 --- a/interfaces/innerkits/accesstoken/include/access_token_error.h +++ b/interfaces/innerkits/accesstoken/include/access_token_error.h @@ -80,7 +80,8 @@ enum AccessTokenError { ERR_ADD_DEATH_RECIPIENT_FAILED, ERR_PRASE_RAW_DATA_FAILED, ERR_PERMISSION_WITHOUT_VALUE, - ERR_PERMISSION_RESTRICTED + ERR_PERMISSION_RESTRICTED, + ERR_EXPECTED_PERMISSION_TYPE }; } // namespace AccessToken } // namespace Security diff --git a/interfaces/innerkits/accesstoken/include/accesstoken_kit.h b/interfaces/innerkits/accesstoken/include/accesstoken_kit.h index a2a9af9d5..95ba9e19f 100644 --- a/interfaces/innerkits/accesstoken/include/accesstoken_kit.h +++ b/interfaces/innerkits/accesstoken/include/accesstoken_kit.h @@ -325,17 +325,21 @@ public: * @param tokenID token id * @param permissionName permission name quote * @param flag enum PermissionFlag, see access_token.h + * @param grantMode the final grantable type * @return error code, see access_token_error.h */ - static int GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); + static int GrantPermission(AccessTokenID tokenID, + const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag = USER_GRANTED_PERM); /** * @brief Revoke input permission to input tokenID with input flag. * @param tokenID token id * @param permissionName permission name quote * @param flag enum PermissionFlag, see access_token.h + * @param grantMode the final revocable type * @return error code, see access_token_error.h */ - static int RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); + static int RevokePermission(AccessTokenID tokenID, + const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag = USER_GRANTED_PERM); /** * @brief Clear all user granted permissions state in input tokenID. * @param tokenID token id diff --git a/interfaces/innerkits/accesstoken/libaccesstoken_sdk.map b/interfaces/innerkits/accesstoken/libaccesstoken_sdk.map index 8c89678b9..6944ff9d7 100644 --- a/interfaces/innerkits/accesstoken/libaccesstoken_sdk.map +++ b/interfaces/innerkits/accesstoken/libaccesstoken_sdk.map @@ -27,9 +27,9 @@ "OHOS::Security::AccessToken::AccessTokenKit::GetTokenIDByUserID(int, std::__h::unordered_set, std::__h::equal_to, std::__h::allocator>&)"; "OHOS::Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(unsigned int, OHOS::Security::AccessToken::NativeTokenInfo&)"; "OHOS::Security::AccessToken::AccessTokenKit::GetPermissionFlag(unsigned int, std::__h::basic_string, std::__h::allocator> const&, unsigned int&)"; - "OHOS::Security::AccessToken::AccessTokenKit::GrantPermission(unsigned int, std::__h::basic_string, std::__h::allocator> const&, unsigned int)"; + "OHOS::Security::AccessToken::AccessTokenKit::GrantPermission(unsigned int, std::__h::basic_string, std::__h::allocator> const&, unsigned int, OHOS::Security::AccessToken::TypeUpdatePermissionFlag)"; "OHOS::Security::AccessToken::AccessTokenKit::SetPermissionStatusWithPolicy(unsigned int, std::__h::vector, std::__h::allocator>, std::__h::allocator, std::__h::allocator>>> const&, int, unsigned int)"; - "OHOS::Security::AccessToken::AccessTokenKit::RevokePermission(unsigned int, std::__h::basic_string, std::__h::allocator> const&, unsigned int)"; + "OHOS::Security::AccessToken::AccessTokenKit::RevokePermission(unsigned int, std::__h::basic_string, std::__h::allocator> const&, unsigned int, OHOS::Security::AccessToken::TypeUpdatePermissionFlag)"; "OHOS::Security::AccessToken::AccessTokenKit::ClearUserGrantedPermissionState(unsigned int)"; "OHOS::Security::AccessToken::PermStateChangeCallbackCustomize::PermStateChangeCallbackCustomize(OHOS::Security::AccessToken::PermStateChangeScope const&)"; "OHOS::Security::AccessToken::AccessTokenKit::RegisterPermStateChangeCallback(std::__h::shared_ptr const&)"; diff --git a/interfaces/innerkits/accesstoken/src/accesstoken_kit.cpp b/interfaces/innerkits/accesstoken/src/accesstoken_kit.cpp index cd5b99e09..75bc67ca0 100644 --- a/interfaces/innerkits/accesstoken/src/accesstoken_kit.cpp +++ b/interfaces/innerkits/accesstoken/src/accesstoken_kit.cpp @@ -492,7 +492,8 @@ int AccessTokenKit::GetPermissionFlag(AccessTokenID tokenID, const std::string& return AccessTokenManagerClient::GetInstance().GetPermissionFlag(tokenID, permissionName, flag); } -int AccessTokenKit::GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenKit::GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { LOGD(ATM_DOMAIN, ATM_TAG, "TokenID=%{public}d, permissionName=%{public}s, flag=%{public}d.", tokenID, permissionName.c_str(), flag); @@ -512,10 +513,11 @@ int AccessTokenKit::GrantPermission(AccessTokenID tokenID, const std::string& pe LOGE(ATM_DOMAIN, ATM_TAG, "Flag is invalid"); return AccessTokenError::ERR_PARAM_INVALID; } - return AccessTokenManagerClient::GetInstance().GrantPermission(tokenID, permissionName, flag); + return AccessTokenManagerClient::GetInstance().GrantPermission(tokenID, permissionName, flag, updateFlag); } -int AccessTokenKit::RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenKit::RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { LOGD(ATM_DOMAIN, ATM_TAG, "TokenID=%{public}d, permissionName=%{public}s, flag=%{public}d.", tokenID, permissionName.c_str(), flag); @@ -535,7 +537,7 @@ int AccessTokenKit::RevokePermission(AccessTokenID tokenID, const std::string& p LOGE(ATM_DOMAIN, ATM_TAG, "Invalid flag"); return AccessTokenError::ERR_PARAM_INVALID; } - return AccessTokenManagerClient::GetInstance().RevokePermission(tokenID, permissionName, flag); + return AccessTokenManagerClient::GetInstance().RevokePermission(tokenID, permissionName, flag, updateFlag); } int AccessTokenKit::ClearUserGrantedPermissionState(AccessTokenID tokenID) diff --git a/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.cpp b/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.cpp index 3aa5f2d49..20b02337e 100644 --- a/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.cpp +++ b/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.cpp @@ -328,14 +328,15 @@ int32_t AccessTokenManagerClient::GetPermissionsStatus( return result; } -int AccessTokenManagerClient::GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenManagerClient::GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { auto proxy = GetProxy(); if (proxy == nullptr) { LOGE(ATM_DOMAIN, ATM_TAG, "Proxy is null"); return AccessTokenError::ERR_SERVICE_ABNORMAL; } - int32_t result = proxy->GrantPermission(tokenID, permissionName, flag); + int32_t result = proxy->GrantPermission(tokenID, permissionName, flag, updateFlag); if (result != RET_SUCCESS) { result = ConvertResult(result); } @@ -343,14 +344,15 @@ int AccessTokenManagerClient::GrantPermission(AccessTokenID tokenID, const std:: return result; } -int AccessTokenManagerClient::RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenManagerClient::RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { auto proxy = GetProxy(); if (proxy == nullptr) { LOGE(ATM_DOMAIN, ATM_TAG, "Proxy is null"); return AccessTokenError::ERR_SERVICE_ABNORMAL; } - int32_t result = proxy->RevokePermission(tokenID, permissionName, flag); + int32_t result = proxy->RevokePermission(tokenID, permissionName, flag, updateFlag); if (result != RET_SUCCESS) { result = ConvertResult(result); } diff --git a/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.h b/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.h index c3c9efd34..26b1d1854 100644 --- a/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.h +++ b/interfaces/innerkits/accesstoken/src/accesstoken_manager_client.h @@ -61,8 +61,10 @@ public: PermissionOper GetSelfPermissionsState(std::vector& permList, PermissionGrantInfo& info); int32_t GetPermissionsStatus(AccessTokenID tokenID, std::vector& permList); - int GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); - int RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); + int GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag); + int RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag); int GrantPermissionForSpecifiedTime( AccessTokenID tokenID, const std::string& permissionName, uint32_t onceTime); int ClearUserGrantedPermissionState(AccessTokenID tokenID); diff --git a/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/init_hap_token_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/init_hap_token_test.cpp index 56d10b2bf..63ce2cd9e 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/init_hap_token_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/init_hap_token_test.cpp @@ -1512,6 +1512,42 @@ HWTEST_F(InitHapTokenTest, InitHapTokenAbnormalTest006, TestSize.Level0) int32_t ret = AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId); EXPECT_EQ(ERR_PARAM_INVALID, ret); } + +/** + * @tc.name: InitHapTokenWithManualTest001 + * @tc.desc: InitHapToken with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InitHapTokenTest, InitHapTokenWithManualTest001, TestSize.Level0) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "InitHapTokenWithManualTest001"); + MockNativeToken mock("foundation"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + AccessTokenIDEx fullTokenId; + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + AccessTokenID tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + + std::vector reqPermList; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList, true)); + EXPECT_EQ(reqPermList.size(), 0); + + std::vector reqPermList2; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList2, false)); + EXPECT_EQ(reqPermList2.size(), NUMBER_THREE); + + for (auto permState : reqPermList2) { + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, permState.permissionName)); + } + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::DeleteToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/update_hap_token_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/update_hap_token_test.cpp index 8d4201d3e..be961fb23 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/update_hap_token_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/HapTokenTest/update_hap_token_test.cpp @@ -43,6 +43,7 @@ static const int THREAD_NUM = 3; static constexpr int32_t CYCLE_TIMES = 100; static const int INVALID_APPIDDESC_LEN = 10244; static const int32_t INDEX_ZERO = 0; +static const int32_t INDEX_THREE = 3; static uint64_t g_selfTokenId = 0; static constexpr int32_t API_VERSION_EIGHT = 8; const std::string APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM = "enterprise_mdm"; @@ -1873,6 +1874,106 @@ HWTEST_F(UpdateHapTokenTest, UpdateHapTokenAbnormalTest006, TestSize.Level0) tokenIdEx, info, g_testPolicyParams); EXPECT_EQ(AccessTokenError::ERR_PARAM_INVALID, ret); } + +/** + * @tc.name: UpdateHapTokenWithManualTest001 + * @tc.desc: UpdateHapToken with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(UpdateHapTokenTest, UpdateHapTokenWithManualTest001, TestSize.Level0) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "UpdateHapTokenWithManualTest001"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + AccessTokenIDEx fullTokenId; + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + AccessTokenID tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + + std::vector reqPermList; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList, true)); + EXPECT_EQ(reqPermList.size(), 0); + + std::vector reqPermList2; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList2, false)); + EXPECT_EQ(reqPermList2.size(), 0); + + UpdateHapInfoParams updateInfoParams = { + .appIDDesc = infoParams.appIDDesc, + .apiVersion = infoParams.apiVersion, + .isSystemApp = false, + .appDistributionType = "" + }; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::UpdateHapToken(fullTokenId, updateInfoParams, policyParams)); + + std::vector reqPermList3; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList3, false)); + EXPECT_EQ(reqPermList3.size(), INDEX_THREE); + + for (auto permState : reqPermList3) { + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, permState.permissionName)); + } + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::DeleteToken(tokenID)); +} + +/** + * @tc.name: UpdateHapTokenWithManualTest002 + * @tc.desc: UpdateHapToken with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(UpdateHapTokenTest, UpdateHapTokenWithManualTest002, TestSize.Level0) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "UpdateHapTokenWithManualTest002"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + AccessTokenIDEx fullTokenId; + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + AccessTokenID tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + + std::vector reqPermList; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList, true)); + EXPECT_EQ(reqPermList.size(), 0); + + std::vector reqPermList2; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList2, false)); + EXPECT_EQ(reqPermList2.size(), INDEX_THREE); + + for (auto permState : reqPermList2) { + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, permState.permissionName)); + } + + UpdateHapInfoParams updateInfoParams = { + .appIDDesc = infoParams.appIDDesc, + .apiVersion = infoParams.apiVersion, + .isSystemApp = false, + .appDistributionType = "" + }; + + HapPolicyParams policyParams2; + TestCommon::GetHapParams(infoParams, policyParams2); + policyParams2.apl = APL_NORMAL; + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::UpdateHapToken(fullTokenId, updateInfoParams, policyParams2)); + + std::vector reqPermList3; + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GetReqPermissions(tokenID, reqPermList3, false)); + EXPECT_EQ(reqPermList3.size(), 0); + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::DeleteToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_state_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_state_test.cpp index 374e36e69..bfdb89531 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_state_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_state_test.cpp @@ -553,6 +553,53 @@ HWTEST_F(GetSelfPermissionStateTest, GetSelfPermissionsState009, TestSize.Level0 ASSERT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenIdEx.tokenIdExStruct.tokenID)); EXPECT_EQ(0, SetSelfTokenID(g_selfTokenId)); // set self hap token } + +/** + * @tc.name: GetSelfPermissionsStateWithManualTest001 + * @tc.desc: GetSelfPermissionsState with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(GetSelfPermissionStateTest, GetSelfPermissionsStateWithManualTest001, TestSize.Level0) +{ + AccessTokenIDEx fullTokenId; + AccessTokenID tokenID; + { + MockNativeToken mock("foundation"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + } + + EXPECT_EQ(0, SetSelfTokenID(tokenID)); + + std::vector permsList; + PermissionListState manualState = { + .permissionName = "ohos.permission.MANUAL_ATM_SELF_USE", + .state = FORBIDDEN_OPER + }; + permsList.emplace_back(manualState); + PermissionGrantInfo info; + EXPECT_NE(DYNAMIC_OPER, AccessTokenKit::GetSelfPermissionsState(permsList, info)); + EXPECT_EQ(permsList[0].state, SETTING_OPER); + EXPECT_EQ(permsList[0].errorReason, MANUAL_SETTING_PERM); + + PermissionListState userState = { + .permissionName = "ohos.permission.CAMERA", + .state = FORBIDDEN_OPER + }; + permsList.emplace_back(userState); + EXPECT_EQ(DYNAMIC_OPER, AccessTokenKit::GetSelfPermissionsState(permsList, info)); + + EXPECT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_status_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_status_test.cpp index f962bcf97..c5a8777a9 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_status_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/PermisionDialogTest/get_self_permission_status_test.cpp @@ -555,6 +555,54 @@ HWTEST_F(GetSelfPermissionStatusTest, GetSelfPermissionStatus009, TestSize.Level EXPECT_EQ(RET_SUCCESS, ret); EXPECT_EQ(PASS_OPER, status); } + +/** + * @tc.name: GetSelfPermissionStatusWithManualTest001 + * @tc.desc: GetSelfPermissionStatus with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: Issue Number + */ +HWTEST_F(GetSelfPermissionStatusTest, GetSelfPermissionStatusWithManualTest001, TestSize.Level0) +{ + AccessTokenIDEx fullTokenId; + AccessTokenID tokenID; + { + MockNativeToken mock("foundation"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + } + + EXPECT_EQ(0, SetSelfTokenID(tokenID)); + PermissionOper status; + int32_t ret = AccessTokenKit::GetSelfPermissionStatus("ohos.permission.MANUAL_ATM_SELF_USE", status); + EXPECT_EQ(RET_SUCCESS, ret); + EXPECT_EQ(SETTING_OPER, status); + + { + std::vector reqPerm; + reqPerm.emplace_back("ohos.permission.GRANT_SENSITIVE_PERMISSIONS"); + MockHapToken mock("GetSelfPermissionStatusWithManualTest0012", reqPerm, true); + + // grant MANUAL_SETTINGS permission + ASSERT_EQ(0, AccessTokenKit::GrantPermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_SET, OPERABLE_PERM)); + } + + EXPECT_EQ(0, SetSelfTokenID(tokenID)); + ret = AccessTokenKit::GetSelfPermissionStatus("ohos.permission.MANUAL_ATM_SELF_USE", status); + EXPECT_EQ(RET_SUCCESS, ret); + EXPECT_EQ(PASS_OPER, status); + + EXPECT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/grant_permission_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/grant_permission_test.cpp index b7fea6a43..306b1904c 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/grant_permission_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/grant_permission_test.cpp @@ -51,6 +51,7 @@ void GrantPermissionTest::SetUpTestCase() std::vector reqPerm; reqPerm.emplace_back("ohos.permission.GRANT_SENSITIVE_PERMISSIONS"); reqPerm.emplace_back("ohos.permission.REVOKE_SENSITIVE_PERMISSIONS"); + reqPerm.emplace_back("ohos.permission.MANAGE_HAP_TOKENID"); g_mock = new (std::nothrow) MockHapToken("GrantPermissionTest", reqPerm); // clean up test cases @@ -324,6 +325,41 @@ HWTEST_F(GrantPermissionTest, GrantPermissionWithRenderTest001, TestSize.Level0) ASSERT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); } + +/** + * @tc.name: GrantPermissionWithManualTest001 + * @tc.desc: GrantPermission with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(GrantPermissionTest, GrantPermissionWithManualTest001, TestSize.Level0) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "GrantPermissionWithManualTest001"); + MockNativeToken mock("foundation"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + AccessTokenIDEx fullTokenId; + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + AccessTokenID tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + // old grant function can't grant MANUAL_SETTINGS + EXPECT_EQ(ERR_PERMISSION_NOT_EXIST, AccessTokenKit::GrantPermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_FIXED, USER_GRANTED_PERM)); + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + + // new grant function can grant MANUAL_SETTINGS + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GrantPermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_FIXED, OPERABLE_PERM)); + EXPECT_EQ(PERMISSION_GRANTED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + + EXPECT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/revoke_permission_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/revoke_permission_test.cpp index d2512fe43..d0e54d27f 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/revoke_permission_test.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/revoke_permission_test.cpp @@ -49,7 +49,9 @@ void RevokePermissionTest::SetUpTestCase() TestCommon::SetTestEvironment(g_selfTokenId); std::vector reqPerm; + reqPerm.emplace_back("ohos.permission.GRANT_SENSITIVE_PERMISSIONS"); reqPerm.emplace_back("ohos.permission.REVOKE_SENSITIVE_PERMISSIONS"); + reqPerm.emplace_back("ohos.permission.MANAGE_HAP_TOKENID"); g_mock = new (std::nothrow) MockHapToken("RevokePermissionTest", reqPerm); // clean up test cases @@ -323,6 +325,44 @@ HWTEST_F(RevokePermissionTest, RevokePermissionWithRenderTest001, TestSize.Level ASSERT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); } + +/** + * @tc.name: RevokePermissionWithManualTest001 + * @tc.desc: RevokePermission with MANUAL_SETTINGS permission + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(RevokePermissionTest, RevokePermissionWithManualTest001, TestSize.Level0) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "RevokePermissionWithManualTest001"); + MockNativeToken mock("foundation"); + + HapInfoParams infoParams; + HapPolicyParams policyParams; + TestCommon::GetHapParams(infoParams, policyParams); + policyParams.apl = APL_NORMAL; + TestCommon::TestPrepareManualPermissionStatus(policyParams); + AccessTokenIDEx fullTokenId; + ASSERT_EQ(RET_SUCCESS, AccessTokenKit::InitHapToken(infoParams, policyParams, fullTokenId)); + AccessTokenID tokenID = fullTokenId.tokenIdExStruct.tokenID; + ASSERT_NE(INVALID_TOKENID, tokenID); + + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::GrantPermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_FIXED, OPERABLE_PERM)); + EXPECT_EQ(PERMISSION_GRANTED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + + // old revoke function can't revoke MANUAL_SETTINGS + EXPECT_EQ(ERR_PERMISSION_NOT_EXIST, AccessTokenKit::RevokePermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_FIXED, USER_GRANTED_PERM)); + EXPECT_EQ(PERMISSION_GRANTED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + + // new revoke function can revoke MANUAL_SETTINGS + EXPECT_EQ(RET_SUCCESS, AccessTokenKit::RevokePermission( + tokenID, "ohos.permission.MANUAL_ATM_SELF_USE", PERMISSION_USER_FIXED, OPERABLE_PERM)); + EXPECT_EQ(PERMISSION_DENIED, AccessTokenKit::VerifyAccessToken(tokenID, "ohos.permission.MANUAL_ATM_SELF_USE")); + + EXPECT_EQ(RET_SUCCESS, TestCommon::DeleteTestHapToken(tokenID)); +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/common/test_common.cpp b/interfaces/innerkits/accesstoken/test/unittest/common/test_common.cpp index 9c22c054a..28a74949d 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/common/test_common.cpp +++ b/interfaces/innerkits/accesstoken/test/unittest/common/test_common.cpp @@ -230,6 +230,25 @@ void TestCommon::TestPrepareKernelPermissionStatus(HapPolicyParams& policyParams policyParams.aclExtendedMap["ohos.permission.CAMERA"] = "789"; // filtered } +void TestCommon::TestPrepareManualPermissionStatus(HapPolicyParams& policyParams) +{ + PermissionStateFull permissionStatusBasic = { + .permissionName = "ohos.permission.test_basic", + .isGeneral = false, + .resDeviceID = {"local"}, + .grantStatus = {PERMISSION_DENIED}, + .grantFlags = {PERMISSION_DEFAULT_FLAG} + }; + + PermissionStateFull permissionStateFull001 = permissionStatusBasic; + permissionStateFull001.permissionName = "ohos.permission.MANUAL_ATM_SELF_USE"; + PermissionStateFull permissionStateFull002 = permissionStatusBasic; + permissionStateFull002.permissionName = "ohos.permission.MICROPHONE"; + PermissionStateFull permissionStateFull003 = permissionStatusBasic; + permissionStateFull003.permissionName = "ohos.permission.CAMERA"; + policyParams.permStateList = {permissionStateFull001, permissionStateFull002, permissionStateFull003}; +} + void TestCommon::SetTestEvironment(uint64_t shellTokenId) { std::lock_guard lock(g_lockSetToken); diff --git a/interfaces/innerkits/accesstoken/test/unittest/common/test_common.h b/interfaces/innerkits/accesstoken/test/unittest/common/test_common.h index 3ac03a171..23e78b04f 100644 --- a/interfaces/innerkits/accesstoken/test/unittest/common/test_common.h +++ b/interfaces/innerkits/accesstoken/test/unittest/common/test_common.h @@ -56,6 +56,7 @@ public: static void TestPreparePermStateList(HapPolicyParams &policy); static void TestPreparePermDefList(HapPolicyParams &policy); static void TestPrepareKernelPermissionStatus(HapPolicyParams& policyParams); + static void TestPrepareManualPermissionStatus(HapPolicyParams& policyParams); static HapPolicyParams GetTestPolicyParams(); static HapInfoParams GetInfoManagerTestInfoParms(); static HapInfoParams GetInfoManagerTestNormalInfoParms(); diff --git a/interfaces/kits/js/napi/accesstoken/include/napi_atmanager.h b/interfaces/kits/js/napi/accesstoken/include/napi_atmanager.h index 6e9172cf1..10e0e4bf6 100644 --- a/interfaces/kits/js/napi/accesstoken/include/napi_atmanager.h +++ b/interfaces/kits/js/napi/accesstoken/include/napi_atmanager.h @@ -125,6 +125,8 @@ private: static napi_value VerifyAccessTokenSync(napi_env env, napi_callback_info info); static napi_value GrantUserGrantedPermission(napi_env env, napi_callback_info info); static napi_value RevokeUserGrantedPermission(napi_env env, napi_callback_info info); + static napi_value GrantPermission(napi_env env, napi_callback_info info); + static napi_value RevokePermission(napi_env env, napi_callback_info info); static napi_value CheckAccessToken(napi_env env, napi_callback_info info); static napi_value GetPermissionFlags(napi_env env, napi_callback_info info); static napi_value GetVersion(napi_env env, napi_callback_info info); @@ -148,11 +150,15 @@ private: static void CheckAccessTokenExecute(napi_env env, void* data); static void CheckAccessTokenComplete(napi_env env, napi_status status, void* data); static bool ParseInputGrantOrRevokePermission(const napi_env env, const napi_callback_info info, - AtManagerAsyncContext& asyncContext); + AtManagerAsyncContext& asyncContext, UpdatePermissionFlag updateFlag = USER_GRANTED_PERM); static void GrantUserGrantedPermissionExecute(napi_env env, void *data); static void GrantUserGrantedPermissionComplete(napi_env env, napi_status status, void *data); static void RevokeUserGrantedPermissionExecute(napi_env env, void *data); static void RevokeUserGrantedPermissionComplete(napi_env env, napi_status status, void *data); + static void GrantPermissionExecute(napi_env env, void *data); + static void GrantPermissionComplete(napi_env env, napi_status status, void *data); + static void RevokePermissionExecute(napi_env env, void *data); + static void RevokePermissionComplete(napi_env env, napi_status status, void *data); static void GetVersionExecute(napi_env env, void *data); static void GetVersionComplete(napi_env env, napi_status status, void *data); static void GetPermissionFlagsExecute(napi_env env, void *data); diff --git a/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h b/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h index 8c0e8dbb1..944a6f05a 100644 --- a/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h +++ b/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h @@ -108,6 +108,7 @@ private: std::shared_ptr& asyncContext); static void RequestPermissionOnSettingExecute(napi_env env, void* data); static void RequestPermissionOnSettingComplete(napi_env env, napi_status status, void* data); + static bool CheckManualSettingPerm(const std::vector& permissionList, std::string& permission); }; } // namespace AccessToken } // namespace Security diff --git a/interfaces/kits/js/napi/common/include/napi_error.h b/interfaces/kits/js/napi/common/include/napi_error.h index 4d38988e0..75eb62e8e 100644 --- a/interfaces/kits/js/napi/common/include/napi_error.h +++ b/interfaces/kits/js/napi/common/include/napi_error.h @@ -45,6 +45,7 @@ typedef enum { JS_ERROR_ALL_PERM_GRANTED = 12100011, JS_ERROR_PERM_REVOKE_BY_USER = 12100012, JS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN = 12100013, + JS_ERROR_EXPECTED_PERMISSION_TYPE = 12100014, } JsErrorCode; struct AtmResult { diff --git a/services/accesstokenmanager/idl/IAccessTokenManager.idl b/services/accesstokenmanager/idl/IAccessTokenManager.idl index 3d8317a4b..74434a487 100644 --- a/services/accesstokenmanager/idl/IAccessTokenManager.idl +++ b/services/accesstokenmanager/idl/IAccessTokenManager.idl @@ -38,8 +38,8 @@ interface OHOS.Security.AccessToken.IAccessTokenManager{ [ipccode 2] void GetDefPermission([in] String permissionName, [out] PermissionDefParcel permissionDefResult); [ipccode 3] void GetReqPermissions([in] unsigned int tokenID, [out] List reqPermList, [in] boolean isSystemGrant); [ipccode 4] void GetPermissionFlag([in] unsigned int tokenID, [in] String permissionName, [out] unsigned int flag); - [ipccode 5] void GrantPermission([in] unsigned int tokenID, [in] String permissionName, [in] unsigned int flag); - [ipccode 6] void RevokePermission([in] unsigned int tokenID, [in] String permissionName, [in] unsigned int flag); + [ipccode 5] void GrantPermission([in] unsigned int tokenID, [in] String permissionName, [in] unsigned int flag, [in] int updateFlag); + [ipccode 6] void RevokePermission([in] unsigned int tokenID, [in] String permissionName, [in] unsigned int flag, [in] int updateFlag); [ipccode 7] void ClearUserGrantedPermissionState([in] unsigned int tokenID); [ipccode 8] void AllocHapToken([in] HapInfoParcel hapInfo, [in] HapPolicyParcel policyParcel, [out] unsigned long fullTokenId); [ipccode 9] void DeleteToken([in] unsigned int tokenID); diff --git a/services/accesstokenmanager/main/cpp/include/permission/permission_manager.h b/services/accesstokenmanager/main/cpp/include/permission/permission_manager.h index 8c390755d..c7e79d545 100644 --- a/services/accesstokenmanager/main/cpp/include/permission/permission_manager.h +++ b/services/accesstokenmanager/main/cpp/include/permission/permission_manager.h @@ -79,8 +79,10 @@ public: AccessTokenID tokenID, const std::vector& permissionList, int32_t status, uint32_t flag); int32_t UpdatePermission(AccessTokenID tokenID, const std::string& permissionName, bool isGranted, uint32_t flag, bool needKill); - int32_t GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); - int32_t RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag); + int32_t GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, + UpdatePermissionFlag updateFlag = USER_GRANTED_PERM); + int32_t RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, + UpdatePermissionFlag updateFlag = USER_GRANTED_PERM); int32_t GrantPermissionForSpecifiedTime( AccessTokenID tokenID, const std::string& permissionName, uint32_t onceTime); int32_t SetPermissionStatusWithPolicy( diff --git a/services/accesstokenmanager/main/cpp/include/service/accesstoken_manager_service.h b/services/accesstokenmanager/main/cpp/include/service/accesstoken_manager_service.h index e1ef079b3..053d10278 100644 --- a/services/accesstokenmanager/main/cpp/include/service/accesstoken_manager_service.h +++ b/services/accesstokenmanager/main/cpp/include/service/accesstoken_manager_service.h @@ -72,8 +72,10 @@ public: int32_t GetPermissionRequestToggleStatus(const std::string& permissionName, uint32_t& status, int32_t userID) override; int32_t RequestAppPermOnSetting(AccessTokenID tokenID) override; - int GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) override; - int RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) override; + int GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, int32_t updateFlag) override; + int RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, int32_t updateFlag) override; int GrantPermissionForSpecifiedTime( AccessTokenID tokenID, const std::string& permissionName, uint32_t onceTime) override; int ClearUserGrantedPermissionState(AccessTokenID tokenID) override; diff --git a/services/accesstokenmanager/main/cpp/src/permission/permission_manager.cpp b/services/accesstokenmanager/main/cpp/src/permission/permission_manager.cpp index d8c3deda9..fcfa825b8 100644 --- a/services/accesstokenmanager/main/cpp/src/permission/permission_manager.cpp +++ b/services/accesstokenmanager/main/cpp/src/permission/permission_manager.cpp @@ -143,7 +143,6 @@ int PermissionManager::GetReqPermissions( LOGE(ATM_DOMAIN, ATM_TAG, "Token %{public}u is invalid.", tokenID); return AccessTokenError::ERR_TOKENID_NOT_EXIST; } - GrantMode mode = isSystemGrant ? SYSTEM_GRANT : USER_GRANT; std::vector tmpList; int32_t ret = infoPtr->GetPermissionStateList(tmpList); if (ret != RET_SUCCESS) { @@ -156,7 +155,8 @@ int PermissionManager::GetReqPermissions( continue; } - if (briefDef.grantMode == mode) { + if ((isSystemGrant && briefDef.grantMode == SYSTEM_GRANT) || + (!isSystemGrant && briefDef.grantMode != SYSTEM_GRANT)) { reqPermList.emplace_back(perm); } } @@ -214,6 +214,12 @@ static bool IsPermissionRestrictedByRules(const std::string& permission) bool PermissionManager::HandlePermissionDeniedCase(uint32_t goalGrantFlag, PermissionListState& permState) { + PermissionBriefDef briefDef; + if (GetPermissionBriefDef(permState.permissionName, briefDef) && briefDef.grantMode == MANUAL_SETTINGS) { + permState.state = SETTING_OPER; + permState.errorReason = MANUAL_SETTING_PERM; + return true; + } if ((goalGrantFlag & PERMISSION_FIXED_BY_ADMIN_POLICY) != 0) { permState.state = FORBIDDEN_OPER; permState.errorReason = FIXED_BY_POLICY; @@ -340,7 +346,7 @@ int32_t PermissionManager::RequestAppPermOnSetting(const HapTokenInfo& hapInfo, void PermissionManager::ParamUpdate(const std::string& permissionName, uint32_t flag, bool filtered) { Utils::UniqueWriteGuard infoGuard(this->permParamSetLock_); - if (filtered || (IsUserGrantPermission(permissionName) && + if (filtered || (IsOperablePermission(permissionName) && ((flag != PERMISSION_PRE_AUTHORIZED_CANCELABLE) && (flag != PERMISSION_SYSTEM_FIXED)))) { paramValue_++; LOGD(ATM_DOMAIN, ATM_TAG, @@ -729,17 +735,35 @@ int32_t PermissionManager::CheckAndUpdateMultiPermissionStatus( return RET_SUCCESS; } -int32_t PermissionManager::GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int32_t PermissionManager::GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { LOGI(ATM_DOMAIN, ATM_TAG, "TokenID: %{public}u, permissionName: %{public}s, flag: %{public}d", tokenID, permissionName.c_str(), flag); + + if (updateFlag < OPERABLE_PERM) { + PermissionBriefDef briefDef; + if (GetPermissionBriefDef(permissionName, briefDef) && briefDef.grantMode == MANUAL_SETTINGS) { + LOGE(ATM_DOMAIN, ATM_TAG, "MANUAL_SETTINGS %{public}s can't be grant.", permissionName.c_str()); + return AccessTokenError::ERR_PERMISSION_NOT_EXIST; + } + } return CheckAndUpdatePermissionInner(tokenID, permissionName, true, flag); } -int32_t PermissionManager::RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int32_t PermissionManager::RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, UpdatePermissionFlag updateFlag) { LOGI(ATM_DOMAIN, ATM_TAG, "TokenID: %{public}u, permissionName: %{public}s, flag: %{public}d", tokenID, permissionName.c_str(), flag); + + if (updateFlag < OPERABLE_PERM) { + PermissionBriefDef briefDef; + if (GetPermissionBriefDef(permissionName, briefDef) && briefDef.grantMode == MANUAL_SETTINGS) { + LOGE(ATM_DOMAIN, ATM_TAG, "MANUAL_SETTINGS %{public}s can't be revoke.", permissionName.c_str()); + return AccessTokenError::ERR_PERMISSION_NOT_EXIST; + } + } return CheckAndUpdatePermissionInner(tokenID, permissionName, false, flag); } diff --git a/services/accesstokenmanager/main/cpp/src/service/accesstoken_manager_service.cpp b/services/accesstokenmanager/main/cpp/src/service/accesstoken_manager_service.cpp index cf0043e31..a499391db 100644 --- a/services/accesstokenmanager/main/cpp/src/service/accesstoken_manager_service.cpp +++ b/services/accesstokenmanager/main/cpp/src/service/accesstoken_manager_service.cpp @@ -487,7 +487,8 @@ int32_t AccessTokenManagerService::RequestAppPermOnSetting(AccessTokenID tokenID grantBundleName_, applicationSettingAbilityName_); } -int AccessTokenManagerService::GrantPermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenManagerService::GrantPermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, int32_t updateFlag) { AccessTokenID callingTokenID = IPCSkeleton::GetCallingTokenID(); if ((this->GetTokenType(callingTokenID) == TOKEN_HAP) && (!IsSystemAppCalling())) { @@ -503,11 +504,13 @@ int AccessTokenManagerService::GrantPermission(AccessTokenID tokenID, const std: return AccessTokenError::ERR_PERMISSION_DENIED; } - int32_t ret = PermissionManager::GetInstance().GrantPermission(tokenID, permissionName, flag); + int32_t ret = PermissionManager::GetInstance().GrantPermission( + tokenID, permissionName, flag, static_cast(updateFlag)); return ret; } -int AccessTokenManagerService::RevokePermission(AccessTokenID tokenID, const std::string& permissionName, uint32_t flag) +int AccessTokenManagerService::RevokePermission( + AccessTokenID tokenID, const std::string& permissionName, uint32_t flag, int32_t updateFlag) { AccessTokenID callingTokenID = IPCSkeleton::GetCallingTokenID(); if ((this->GetTokenType(callingTokenID) == TOKEN_HAP) && (!IsSystemAppCalling())) { @@ -522,7 +525,9 @@ int AccessTokenManagerService::RevokePermission(AccessTokenID tokenID, const std LOGE(ATM_DOMAIN, ATM_TAG, "Permission denied(tokenID=%{public}d)", callingTokenID); return AccessTokenError::ERR_PERMISSION_DENIED; } - return PermissionManager::GetInstance().RevokePermission(tokenID, permissionName, flag); + + return PermissionManager::GetInstance().RevokePermission( + tokenID, permissionName, flag, static_cast(updateFlag)); } int AccessTokenManagerService::GrantPermissionForSpecifiedTime( @@ -1465,7 +1470,7 @@ void AccessTokenManagerService::UpdateUndefinedInfoCache(const std::vector validValueList; validValueList.emplace_back(value1); validValueList.emplace_back(value2); + validValueList.emplace_back(value3); PermissionDataBrief::GetInstance().DeleteBriefPermDataByTokenId(RANDOM_TOKENID); std::shared_ptr atManagerService_ = diff --git a/services/accesstokenmanager/test/unittest/accesstoken_info_manager_test.cpp b/services/accesstokenmanager/test/unittest/accesstoken_info_manager_test.cpp index 7ee477808..b7c288d46 100644 --- a/services/accesstokenmanager/test/unittest/accesstoken_info_manager_test.cpp +++ b/services/accesstokenmanager/test/unittest/accesstoken_info_manager_test.cpp @@ -49,6 +49,7 @@ static constexpr int USER_ID = 100; static constexpr int INST_INDEX = 0; static constexpr int32_t MAX_EXTENDED_MAP_SIZE = 512; static constexpr int32_t MAX_VALUE_LENGTH = 1024; +static constexpr int32_t INVALID_GRANT_MODE = 1000; static AccessTokenID g_selfTokenId = 0; static PermissionDef g_infoManagerTestPermDef1 = { .permissionName = "open the door", @@ -1680,7 +1681,7 @@ HWTEST_F(AccessTokenInfoManagerTest, IsPermissionDefValid001, TestSize.Level0) PermissionDef permDef = { .permissionName = "ohos.permission.TEST", .bundleName = "com.ohos.test", - .grantMode = static_cast(2), + .grantMode = static_cast(INVALID_GRANT_MODE), .availableLevel = ATokenAplEnum::APL_NORMAL, .provisionEnable = false, .distributedSceneEnable = false, diff --git a/services/accesstokenmanager/test/unittest/permission_manager_test.cpp b/services/accesstokenmanager/test/unittest/permission_manager_test.cpp index 91e4eea80..97e024641 100644 --- a/services/accesstokenmanager/test/unittest/permission_manager_test.cpp +++ b/services/accesstokenmanager/test/unittest/permission_manager_test.cpp @@ -1962,6 +1962,52 @@ HWTEST_F(PermissionManagerTest, ContinuousTaskCallbackCall001, TestSize.Level1) ASSERT_EQ(RET_SUCCESS, BackgroundTaskManagerAccessClient::GetInstance().GetContinuousTaskApps(list)); } #endif + +/** + * @tc.name: HandlePermissionDeniedCaseWithInvalidAndManualPermTest001 + * @tc.desc: HandlePermissionDeniedCase invalid and manual permission test. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionManagerTest, HandlePermissionDeniedCaseWithInvalidAndManualPermTest001, TestSize.Level0) +{ + accessTokenService_->state_ = ServiceRunningState::STATE_RUNNING; + accessTokenService_->Initialize(); + + PermissionListState state; + state.permissionName = "ohos.permission.TEST123"; + state.state = DYNAMIC_OPER; + state.errorReason = REQ_SUCCESS; + EXPECT_EQ(true, PermissionManager::GetInstance().HandlePermissionDeniedCase(PERMISSION_ALLOW_THIS_TIME, state)); + + state.permissionName = "ohos.permission.MANUAL_ATM_SELF_USE"; + state.state = DYNAMIC_OPER; + state.errorReason = REQ_SUCCESS; + EXPECT_EQ(true, PermissionManager::GetInstance().HandlePermissionDeniedCase(PERMISSION_USER_FIXED, state)); +} + +/** + * @tc.name: UpdatePermissionWithInvalidPermTest001 + * @tc.desc: GrantPermission & RevokePermission with MANUAL_SETTINGS & invalid permission test. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionManagerTest, UpdatePermissionWithInvalidPermTest001, TestSize.Level0) +{ + accessTokenService_->state_ = ServiceRunningState::STATE_RUNNING; + accessTokenService_->Initialize(); + AccessTokenID tokenID = CreateTempHapTokenInfo(); + + EXPECT_NE(RET_SUCCESS, PermissionManager::GetInstance().GrantPermission( + tokenID, "ohos.permission.TEST123", PERMISSION_USER_FIXED, OPERABLE_PERM)); + + EXPECT_NE(RET_SUCCESS, PermissionManager::GetInstance().RevokePermission( + tokenID, "ohos.permission.TEST123", PERMISSION_USER_FIXED, OPERABLE_PERM)); + + PermissionManager::GetInstance().ParamUpdate("ohos.permission.TEST123", 0, false); + + EXPECT_EQ(false, IsOperablePermission("ohos.permission.TEST123")); +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/test/fuzztest/services/accesstoken/grantpermissionstub_fuzzer/grantpermissionstub_fuzzer.cpp b/test/fuzztest/services/accesstoken/grantpermissionstub_fuzzer/grantpermissionstub_fuzzer.cpp index e1c1ae4e5..7668fec79 100644 --- a/test/fuzztest/services/accesstoken/grantpermissionstub_fuzzer/grantpermissionstub_fuzzer.cpp +++ b/test/fuzztest/services/accesstoken/grantpermissionstub_fuzzer/grantpermissionstub_fuzzer.cpp @@ -61,9 +61,12 @@ namespace OHOS { std::string permissionName = provider.ConsumeRandomLengthString(); uint32_t flag = provider.ConsumeIntegralInRange( 0, static_cast(PermissionFlag::PERMISSION_ALLOW_THIS_TIME)); + int32_t grantMode = static_cast(provider.ConsumeIntegralInRange(1, 2)); + MessageParcel datas; datas.WriteInterfaceToken(IAccessTokenManager::GetDescriptor()); - if (!datas.WriteUint32(tokenId) || !datas.WriteString(permissionName) || !datas.WriteInt32(flag)) { + if (!datas.WriteUint32(tokenId) || !datas.WriteString(permissionName) || + !datas.WriteInt32(flag) || !datas.WriteInt32(grantMode)) { return false; } diff --git a/test/fuzztest/services/accesstoken/revokepermissionstub_fuzzer/revokepermissionstub_fuzzer.cpp b/test/fuzztest/services/accesstoken/revokepermissionstub_fuzzer/revokepermissionstub_fuzzer.cpp index ecb1d4488..c17a2572a 100644 --- a/test/fuzztest/services/accesstoken/revokepermissionstub_fuzzer/revokepermissionstub_fuzzer.cpp +++ b/test/fuzztest/services/accesstoken/revokepermissionstub_fuzzer/revokepermissionstub_fuzzer.cpp @@ -43,11 +43,12 @@ namespace OHOS { std::string testName = provider.ConsumeRandomLengthString(); uint32_t flag = static_cast(provider.ConsumeIntegralInRange( 0, static_cast(PermissionFlag::PERMISSION_ALLOW_THIS_TIME))); + int32_t grantMode = static_cast(provider.ConsumeIntegralInRange(1, 2)); MessageParcel datas; datas.WriteInterfaceToken(IAccessTokenManager::GetDescriptor()); if (!datas.WriteUint32(tokenId) || !datas.WriteString(testName) || - !datas.WriteInt32(flag)) { + !datas.WriteInt32(flag) || !datas.WriteInt32(grantMode)) { return false; } uint32_t code = static_cast( diff --git a/tools/accesstoken/src/to_string.cpp b/tools/accesstoken/src/to_string.cpp index 071c2645f..90ede5514 100644 --- a/tools/accesstoken/src/to_string.cpp +++ b/tools/accesstoken/src/to_string.cpp @@ -141,7 +141,16 @@ static std::string FormatAvailableType(ATokenAvailableTypeEnum availableType) static void PermDefToJson(const PermissionBriefDef& briefDef, CJsonUnique& permDefJson) { - std::string grantMode = briefDef.grantMode == GrantMode::USER_GRANT ? "USER_GRANT" : "SYSTEM_GRANT"; + std::string grantMode; + if (briefDef.grantMode == GrantMode::USER_GRANT) { + grantMode = "USER_GRANT"; + } else if (briefDef.grantMode == GrantMode::SYSTEM_GRANT) { + grantMode = "SYSTEM_GRANT"; + } else if (briefDef.grantMode == GrantMode::MANUAL_SETTINGS) { + grantMode = "MANUAL_SETTINGS"; + } else { + grantMode = "UNDEFINED"; + } (void)AddStringToJson(permDefJson, "permissionName", briefDef.permissionName); (void)AddStringToJson(permDefJson, "grantMode", grantMode); (void)AddStringToJson(permDefJson, "availableLevel", FormatApl(briefDef.availableLevel)); -- Gitee