Checks if a device is already saved before writing accountkey

PiperOrigin-RevId: 551045458
This commit is contained in:
Qin Wang
2023-07-25 17:33:45 -07:00
committed by Copybara-Service
parent c6d96b5971
commit bccdf6543e
10 changed files with 276 additions and 20 deletions
@@ -289,7 +289,30 @@ void FastPairPairerImpl::AttemptSendAccountKey() {
NotifyPairingCompleted();
return;
}
// TODO(b/281782018) : Handle BLE address rotation
// It's possible that the user has opted to initial pair to a device that
// already has an account key saved. We check to see if this is the case
// before writing a new account key.
if (device_.GetProtocol() == Protocol::kFastPairInitialPairing) {
FastPairRepository::Get()->IsDeviceSavedToAccount(
device_.GetPublicAddress().value(), [this](absl::Status status) {
if (status.ok()) {
NEARBY_LOGS(VERBOSE)
<< __func__
<< ": Device is already saved, skipping write account key. "
"Pairing procedure complete.";
NotifyPairingCompleted();
return;
}
WriteAccountKey();
});
} else {
// TODO(b/281782018) : Handle BLE address rotation
WriteAccountKey();
}
}
void FastPairPairerImpl::WriteAccountKey() {
fast_pair_gatt_service_client_->WriteAccountKey(
*fast_pair_handshake_->fast_pair_data_encryptor(),
[&](const std::optional<AccountKey> account_key,
@@ -88,6 +88,7 @@ class FastPairPairerImpl : public FastPairPairer {
// Attempts to write account key to remote device
void AttemptSendAccountKey() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void WriteAccountKey();
// FastPairDataEncryptor::WriteAccountKey callback
void OnWriteAccountKey(std::optional<AccountKey> account_key,
std::optional<PairFailure> failure);
@@ -402,6 +402,8 @@ TEST_F(FastPairPairerImplTest,
SuccessInitialPairingWithDeviceVersionHigherThanV1) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
repository->SetResultOfWriteAccountAssociationToFootprints(absl::OkStatus());
ConfigurePairingContext();
SetPairingResult(std::nullopt);
@@ -786,9 +788,51 @@ TEST_F(FastPairPairerImplTest, SkipWriteAccountKeyBecauseNoLoggedInUser) {
EXPECT_FALSE(device_->GetAccountKey().Ok());
}
TEST_F(FastPairPairerImplTest,
SkipWriteAccountKeyBecauseDeviceAlreadySavedToAccount) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(absl::OkStatus());
ConfigurePairingContext();
SetPairingResult(std::nullopt);
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairInitialPairing);
SetupProviderGattServer();
SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse);
SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse);
SetDecryptedResponse();
SetDecryptedPasskey();
CreateFastPairHandshakeInstanceForDevice();
CountDownLatch paired_latch(1);
CountDownLatch complete_latch(1);
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
*device_, *mediums_, &executor_, account_manager_.get(),
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
[&](FastPairDevice& device, PairFailure failure) {
FAIL() << "Unexpected pairing failure " << failure;
},
[&](FastPairDevice& device, PairFailure failure) {
FAIL() << "Unexpected pairing failure " << failure;
},
[&](FastPairDevice& device) {
EXPECT_FALSE(device.GetAccountKey().Ok());
complete_latch.CountDown();
});
fast_pair_pairer_->StartPairing();
paired_latch.Await();
complete_latch.Await();
EXPECT_TRUE(fast_pair_pairer_->IsPaired());
EXPECT_FALSE(device_->GetAccountKey().Ok());
}
TEST_F(FastPairPairerImplTest,
SuccessPairingWithDeviceButFailedToWriteAccountkeyToRemoteDevice) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
ConfigurePairingContext();
SetPairingResult(std::nullopt);
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
@@ -835,6 +879,8 @@ TEST_F(FastPairPairerImplTest,
SuccessPairingWithDeviceButFailedToWriteAccountkeyToFootprints) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
repository->SetResultOfWriteAccountAssociationToFootprints(
absl::InternalError("Failed to write account key to foot prints"));
ConfigurePairingContext();
@@ -457,6 +457,8 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) {
TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
repository->SetResultOfWriteAccountAssociationToFootprints(absl::OkStatus());
ConfigurePairingContext();
SetPairingResult(std::nullopt);
@@ -616,8 +618,45 @@ TEST_F(PairerBrokerImplTest, SkipWriteAccountKeyBecauseNoLoggedInUser) {
EXPECT_FALSE(device_->GetAccountKey().Ok());
}
TEST_F(PairerBrokerImplTest,
SkipWriteAccountKeyBecauseDeviceAlreadySavedToAccount) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(absl::OkStatus());
ConfigurePairingContext();
SetPairingResult(std::nullopt);
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairInitialPairing);
SetupProviderGattServer();
SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse);
SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse);
SetDecryptedResponse();
SetDecryptedPasskey();
CreateFastPairHandshakeInstanceForDevice();
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_,
account_manager_.get());
PairerBrokerObserver pairer_broker_observer(
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker_->PairDevice(*device_);
device_paired_latch.Await();
pairing_completed_latch.Await();
EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
}
TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToRemoteDevice) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
ConfigurePairingContext();
SetPairingResult(std::nullopt);
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
@@ -656,6 +695,8 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToRemoteDevice) {
TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToFootprints) {
LogInAccount();
auto repository = std::make_unique<FakeFastPairRepository>();
repository->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
repository->SetResultOfWriteAccountAssociationToFootprints(
absl::InternalError("Failed to write account key to foot prints"));
ConfigurePairingContext();
@@ -56,6 +56,11 @@ void FakeFastPairRepository::SetResultOfDeleteAssociatedDeviceByAccountKey(
deleted_associated_device_ = status;
}
void FakeFastPairRepository::SetResultOfIsDeviceSavedToAccount(
absl::Status status) {
is_device_saved_to_account_ = status;
}
void FakeFastPairRepository::GetDeviceMetadata(
absl::string_view hex_model_id, DeviceMetadataCallback callback) {
executor_.Execute([this, callback = std::move(callback),
@@ -69,14 +74,14 @@ void FakeFastPairRepository::GetDeviceMetadata(
}
void FakeFastPairRepository::WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) {
FastPairDevice& device, OperationCallback callback) {
executor_.Execute([callback = std::move(callback), this]() mutable {
callback(write_account_association_to_footprints_);
});
}
void FakeFastPairRepository::DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key, OperationToFootprintsCallback callback) {
const AccountKey& account_key, OperationCallback callback) {
executor_.Execute([callback = std::move(callback), this]() mutable {
callback(deleted_associated_device_);
});
@@ -89,6 +94,13 @@ void FakeFastPairRepository::CheckIfAssociatedWithCurrentAccount(
});
}
void FakeFastPairRepository::IsDeviceSavedToAccount(
absl::string_view mac_address, OperationCallback callback) {
executor_.Execute([callback = std::move(callback), this]() mutable {
callback(is_device_saved_to_account_);
});
}
std::unique_ptr<FakeFastPairRepository> FakeFastPairRepository::Create(
absl::string_view model_id, absl::string_view public_anti_spoof_key) {
proto::Device metadata;
@@ -46,6 +46,7 @@ class FakeFastPairRepository : public FastPairRepository {
void SetResultOfCheckIfAssociatedWithCurrentAccount(
std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id);
void SetResultOfIsDeviceSavedToAccount(absl::Status status);
// FastPairRepository::
void AddObserver(Observer* observer) override{};
@@ -56,17 +57,19 @@ class FakeFastPairRepository : public FastPairRepository {
void GetUserSavedDevices() override{};
void WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) override;
void WriteAccountAssociationToFootprints(FastPairDevice& device,
OperationCallback callback) override;
void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) override;
void DeleteAssociatedDeviceByAccountKey(const AccountKey& account_key,
OperationCallback callback) override;
void CheckIfAssociatedWithCurrentAccount(
AccountKeyFilter& account_key_filter,
CheckAccountKeysCallback callback) override;
void IsDeviceSavedToAccount(absl::string_view mac_address,
OperationCallback callback) override;
private:
absl::flat_hash_map<std::string, std::unique_ptr<DeviceMetadata>> data_;
@@ -77,6 +80,8 @@ class FakeFastPairRepository : public FastPairRepository {
absl::Status write_account_association_to_footprints_;
// Results of DeleteAssociatedDeviceByAccountKey
absl::Status deleted_associated_device_;
// Results of IsDeviceSavedToAccount
absl::Status is_device_saved_to_account_;
SingleThreadExecutor executor_;
};
} // namespace fastpair
+9 -5
View File
@@ -36,8 +36,7 @@ using DeviceMetadataCallback =
using CheckAccountKeysCallback =
absl::AnyInvocable<void(std::optional<AccountKey> account_key,
std::optional<absl::string_view> model_id)>;
using OperationToFootprintsCallback =
absl::AnyInvocable<void(absl::Status status)>;
using OperationCallback = absl::AnyInvocable<void(absl::Status status)>;
class FastPairRepository {
public:
@@ -72,12 +71,11 @@ class FastPairRepository {
// Stores the given |account_key| for a |device| on the Footprints server.
virtual void WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) = 0;
FastPairDevice& device, OperationCallback callback) = 0;
// Deletes the associated data for a given |account_key|.
virtual void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) = 0;
const AccountKey& account_key, OperationCallback callback) = 0;
// Checks all account keys associated with current user's account against the
// given filter. If a match is found, return the account key.
@@ -85,6 +83,12 @@ class FastPairRepository {
AccountKeyFilter& account_key_filter,
CheckAccountKeysCallback callback) = 0;
// Checks if a device with an address |mac_address| is already saved to
// the user's account by cross referencing the |mac_address| with any
// associated account keys.
virtual void IsDeviceSavedToAccount(absl::string_view mac_address,
OperationCallback callback) = 0;
protected:
static void SetInstance(FastPairRepository* instance);
};
@@ -56,6 +56,20 @@ bool DoesDeviceHaveForgetPattern(const proto::FastPairDevice& device) {
return (device.sha256_account_key_public_address().compare(
0, kForgetPattern.length(), kForgetPattern) == 0);
}
// Checks if the mac address of a FastPairDevice is the same as the given
// |mac_address| by checking if the SHA256 from the given |device| equals to
// SHA256(concat(account_key of |device|, |mac_address|)).
bool IsDeviceSha256Matched(const proto::FastPairDevice& device,
absl::string_view mac_address) {
if (DoesDeviceHaveForgetPattern(device)) {
return false;
}
return device.sha256_account_key_public_address() ==
FastPairRepository::GenerateSha256OfAccountKeyAndMacAddress(
AccountKey(device.account_key()), mac_address);
}
} // namespace
FastPairRepositoryImpl::FastPairRepositoryImpl(FastPairClient* fast_pair_client)
@@ -98,7 +112,7 @@ void FastPairRepositoryImpl::GetDeviceMetadata(
}
void FastPairRepositoryImpl::WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) {
FastPairDevice& device, OperationCallback callback) {
proto::UserWriteDeviceRequest request;
auto* fast_pair_info = request.mutable_fast_pair_info();
BuildFastPairInfo(fast_pair_info, device);
@@ -124,7 +138,7 @@ void FastPairRepositoryImpl::WriteAccountAssociationToFootprints(
}
void FastPairRepositoryImpl::DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key, OperationToFootprintsCallback callback) {
const AccountKey& account_key, OperationCallback callback) {
std::string hex_string = absl::BytesToHexString(account_key.GetAsBytes());
absl::AsciiStrToUpper(&hex_string);
executor_.Execute(
@@ -230,5 +244,38 @@ void FastPairRepositoryImpl::CheckIfAssociatedWithCurrentAccount(
});
}
void FastPairRepositoryImpl::IsDeviceSavedToAccount(
absl::string_view mac_address, OperationCallback callback) {
executor_.Execute(
"Check is device saved to account.",
[this, mac_address = std::string(mac_address),
callback = std::move(callback)]() mutable {
NEARBY_LOGS(INFO) << __func__
<< ": Start to check is device saved to account.";
proto::UserReadDevicesRequest request;
absl::StatusOr<proto::UserReadDevicesResponse> response =
fast_pair_client_->UserReadDevices(request);
if (!response.ok()) {
NEARBY_LOGS(WARNING)
<< __func__
<< "Failed to get UserDeleteDeviceResponse from backend.";
std::move(callback)(response.status());
return;
}
for (const auto& info : response->fast_pair_info()) {
if (info.has_device() &&
IsDeviceSha256Matched(info.device(), mac_address)) {
NEARBY_LOGS(VERBOSE)
<< __func__ << ": found a SHA256 match for device at address = "
<< mac_address;
std::move(callback)(absl::OkStatus());
return;
}
}
std::move(callback)(absl::NotFoundError("Device " + mac_address +
" is not saved to account."));
});
}
} // namespace fastpair
} // namespace nearby
@@ -44,17 +44,19 @@ class FastPairRepositoryImpl : public FastPairRepository {
void GetUserSavedDevices() override;
void WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) override;
void WriteAccountAssociationToFootprints(FastPairDevice& device,
OperationCallback callback) override;
void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) override;
void DeleteAssociatedDeviceByAccountKey(const AccountKey& account_key,
OperationCallback callback) override;
void CheckIfAssociatedWithCurrentAccount(
AccountKeyFilter& account_key_filter,
CheckAccountKeysCallback callback) override;
void IsDeviceSavedToAccount(absl::string_view mac_address,
OperationCallback callback) override;
private:
// A thread for running blocking tasks.
SingleThreadExecutor executor_;
@@ -468,6 +468,81 @@ TEST(FastPairRepositoryImplTest, DeviceNotAssociatedWithCurrentAccount) {
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, DeviceIsSavedToCurrentAccount) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up two devices to proto::UserReadDevicesResponse.
proto::UserReadDevicesResponse response_proto;
// Device 1
FastPairDevice device_1(kHexModelId, kBleAddress,
Protocol::kFastPairInitialPairing);
AccountKey account_key_1(absl::HexStringToBytes(kAccountKey));
device_1.SetAccountKey(account_key_1);
device_1.SetPublicAddress(kPublicAddress);
proto::GetObservedDeviceResponse get_observed_device_response;
DeviceMetadata device_metadata_1(get_observed_device_response);
device_1.SetMetadata(device_metadata_1);
auto* fast_pair_info_1 = response_proto.add_fast_pair_info();
BuildFastPairInfo(fast_pair_info_1, device_1);
// Device 2
auto* fast_pair_info_2 = response_proto.add_fast_pair_info();
fast_pair_info_2->set_opt_in_status(
proto::OptInStatus::OPT_IN_STATUS_OPTED_IN);
fake_fast_pair_client.SetUserReadDevicesResponse(response_proto);
CountDownLatch latch(1);
fast_pair_repository->IsDeviceSavedToAccount(kPublicAddress,
[&](absl::Status status) {
EXPECT_OK(status);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, DeviceIsNotSavedToCurrentAccount) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up two devices to proto::UserReadDevicesResponse.
proto::UserReadDevicesResponse response_proto;
FastPairDevice device(kHexModelId, kBleAddress,
Protocol::kFastPairInitialPairing);
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
device.SetAccountKey(account_key);
device.SetPublicAddress(kPublicAddress);
proto::GetObservedDeviceResponse get_observed_device_response;
DeviceMetadata device_metadata(get_observed_device_response);
device.SetMetadata(device_metadata);
auto* fast_pair_info = response_proto.add_fast_pair_info();
BuildFastPairInfo(fast_pair_info, device);
fake_fast_pair_client.SetUserReadDevicesResponse(response_proto);
CountDownLatch latch(1);
fast_pair_repository->IsDeviceSavedToAccount(
"11:22:33:44:55:66", [&](absl::Status status) {
EXPECT_EQ(status.code(), absl::StatusCode::kNotFound);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, FailedToCheckDeviceIsSavedToCurrentAccount) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
CountDownLatch latch(1);
fast_pair_repository->IsDeviceSavedToAccount(kPublicAddress,
[&](absl::Status status) {
EXPECT_FALSE(status.ok());
latch.CountDown();
});
latch.Await();
}
} // namespace
} // namespace fastpair
} // namespace nearby