ee399bd9创建于 2022年7月7日历史提交
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dm_credential_manager.h"

#include "dm_anonymous.h"
#include "dm_constants.h"
#include "dm_hash.h"
#include "dm_log.h"
#include "dm_random.h"
#include "parameter.h"

namespace OHOS {
namespace DistributedHardware {
struct CredentialDataInfo {
    int32_t credentialType;
    std::string credentailId;
    std::string serverPk;
    std::string pkInfoSignature;
    std::string pkInfo;
    std::string authCode;
    std::string peerDeviceId;
    std::string userId;
    CredentialDataInfo() : credentialType(UNKNOWN_CREDENTIAL_TYPE)
    {
    }
};

struct PeerCredentialInfo {
    std::string peerDeviceId;
    std::string peerCredentialId;
};
void from_json(const nlohmann::json &jsonObject, CredentialData &credentialData)
{
    if (!jsonObject.contains(FIELD_CREDENTIAL_TYPE) || !jsonObject.contains(FIELD_CREDENTIAL_ID) ||
        !jsonObject.contains(FIELD_SERVER_PK) || !jsonObject.contains(FIELD_PKINFO_SIGNATURE) ||
        !jsonObject.contains(FIELD_PKINFO) || !jsonObject.contains(FIELD_AUTH_CODE) ||
        !jsonObject.contains(FIELD_PEER_DEVICE_ID)) {
        LOGE("CredentialData json key not complete");
        return;
    }
    jsonObject[FIELD_CREDENTIAL_TYPE].get_to(credentialData.credentialType);
    jsonObject[FIELD_CREDENTIAL_ID].get_to(credentialData.credentialId);
    jsonObject[FIELD_SERVER_PK].get_to(credentialData.serverPk);
    jsonObject[FIELD_PKINFO_SIGNATURE].get_to(credentialData.pkInfoSignature);
    jsonObject[FIELD_PKINFO].get_to(credentialData.pkInfo);
    jsonObject[FIELD_AUTH_CODE].get_to(credentialData.authCode);
    jsonObject[FIELD_PEER_DEVICE_ID].get_to(credentialData.peerDeviceId);
}

DmCredentialManager::DmCredentialManager(std::shared_ptr<HiChainConnector> hiChainConnector,
                                         std::shared_ptr<IDeviceManagerServiceListener> listener)
    : hiChainConnector_(hiChainConnector), listener_(listener)
{
    LOGI("DmCredentialManager constructor");
}

DmCredentialManager::~DmCredentialManager()
{
    LOGI("DmCredentialManager destructor");
}

int32_t DmCredentialManager::RequestCredential(const std::string &reqJsonStr, std::string &returnJsonStr)
{
    LOGI("start to request credential.");
    char localDeviceId[DEVICE_UUID_LENGTH] = {0};
    GetDevUdid(localDeviceId, DEVICE_UUID_LENGTH);
    nlohmann::json jsonObject = nlohmann::json::parse(reqJsonStr, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("reqJsonStr string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_USER_ID) || !jsonObject.contains(FIELD_CREDENTIAL_VERSION)) {
        LOGE("user id or credential version string key not exist!");
        return ERR_DM_FAILED;
    }
    std::string userId = jsonObject[FIELD_USER_ID];
    std::string credentialVersion = jsonObject[FIELD_CREDENTIAL_VERSION];
    nlohmann::json jsonObj;
    jsonObj[FIELD_CREDENTIAL_VERSION] = credentialVersion;
    jsonObj[FIELD_USER_ID] = userId;
    jsonObj[FIELD_DEVICE_ID] = localDeviceId;
    std::string tmpStr = jsonObj.dump();
    return hiChainConnector_->getRegisterInfo(tmpStr.c_str(), returnJsonStr);
}

int32_t DmCredentialManager::ImportCredential(const std::string &pkgName, const std::string &credentialInfo)
{
    std::lock_guard<std::mutex> autoLock(locks_);
    std::vector<std::string>::iterator iter = std::find(credentialVec_.begin(), credentialVec_.end(), pkgName);
    if (iter == credentialVec_.end()) {
        LOGE("credentialInfo not found by pkgName %s", GetAnonyString(pkgName).c_str());
        return ERR_DM_FAILED;
    }
    pkgName_ = pkgName;
    nlohmann::json jsonObject = nlohmann::json::parse(credentialInfo, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("credentialInfo string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_PROCESS_TYPE)) {
        LOGE("credential type string key not exist!");
        return ERR_DM_FAILED;
    }
    int32_t processType = jsonObject[FIELD_PROCESS_TYPE];
    if (processType == LOCAL_CREDENTIAL_DEAL_TYPE) {
        return ImportLocalCredential(credentialInfo);
    } else if (processType == REMOTE_CREDENTIAL_DEAL_TYPE) {
        return ImportRemoteCredential(credentialInfo);
    } else {
        LOGE("credential type error!");
    }
    return ERR_DM_FAILED;
}

int32_t DmCredentialManager::ImportLocalCredential(const std::string &credentialInfo)
{
    LOGI("ImportLocalCredential start");
    nlohmann::json jsonObject = nlohmann::json::parse(credentialInfo, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("credentialInfo string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_AUTH_TYPE) || !jsonObject.contains(FIELD_USER_ID)
        || !jsonObject.contains(FIELD_CREDENTIAL_DATA)) {
        LOGE("auth type or user id string key not exist!");
        return ERR_DM_FAILED;
    }
    int32_t authType = jsonObject[FIELD_AUTH_TYPE];
    if (authType == SAME_ACCOUNT_TYPE) {
        authType = IDENTICAL_ACCOUNT_GROUP;
    }
    if (authType == CROSS_ACCOUNT_TYPE) {
        authType = ACROSS_ACCOUNT_AUTHORIZE_GROUP;
    }
    std::string userId = jsonObject[FIELD_USER_ID];
    requestId_ = GenRandLongLong(MIN_REQUEST_ID, MAX_REQUEST_ID);
    nlohmann::json creArray = jsonObject[FIELD_CREDENTIAL_DATA.c_str()];
    if (!creArray.is_array()) {
        LOGI("ImportLocalCredential credentialData is not a array object!");
        return ERR_DM_FAILED;
    }
    std::vector<CredentialData> vecCredentialData =
        jsonObject[FIELD_CREDENTIAL_DATA.c_str()].get<std::vector<CredentialData>>();
    if (vecCredentialData.size() != 1) {
        LOGI("ImportLocalCredential credentialData err");
        return ERR_DM_FAILED;
    }
    LOGI("ImportLocalCredential get credentialData success!");
    nlohmann::json jsonOutObj;
    if (GetCredentialData(credentialInfo, vecCredentialData[0], jsonOutObj) != DM_OK) {
        LOGE("failed to get credentialData field from input credential.");
        return ERR_DM_FAILED;
    }
    if (hiChainConnector_->CreateGroup(requestId_, authType, userId, jsonOutObj) != DM_OK) {
        LOGE("failed to create hichain group function.");
        return ERR_DM_FAILED;
    }
    return DM_OK;
}

int32_t DmCredentialManager::DeleteCredential(const std::string &pkgName, const std::string &deleteInfo)
{
    std::lock_guard<std::mutex> autoLock(locks_);
    std::vector<std::string>::iterator iter = std::find(credentialVec_.begin(), credentialVec_.end(), pkgName);
    if (iter == credentialVec_.end()) {
        LOGE("credentialInfo not found by pkgName %s", GetAnonyString(pkgName).c_str());
        return ERR_DM_FAILED;
    }
    pkgName_ = pkgName;
    nlohmann::json jsonObject = nlohmann::json::parse(deleteInfo, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("deleteInfo string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_PROCESS_TYPE) || !jsonObject.contains(FIELD_AUTH_TYPE)
        || !jsonObject.contains(FIELD_USER_ID)) {
        LOGE("process type string key not exist!");
        return ERR_DM_FAILED;
    }
    int32_t processType = jsonObject[FIELD_PROCESS_TYPE];
    int32_t authType = jsonObject[FIELD_AUTH_TYPE];
    if (authType == SAME_ACCOUNT_TYPE) {
        authType = IDENTICAL_ACCOUNT_GROUP;
    }
    if (authType == CROSS_ACCOUNT_TYPE) {
        authType = ACROSS_ACCOUNT_AUTHORIZE_GROUP;
    }
    std::string userId = jsonObject[FIELD_USER_ID];
    requestId_ = GenRandLongLong(MIN_REQUEST_ID, MAX_REQUEST_ID);
    if (processType == LOCAL_CREDENTIAL_DEAL_TYPE) {
        return hiChainConnector_->DeleteGroup(requestId_, userId, authType);
    } else if (processType == REMOTE_CREDENTIAL_DEAL_TYPE) {
        return DeleteRemoteCredential(deleteInfo);
    } else {
        LOGE("credential type error!");
    }
    return DM_OK;
}

void DmCredentialManager::OnGroupResult(int64_t requestId, int32_t action,
    const std::string &resultInfo)
{
    LOGI("DmCredentialManager::OnImportResult");
    if (requestId_ != requestId) {
        return;
    }
    listener_->OnCredentialResult(pkgName_, action, resultInfo);
}

int32_t DmCredentialManager::RegisterCredentialCallback(const std::string &pkgName)
{
    if (pkgName.empty()) {
        LOGE("DmCredentialManager::RegisterCredentialCallback input param is empty");
        return ERR_DM_FAILED;
    }
    LOGI("DmCredentialManager::RegisterCredentialCallback pkgName=%s",
        GetAnonyString(pkgName).c_str());
    credentialVec_.push_back(pkgName);
    return hiChainConnector_->RegisterHiChainGroupCallback(std::shared_ptr<IDmGroupResCallback>(shared_from_this()));
}

int32_t DmCredentialManager::UnRegisterCredentialCallback(const std::string &pkgName)
{
    if (pkgName.empty()) {
        LOGE("DmCredentialManager::UnRegisterCredentialStateCallback input param is empty");
        return ERR_DM_FAILED;
    }
    LOGI("DmCredentialManager::UnRegisterCredentialStateCallback pkgName=%s",
        GetAnonyString(pkgName).c_str());
    std::vector<std::string>::iterator iter = std::find(credentialVec_.begin(), credentialVec_.end(), pkgName);
    if (iter != credentialVec_.end()) {
        credentialVec_.erase(iter);
    }
    return hiChainConnector_->UnRegisterHiChainGroupCallback();
}

int32_t DmCredentialManager::GetCredentialData(const std::string &credentialInfo, const CredentialData &inputCreData,
    nlohmann::json &jsonOutObj)
{
    nlohmann::json jsonCreObj;
    jsonCreObj[FIELD_CREDENTIAL_TYPE] = inputCreData.credentialType;
    int32_t credentialType = inputCreData.credentialType;
    if (credentialType == NONSYMMETRY_CREDENTIAL_TYPE) {
        nlohmann::json jsonObject = nlohmann::json::parse(credentialInfo, nullptr, false);
        if (jsonObject.is_discarded()) {
            LOGE("credentialInfo string not a json type.");
            return ERR_DM_FAILED;
        }
        if (!jsonObject.contains(FIELD_USER_ID) || !jsonObject.contains(FIELD_CREDENTIAL_VERSION)
            || !jsonObject.contains(FIELD_DEVICE_ID) || !jsonObject.contains(FIELD_DEVICE_PK)) {
            LOGE("auth type or user id string key not exist!");
            return ERR_DM_FAILED;
        }
        std::string userId = jsonObject[FIELD_USER_ID];
        std::string deviceId = jsonObject[FIELD_DEVICE_ID];
        std::string verSion = jsonObject[FIELD_CREDENTIAL_VERSION];
        std::string devicePk = jsonObject[FIELD_DEVICE_PK];
        nlohmann::json jsonPkInfo;
        jsonPkInfo[FIELD_USER_ID] = userId;
        jsonPkInfo[FIELD_DEVICE_ID] = deviceId;
        jsonPkInfo[FIELD_CREDENTIAL_VERSION] = verSion;
        jsonPkInfo[FIELD_DEVICE_PK] = devicePk;
        jsonCreObj[FIELD_PKINFO] = jsonPkInfo;
        jsonCreObj[FIELD_SERVER_PK] = inputCreData.serverPk;
        jsonCreObj[FIELD_PKINFO_SIGNATURE] = inputCreData.pkInfoSignature;
    } else if (credentialType == SYMMETRY_CREDENTIAL_TYPE) {
        jsonCreObj[FIELD_AUTH_CODE] = inputCreData.authCode;
    } else {
        LOGE("invalid credentialType field!");
        return ERR_DM_FAILED;
    }
    jsonOutObj = jsonCreObj;
    return DM_OK;
}

void from_json(const nlohmann::json &jsonObject, CredentialDataInfo &credentialDataInfo)
{
    if (!jsonObject.contains(FIELD_CREDENTIAL_TYPE)) {
        LOGE("credentialType json key not exist");
        return;
    }
    jsonObject[FIELD_CREDENTIAL_TYPE].get_to(credentialDataInfo.credentialType);
    if (jsonObject.contains(FIELD_CREDENTIAL_ID)) {
        jsonObject[FIELD_CREDENTIAL_ID].get_to(credentialDataInfo.credentailId);
    }
    if (credentialDataInfo.credentialType == NONSYMMETRY_CREDENTIAL_TYPE) {
        if (jsonObject.contains(FIELD_SERVER_PK)) {
            jsonObject[FIELD_SERVER_PK].get_to(credentialDataInfo.serverPk);
        }
        if (jsonObject.contains(FIELD_PKINFO_SIGNATURE)) {
            jsonObject[FIELD_PKINFO_SIGNATURE].get_to(credentialDataInfo.pkInfoSignature);
        }
        if (jsonObject.contains(FIELD_PKINFO)) {
            nlohmann::json jsonPkInfo = jsonObject[FIELD_PKINFO];
            credentialDataInfo.pkInfo = jsonPkInfo.dump().c_str();
        }
    } else if (credentialDataInfo.credentialType == SYMMETRY_CREDENTIAL_TYPE) {
        if (jsonObject.contains(FIELD_AUTH_CODE)) {
            jsonObject[FIELD_AUTH_CODE].get_to(credentialDataInfo.authCode);
        }
    } else {
        LOGE("credentialType john key is unknown");
        return;
    }
    if (jsonObject.contains(FIELD_PEER_DEVICE_ID)) {
        jsonObject[FIELD_PEER_DEVICE_ID].get_to(credentialDataInfo.peerDeviceId);
    }
}

void to_json(nlohmann::json &jsonObject, const CredentialDataInfo &credentialDataInfo)
{
    jsonObject[FIELD_DEVICE_ID] = credentialDataInfo.peerDeviceId;
    jsonObject[FIELD_UDID] =credentialDataInfo.peerDeviceId;
    jsonObject[FIELD_USER_ID] = credentialDataInfo.userId;
    jsonObject[FIELD_CREDENTIAL_TYPE] = credentialDataInfo.credentialType;
    jsonObject[FIELD_CREDENTIAL_ID] = atoi(credentialDataInfo.credentailId.c_str());
    if (credentialDataInfo.credentialType == NONSYMMETRY_CREDENTIAL_TYPE) {
        jsonObject[FIELD_SERVER_PK] = credentialDataInfo.serverPk;
        jsonObject[FIELD_PKINFO_SIGNATURE] = credentialDataInfo.pkInfoSignature;
        jsonObject[FIELD_PKINFO] = credentialDataInfo.pkInfo;
    } else if (credentialDataInfo.credentialType == SYMMETRY_CREDENTIAL_TYPE) {
        jsonObject[FIELD_AUTH_CODE] = credentialDataInfo.authCode;
    }
}

int32_t DmCredentialManager::GetAddDeviceList(const nlohmann::json &jsonObject, nlohmann::json &jsonDeviceList)
{
    if (!jsonObject.contains(FIELD_CREDENTIAL_DATA) || !jsonObject.contains(FIELD_AUTH_TYPE)) {
        LOGE("credentaildata or authType string key not exist!");
        return ERR_DM_FAILED;
    }
    nlohmann::json credentialJson = jsonObject[FIELD_CREDENTIAL_DATA];
    auto credentialDataList = credentialJson.get<std::vector<CredentialDataInfo>>();
    int32_t authType = jsonObject[FIELD_AUTH_TYPE];

    for (auto &credentialData : credentialDataList) {
        if (authType == SAME_ACCOUNT_TYPE) {
            if (jsonObject.contains(FIELD_USER_ID)) {
                credentialData.userId = jsonObject[FIELD_USER_ID];
            }
        } else if (authType == CROSS_ACCOUNT_TYPE) {
            if (jsonObject.contains(FIELD_PEER_USER_ID)) {
                credentialData.userId = jsonObject[FIELD_PEER_USER_ID];
            }
        }
    }
    for (size_t i = 0; i < credentialDataList.size(); i++) {
        jsonDeviceList[FIELD_DEVICE_LIST][i] = credentialDataList.at(i);
    }
    return DM_OK;
}

int32_t DmCredentialManager::ImportRemoteCredential(const std::string &credentialInfo)
{
    nlohmann::json jsonObject = nlohmann::json::parse(credentialInfo, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("credentialInfo string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_AUTH_TYPE) || !jsonObject.contains(FIELD_CREDENTIAL_DATA)) {
        LOGE("auth type, credentialData string key not exist!");
        return ERR_DM_FAILED;
    }
    int32_t authType = jsonObject[FIELD_AUTH_TYPE];
    std::string userId;
    int32_t groupType = 0;
    if (authType == SAME_ACCOUNT_TYPE) {
        groupType = IDENTICAL_ACCOUNT_GROUP;
        if (!jsonObject.contains(FIELD_USER_ID)) {
            LOGE("userId string key not exist!");
            return ERR_DM_FAILED;
        } else {
            userId = jsonObject[FIELD_USER_ID];
        }
    } else if (authType == CROSS_ACCOUNT_TYPE) {
        groupType = ACROSS_ACCOUNT_AUTHORIZE_GROUP;
        if (!jsonObject.contains(FIELD_PEER_USER_ID)) {
            LOGE("peerUserId string key not exist!");
            return ERR_DM_FAILED;
        } else {
            userId = jsonObject[FIELD_PEER_USER_ID];
        }
    }
    nlohmann::json jsonDeviceList;
    if (GetAddDeviceList(jsonObject, jsonDeviceList) != DM_OK) {
        LOGE("failed to get add DeviceList.");
        return ERR_DM_FAILED;
    }
    if (hiChainConnector_->addMultiMembers(groupType, userId, jsonDeviceList) != DM_OK) {
        LOGE("failed to add members to group.");
        return ERR_DM_FAILED;
    }
    return DM_OK;
}

void from_json(const nlohmann::json &jsonObject, PeerCredentialInfo &peerCredentialInfo)
{
    if (jsonObject.contains(FIELD_PEER_USER_ID)) {
        jsonObject[FIELD_PEER_USER_ID].get_to(peerCredentialInfo.peerDeviceId);
    }
}

void to_json(nlohmann::json &jsonObject, const PeerCredentialInfo &peerCredentialInfo)
{
    jsonObject[FIELD_DEVICE_ID] = peerCredentialInfo.peerDeviceId;
}

int32_t GetDeleteDeviceList(const nlohmann::json &jsonObject, nlohmann::json &deviceList)
{
    if (!jsonObject.contains(FIELD_PEER_CREDENTIAL_INFO)) {
        LOGE("devicelist string key not exist!");
        return ERR_DM_FAILED;
    }
    auto peerCredentialInfo = jsonObject[FIELD_PEER_CREDENTIAL_INFO].get<std::vector<PeerCredentialInfo>>();
    for (size_t i = 0; i < peerCredentialInfo.size(); i++) {
        deviceList[FIELD_DEVICE_LIST][i] = peerCredentialInfo[i];
    }
    return DM_OK;
}

int32_t DmCredentialManager::DeleteRemoteCredential(const std::string &deleteInfo)
{
    nlohmann::json jsonObject = nlohmann::json::parse(deleteInfo, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("credentialInfo string not a json type.");
        return ERR_DM_FAILED;
    }
    if (!jsonObject.contains(FIELD_AUTH_TYPE) || !jsonObject.contains(FIELD_PEER_CREDENTIAL_INFO)) {
        LOGE("authType, peerCredential or peerUserId string key not exist!");
        return ERR_DM_FAILED;
    }
    int32_t authType = jsonObject[FIELD_AUTH_TYPE];
    std::string userId;
    int32_t groupType = 0;
    if (authType == SAME_ACCOUNT_TYPE) {
        if (!jsonObject.contains(FIELD_USER_ID)) {
            LOGE("userId string key not exist.");
            return ERR_DM_FAILED;
        } else {
            userId = jsonObject[FIELD_USER_ID];
        }
        groupType = IDENTICAL_ACCOUNT_GROUP;
    } else if (authType == CROSS_ACCOUNT_TYPE) {
        if (!jsonObject.contains(FIELD_PEER_USER_ID)) {
            LOGE("peerUserId string key not exist.");
            return ERR_DM_FAILED;
        } else {
            userId = jsonObject[FIELD_PEER_USER_ID];
        }
        groupType = ACROSS_ACCOUNT_AUTHORIZE_GROUP;
    }
    nlohmann::json jsonDeviceList;
    if (GetDeleteDeviceList(jsonObject, jsonDeviceList) != DM_OK) {
        LOGE("failed to get delete DeviceList.");
        return ERR_DM_FAILED;
    }
    if (hiChainConnector_->deleteMultiMembers(groupType, userId, jsonDeviceList) != DM_OK) {
        LOGE("failed to delete members from group.");
        return ERR_DM_FAILED;
    }
    return DM_OK;
}
} // namespace DistributedHardware
} // namespace OHOS