* Copyright (C) 2021-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 "challenge_token_manager.h"
#include <openssl/rand.h>
#include "securec.h"
#include "telephony_log_wrapper.h"
namespace OHOS {
namespace Telephony {
std::list<ChallengeToken> ChallengeTokenManager::challengeTokenList_;
ffrt::mutex ChallengeTokenManager::tokenMutex_;
bool ChallengeTokenManager::TryUpdateChallengeTokenList(
const std::string &phoneNumber, const ChallengeToken &challenge)
{
std::lock_guard<ffrt::mutex> lock(tokenMutex_);
CleanupExpiredChallengeTokensUnsafe();
auto it = std::find_if(challengeTokenList_.begin(), challengeTokenList_.end(),
[&challenge](const ChallengeToken &tc) { return tc.uid == challenge.uid; });
if (it != challengeTokenList_.end()) {
it->token = challenge.token;
it->phoneNumber = phoneNumber;
it->isCustomAccessibility = challenge.isCustomAccessibility;
it->createTime = std::chrono::steady_clock::now();
return true;
}
if (challengeTokenList_.size() >= MAX_CHALLENGE_TOKEN_COUNT) {
TELEPHONY_LOGW("Token challenge list is full, reject new token for uid %{public}d", challenge.uid);
return false;
}
challengeTokenList_.push_back(challenge);
return true;
}
std::optional<ChallengeToken> ChallengeTokenManager::PopChallengeTokenByPhone(const std::string &phoneNumber)
{
std::lock_guard<ffrt::mutex> lock(tokenMutex_);
CleanupExpiredChallengeTokensUnsafe();
auto it = std::find_if(challengeTokenList_.begin(), challengeTokenList_.end(),
[&phoneNumber](const ChallengeToken &tc) { return tc.phoneNumber == phoneNumber; });
if (it != challengeTokenList_.end()) {
ChallengeToken result = *it;
challengeTokenList_.erase(it);
return result;
}
return std::nullopt;
}
void ChallengeTokenManager::CleanupExpiredChallengeTokensUnsafe()
{
auto now = std::chrono::steady_clock::now();
challengeTokenList_.remove_if([&now](const ChallengeToken &tc) {
auto duration = std::chrono::duration_cast<std::chrono::minutes>(now - tc.createTime);
return duration.count() >= CHALLENGE_TOKEN_EXPIRE_MINUTES;
});
}
void ChallengeTokenManager::FillExtrasFromChallengeToken(
const std::string &phoneNumber, AppExecFwk::PacMap &extras)
{
auto challenge = PopChallengeTokenByPhone(phoneNumber);
if (challenge.has_value()) {
extras.PutBooleanValue("isCustomAccessibility", challenge->isCustomAccessibility);
extras.PutStringValue("token", challenge->token);
}
}
std::string ChallengeTokenManager::GenerateToken()
{
unsigned char nonce[TOKEN_BYTES_LENGTH];
if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
return "";
}
std::string token;
token.reserve(sizeof(nonce) * HEX_STRING_RATIO);
for (int32_t i = 0; i < TOKEN_BYTES_LENGTH; ++i) {
char hex[3];
if (snprintf_s(hex, sizeof(hex), sizeof(hex), "%02x", nonce[i]) < 0) {
return "";
}
token += hex;
}
return token;
}
}
}