a6c97aab创建于 17 小时前历史提交
/*

 * Copyright (c) 2022-2026 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *    http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



#include "cm_napi_grant.h"



#include "securec.h"



#include <memory>



#include "cert_manager_api.h"

#include "cm_log.h"

#include "cm_mem.h"

#include "cm_type.h"

#include "cm_napi_common.h"

#include "cm_util.h"

#include "cm_metrics.h"



namespace CMNapi {

namespace {

constexpr int CM_NAPI_GRANT_ARGS_CNT = 2;

constexpr int CM_NAPI_IS_AUTHED_ARGS_CNT = 1;



constexpr uint32_t OUT_AUTH_URI_SIZE = 1000;

constexpr uint32_t OUT_AUTH_LIST_SIZE = 512;

constexpr uint32_t OUT_UINT32_STRING_SIZE = 16;

} // namespace



struct GrantAsyncContextT {

    napi_async_work asyncWork = nullptr;

    napi_deferred deferred = nullptr;

    napi_ref callback = nullptr;



    int32_t errCode = 0;

    uint32_t appUid = 0;

    struct CmBlob *keyUri = nullptr;

    struct CmBlob *authUri = nullptr;

    struct CmAppUidList *uidList = nullptr;

    std::shared_ptr<OHOS::Security::CertManager::CmMetricsReport> metricsReport = nullptr;

};

using GrantAsyncContext = GrantAsyncContextT *;



static GrantAsyncContext InitGrantAsyncContext(void)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(CmMalloc(sizeof(GrantAsyncContextT)));

    if (context != nullptr) {

        (void)memset_s(context, sizeof(GrantAsyncContextT), 0, sizeof(GrantAsyncContextT));

    }

    return context;

}



static void FreeGrantAsyncContext(napi_env env, GrantAsyncContext &context)

{

    if (context == nullptr) {

        return;

    }



    DeleteNapiContext(env, context->asyncWork, context->callback);

    FreeCmBlob(context->keyUri);

    FreeCmBlob(context->authUri);

    if (context->uidList != nullptr) {

        CM_FREE_PTR(context->uidList->appUid);

        CM_FREE_PTR(context->uidList);

    }

    CM_FREE_PTR(context);

}



static napi_value ParseGrantUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)

{

    size_t argc = CM_NAPI_GRANT_ARGS_CNT;

    napi_value argv[CM_NAPI_GRANT_ARGS_CNT] = { nullptr };

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));



    if (argc != CM_NAPI_GRANT_ARGS_CNT) {

        ThrowError(env, PARAM_ERROR, "arguments count invalid when grant or remove uid", context->metricsReport.get());

        CM_LOG_E("arguments count is not expected when grant or remove uid");

        return nullptr;

    }



    size_t index = 0;

    napi_value result = ParseString(env, argv[index], context->keyUri);

    if (result == nullptr) {

        ThrowError(env, PARAM_ERROR, "keyUri type error", context->metricsReport.get());

        CM_LOG_E("get uri failed when grant or remove uid");

        return nullptr;

    }



    index++;

    result = ParseUint32(env, argv[index], context->appUid);

    if (result == nullptr) {

        ThrowError(env, PARAM_ERROR, "appUid type error", context->metricsReport.get());

        CM_LOG_E("get app uid failed when grant or remove uid ");

        return nullptr;

    }



    return GetInt32(env, 0);

}



static napi_value ParseRemoveUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)

{

    return ParseGrantUidParams(env, info, context);

}



static napi_value ParseIsAuthedParams(napi_env env, napi_callback_info info, GrantAsyncContext context)

{

    size_t argc = CM_NAPI_IS_AUTHED_ARGS_CNT;

    napi_value argv[CM_NAPI_IS_AUTHED_ARGS_CNT] = { nullptr };

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));



    if (argc != CM_NAPI_IS_AUTHED_ARGS_CNT) {

        ThrowError(env, PARAM_ERROR, "arguments count invalid, arguments count need 1.", context->metricsReport.get());

        CM_LOG_E("arguments count is not expected when using isAuthed");

        return nullptr;

    }



    size_t index = 0;

    napi_value result = ParseString(env, argv[index], context->keyUri);

    if (result == nullptr) {

        ThrowError(env, PARAM_ERROR, "keyUri is not a string or length is 0 or too long.",

            context->metricsReport.get());

        CM_LOG_E("get uri failed when using isAuthed");

        return nullptr;

    }



    return GetInt32(env, 0);

}



static napi_value ParseGetUidListParams(napi_env env, napi_callback_info info, GrantAsyncContext context)

{

    return ParseIsAuthedParams(env, info, context);

}



static void GrantUidExecute(napi_env env, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    context->authUri = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));

    if (context->authUri == nullptr) {

        CM_LOG_E("malloc authUri failed");

        context->errCode = CMR_ERROR_MALLOC_FAIL;

        return;

    }

    (void)memset_s(context->authUri, sizeof(CmBlob), 0, sizeof(CmBlob));



    context->authUri->data = static_cast<uint8_t *>(CmMalloc(OUT_AUTH_URI_SIZE));

    if (context->authUri->data == nullptr) {

        CM_LOG_E("malloc authUri.data failed");

        context->errCode = CMR_ERROR_MALLOC_FAIL;

        return;

    }

    (void)memset_s(context->authUri->data, OUT_AUTH_URI_SIZE, 0, OUT_AUTH_URI_SIZE);

    context->authUri->size = OUT_AUTH_URI_SIZE;



    context->errCode = CmGrantAppCertificate(context->keyUri, context->appUid, context->authUri);

}



static napi_value ConvertResultAuthUri(napi_env env, const CmBlob *authUri)

{

    napi_value result = nullptr;

    NAPI_CALL(env, napi_create_object(env, &result));



    napi_value authUriNapi = nullptr;

    NAPI_CALL(env, napi_create_string_latin1(env,

        reinterpret_cast<const char *>(authUri->data), NAPI_AUTO_LENGTH, &authUriNapi));

    NAPI_CALL(env, napi_set_named_property(env, result, "uri", authUriNapi));



    return result;

}



static void GrantUidResolve(napi_env env, GrantAsyncContext context)

{

    napi_value result[RESULT_NUMBER] = { nullptr };

    if (context->errCode == CM_SUCCESS) {

        napi_create_uint32(env, 0, &result[0]);

        result[1] = ConvertResultAuthUri(env, context->authUri);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else {

        result[0] = GenerateBusinessError(env, context->errCode, context->metricsReport.get());

        napi_get_undefined(env, &result[1]);

    }



    GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));

}



static void GrantUidComplete(napi_env env, napi_status status, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    GrantUidResolve(env, context);

    FreeGrantAsyncContext(env, context);

}



static void RemoveUidExecute(napi_env env, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    context->errCode = CmRemoveGrantedApp(context->keyUri, context->appUid);

}



static void RemoveUidResove(napi_env env, GrantAsyncContext context)

{

    napi_value result[RESULT_NUMBER] = { nullptr };

    if (context->errCode == CM_SUCCESS) {

        napi_create_uint32(env, 0, &result[0]);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else if (context->errCode == CMR_ERROR_AUTH_CHECK_FAILED) {

        napi_create_uint32(env, 0, &result[0]);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else {

        result[0] = GenerateBusinessError(env, context->errCode, context->metricsReport.get());

    }

    napi_get_undefined(env, &result[1]);



    GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));

}



static void RemoveUidComplete(napi_env env, napi_status status, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    RemoveUidResove(env, context);

    FreeGrantAsyncContext(env, context);

}



static void IsAuthedResolve(napi_env env, GrantAsyncContext context)

{

    napi_value result[RESULT_NUMBER] = { nullptr };

    if (context->errCode == CM_SUCCESS) {

        napi_create_uint32(env, 0, &result[0]);

        napi_get_boolean(env, true, &result[1]);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else if (context->errCode == CMR_ERROR_AUTH_CHECK_FAILED) {

        napi_create_uint32(env, 0, &result[0]);

        napi_get_boolean(env, false, &result[1]);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else {

        result[0] = GenerateBusinessError(env, context->errCode, context->metricsReport.get());

        napi_get_undefined(env, &result[1]);

    }



    GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));

}



static void IsAuthedComplete(napi_env env, napi_status status, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    IsAuthedResolve(env, context);

    FreeGrantAsyncContext(env, context);

}



static void IsAuthedExecute(napi_env env, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    context->errCode = CmIsAuthorizedApp(context->keyUri);

}



static void GetUidListExecute(napi_env env, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    context->uidList = static_cast<CmAppUidList *>(CmMalloc(sizeof(CmAppUidList)));

    if (context->uidList == nullptr) {

        CM_LOG_E("malloc uid list failed");

        context->errCode = CMR_ERROR_MALLOC_FAIL;

        return;

    }

    (void)memset_s(context->uidList, sizeof(CmAppUidList), 0, sizeof(CmAppUidList));



    uint32_t uidListSize = OUT_AUTH_LIST_SIZE * sizeof(uint32_t);

    context->uidList->appUid = static_cast<uint32_t *>(CmMalloc(uidListSize));

    if (context->uidList->appUid == nullptr) {

        CM_LOG_E("malloc uid_list.appUid failed");

        context->errCode = CMR_ERROR_MALLOC_FAIL;

        return;

    }

    (void)memset_s(context->uidList->appUid, uidListSize, 0, uidListSize);

    context->uidList->appUidCount = OUT_AUTH_LIST_SIZE;



    context->errCode = CmGetAuthorizedAppList(context->keyUri, context->uidList);

}



static napi_value ConvertResultAuthList(napi_env env, const CmAppUidList *appUidList)

{

    napi_value result = nullptr;

    NAPI_CALL(env, napi_create_object(env, &result));



    napi_value uidListArray = nullptr;

    NAPI_CALL(env, napi_create_array(env, &uidListArray));



    for (uint32_t i = 0; i < appUidList->appUidCount; ++i) {

        char uidStr[OUT_UINT32_STRING_SIZE] = {0};

        if (snprintf_s(uidStr, sizeof(uidStr), sizeof(uidStr) - 1, "%u", appUidList->appUid[i]) < 0) {

            CM_LOG_E("uid to string failed");

            return result;

        }



        napi_value element = nullptr;

        NAPI_CALL(env, napi_create_string_latin1(env, static_cast<const char *>(uidStr), NAPI_AUTO_LENGTH, &element));

        NAPI_CALL(env, napi_set_element(env, uidListArray, i, element));

    }



    NAPI_CALL(env, napi_set_named_property(env, result, "appUidList", uidListArray));

    return result;

}



static void GetUidListResolve(napi_env env, GrantAsyncContext context)

{

    napi_value result[RESULT_NUMBER] = { nullptr };

    if (context->errCode == CM_SUCCESS) {

        napi_create_uint32(env, 0, &result[0]);

        result[1] = ConvertResultAuthList(env, context->uidList);

        if (context->metricsReport != nullptr) {

            context->metricsReport->Finish(CM_SUCCESS);

        }

    } else {

        result[0] = GenerateBusinessError(env, context->errCode, context->metricsReport.get());

        napi_get_undefined(env, &result[1]);

    }



    GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));

}



static void GetUidListComplete(napi_env env, napi_status status, void *data)

{

    GrantAsyncContext context = static_cast<GrantAsyncContext>(data);

    GetUidListResolve(env, context);

    FreeGrantAsyncContext(env, context);

}



static napi_value GrantUidAsyncWork(napi_env env, GrantAsyncContext context)

{

    napi_value promise = nullptr;

    NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));



    napi_value resourceName = nullptr;

    NAPI_CALL(env, napi_create_string_latin1(env, "grantAppCertificate", NAPI_AUTO_LENGTH, &resourceName));



    NAPI_CALL(env, napi_create_async_work(

        env, nullptr, resourceName,

        GrantUidExecute,

        GrantUidComplete,

        static_cast<void *>(context),

        &context->asyncWork));



    napi_status status = napi_queue_async_work(env, context->asyncWork);

    if (status != napi_ok) {

        ThrowError(env, INNER_FAILURE, GENERIC_MSG, context->metricsReport.get());

        CM_LOG_E("get async work failed when granting uid");

        DeferredResolveUndefined(env, context->deferred);

        return nullptr;

    }

    return promise;

}



static napi_value RemoveUidAsyncWork(napi_env env, GrantAsyncContext context)

{

    napi_value promise = nullptr;

    NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));



    napi_value resourceName = nullptr;

    NAPI_CALL(env, napi_create_string_latin1(env, "removeGrantedAppCertificate", NAPI_AUTO_LENGTH, &resourceName));



    NAPI_CALL(env, napi_create_async_work(

        env, nullptr, resourceName,

        RemoveUidExecute,

        RemoveUidComplete,

        static_cast<void *>(context),

        &context->asyncWork));



    napi_status status = napi_queue_async_work(env, context->asyncWork);

    if (status != napi_ok) {

        ThrowError(env, INNER_FAILURE, GENERIC_MSG, context->metricsReport.get());

        CM_LOG_E("queue async work failed when removing uid");

        DeferredResolveUndefined(env, context->deferred);

        return nullptr;

    }

    return promise;

}



static napi_value IsAuthedAsyncWork(napi_env env, GrantAsyncContext context)

{

    napi_value promise = nullptr;

    NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));



    napi_value resourceName = nullptr;

    NAPI_CALL(env, napi_create_string_latin1(env, "isAuthorizedApp", NAPI_AUTO_LENGTH, &resourceName));



    NAPI_CALL(env, napi_create_async_work(

        env, nullptr, resourceName,

        IsAuthedExecute,

        IsAuthedComplete,

        static_cast<void *>(context),

        &context->asyncWork));



    napi_status status = napi_queue_async_work(env, context->asyncWork);

    if (status != napi_ok) {

        ThrowError(env, INNER_FAILURE, GENERIC_MSG, context->metricsReport.get());

        CM_LOG_E("queue async work failed when using isAuthed");

        DeferredResolveUndefined(env, context->deferred);

        return nullptr;

    }

    return promise;

}



static napi_value GetUidListAsyncWork(napi_env env, GrantAsyncContext context)

{

    napi_value promise = nullptr;

    NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));



    napi_value resourceName = nullptr;

    NAPI_CALL(env, napi_create_string_latin1(env, "getAuthorizedAppList", NAPI_AUTO_LENGTH, &resourceName));



    NAPI_CALL(env, napi_create_async_work(

        env, nullptr, resourceName,

        GetUidListExecute,

        GetUidListComplete,

        static_cast<void *>(context),

        &context->asyncWork));



    napi_status status = napi_queue_async_work(env, context->asyncWork);

    if (status != napi_ok) {

        ThrowError(env, INNER_FAILURE, GENERIC_MSG, context->metricsReport.get());

        CM_LOG_E("queue async work failed when getting authed uid list");

        DeferredResolveUndefined(env, context->deferred);

        return nullptr;

    }

    return promise;

}



napi_value CMNapiGrantPublicCertificate(napi_env env, napi_callback_info info)

{

    CM_LOG_I("grant publice cert enter");

    OHOS::Security::CertManager::CmMetricsReport report("grantPublicCertificate");

    report.Start();



    GrantAsyncContext context = InitGrantAsyncContext();

    if (context == nullptr) {

        CM_LOG_E("init grant uid context failed");

        report.Finish(INNER_FAILURE);

        return nullptr;

    }

    auto reportHolder = std::make_shared<OHOS::Security::CertManager::CmMetricsReport>(std::move(report));

    context->metricsReport = reportHolder;



    napi_value result = ParseGrantUidParams(env, info, context);

    if (result == nullptr) {

        CM_LOG_E("parse grant uid params failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    result = GrantUidAsyncWork(env, context);

    if (result == nullptr) {

        CM_LOG_E("start grant uid async work failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    CM_LOG_I("grant publice cert end");

    return result;

}



napi_value CMNapiIsAuthorizedApp(napi_env env, napi_callback_info info)

{

    CM_LOG_I("is authed app enter");

    OHOS::Security::CertManager::CmMetricsReport report("isAuthorizedApp");

    report.Start();



    GrantAsyncContext context = InitGrantAsyncContext();

    if (context == nullptr) {

        CM_LOG_E("init is authed uid context failed");

        report.Finish(INNER_FAILURE);

        return nullptr;

    }

    auto reportHolder = std::make_shared<OHOS::Security::CertManager::CmMetricsReport>(std::move(report));

    context->metricsReport = reportHolder;



    napi_value result = ParseIsAuthedParams(env, info, context);

    if (result == nullptr) {

        CM_LOG_E("parse is authed uid params failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    result = IsAuthedAsyncWork(env, context);

    if (result == nullptr) {

        CM_LOG_E("start is authed uid async work failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    CM_LOG_I("is authed app end");

    return result;

}



napi_value CMNapiGetAuthorizedAppList(napi_env env, napi_callback_info info)

{

    CM_LOG_I("get auth app list enter");

    OHOS::Security::CertManager::CmMetricsReport report("getAuthorizedAppList");

    report.Start();



    GrantAsyncContext context = InitGrantAsyncContext();

    if (context == nullptr) {

        CM_LOG_E("init get authed uid list context failed");

        report.Finish(INNER_FAILURE);

        return nullptr;

    }

    auto reportHolder = std::make_shared<OHOS::Security::CertManager::CmMetricsReport>(std::move(report));

    context->metricsReport = reportHolder;



    napi_value result = ParseGetUidListParams(env, info, context);

    if (result == nullptr) {

        CM_LOG_E("parse get uid list params failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    result = GetUidListAsyncWork(env, context);

    if (result == nullptr) {

        CM_LOG_E("start get uid list async work failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    CM_LOG_I("get auth app list end");

    return result;

}



napi_value CMNapiRemoveGrantedPublic(napi_env env, napi_callback_info info)

{

    CM_LOG_I("remove granted app enter");

    OHOS::Security::CertManager::CmMetricsReport report("removeGrantedPublicCertificate");

    report.Start();



    GrantAsyncContext context = InitGrantAsyncContext();

    if (context == nullptr) {

        CM_LOG_E("init remove uid context failed");

        report.Finish(INNER_FAILURE);

        return nullptr;

    }

    auto reportHolder = std::make_shared<OHOS::Security::CertManager::CmMetricsReport>(std::move(report));

    context->metricsReport = reportHolder;



    napi_value result = ParseRemoveUidParams(env, info, context);

    if (result == nullptr) {

        CM_LOG_E("parse remove uid params failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    result = RemoveUidAsyncWork(env, context);

    if (result == nullptr) {

        CM_LOG_E("start remove uid async work failed");

        FreeGrantAsyncContext(env, context);

        return nullptr;

    }



    CM_LOG_I("remove granted app end");

    return result;

}

}  // namespace CMNapi