Files
nearby/presence/implementation/credential_manager_impl.cc
T
2023-07-19 17:12:52 -07:00

782 lines
32 KiB
C++

// Copyright 2022 Google LLC
//
// 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
//
// https://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 "presence/implementation/credential_manager_impl.h"
#include <algorithm>
#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/variant.h"
#include "internal/platform/count_down_latch.h"
#ifdef NEARBY_CHROMIUM
#include "crypto/aead.h"
#include "crypto/ec_private_key.h"
#include "crypto/hkdf.h"
#include "crypto/random.h"
#else
#include "internal/crypto_cros/aead.h"
#include "internal/crypto_cros/ec_private_key.h"
#include "internal/crypto_cros/hkdf.h"
#include "internal/crypto_cros/random.h"
#endif
#include "internal/platform/base64_utils.h"
#include "internal/platform/future.h"
#include "internal/platform/implementation/credential_callbacks.h"
#include "internal/platform/implementation/crypto.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/logging.h"
#include "internal/proto/credential.pb.h"
#include "internal/proto/local_credential.pb.h"
#include "presence/data_types.h"
#include "presence/implementation/base_broadcast_request.h"
#include "presence/implementation/ldt.h"
namespace nearby {
namespace presence {
namespace {
using ::nearby::Base64Utils;
using ::nearby::Crypto;
using ::nearby::Exception;
using ::nearby::ExceptionOr;
using ::nearby::Future;
using ::nearby::internal::IdentityType;
using ::nearby::internal::LocalCredential;
using ::nearby::internal::SharedCredential;
// Key to retrieve local device's Private/Public Key Credentials from key store.
constexpr char kPairedKeyAliasPrefix[] = "nearby_presence_paired_key_alias_";
// The expected number of valid local credentials to be stored on local device.
constexpr int kExpectedValidLocalCredtialSize = 6;
// The expiration time in days for a credential.
constexpr int kCredentialLifeCycleDays = 5;
// Returns a random duration in [0, max_duration] range.
absl::Duration RandomDuration(absl::Duration max_duration) {
uint32_t random = nearby::RandData<uint32_t>();
return max_duration * random / std::numeric_limits<uint32_t>::max();
}
std::string CustomizeBytesSize(absl::string_view bytes, size_t len) {
return ::crypto::HkdfSha256(
/*ikm=*/std::string(bytes), // NOLINT
/*salt=*/std::string(CredentialManagerImpl::kAuthenticityKeyByteSize, 0),
/*info=*/"", /*derived_key_size=*/len);
}
} // namespace
void CredentialManagerImpl::GenerateCredentials(
const Metadata& metadata, absl::string_view manager_app_id,
const std::vector<IdentityType>& identity_types,
int credential_life_cycle_days, int contiguous_copy_of_credentials,
GenerateCredentialsResultCallback credentials_generated_cb) {
std::vector<SharedCredential> public_credentials;
std::vector<LocalCredential> private_credentials;
for (auto identity_type : identity_types) {
absl::Time start_time = SystemClock::ElapsedRealtime();
absl::Duration gap = credential_life_cycle_days * absl::Hours(24);
for (int index = 0; index < contiguous_copy_of_credentials; index++) {
auto public_private_credentials = CreateLocalCredential(
metadata, identity_type, start_time, start_time + gap);
if (public_private_credentials.second.identity_type() !=
IdentityType::IDENTITY_TYPE_UNSPECIFIED) {
private_credentials.push_back(public_private_credentials.first);
public_credentials.push_back(public_private_credentials.second);
}
start_time += gap;
}
}
// Create credential_storage object and invoke SaveCredentials.
credential_storage_ptr_->SaveCredentials(
manager_app_id, metadata.account_name(), private_credentials,
public_credentials, PublicCredentialType::kLocalPublicCredential,
SaveCredentialsResultCallback{
.credentials_saved_cb =
[this, manager_app_id = std::string(manager_app_id),
account_name = metadata.account_name(),
callback = std::move(credentials_generated_cb),
public_credentials](absl::Status status) mutable {
if (!status.ok()) {
NEARBY_LOGS(WARNING)
<< "Save credentials failed with: " << status;
std::move(callback.credentials_generated_cb)(status);
return;
}
std::move(callback.credentials_generated_cb)(
std::move(public_credentials));
RunOnServiceControllerThread(
"local-creds-changed",
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnCredentialsChanged(
manager_app_id, account_name,
PublicCredentialType::kLocalPublicCredential);
});
}});
}
void CredentialManagerImpl::UpdateRemotePublicCredentials(
absl::string_view manager_app_id, absl::string_view account_name,
const std::vector<SharedCredential>& remote_public_creds,
UpdateRemotePublicCredentialsCallback credentials_updated_cb) {
credential_storage_ptr_->SaveCredentials(
manager_app_id, account_name, /* private_credentials */ {},
remote_public_creds, PublicCredentialType::kRemotePublicCredential,
SaveCredentialsResultCallback{
.credentials_saved_cb =
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name),
callback = std::move(credentials_updated_cb)](
absl::Status status) mutable {
if (!status.ok()) {
NEARBY_LOGS(WARNING)
<< "Update remote credentials failed with: " << status;
} else {
RunOnServiceControllerThread(
"remote-creds-changed",
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnCredentialsChanged(
manager_app_id, account_name,
PublicCredentialType::kRemotePublicCredential);
});
}
std::move(callback.credentials_updated_cb)(status);
}});
}
std::pair<LocalCredential, SharedCredential>
CredentialManagerImpl::CreateLocalCredential(const Metadata& metadata,
IdentityType identity_type,
absl::Time start_time,
absl::Time end_time) {
LocalCredential private_credential;
private_credential.set_start_time_millis(absl::ToUnixMillis(start_time));
private_credential.set_end_time_millis(absl::ToUnixMillis(end_time));
private_credential.set_identity_type(identity_type);
// Creates an AES key to encrypt the whole broadcast.
std::string secret_key(kAuthenticityKeyByteSize, 0);
crypto::RandBytes(const_cast<std::string::value_type*>(secret_key.data()),
secret_key.size());
private_credential.set_key_seed(secret_key);
// Uses SHA-256 algorithm to generate the credential ID from the
// authenticity key
auto secret_id = Crypto::Sha256(secret_key);
// Does not expect to fail here since Crypto::Sha256 should not return
// empty ByteArray.
CHECK(!secret_id.Empty()) << "Crypto::Sha256 failed!";
private_credential.set_secret_id(std::string(secret_id.AsStringView()));
std::string alias = Base64Utils::Encode(secret_id);
auto prefixedAlias = kPairedKeyAliasPrefix + alias;
// Generate key pair. Store the private key in private credential.
auto key_pair = crypto::ECPrivateKey::Create();
std::vector<uint8_t> private_key;
key_pair->ExportPrivateKey(&private_key);
private_credential.mutable_connection_signing_key()->set_key(
std::string(private_key.begin(), private_key.end()));
// Create an AES key to encrypt the device metadata.
std::string metadata_key(kBaseMetadataSize, 0);
crypto::RandBytes(const_cast<std::string::value_type*>(metadata_key.data()),
metadata_key.size());
private_credential.set_metadata_encryption_key_v0(metadata_key);
// Generate the public credential
std::vector<uint8_t> public_key;
key_pair->ExportPublicKey(&public_key);
return std::pair<LocalCredential, SharedCredential>(
private_credential,
CreatePublicCredential(private_credential, metadata, public_key));
}
SharedCredential CredentialManagerImpl::CreatePublicCredential(
const LocalCredential& private_credential, const Metadata& metadata,
const std::vector<uint8_t>& public_key) {
// The start time in the public credential should be decreased by a random
// value in 0 - 3 hours range.
// The end time should be increased by a random value in 0 - 3 hours range.
// This improves privacy by making it harder to correlate certificates.
absl::Time start_time =
absl::FromUnixMillis(private_credential.start_time_millis()) -
RandomDuration(absl::Hours(3));
absl::Time end_time =
absl::FromUnixMillis(private_credential.end_time_millis()) +
RandomDuration(absl::Hours(3));
SharedCredential public_credential;
public_credential.set_identity_type(private_credential.identity_type());
public_credential.set_secret_id(private_credential.secret_id());
public_credential.set_key_seed(private_credential.key_seed());
public_credential.set_start_time_millis(absl::ToUnixMillis(start_time));
public_credential.set_end_time_millis(absl::ToUnixMillis(end_time));
// Set up the public key. Note, we are setting the "connection" key but we are
// not setting the "advertisement" key because the latter is not used yet.
public_credential.set_connection_signature_verification_key(
std::string(public_key.begin(), public_key.end()));
auto metadata_encryption_key_tag =
Crypto::Sha256(private_credential.metadata_encryption_key_v0());
public_credential.set_metadata_encryption_key_unsigned_adv_tag(
std::string(metadata_encryption_key_tag.AsStringView()));
// Encrypt the device metadata
auto encrypted_meta_data = EncryptMetadata(
private_credential.metadata_encryption_key_v0(),
private_credential.key_seed(), metadata.SerializeAsString());
if (encrypted_meta_data.empty()) {
NEARBY_LOGS(ERROR) << "Fails to encrypt the device metadata.";
public_credential.set_identity_type(
IdentityType::IDENTITY_TYPE_UNSPECIFIED);
return public_credential;
}
public_credential.set_encrypted_metadata_bytes_v0(encrypted_meta_data);
return public_credential;
}
std::string CredentialManagerImpl::DecryptMetadata(
absl::string_view metadata_encryption_key, absl::string_view key_seed,
absl::string_view metadata_string) {
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
std::vector<uint8_t> derived_key =
ExtendMetadataEncryptionKey(metadata_encryption_key);
aead.Init(derived_key);
auto iv = CustomizeBytesSize(key_seed, CredentialManagerImpl::kAesGcmIVSize);
std::vector<uint8_t> iv_bytes(iv.begin(), iv.end());
std::vector<uint8_t> encrypted_metadata_bytes(metadata_string.begin(),
metadata_string.end());
auto result = aead.Open(encrypted_metadata_bytes,
/*nonce=*/
iv_bytes,
/*additional_data=*/CryptoSpan<uint8_t>());
return std::string(result.value().begin(), result.value().end());
}
std::string CredentialManagerImpl::EncryptMetadata(
absl::string_view metadata_encryption_key, absl::string_view key_seed,
absl::string_view metadata_string) {
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
std::vector<uint8_t> derived_key =
ExtendMetadataEncryptionKey(metadata_encryption_key);
aead.Init(derived_key);
auto iv = CustomizeBytesSize(key_seed, kAesGcmIVSize);
std::vector<uint8_t> iv_bytes(iv.begin(), iv.end());
std::vector<uint8_t> metadata_bytes(metadata_string.begin(),
metadata_string.end());
metadata_bytes.resize(metadata_string.size());
auto encrypted = aead.Seal(metadata_bytes,
/*nonce=*/
iv_bytes,
/*additional_data=*/CryptoSpan<uint8_t>());
return std::string(encrypted.begin(), encrypted.end());
}
std::vector<uint8_t> CredentialManagerImpl::ExtendMetadataEncryptionKey(
absl::string_view metadata_encryption_key) {
return crypto::HkdfSha256(
std::vector<uint8_t>(metadata_encryption_key.begin(),
metadata_encryption_key.end()),
/*salt=*/CryptoSpan<uint8_t>(),
/*info=*/CryptoSpan<uint8_t>(), kNearbyPresenceNumBytesAesGcmKeySize);
}
void CredentialManagerImpl::GetLocalCredentials(
const CredentialSelector& credential_selector,
GetLocalCredentialsResultCallback callback) {
CountDownLatch get_local_credentials_latch(1);
absl::StatusOr<std::vector<LocalCredential>> get_local_credentials_result;
credential_storage_ptr_->GetLocalCredentials(
credential_selector,
GetLocalCredentialsResultCallback{
.credentials_fetched_cb =
[get_local_credentials_latch, &get_local_credentials_result](
absl::StatusOr<std::vector<LocalCredential>>
credentials) mutable {
get_local_credentials_result = std::move(credentials);
get_local_credentials_latch.CountDown();
},
});
if (!WaitForLatch("GetLocalCredentials", &get_local_credentials_latch)) {
NEARBY_LOGS(INFO) << "Failed in awaiting GetLocalCredentials";
callback.credentials_fetched_cb(
absl::DeadlineExceededError("Failed in awaiting GetLocalCredentials"));
return;
}
if (!get_local_credentials_result.ok()) {
callback.credentials_fetched_cb(get_local_credentials_result.status());
return;
}
CheckCredentialsAndRefillIfNeeded(
credential_selector,
/* cal_credentials_list_variant */ &get_local_credentials_result.value(),
/* callback_for_local_credentials */ std::move(callback),
/* callback_for_shared_credentials */ std::nullopt);
}
void CredentialManagerImpl::GetPublicCredentials(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) {
// Not going to refill for remote SharedCredentials.
if (public_credential_type == PublicCredentialType::kRemotePublicCredential) {
credential_storage_ptr_->GetPublicCredentials(
credential_selector, public_credential_type, std::move(callback));
return;
}
CountDownLatch get_shared_credentials_latch(1);
absl::StatusOr<std::vector<SharedCredential>> get_shared_credentials_result;
credential_storage_ptr_->GetPublicCredentials(
credential_selector, public_credential_type,
GetPublicCredentialsResultCallback{
.credentials_fetched_cb =
[get_shared_credentials_latch, &get_shared_credentials_result](
absl::StatusOr<std::vector<SharedCredential>>
credentials) mutable {
get_shared_credentials_result = std::move(credentials);
get_shared_credentials_latch.CountDown();
},
});
if (!WaitForLatch("GetSharedCredentials", &get_shared_credentials_latch)) {
NEARBY_LOGS(INFO) << "Failed in awaiting GetSharedCredentials";
callback.credentials_fetched_cb(
absl::DeadlineExceededError("Failed in awaiting GetsharedCredentials"));
return;
}
if (!get_shared_credentials_result.ok()) {
callback.credentials_fetched_cb(get_shared_credentials_result.status());
return;
}
CheckCredentialsAndRefillIfNeeded(
credential_selector,
/* credentials_list_variant */ &get_shared_credentials_result.value(),
/* callback_for_local_credentials */ std::nullopt,
/* callback_for_shared_credentials */ std::move(callback));
}
ExceptionOr<std::vector<LocalCredential>>
CredentialManagerImpl::GetLocalCredentialsSync(
const CredentialSelector& credential_selector, absl::Duration timeout) {
Future<std::vector<LocalCredential>> result;
GetLocalCredentials(credential_selector,
{.credentials_fetched_cb =
[result](absl::StatusOr<std::vector<LocalCredential>>
credentials) mutable {
if (!credentials.ok()) {
result.SetException({Exception::kFailed});
} else {
result.Set(std::move(*credentials));
}
}});
return result.Get(timeout);
}
ExceptionOr<std::vector<SharedCredential>>
CredentialManagerImpl::GetPublicCredentialsSync(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type, absl::Duration timeout) {
Future<std::vector<SharedCredential>> result;
GetPublicCredentials(
credential_selector, public_credential_type,
{.credentials_fetched_cb =
[result](absl::StatusOr<std::vector<SharedCredential>>
credentials) mutable {
if (!credentials.ok()) {
result.SetException({Exception::kFailed});
} else {
result.Set(std::move(*credentials));
}
}});
return result.Get(timeout);
}
SubscriberId CredentialManagerImpl::SubscribeForPublicCredentials(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) {
SubscriberId id = nearby::RandData<SubscriberId>();
RunOnServiceControllerThread(
"add-subscriber",
[this, key = SubscriberKey{credential_selector, public_credential_type},
id, callback = std::move(callback)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable {
AddSubscriber(key, id, std::move(callback));
});
GetPublicCredentials(credential_selector, public_credential_type,
CreateNotifySubscribersCallback(
{credential_selector, public_credential_type}));
return id;
}
void CredentialManagerImpl::UnsubscribeFromPublicCredentials(SubscriberId id) {
RunOnServiceControllerThread("remove-subscriber",
[this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*executor_) { RemoveSubscriber(id); });
}
void CredentialManagerImpl::AddSubscriber(
SubscriberKey key, SubscriberId id,
GetPublicCredentialsResultCallback callback) {
subscribers_[key].push_back(Subscriber(id, std::move(callback)));
}
void CredentialManagerImpl::RemoveSubscriber(SubscriberId id) {
for (auto& entry : subscribers_) {
auto it = std::find_if(
entry.second.begin(), entry.second.end(),
[&](Subscriber& subscriber) { return subscriber.GetId() == id; });
if (it != entry.second.end()) {
entry.second.erase(it);
if (subscribers_[entry.first].empty()) {
subscribers_.erase(entry.first);
}
return;
}
}
}
absl::flat_hash_set<IdentityType>
CredentialManagerImpl::GetSubscribedIdentities(
absl::string_view manager_app_id, absl::string_view account_name,
PublicCredentialType credential_type) const {
absl::flat_hash_set<IdentityType> identities;
for (auto& entry : subscribers_) {
const SubscriberKey& key = entry.first;
if (key.public_credential_type == credential_type &&
key.credential_selector.manager_app_id == manager_app_id &&
key.credential_selector.account_name == account_name) {
identities.insert(key.credential_selector.identity_type);
}
}
return identities;
}
void CredentialManagerImpl::OnCredentialsChanged(
absl::string_view manager_app_id, absl::string_view account_name,
PublicCredentialType credential_type) {
NEARBY_LOGS(INFO) << "OnCredentialsChanged for app " << manager_app_id
<< ", account " << account_name;
for (IdentityType identity_type :
GetSubscribedIdentities(manager_app_id, account_name, credential_type)) {
CredentialSelector credential_selector = {
.manager_app_id = std::string(manager_app_id),
.account_name = std::string(account_name),
.identity_type = identity_type};
GetPublicCredentials(credential_selector, credential_type,
CreateNotifySubscribersCallback(
{credential_selector, credential_type}));
}
}
GetPublicCredentialsResultCallback
CredentialManagerImpl::CreateNotifySubscribersCallback(SubscriberKey key) {
return GetPublicCredentialsResultCallback{
.credentials_fetched_cb =
[this,
key](absl::StatusOr<std::vector<SharedCredential>> credentials) {
if (!credentials.ok()) {
NEARBY_LOGS(WARNING)
<< "Failed to get public credentials: error code: "
<< credentials.status();
return;
}
RunOnServiceControllerThread(
"notify-subscribers",
[this, key, credentials = std::move(*credentials)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
NotifySubscribers(key, credentials);
});
}};
}
void CredentialManagerImpl::NotifySubscribers(
const SubscriberKey& key, std::vector<SharedCredential> credentials) {
// We are on `executor_` thread, so we can iterate over `subscribers_`
// without locking.
auto it = subscribers_.find(key);
if (it == subscribers_.end()) {
NEARBY_LOGS(WARNING)
<< "No subscribers for (app: " << key.credential_selector.manager_app_id
<< ", account: " << key.credential_selector.account_name
<< ", identity type: "
<< static_cast<int>(key.credential_selector.identity_type)
<< ", credential type: " << static_cast<int>(key.public_credential_type)
<< ")";
return;
}
for (auto& subscriber : it->second) {
subscriber.NotifyCredentialsFetched(credentials);
}
}
void CredentialManagerImpl::Subscriber::NotifyCredentialsFetched(
std::vector<SharedCredential>& credentials) {
callback_.credentials_fetched_cb(credentials);
}
void CredentialManagerImpl::UpdateLocalCredential(
const CredentialSelector& credential_selector,
nearby::internal::LocalCredential credential,
SaveCredentialsResultCallback result_callback) {
credential_storage_ptr_->UpdateLocalCredential(
credential_selector.manager_app_id, credential_selector.account_name,
std::move(credential), std::move(result_callback));
}
void CredentialManagerImpl::CheckCredentialsAndRefillIfNeeded(
const CredentialSelector& credential_selector,
absl::variant<std::vector<nearby::internal::LocalCredential>*,
std::vector<nearby::internal::SharedCredential>*>
credential_list_variant,
std::optional<GetLocalCredentialsResultCallback>
callback_for_local_credentials,
std::optional<GetPublicCredentialsResultCallback>
callback_for_shared_credentials) {
bool invoked_for_local = false;
int valid_credentials_count = 0;
int64_t current_time_millis =
absl::ToUnixMillis(SystemClock::ElapsedRealtime());
int64_t last_valid_end_time_millis = current_time_millis;
std::vector<LocalCredential> valid_local_credentials;
std::vector<SharedCredential> valid_shared_credentials;
if (absl::holds_alternative<std::vector<nearby::internal::LocalCredential>*>(
credential_list_variant) &&
callback_for_local_credentials.has_value()) {
invoked_for_local = true;
for (auto& credential :
*absl::get<std::vector<nearby::internal::LocalCredential>*>(
credential_list_variant)) {
if (credential.end_time_millis() < current_time_millis) {
continue;
}
valid_credentials_count++;
if (last_valid_end_time_millis < credential.end_time_millis()) {
last_valid_end_time_millis = credential.end_time_millis();
}
valid_local_credentials.push_back(credential);
}
} else if (absl::holds_alternative<
std::vector<nearby::internal::SharedCredential>*>(
credential_list_variant) &&
callback_for_shared_credentials.has_value()) {
for (auto& credential :
*absl::get<std::vector<nearby::internal::SharedCredential>*>(
credential_list_variant)) {
if (credential.end_time_millis() < current_time_millis) {
continue;
}
valid_credentials_count++;
if (last_valid_end_time_millis < credential.end_time_millis()) {
last_valid_end_time_millis = credential.end_time_millis();
}
valid_shared_credentials.push_back(credential);
}
} else {
NEARBY_LOGS(ERROR)
<< "Bad parameters for CheckCredentialsAndRefillIfNeeded";
return;
}
// Most invokes are expected to return early here as it already got enough
// valid credentials, no need to refill.
// Otherwise, the long process of refill (another read, merge, then save)
// would start.
if (valid_credentials_count >= kExpectedValidLocalCredtialSize) {
if (invoked_for_local) {
callback_for_local_credentials.value().credentials_fetched_cb(
valid_local_credentials);
} else {
callback_for_shared_credentials.value().credentials_fetched_cb(
valid_shared_credentials);
}
return;
}
std::vector<LocalCredential> newly_generated_local_credentials;
std::vector<SharedCredential> newly_generated_shared_credentials;
// Generate more credential pairs to refill the expired ones.
auto start_time = absl::FromUnixMillis(last_valid_end_time_millis);
auto gap = kCredentialLifeCycleDays * absl::Hours(24);
for (int i = 0; i < kExpectedValidLocalCredtialSize - valid_credentials_count;
i++) {
auto pair =
CreateLocalCredential(metadata_, credential_selector.identity_type,
start_time, start_time + gap);
newly_generated_local_credentials.push_back(pair.first);
newly_generated_shared_credentials.push_back(pair.second);
start_time += gap;
}
// Already got the merged valid credential list for either local or shared.
// Now get the other credentials list from storage.
CountDownLatch get_corresponding_credentials_latch(1);
if (invoked_for_local) {
absl::StatusOr<std::vector<nearby::internal::SharedCredential>>
get_shared_result;
credential_storage_ptr_->GetPublicCredentials(
credential_selector, PublicCredentialType::kLocalPublicCredential,
GetPublicCredentialsResultCallback{
.credentials_fetched_cb =
[get_corresponding_credentials_latch, &get_shared_result](
absl::StatusOr<
std::vector<nearby::internal::SharedCredential>>
result) mutable {
get_shared_result = std::move(result);
get_corresponding_credentials_latch.CountDown();
},
});
if (!WaitForLatch(
"CheckCredentialsAndRefillIfNeeded-GetCorrespondingShared",
&get_corresponding_credentials_latch)) {
callback_for_local_credentials.value().credentials_fetched_cb(
absl::DeadlineExceededError("Failed in GetLocalCredentials"));
return;
}
if (!get_shared_result.ok()) {
callback_for_local_credentials.value().credentials_fetched_cb(
get_shared_result.status());
return;
}
for (const auto& credential : get_shared_result.value()) {
if (credential.end_time_millis() >= current_time_millis) {
valid_shared_credentials.push_back(credential);
}
}
} else {
absl::StatusOr<std::vector<nearby::internal::LocalCredential>>
get_local_result;
credential_storage_ptr_->GetLocalCredentials(
credential_selector,
GetLocalCredentialsResultCallback{
.credentials_fetched_cb =
[get_corresponding_credentials_latch, &get_local_result](
absl::StatusOr<
std::vector<nearby::internal::LocalCredential>>
result) mutable {
get_local_result = std::move(result);
get_corresponding_credentials_latch.CountDown();
},
});
if (!WaitForLatch("CheckCredentialsAndRefillIfNeeded-GetCorrespondingLocal",
&get_corresponding_credentials_latch)) {
callback_for_shared_credentials.value().credentials_fetched_cb(
absl::DeadlineExceededError(
"Failed in awaiting corresponding GetSharedCredentials"));
return;
}
if (!get_local_result.ok()) {
callback_for_local_credentials.value().credentials_fetched_cb(
get_local_result.status());
return;
}
for (const auto& credential : get_local_result.value()) {
if (credential.end_time_millis() >= current_time_millis) {
valid_local_credentials.push_back(credential);
}
}
}
// Now merge newly generated credentails to already existing valid ones.
valid_local_credentials.insert(valid_local_credentials.end(),
newly_generated_local_credentials.begin(),
newly_generated_local_credentials.end());
valid_shared_credentials.insert(valid_shared_credentials.end(),
newly_generated_shared_credentials.begin(),
newly_generated_shared_credentials.end());
// Save merged local and shared credential lists to storage
CountDownLatch save_credentials_latch(1);
absl::Status save_credentials_status;
credential_storage_ptr_->SaveCredentials(
credential_selector.manager_app_id, credential_selector.account_name,
valid_local_credentials, valid_shared_credentials,
PublicCredentialType::kLocalPublicCredential,
SaveCredentialsResultCallback{
.credentials_saved_cb =
[save_credentials_latch,
&save_credentials_status](absl::Status status) mutable {
save_credentials_status = status;
save_credentials_latch.CountDown();
},
});
if (!WaitForLatch("CheckCredentialsAndRefillIfNeeded-SaveCredentials",
&save_credentials_latch)) {
save_credentials_status =
absl::DeadlineExceededError("Failed in awaiting SaveCredentials");
}
if (!save_credentials_status.ok()) {
NEARBY_LOGS(ERROR) << "Save credentials failed with: "
<< save_credentials_status;
if (invoked_for_local) {
callback_for_local_credentials.value().credentials_fetched_cb(
save_credentials_status);
} else {
callback_for_shared_credentials.value().credentials_fetched_cb(
save_credentials_status);
}
return;
}
if (invoked_for_local) {
callback_for_local_credentials.value().credentials_fetched_cb(
valid_local_credentials);
} else {
callback_for_shared_credentials.value().credentials_fetched_cb(
valid_shared_credentials);
}
}
bool CredentialManagerImpl::WaitForLatch(absl::string_view method_name,
CountDownLatch* latch) {
Exception await_exception = latch->Await();
if (!await_exception.Ok()) {
NEARBY_LOGS(ERROR) << "Blocked in " << method_name
<< " with exeception code: " << await_exception.value;
return false;
}
return true;
}
} // namespace presence
} // namespace nearby