/* * Copyright (c) 2023 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 "widget_client.h" #include "system_ability_definition.h" #include "auth_common.h" #include "iam_check.h" #include "iam_logger.h" #include "iam_para2str.h" #include "iam_time.h" #include "nlohmann/json.hpp" #include "iwidget_callback.h" #include "hisysevent_adapter.h" #define LOG_TAG "USER_AUTH_SA" namespace OHOS { namespace UserIam { namespace UserAuth { const std::string PIN_SUB_TYPE_SIX = "PIN_SIX"; const std::string PIN_SUB_TYPE_NUMBER = "PIN_NUMBER"; const std::string PIN_SUB_TYPE_MIXED = "PIN_MIXED"; const std::string PIN_SUB_TYPE_FOUR = "PIN_FOUR"; const std::string PIN_SUB_TYPE_PATTERN = "PIN_PATTERN"; const std::string PIN_SUB_TYPE_MAX = "PIN_MAX"; WidgetClient &WidgetClient::Instance() { static WidgetClient widgetClient; return widgetClient; } void WidgetClient::SetWidgetSchedule(uint64_t contextId, const std::shared_ptr &schedule) { IF_FALSE_LOGE_AND_RETURN(schedule != nullptr); std::lock_guard lock(mutex_); widgetContextId_ = contextId; schedule_ = schedule; InsertScheduleNode(widgetContextId_, schedule_); } ResultCode WidgetClient::OnNotice(NoticeType type, const std::string &eventData) { // handle notice from widget if (type != WIDGET_NOTICE) { IAM_LOGE("Invalid notice type"); return ResultCode::INVALID_PARAMETERS; } if (eventData.empty()) { IAM_LOGE("Invalid notice event data"); return ResultCode::INVALID_PARAMETERS; } IAM_LOGI("recv notice eventData: %{public}s", eventData.c_str()); auto root = nlohmann::json::parse(eventData.c_str(), nullptr, false); if (root.is_null() || root.is_discarded()) { IAM_LOGE("OnNotice eventData is not json format"); return ResultCode::INVALID_PARAMETERS; } WidgetNotice notice = root.get(); if (notice.widgetContextId == 0) { IAM_LOGE("Invalid widget context id"); return ResultCode::INVALID_PARAMETERS; } if (!IsValidNoticeType(notice)) { IAM_LOGE("Not support notice event"); return ResultCode::INVALID_PARAMETERS; } if (schedule_ == nullptr) { IAM_LOGE("Invalid schedule node, report auth false"); return ResultCode::GENERAL_ERROR; } std::vector authTypeList = {}; if (!GetAuthTypeList(notice, authTypeList)) { IAM_LOGE("Invalid auth type list"); return ResultCode::INVALID_PARAMETERS; } ProcessNotice(notice, authTypeList); return ResultCode::SUCCESS; } void WidgetClient::ProcessNotice(const WidgetNotice ¬ice, std::vector &authTypeList) { IAM_LOGI("start, event:%{public}s", notice.event.c_str()); std::lock_guard lock(mutex_); if (notice.event == NOTICE_EVENT_AUTH_READY) { schedule_->StartAuthList(authTypeList, notice.endAfterFirstFail, notice.authIntent); } else if (notice.event == NOTICE_EVENT_CANCEL_AUTH) { if (notice.widgetContextId != widgetContextId_) { IAM_LOGE("Invalid widgetContextId ****%{public}hx", static_cast(widgetContextId_)); return; } if (authTypeList.size() == 1 && authTypeList[0] == AuthType::ALL) { schedule_->StopSchedule(); } else { schedule_->StopAuthList(authTypeList); } } else if (notice.event == NOTICE_EVENT_USER_NAVIGATION) { schedule_->NaviPinAuth(); } else if (notice.event == NOTICE_EVENT_WIDGET_PARA_INVALID) { schedule_->WidgetParaInvalid(); } else if (notice.event == NOTICE_EVENT_END) { schedule_->StopAuthList(authTypeList); } else if (notice.event == NOTICE_EVENT_RELOAD) { if ((authTypeList.size() == 1 && authTypeList[0] == AuthType::ALL) || authTypeList.size() != 1) { schedule_->WidgetParaInvalid(); } else { schedule_->WidgetReload(notice.orientation, notice.needRotate, notice.alreadyLoad, authTypeList[0]); } } else if (notice.event == NOTICE_EVENT_AUTH_WIDGET_LOADED) { WidgetLoad(notice.widgetContextId, authTypeList); } else if (notice.event == NOTICE_EVENT_AUTH_WIDGET_RELEASED) { WidgetRelease(notice.widgetContextId, authTypeList); } else if (notice.event == NOTICE_EVENT_PROCESS_TERMINATE) { ClearSchedule(notice.widgetContextId); } else if (notice.event == NOTICE_EVENT_AUTH_SEND_TIP) { schedule_->SendAuthTipInfo(authTypeList, notice.tipCode); } } void WidgetClient::SendCommand(const WidgetCommand &command) { std::lock_guard lock(mutex_); if (widgetCallback_ == nullptr) { IAM_LOGE("SendCommand widget callback is null"); return; } nlohmann::json root = command; std::string cmdData = root.dump(); IAM_LOGD("SendCommand cmdData"); widgetCallback_->SendCommand(cmdData); } void WidgetClient::ReportWidgetResult(int32_t result, AuthType authType, int32_t lockoutDuration, int32_t remainAttempts, bool skipLockedBiometricAuth) { std::lock_guard lock(mutex_); WidgetCommand::ExtraInfo extraInfo { .callingBundleName = callingBundleName_, .challenge = challenge_ }; // sendCommand of CMD_NOTIFY_AUTH_RESULT WidgetCommand::Cmd cmd { .event = CMD_NOTIFY_AUTH_RESULT, .version = NOTICE_VERSION_STR, .type = AuthType2Str(authType), .result = result, .lockoutDuration = lockoutDuration, .remainAttempts = remainAttempts, .extraInfo = extraInfo }; if (authType == AuthType::FINGERPRINT && !sensorInfo_.empty()) { cmd.sensorInfo = sensorInfo_; } WidgetCommand widgetCmd { .widgetContextId = widgetContextId_, .title = widgetParam_.title, .windowModeType = WinModeType2Str(widgetParam_.windowMode), .navigationButtonText = widgetParam_.navigationButtonText, .cmdList = { cmd }, .skipLockedBiometricAuth = skipLockedBiometricAuth }; for (auto &type : authTypeList_) { widgetCmd.typeList.emplace_back(AuthType2Str(type)); } if (!pinSubType_.empty()) { widgetCmd.pinSubType = pinSubType_; } SendCommand(widgetCmd); } void WidgetClient::ReportWidgetTip(int32_t tipType, AuthType authType, std::vector tipInfo, bool skipLockedBiometricAuth) { // sendCommand of CMD_NOTIFY_AUTH_TIP WidgetCommand::Cmd cmd { .event = CMD_NOTIFY_AUTH_TIP, .version = NOTICE_VERSION_STR, .type = AuthType2Str(authType), .tipType = tipType, .tipInfo = tipInfo }; std::lock_guard lock(mutex_); WidgetCommand widgetCmd { .widgetContextId = widgetContextId_, .cmdList = { cmd }, .skipLockedBiometricAuth = skipLockedBiometricAuth }; SendCommand(widgetCmd); } void WidgetClient::SetWidgetParam(const WidgetParamInner ¶m) { std::lock_guard lock(mutex_); widgetParam_ = param; } void WidgetClient::SetAuthTypeList(const std::vector &authTypeList) { std::lock_guard lock(mutex_); authTypeList_ = authTypeList; } void WidgetClient::SetWidgetCallback(const sptr &callback) { std::lock_guard lock(mutex_); widgetCallback_ = callback; } void WidgetClient::SetAuthTokenId(uint32_t tokenId) { std::lock_guard lock(mutex_); authTokenId_ = tokenId; IAM_LOGI("WidgetClient SetAuthTokenId authTokenId: %{public}s", GET_MASKED_STRING(authTokenId_).c_str()); } uint32_t WidgetClient::GetAuthTokenId() { std::lock_guard lock(mutex_); return authTokenId_; } void WidgetClient::Reset() { IAM_LOGI("WidgetClient Reset"); std::lock_guard lock(mutex_); widgetParam_.title.clear(); widgetParam_.navigationButtonText.clear(); widgetParam_.windowMode = WindowModeType::DIALOG_BOX; widgetContextId_ = 0; authTokenId_ = 0; schedule_ = nullptr; widgetCallback_ = nullptr; pinSubType_.clear(); sensorInfo_.clear(); } void WidgetClient::ForceStopAuth() { IAM_LOGI("stop auth process forcely by disconnect"); std::lock_guard lock(mutex_); if (schedule_ != nullptr) { schedule_->StopSchedule(); } ClearSchedule(widgetContextId_); } void WidgetClient::SetPinSubType(const PinSubType &subType) { std::lock_guard lock(mutex_); pinSubType_ = PIN_SUB_TYPE_SIX; switch (subType) { case PinSubType::PIN_NUMBER: pinSubType_ = PIN_SUB_TYPE_NUMBER; break; case PinSubType::PIN_MIXED: pinSubType_ = PIN_SUB_TYPE_MIXED; break; case PinSubType::PIN_MAX: pinSubType_ = PIN_SUB_TYPE_MAX; break; case PinSubType::PIN_FOUR: pinSubType_ = PIN_SUB_TYPE_FOUR; break; case PinSubType::PIN_PATTERN: pinSubType_ = PIN_SUB_TYPE_PATTERN; break; default: break; } } void WidgetClient::SetSensorInfo(const std::string &info) { std::lock_guard lock(mutex_); sensorInfo_ = info; } bool WidgetClient::GetAuthTypeList(const WidgetNotice ¬ice, std::vector &authTypeList) { std::lock_guard lock(mutex_); if (authTypeList_.empty()) { IAM_LOGE("inner auth type list is empty"); return false; } std::vector tempList = notice.AuthTypeList(); if (tempList.empty()) { IAM_LOGE("auth type list is empty"); return false; } if (tempList.size() == 1 && tempList[0] == AuthType::ALL) { if (notice.event != NOTICE_EVENT_CANCEL_AUTH && notice.event != NOTICE_EVENT_PROCESS_TERMINATE) { IAM_LOGE("invalid type all case event type: %{public}s", notice.event.c_str()); return false; } authTypeList.emplace_back(AuthType::ALL); return true; } for (auto &type : tempList) { authTypeList.emplace_back(type); } if (authTypeList.size() == authTypeList_.size() && notice.event == NOTICE_EVENT_CANCEL_AUTH) { authTypeList.clear(); authTypeList.emplace_back(AuthType::ALL); } return true; } bool WidgetClient::IsValidNoticeType(const WidgetNotice ¬ice) { if (notice.event != NOTICE_EVENT_AUTH_READY && notice.event != NOTICE_EVENT_CANCEL_AUTH && notice.event != NOTICE_EVENT_USER_NAVIGATION && notice.event != NOTICE_EVENT_WIDGET_PARA_INVALID && notice.event != NOTICE_EVENT_RELOAD && notice.event != NOTICE_EVENT_END && notice.event != NOTICE_EVENT_AUTH_WIDGET_LOADED && notice.event != NOTICE_EVENT_AUTH_WIDGET_RELEASED && notice.event != NOTICE_EVENT_PROCESS_TERMINATE && notice.event != NOTICE_EVENT_AUTH_SEND_TIP) { return false; } return true; } void WidgetClient::SetChallenge(const std::vector &challenge) { std::lock_guard lock(mutex_); challenge_ = challenge; } void WidgetClient::SetCallingBundleName(const std::string &callingBundleName) { std::lock_guard lock(mutex_); callingBundleName_ = callingBundleName; } void WidgetClient::InsertScheduleNode(uint64_t contextId, std::shared_ptr &scheduleNode) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); IF_FALSE_LOGE_AND_RETURN(scheduleNode != nullptr); std::lock_guard lock(mutex_); scheduleMap_.insert(std::pair>(contextId, scheduleNode)); } void WidgetClient::RemoveScheduleNode(uint64_t contextId) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); std::lock_guard lock(mutex_); scheduleMap_.erase(contextId); } std::shared_ptr WidgetClient::GetScheduleNode(uint64_t contextId) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); std::lock_guard lock(mutex_); std::shared_ptr scheduleNode = nullptr; auto iter = scheduleMap_.find(contextId); if (iter != scheduleMap_.end()) { scheduleNode = iter->second; IAM_LOGI("success, contextId:%{public}hx", static_cast(contextId)); } return scheduleNode; } void WidgetClient::ClearSchedule(uint64_t contextId) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); std::lock_guard lock(mutex_); auto schedule = GetScheduleNode(contextId); if (schedule != nullptr) { if (contextId == widgetContextId_) { Reset(); if (!loadedAuthTypeList_.empty()) { schedule->SendAuthTipInfo(loadedAuthTypeList_, TIP_CODE_WIDGET_RELEASED); loadedAuthTypeList_.clear(); } } schedule->ClearSchedule(); RemoveScheduleNode(contextId); } } void WidgetClient::WidgetLoad(uint64_t contextId, std::vector &authTypeList) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); std::lock_guard lock(mutex_); auto schedule = GetScheduleNode(contextId); if (schedule != nullptr) { if (contextId != widgetContextId_) { IAM_LOGE("widgetContextId_:%{public}hx", static_cast(widgetContextId_)); return; } schedule->SendAuthTipInfo(authTypeList, TIP_CODE_WIDGET_LOADED); loadedAuthTypeList_ = authTypeList; } } void WidgetClient::WidgetRelease(uint64_t contextId, std::vector &authTypeList) { IAM_LOGI("start, contextId:%{public}hx", static_cast(contextId)); std::lock_guard lock(mutex_); auto schedule = GetScheduleNode(contextId); if (schedule != nullptr) { schedule->SendAuthTipInfo(authTypeList, TIP_CODE_WIDGET_RELEASED); if (contextId != widgetContextId_) { IAM_LOGI("widgetContextId_:%{public}hx", static_cast(widgetContextId_)); return; } loadedAuthTypeList_.clear(); } } } // namespace UserAuth } // namespace UserIam } // namespace OHOS