Remove unused fastpair C++ implementation to streamline the codebase

PiperOrigin-RevId: 712639309
This commit is contained in:
Janusz Sobczak
2025-01-06 13:26:55 -08:00
committed by Copybara-Service
parent af790d0103
commit f9292be707
296 changed files with 17 additions and 34717 deletions
-4
View File
@@ -10,10 +10,6 @@ This is not an officially supported Google product.
A peer-to-peer networking API that allows apps to easily discover, connect to, and exchange data with nearby devices in real-time, regardless of network connectivity.
### [Fast Pair](fastpair/)
Utilizes Bluetooth Low Energy (BLE) to discover nearby Bluetooth devices without using significant phone battery, enabling "magical" scenarios based on device proximity.
### [Nearby Presence](presence/)
An extension to Nearby Connections that features an extensible identity model for authentication and restricted visibility, resource management for system health, and proximity detection through sensor fusion.
-158
View File
@@ -1,158 +0,0 @@
# 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.
package_group(
name = "nearby_fastpair",
packages = [
"//fastpair/...",
],
)
cc_library(
name = "fast_pair_controller",
srcs = ["fast_pair_controller.cc"],
hdrs = ["fast_pair_controller.h"],
visibility = ["//:__subpackages__"],
deps = [
"//fastpair/common",
"//fastpair/handshake",
"//fastpair/message_stream",
"//fastpair/repository",
"//internal/base",
"//internal/platform:comm",
"//internal/platform:types",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
],
)
cc_test(
name = "fast_pair_controller_test",
size = "small",
srcs = [
"fast_pair_controller_test.cc",
],
deps = [
":fast_pair_controller",
"//fastpair/message_stream:fake_provider",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "fast_pair_seeker",
hdrs = ["fast_pair_seeker.h"],
visibility = ["//:__subpackages__"],
deps = [
"//fastpair/common",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
],
)
cc_library(
name = "fast_pair_plugin",
hdrs = ["fast_pair_plugin.h"],
visibility = ["//:__subpackages__"],
deps = [
":fast_pair_events",
":fast_pair_seeker",
],
)
cc_library(
name = "fast_pair_events",
hdrs = ["fast_pair_events.h"],
visibility = ["//:__subpackages__"],
deps = [
],
)
cc_library(
name = "fast_pair_service",
srcs = ["fast_pair_service.cc"],
hdrs = ["fast_pair_service.h"],
visibility = ["//:__subpackages__"],
deps = [
":fast_pair_plugin",
":fast_pair_seeker",
"//fastpair/common",
"//fastpair/internal",
"//fastpair/repository",
"//fastpair/repository:device_repository",
"//fastpair/repository:repository_impl",
"//fastpair/server_access",
"//internal/account",
"//internal/auth:oauth_lib",
"//internal/auth:types",
"//internal/flags:nearby_flags",
"//internal/network:nearby_http_client",
"//internal/network:types",
"//internal/platform:base",
"//internal/platform:types",
"//internal/platform/flags:platform_flags",
"//internal/platform/implementation:account_manager",
"//internal/platform/implementation:types",
"//internal/preferences",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
cc_test(
name = "fast_pair_service_test",
size = "small",
srcs = [
"fast_pair_service_test.cc",
],
deps = [
":fast_pair_events",
":fast_pair_service",
"//fastpair/internal",
"//fastpair/message_stream:fake_provider",
"//fastpair/plugins:fake_fast_pair_plugin",
"//internal/account",
"//internal/network:types",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/test",
"//internal/test/google3_only:test",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "test_support",
testonly = True,
hdrs = [
"mock_fast_pair_seeker.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
":fast_pair_seeker",
"@com_google_absl//absl/status",
"@com_google_googletest//:gtest_for_library_testonly",
],
)
-46
View File
@@ -1,46 +0,0 @@
licenses(["notice"])
# Copyright 2023 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.
cc_library(
name = "analytics",
srcs = [
"analytics_recorder.cc",
],
hdrs = [
"analytics_recorder.h",
],
copts = [
"-Ithird_party",
],
visibility = ["//fastpair:__subpackages__"],
deps = [
"//internal/analytics:event_logger",
"//internal/proto/analytics:fast_pair_log_cc_proto",
"//proto:fast_pair_enums_cc_proto",
],
)
cc_test(
name = "analytics_recorder_test",
srcs = ["analytics_recorder_test.cc"],
deps = [
":analytics",
"//internal/analytics:mock_event_logger",
"//internal/proto/analytics:fast_pair_log_cc_proto",
"//proto:fast_pair_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
-129
View File
@@ -1,129 +0,0 @@
// Copyright 2023 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 "fastpair/analytics/analytics_recorder.h"
#include <memory>
#include "internal/analytics/event_logger.h"
#include "internal/proto/analytics/fast_pair_log.proto.h"
#include "proto/fast_pair_enums.proto.h"
namespace nearby {
namespace fastpair {
namespace analytics {
using ::nearby::fastpair::analytics::AnalyticsRecorder;
using ::nearby::proto::fastpair::FastPairLog;
void AnalyticsRecorder::NewGattEvent(int error_from_os) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto gatt_event = FastPairLog::GattEvent::default_instance().New();
gatt_event->set_error_from_os(error_from_os);
fast_pair_log->set_allocated_gatt_event(gatt_event);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewBrEdrHandoverEvent(
::nearby::proto::fastpair::FastPairEvent::BrEdrHandoverErrorCode
error_code) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto br_edr_event = FastPairLog::BrEdrHandoverEvent::default_instance().New();
br_edr_event->set_error_code(error_code);
fast_pair_log->set_allocated_br_edr_handover_event(br_edr_event);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewCreateBondEvent(
::nearby::proto::fastpair::FastPairEvent::CreateBondErrorCode error_code,
int unbond_reason) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto create_bond_event =
FastPairLog::CreateBondEvent::default_instance().New();
create_bond_event->set_error_code(error_code);
create_bond_event->set_unbond_reason(unbond_reason);
fast_pair_log->set_allocated_bond_event(create_bond_event);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewConnectEvent(
::nearby::proto::fastpair::FastPairEvent::ConnectErrorCode error_code,
int profile_uuid) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto connect_event = FastPairLog::ConnectEvent::default_instance().New();
connect_event->set_error_code(error_code);
connect_event->set_profile_uuid(profile_uuid);
fast_pair_log->set_allocated_connect_event(connect_event);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewProviderInfo(int number_account_keys_on_provider) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto provider_info = FastPairLog::ProviderInfo::default_instance().New();
provider_info->set_number_account_keys_on_provider(
number_account_keys_on_provider);
fast_pair_log->set_allocated_provider_info(provider_info);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewFootprintsInfo(int number_devices_on_footprints) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto footprints_info = FastPairLog::FootprintsInfo::default_instance().New();
footprints_info->set_number_devices_on_footprints(
number_devices_on_footprints);
fast_pair_log->set_allocated_footprints_info(footprints_info);
LogEvent(*fast_pair_log);
}
void AnalyticsRecorder::NewKeyBasedPairingInfo(int request_flag,
int response_type,
int response_flag,
int response_device_count) {
auto fast_pair_log = std::make_unique<FastPairLog>();
auto key_based_pairing_info =
FastPairLog::KeyBasedPairingInfo::default_instance().New();
key_based_pairing_info->set_request_flag(request_flag);
key_based_pairing_info->set_response_flag(response_flag);
key_based_pairing_info->set_response_device_count(response_device_count);
key_based_pairing_info->set_response_type(response_type);
fast_pair_log->set_allocated_key_based_pairing_info(key_based_pairing_info);
LogEvent(*fast_pair_log);
}
// start private methods
void AnalyticsRecorder::LogEvent(const FastPairLog& message) {
if (event_logger_ == nullptr) {
return;
}
event_logger_->Log(message);
}
} // namespace analytics
} // namespace fastpair
} // namespace nearby
-66
View File
@@ -1,66 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_ANALYTICS_ANALYTICS_RECORDER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_ANALYTICS_ANALYTICS_RECORDER_H_
#include <memory>
#include "internal/analytics/event_logger.h"
#include "internal/proto/analytics/fast_pair_log.proto.h"
#include "proto/fast_pair_enums.proto.h"
namespace nearby {
namespace fastpair {
namespace analytics {
class AnalyticsRecorder {
public:
explicit AnalyticsRecorder(::nearby::analytics::EventLogger* event_logger)
: event_logger_(event_logger) {}
~AnalyticsRecorder() = default;
void NewGattEvent(int error_from_os);
void NewBrEdrHandoverEvent(
nearby::proto::fastpair::FastPairEvent::BrEdrHandoverErrorCode error_code
);
void NewCreateBondEvent(
::nearby::proto::fastpair::FastPairEvent::CreateBondErrorCode error_code,
int unbond_reason);
void NewConnectEvent(
nearby::proto::fastpair::FastPairEvent::ConnectErrorCode error_code,
int profile_uuid);
void NewProviderInfo(int number_account_keys_on_provider);
void NewFootprintsInfo(int number_devices_on_footprints);
void NewKeyBasedPairingInfo(int request_flag, int response_type,
int response_flag, int response_device_count);
private:
void LogEvent(const nearby::proto::fastpair::FastPairLog& message);
nearby::analytics::EventLogger* event_logger_ = nullptr;
};
} // namespace analytics
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_ANALYTICS_ANALYTICS_RECORDER_H_
@@ -1,119 +0,0 @@
// Copyright 2023 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 "fastpair/analytics/analytics_recorder.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "internal/analytics/mock_event_logger.h"
#include "internal/proto/analytics/fast_pair_log.proto.h"
#include "proto/fast_pair_enums.proto.h"
namespace nearby {
namespace fastpair {
namespace analytics {
namespace {
using ::nearby::analytics::MockEventLogger;
using ::nearby::proto::fastpair::FastPairEvent;
using ::nearby::proto::fastpair::FastPairLog;
using ::testing::An;
class AnalyticsRecorderTest : public ::testing::Test {
public:
AnalyticsRecorderTest() = default;
~AnalyticsRecorderTest() override = default;
MockEventLogger& event_logger() { return event_logger_; }
AnalyticsRecorder analytics_recoder() { return analytics_recorder_; }
private:
MockEventLogger event_logger_;
AnalyticsRecorder analytics_recorder_{&event_logger_};
};
TEST_F(AnalyticsRecorderTest, NewGattEvent) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
EXPECT_EQ(message.gatt_event().error_from_os(), 1);
});
analytics_recoder().NewGattEvent(1);
}
TEST_F(AnalyticsRecorderTest, NewBrEdrHandoverEvent) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.br_edr_handover_event().error_code(),
FastPairEvent::BLUETOOTH_MAC_INVALID);
});
analytics_recoder().NewBrEdrHandoverEvent(
FastPairEvent::BLUETOOTH_MAC_INVALID);
}
TEST_F(AnalyticsRecorderTest, NewCreateBondEvent) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.bond_event().error_code(),
FastPairEvent::NO_PERMISSION);
ASSERT_EQ(message.bond_event().unbond_reason(), 12);
});
analytics_recoder().NewCreateBondEvent(FastPairEvent::NO_PERMISSION, 12);
}
TEST_F(AnalyticsRecorderTest, NewConnectEvent) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.connect_event().error_code(),
FastPairEvent::GET_PROFILE_PROXY_FAILED);
ASSERT_EQ(message.connect_event().profile_uuid(), 13);
});
analytics_recoder().NewConnectEvent(FastPairEvent::GET_PROFILE_PROXY_FAILED,
13);
}
TEST_F(AnalyticsRecorderTest, NewProviderInfo) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.provider_info().number_account_keys_on_provider(),
14);
});
analytics_recoder().NewProviderInfo(14);
}
TEST_F(AnalyticsRecorderTest, NewFootprintsInfo) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.footprints_info().number_devices_on_footprints(), 15);
});
analytics_recoder().NewFootprintsInfo(15);
}
TEST_F(AnalyticsRecorderTest, NewKeyBasedPairingInfo) {
EXPECT_CALL(event_logger(), Log(An<const FastPairLog&>()))
.WillOnce([=](const FastPairLog& message) {
ASSERT_EQ(message.key_based_pairing_info().request_flag(), 16);
ASSERT_EQ(message.key_based_pairing_info().response_type(), 17);
ASSERT_EQ(message.key_based_pairing_info().response_flag(), 18);
ASSERT_EQ(message.key_based_pairing_info().response_device_count(), 19);
});
analytics_recoder().NewKeyBasedPairingInfo(16, 17, 18, 19);
}
} // namespace
} // namespace analytics
} // namespace fastpair
} // namespace nearby
-149
View File
@@ -1,149 +0,0 @@
# 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.
licenses(["notice"])
cc_library(
name = "common",
srcs = [
"account_key_filter.cc",
"battery_notification.cc",
"fast_pair_device.cc",
"fast_pair_http_result.cc",
"fast_pair_prefs.cc",
"fast_pair_switches.cc",
"pair_failure.cc",
"protocol.cc",
],
hdrs = [
"account_key.h",
"account_key_filter.h",
"battery_notification.h",
"constant.h",
"device_metadata.h",
"fast_pair_device.h",
"fast_pair_http_result.h",
"fast_pair_prefs.h",
"fast_pair_switches.h",
"fast_pair_version.h",
"non_discoverable_advertisement.h",
"pair_failure.h",
"protocol.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
"//fastpair/proto:fastpair_cc_proto",
"//internal/crypto_cros",
"//internal/platform:types",
"//internal/preferences",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
],
)
cc_test(
name = "account_key_filter_test",
size = "small",
srcs = [
"account_key_filter_test.cc",
],
shard_count = 16,
deps = [
":common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_device_test",
size = "small",
srcs = [
"fast_pair_device_test.cc",
],
shard_count = 16,
deps = [
":common",
"//fastpair/proto:fastpair_cc_proto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "pair_failure_test",
size = "small",
srcs = [
"pair_failure_test.cc",
],
shard_count = 16,
deps = [
":common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "battery_notification_test",
size = "small",
srcs = [
"battery_notification_test.cc",
],
shard_count = 16,
deps = [
":common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_prefs_test",
size = "small",
srcs = [
"fast_pair_prefs_test.cc",
],
shard_count = 16,
deps = [
":common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_switches_test",
size = "small",
srcs = [
"fast_pair_switches_test.cc",
],
shard_count = 16,
deps = [
":common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
-66
View File
@@ -1,66 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_H_
#include <ostream>
#include <string>
#include <vector>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/constant.h"
#include "internal/platform/crypto.h"
namespace nearby {
namespace fastpair {
class AccountKey {
public:
AccountKey() = default;
explicit AccountKey(absl::string_view bytes) : bytes_(bytes) {}
explicit AccountKey(const std::vector<uint8_t> bytes) {
bytes_ = std::string(bytes.begin(), bytes.end());
}
static AccountKey CreateRandomKey() {
std::string key(kAccountKeySize, 0);
RandBytes(key.data(), kAccountKeySize);
return AccountKey(key);
}
absl::string_view GetAsBytes() const { return bytes_; }
bool Ok() const { return bytes_.size() == kAccountKeySize; }
explicit operator bool() const { return Ok(); }
private:
std::string bytes_;
};
inline std::ostream& operator<<(std::ostream& stream, const AccountKey& key) {
stream << "AccountKey(" << absl::BytesToHexString(key.GetAsBytes()) << ")";
return stream;
}
inline bool operator==(const AccountKey& a, const AccountKey& b) {
return a.GetAsBytes() == b.GetAsBytes();
}
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_H_
-125
View File
@@ -1,125 +0,0 @@
// Copyright 2023 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 "fastpair/common/account_key_filter.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <vector>
#include "absl/strings/string_view.h"
#include "fastpair/common/battery_notification.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "internal/crypto_cros/sha2.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr int kBitsInByte = 8;
// SASS enabled peripherals create their Bloom filters with the first byte
// equals to either `the account key in use`
// or `the most recently used account key`
// see this spec:
// https://developers.google.com/nearby/fast-pair/early-access/specifications/extensions/sass#SassInUseAccountKey
constexpr uint8_t kRecentlyUsedByte = 0x05;
constexpr uint8_t kInUseByte = 0x06;
constexpr uint8_t kShowUi = 0b00110011;
constexpr uint8_t kHideUi = 0b00110100;
// Helper to AccountKeyFilter::IsAccountKeyInFilter().
// Performs the test to see if |data| is in |bit_sets|, a Bloom filter.
bool AccountKeyFilterChecker(const std::vector<uint8_t>& data,
const std::vector<uint8_t>& bit_sets) {
std::array<uint8_t, 32> hashed = crypto::SHA256Hash(data);
// Iterate over the hashed input in 4 byte increments, combine those 4
// bytes into an unsigned int and use it as the index into our
// |bit_sets|.
for (size_t i = 0; i < hashed.size(); i += 4) {
uint32_t hash = uint32_t{hashed[i]} << 24 | uint32_t{hashed[i + 1]} << 16 |
uint32_t{hashed[i + 2]} << 8 | hashed[i + 3];
size_t num_bits = bit_sets.size() * kBitsInByte;
size_t n = hash % num_bits;
size_t byte_index = floor(n / kBitsInByte);
size_t bit_index = n % kBitsInByte;
bool is_set = (bit_sets[byte_index] >> bit_index) & 0x01;
if (!is_set) return false;
}
NEARBY_LOGS(INFO) << __func__ << " The accountkey is possibly in set.";
return true;
}
} // namespace
AccountKeyFilter::AccountKeyFilter(
const NonDiscoverableAdvertisement& advertisement)
: bit_sets_(advertisement.account_key_filter) {
salt_values_.resize(advertisement.salt.size());
std::copy(advertisement.salt.begin(), advertisement.salt.end(),
salt_values_.begin());
// If the advertisement contains battery information, then that information
// was also appended to the account keys to generate the filter. We need to
// do the same when checking for matches, so save the values in salt_values_
// for that purpose later.
if (advertisement.battery_notification) {
salt_values_.push_back(advertisement.battery_notification->type ==
BatteryNotification::Type::kShowUi
? kShowUi
: kHideUi);
for (auto battery_info :
advertisement.battery_notification->battery_infos) {
salt_values_.push_back(battery_info.ToByte());
}
}
}
AccountKeyFilter::AccountKeyFilter(
const std::vector<uint8_t>& account_key_filter_bytes,
const std::vector<uint8_t>& salt_values)
: bit_sets_(account_key_filter_bytes), salt_values_(salt_values) {}
bool AccountKeyFilter::IsPossiblyInSet(const AccountKey& account_key) {
if (!account_key.Ok()) {
NEARBY_LOGS(INFO) << __func__ << " Invalid account key.";
return false;
}
if (bit_sets_.empty()) return false;
// We first need to append the salt value to the input (see
// https://developers.google.com/nearby/fast-pair/spec#AccountKeyFilter).
std::vector<uint8_t> data(account_key.GetAsBytes().begin(),
account_key.GetAsBytes().end());
for (auto& byte : salt_values_) data.push_back(byte);
// We need to try account keys with different first bytes in case
// the peripheral is SASS per
// https://developers.google.com/nearby/fast-pair/early-access/specifications/extensions/sass#SassAdvertisingPayload
if (AccountKeyFilterChecker(data, bit_sets_)) {
return true;
}
data[0] = kRecentlyUsedByte;
if (AccountKeyFilterChecker(data, bit_sets_)) {
return true;
}
data[0] = kInUseByte;
return AccountKeyFilterChecker(data, bit_sets_);
}
} // namespace fastpair
} // namespace nearby
-49
View File
@@ -1,49 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_FILTER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_FILTER_H_
#include <cstdint>
#include <vector>
#include "fastpair/common/account_key.h"
#include "fastpair/common/non_discoverable_advertisement.h"
namespace nearby {
namespace fastpair {
// Class which represents a Fast Pair Account Key account_key_filter
// https://developers.google.com/nearby/fast-pair/specifications/service/provider#AccountKeyFilter
class AccountKeyFilter {
public:
explicit AccountKeyFilter(const NonDiscoverableAdvertisement& advertisement);
AccountKeyFilter(const std::vector<uint8_t>& account_key_filter_bytes,
const std::vector<uint8_t>& salt_values);
~AccountKeyFilter() = default;
// Returns true if the `account_key` is possibly in the account key set
// defined by the filter.
// Return false if `account_key` is definitely not in set.
bool IsPossiblyInSet(const AccountKey& account_key);
private:
std::vector<uint8_t> bit_sets_;
std::vector<uint8_t> salt_values_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_ACCOUNT_KEY_FILTER_H_
-135
View File
@@ -1,135 +0,0 @@
// Copyright 2023 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 "fastpair/common/account_key_filter.h"
#include <optional>
#include <vector>
#include "gtest/gtest.h"
#include "fastpair/common/battery_notification.h"
#include "fastpair/common/non_discoverable_advertisement.h"
namespace nearby {
namespace fastpair {
namespace {
// Test data comes from:
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
class AccountKeyFilterTest : public testing::Test {
protected:
const std::vector<uint8_t> salt_{0xC7, 0xC8};
const std::vector<uint8_t> account_key_1_{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
const std::vector<uint8_t> account_key_2_{0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
0x44, 0x44, 0x55, 0x55, 0x66, 0x66,
0x77, 0x77, 0x88, 0x88};
const std::vector<uint8_t> filter_1_{0x02, 0x0C, 0x80, 0x2A};
const std::vector<uint8_t> filter_2_{0x84, 0x4A, 0x62, 0x20, 0x8B};
const std::vector<uint8_t> filter_1_and_2_{0x84, 0x4A, 0x62, 0x20, 0x8B};
const std::vector<uint8_t> battery_data_{0b00110011, 0b01000000, 0b01000000,
0b01000000};
const std::vector<uint8_t> filter_1_with_battery_{0x01, 0x01, 0x46, 0x0A};
const std::vector<uint8_t> filter_2_with_battery_{0x46, 0x15, 0x24, 0xD0,
0x08};
};
TEST_F(AccountKeyFilterTest, ConstrutorWithNonDiscoverableAdvertisement) {
NonDiscoverableAdvertisement non_discoverable_advertisement(
filter_1_, NonDiscoverableAdvertisement::Type::kShowUi, salt_, {});
EXPECT_TRUE(AccountKeyFilter(non_discoverable_advertisement)
.IsPossiblyInSet(AccountKey(account_key_1_)));
NonDiscoverableAdvertisement non_discoverable_advertisement_with_battery(
filter_1_with_battery_, NonDiscoverableAdvertisement::Type::kShowUi,
salt_,
BatteryNotification::FromBytes({0b01000000, 0b01000000, 0b01000000},
BatteryNotification::Type::kShowUi));
EXPECT_TRUE(AccountKeyFilter(non_discoverable_advertisement_with_battery)
.IsPossiblyInSet(AccountKey(account_key_1_)));
}
TEST_F(AccountKeyFilterTest, EmptyAccountKeyFilter) {
AccountKeyFilter filter({}, {});
EXPECT_FALSE(filter.IsPossiblyInSet(AccountKey(account_key_1_)));
EXPECT_FALSE(filter.IsPossiblyInSet(AccountKey(account_key_2_)));
}
TEST_F(AccountKeyFilterTest, EmptyAccountKey) {
EXPECT_FALSE(
AccountKeyFilter(filter_1_, salt_).IsPossiblyInSet(AccountKey("")));
}
TEST_F(AccountKeyFilterTest, SingleAccountKey) {
EXPECT_TRUE(AccountKeyFilter(filter_1_, salt_)
.IsPossiblyInSet(AccountKey(AccountKey(account_key_1_))));
EXPECT_TRUE(AccountKeyFilter(filter_2_, salt_)
.IsPossiblyInSet(AccountKey(account_key_2_)));
}
TEST_F(AccountKeyFilterTest, TwoAccountKeys) {
AccountKeyFilter filter(filter_1_and_2_, salt_);
EXPECT_TRUE(filter.IsPossiblyInSet(AccountKey(account_key_1_)));
EXPECT_TRUE(filter.IsPossiblyInSet(AccountKey(account_key_2_)));
}
TEST_F(AccountKeyFilterTest, MissingAccountKey) {
const std::vector<uint8_t> bytes{0x12, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
AccountKey account_key(bytes);
EXPECT_FALSE(AccountKeyFilter(filter_1_, salt_).IsPossiblyInSet(account_key));
EXPECT_FALSE(
AccountKeyFilter(filter_1_and_2_, salt_).IsPossiblyInSet(account_key));
}
TEST_F(AccountKeyFilterTest, AccountKeyWithBatteryData) {
std::vector<uint8_t> salt_1 = salt_;
for (auto& byte : battery_data_) salt_1.push_back(byte);
EXPECT_TRUE(AccountKeyFilter(filter_1_with_battery_, salt_1)
.IsPossiblyInSet(AccountKey(account_key_1_)));
std::vector<uint8_t> salt_2 = salt_;
for (auto& byte : battery_data_) salt_2.push_back(byte);
EXPECT_TRUE(AccountKeyFilter(filter_2_with_battery_, salt_2)
.IsPossiblyInSet(AccountKey(account_key_2_)));
}
TEST_F(AccountKeyFilterTest, SassEnabledPeripheral) {
// Value source: b/243855406#comment24
const std::vector<uint8_t> bytes{0x06, 0x3F, 0xC1, 0x8C, 0x63, 0xDC,
0x75, 0x1A, 0xE8, 0x1A, 0xCF, 0x65,
0x10, 0x15, 0x1D, 0xB0};
AccountKey account_key_3(bytes);
const std::vector<uint8_t> filter4{0x19, 0x23, 0x50, 0xE8, 0x37,
0x68, 0xF0, 0x65, 0x22};
const std::vector<uint8_t> salt4{0xD7, 0xDE};
const std::vector<uint8_t> batteryData4{0x33, 0xE4, 0xE4, 0x64};
std::vector<uint8_t> salt_values{};
salt_values.insert(salt_values.end(), salt4.begin(), salt4.end());
salt_values.insert(salt_values.end(), batteryData4.begin(),
batteryData4.end());
EXPECT_TRUE(
AccountKeyFilter(filter4, salt_values).IsPossiblyInSet(account_key_3));
}
} // namespace
} // namespace fastpair
} // namespace nearby
-86
View File
@@ -1,86 +0,0 @@
// Copyright 2023 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 "fastpair/common/battery_notification.h"
#include <optional>
#include <utility>
#include <vector>
#include "fastpair/common/constant.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
BatteryInfo::BatteryInfo(bool is_charging)
: is_charging(is_charging), percentage(std::nullopt) {}
BatteryInfo::BatteryInfo(bool is_charging, int8_t percentage)
: is_charging(is_charging), percentage(percentage) {}
// static
BatteryInfo BatteryInfo::FromByte(uint8_t byte) {
// Battery value is in the form 0bSVVVVVVV.
// S = charging (0b1) or not (0b0).
// V = value, Ranges from 0-100, or 0bS1111111 if unknown.
bool is_charging = byte & kBatteryChargingMask;
uint8_t percentage = byte & kBatteryPercentageMask;
int8_t percentage_signed = static_cast<int8_t>(percentage);
if (percentage_signed < 0 || percentage_signed > 100) {
NEARBY_LOGS(INFO) << __func__ << "Invalid battery percentage.";
return BatteryInfo(is_charging);
}
return BatteryInfo(is_charging, percentage_signed);
}
uint8_t BatteryInfo::ToByte() const {
// Battery value is in the form 0bSVVVVVVV.
// S = charging (0b1) or not (0b0).
// V = value, Ranges from 0-100, or 1111111 if unknown.
if (!percentage) {
return is_charging ? kBatteryIsChargingByte : kBatteryNotChargingByte;
} else {
return percentage.value() | (is_charging ? kBatteryChargingMask : 0);
}
}
BatteryNotification::BatteryNotification(
Type type, const std::vector<BatteryInfo>& battery_infos)
: type(type), battery_infos(battery_infos) {}
// static
std::optional<BatteryNotification> BatteryNotification::FromBytes(
const std::vector<uint8_t>& bytes, Type type) {
if (bytes.size() == 1) {
// Single component device.
NEARBY_LOGS(INFO) << __func__ << " : Single component device.";
std::vector<BatteryInfo> battery_infos = {BatteryInfo::FromByte(bytes[0])};
return std::make_optional<BatteryNotification>(type, battery_infos);
} else if (bytes.size() == 3) {
// True wireless headset expecting 3 bytes - Left bud, Right bud and case.
NEARBY_LOGS(INFO) << __func__ << " : True wireless headset.";
std::vector<BatteryInfo> battery_infos = {
/* left bud info */ BatteryInfo::FromByte(bytes[0]),
/* right bud info */ BatteryInfo::FromByte(bytes[1]),
/* case info */ BatteryInfo::FromByte(bytes[2])};
return std::make_optional<BatteryNotification>(type, battery_infos);
}
NEARBY_LOGS(WARNING) << __func__
<< " : Unexpected battery notification length :"
<< bytes.size();
return std::nullopt;
}
} // namespace fastpair
} // namespace nearby
-66
View File
@@ -1,66 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
#include <cstdint>
#include <optional>
#include <vector>
namespace nearby {
namespace fastpair {
// Fast Pair battery information from notification. See
// https://developers.google.com/nearby/fast-pair/spec#BatteryNotification
struct BatteryInfo {
BatteryInfo() = default;
explicit BatteryInfo(bool is_charging);
BatteryInfo(bool is_charging, int8_t percentage);
~BatteryInfo() = default;
static BatteryInfo FromByte(uint8_t byte);
uint8_t ToByte() const;
bool is_charging = false;
std::optional<int8_t> percentage;
};
// Fast Pair battery notification. See
// https://developers.google.com/nearby/fast-pair/spec#BatteryNotification
struct BatteryNotification {
// Represents if the provider wants to show an indication
// of the battery values
enum class Type {
kNone = 0,
kShowUi = 3, /* Show UI indication: 0b0011 */
kHideUi = 4, /* Hide UI indication: 0b0100 */
};
BatteryNotification() = default;
BatteryNotification(Type type, const std::vector<BatteryInfo>& battery_infos);
~BatteryNotification() = default;
static std::optional<BatteryNotification> FromBytes(
const std::vector<uint8_t>& bytes, Type type);
Type type = Type::kNone;
std::vector<BatteryInfo> battery_infos;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
@@ -1,152 +0,0 @@
// Copyright 2023 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 "fastpair/common/battery_notification.h"
#include <cstdint>
#include <vector>
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
// Test data comes from:
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
TEST(BatteryNotificationTest, TestBatteryInfo) {
// Tests default constructor
BatteryInfo battery_info_1;
EXPECT_FALSE(battery_info_1.is_charging);
// Tests Constructor with is_charging
BatteryInfo battery_info_2(true);
EXPECT_TRUE(battery_info_2.is_charging);
// Tests ToByte and FromByte
BatteryInfo battery_info_3 = BatteryInfo::FromByte(battery_info_2.ToByte());
EXPECT_TRUE(battery_info_3.is_charging);
EXPECT_FALSE(battery_info_3.percentage.has_value());
// Tests Constructor with is_charging and percentage value
BatteryInfo battery_info_4(true, 80);
EXPECT_TRUE(battery_info_4.is_charging);
EXPECT_EQ(battery_info_4.percentage.value(), 80);
// Tests ToByte and FromByte
BatteryInfo battery_info_5 = BatteryInfo::FromByte(battery_info_4.ToByte());
EXPECT_TRUE(battery_info_5.is_charging);
EXPECT_EQ(battery_info_5.percentage.value(), 80);
// Tests Constructor with is_charging and wrong percentage value
BatteryInfo battery_info_6(true, 110);
// Tests ToByte and FromByte
BatteryInfo battery_info_7 = BatteryInfo::FromByte(battery_info_6.ToByte());
EXPECT_TRUE(battery_info_7.is_charging);
EXPECT_FALSE(battery_info_7.percentage.has_value());
// Tests FromByte with battery percentage = 0
BatteryInfo battery_info_8 = BatteryInfo::FromByte(0);
EXPECT_FALSE(battery_info_8.is_charging);
EXPECT_EQ(battery_info_8.percentage.value(), 0);
BatteryInfo battery_info_10 = BatteryInfo::FromByte(0x80);
EXPECT_TRUE(battery_info_10.is_charging);
EXPECT_EQ(battery_info_10.percentage.value(), 0);
// Tests FromByte with battery percentage = 100
BatteryInfo battery_info_9 = BatteryInfo::FromByte(100);
EXPECT_FALSE(battery_info_9.is_charging);
EXPECT_EQ(battery_info_9.percentage.value(), 100);
BatteryInfo battery_info_11 = BatteryInfo::FromByte(0x80 | 100);
EXPECT_TRUE(battery_info_11.is_charging);
EXPECT_EQ(battery_info_11.percentage.value(), 100);
// Test battery with invalid battery percentage
BatteryInfo battery_info_12 = BatteryInfo::FromByte(0x7F);
EXPECT_FALSE(battery_info_12.is_charging);
EXPECT_FALSE(battery_info_12.percentage.has_value());
BatteryInfo battery_info_13 = BatteryInfo::FromByte(0xFF);
EXPECT_TRUE(battery_info_13.is_charging);
EXPECT_FALSE(battery_info_13.percentage.has_value());
}
TEST(BatteryNotificationTest, TestBatteryNotificationDefaultConstructor) {
// Tests default constructor
BatteryNotification battery_notification;
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kNone);
EXPECT_EQ(battery_notification.battery_infos.size(), 0);
}
TEST(BatteryNotificationTest, TestBatteryNotificationForSingleComponentDevice) {
std::vector<BatteryInfo> battery_infos = {BatteryInfo(false, 70)};
BatteryNotification battery_notification(BatteryNotification::Type::kShowUi,
battery_infos);
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
EXPECT_FALSE(battery_notification.battery_infos.at(0).is_charging);
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 70);
}
TEST(BatteryNotificationTest, TestBatteryNotificationForTrueWirelessHeadset) {
std::vector<BatteryInfo> battery_infos = {
BatteryInfo(false, 70), BatteryInfo(false, 80), BatteryInfo(true, 90)};
BatteryNotification battery_notification(BatteryNotification::Type::kShowUi,
battery_infos);
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
// Left bud
EXPECT_FALSE(battery_notification.battery_infos.at(0).is_charging);
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 70);
// Right bud
EXPECT_FALSE(battery_notification.battery_infos.at(1).is_charging);
EXPECT_EQ(battery_notification.battery_infos.at(1).percentage.value(), 80);
// Case
EXPECT_TRUE(battery_notification.battery_infos.at(2).is_charging);
EXPECT_EQ(battery_notification.battery_infos.at(2).percentage.value(), 90);
}
TEST(BatteryNotificationTest,
TestBatteryNotificationFromBytesForSingleComponentDevice) {
const std::vector<uint8_t> batteryData{0b01000000};
BatteryNotification battery_notification =
BatteryNotification::FromBytes(batteryData,
BatteryNotification::Type::kShowUi)
.value();
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 64);
}
TEST(BatteryNotificationTest,
TestBatteryNotificationFromBytesForTrueWirelessHeadset) {
const std::vector<uint8_t> batteryData{0b01000000, 0b01000000, 0b01000000};
BatteryNotification battery_notification =
BatteryNotification::FromBytes(batteryData,
BatteryNotification::Type::kShowUi)
.value();
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 64);
EXPECT_EQ(battery_notification.battery_infos.at(1).percentage.value(), 64);
EXPECT_EQ(battery_notification.battery_infos.at(2).percentage.value(), 64);
}
TEST(BatteryNotificationTest, TestBatteryNotificationFromWrongBytes) {
const std::vector<uint8_t> batteryDataWithWrongLenth{0b01000000, 0b01000000};
EXPECT_FALSE(
BatteryNotification::FromBytes(batteryDataWithWrongLenth,
BatteryNotification::Type::kShowUi)
.has_value());
}
} // namespace
} // namespace fastpair
} // namespace nearby
-72
View File
@@ -1,72 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_CONSTANT_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_CONSTANT_H_
#include <stdint.h>
namespace nearby {
namespace fastpair {
// Bluetooth Uuid
constexpr char kServiceId[] = "Fast Pair";
constexpr char kRfcommUuid[] = "df21fe2c-2515-4fdb-8886-f12c4d67927c";
constexpr int kAccountKeySize = 16;
// Key pair
constexpr int kSharedSecretKeyByteSize = 16;
constexpr int kPublicKeyByteSize = 64;
// Encryption
constexpr int kAesBlockByteSize = 16;
constexpr int kEncryptedDataByteSize = 16;
// Decryption
constexpr int kDecryptedResponseAddressByteSize = 6;
constexpr int kDecryptedResponseSaltByteSize = 9;
constexpr int kDecryptedPasskeySaltByteSize = 12;
// Handshake response index
constexpr int kMessageTypeIndex = 0;
constexpr int kResponseAddressStartIndex = 1;
constexpr int kResponseSaltStartIndex = 7;
constexpr int kPasskeySaltStartIndex = 4;
// Handshake response message type
constexpr uint8_t kKeybasedPairingResponseType = 0x01;
constexpr uint8_t kSeekerPasskeyType = 0x02;
constexpr uint8_t kProviderPasskeyType = 0x03;
// Handshake request inex
constexpr uint8_t kProviderAddressStartIndex = 2;
constexpr uint8_t kSeekerAddressStartIndex = 8;
constexpr uint8_t kSeekerPasskey = 0x02;
constexpr uint8_t kAccountKeyStartByte = 0x04;
// Handshake request message type
constexpr uint8_t kKeyBasedPairingType = 0x00;
constexpr uint8_t kInitialOrSubsequentFlags = 0x00;
constexpr uint8_t kRetroactiveFlags = 0x10;
// Battery Info
constexpr int kBatteryChargingMask = 0b10000000;
constexpr int kBatteryPercentageMask = 0b01111111;
constexpr int kBatteryIsChargingByte = 0b11111111;
constexpr int kBatteryNotChargingByte = 0b01111111;
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_CONSTANT_H_
-54
View File
@@ -1,54 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_REPOSITORY_DEVICE_METADATA_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_REPOSITORY_DEVICE_METADATA_H_
#include <utility>
#include "fastpair/common/fast_pair_version.h"
#include "fastpair/proto/fastpair_rpcs.proto.h"
namespace nearby {
namespace fastpair {
class DeviceMetadata {
public:
explicit DeviceMetadata(const proto::GetObservedDeviceResponse response)
: response_(std::move(response)) {}
DeviceMetadata(DeviceMetadata &&) = default;
DeviceMetadata(const DeviceMetadata &) = default;
DeviceMetadata &operator=(const DeviceMetadata &) = default;
DeviceMetadata &operator=(DeviceMetadata &&) = default;
~DeviceMetadata() = default;
const proto::Device &GetDetails() const { return response_.device(); }
const proto::GetObservedDeviceResponse &GetResponse() const {
return response_;
}
DeviceFastPairVersion GetFastPairVersion() const {
// Anti-spoofing keys were introduced in Fast Pair v2, so if this isn't
// available then the device is v1.
if (GetDetails().anti_spoofing_key_pair().public_key().empty()) {
return DeviceFastPairVersion::kV1;
}
return DeviceFastPairVersion::kHigherThanV1;
}
private:
proto::GetObservedDeviceResponse response_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_REPOSITORY_DEVICE_METADATA_H_
-38
View File
@@ -1,38 +0,0 @@
// 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 "fastpair/common/fast_pair_device.h"
#include <ostream>
#include <string>
#include <utility>
#include "fastpair/common/protocol.h"
namespace nearby {
namespace fastpair {
std::ostream& operator<<(std::ostream& stream, const FastPairDevice& device) {
stream << "[Device: model_id = " << device.GetModelId()
<< ", ble_address = " << device.GetBleAddress()
<< ", public_address = " << device.GetPublicAddress().value_or("null")
<< ", display_name = " << device.GetDisplayName().value_or("null")
<< ", " << device.GetAccountKey()
<< ", protocol = " << device.GetProtocol() << "]";
return stream;
}
} // namespace fastpair
} // namespace nearby
-152
View File
@@ -1,152 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_DEVICE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_DEVICE_H_
#include <cstdint>
#include <optional>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/fast_pair_version.h"
#include "fastpair/common/protocol.h"
namespace nearby {
namespace fastpair {
// Thin class which is used by the higher level components of the Fast Pair
// system to represent a device.
class FastPairDevice {
public:
explicit FastPairDevice(Protocol protocol) : protocol_(protocol) {}
FastPairDevice(absl::string_view model_id, absl::string_view ble_address,
Protocol protocol)
: model_id_(model_id), ble_address_(ble_address), protocol_(protocol) {}
FastPairDevice(const FastPairDevice&) = delete;
FastPairDevice(FastPairDevice&&) = default;
FastPairDevice& operator=(const FastPairDevice&) = delete;
FastPairDevice& operator=(FastPairDevice&&) = default;
~FastPairDevice() = default;
std::optional<std::string> GetPublicAddress() const {
return public_address_;
}
void SetPublicAddress(absl::string_view address) {
public_address_ = std::string(address);
}
std::optional<std::string> GetDisplayName() const { return display_name_; }
void SetDisplayName(absl::string_view display_name) {
display_name_ = std::string(display_name);
}
std::optional<DeviceFastPairVersion> GetVersion() const {
if (metadata_) {
return metadata_->GetFastPairVersion();
}
return std::nullopt;
}
const AccountKey& GetAccountKey() const { return account_key_; }
void SetAccountKey(AccountKey account_key) { account_key_ = account_key; }
void SetModelId(absl::string_view model_id) {
model_id_ = std::string(model_id);
}
absl::string_view GetModelId() const { return model_id_; }
void SetBleAddress(absl::string_view address) {
ble_address_ = std::string(address);
}
absl::string_view GetBleAddress() const { return ble_address_; }
Protocol GetProtocol() const { return protocol_; }
void SetMetadata(const DeviceMetadata& metadata) { metadata_ = metadata; }
const std::optional<DeviceMetadata>& GetMetadata() const { return metadata_; }
const std::string& GetUniqueId() const {
if (public_address_.has_value()) {
return *public_address_;
}
return ble_address_;
}
void SetShowUiNotification(bool should_show_ui_notification) {
should_show_ui_notification_ = should_show_ui_notification;
}
std::optional<bool> ShouldShowUiNotification() const {
return should_show_ui_notification_;
}
void StartedPairing(bool started_pairing) {
has_started_pairing_ = started_pairing;
}
bool HasStartedPairing() const { return has_started_pairing_; }
private:
std::string model_id_;
// Bluetooth LE address of the device.
std::string ble_address_;
// The Quick Pair protocol implementation that this device belongs to.
Protocol protocol_;
// Bluetooth public classic address of the device.
std::optional<std::string> public_address_;
// Display name for the device
// Similar to Bluetooth classic address field, this will be null when a
// device is found from a discoverable advertisement due to the fact that
// initial pair notifications show the OEM default name from the device
// metadata instead of the display name.
std::optional<std::string> display_name_;
// Fast Pair version number, possible versions numbers are defined at the top
// of this file.
std::optional<DeviceFastPairVersion> version_;
// Account key which will be saved to the user's account during Fast Pairing
// for eligible devices (V2 or higher) and used for detecting subsequent
// pairing scenarios.
AccountKey account_key_;
std::optional<DeviceMetadata> metadata_;
std::optional<bool> should_show_ui_notification_;
bool has_started_pairing_ = false;
};
std::ostream& operator<<(std::ostream& stream, const FastPairDevice& device);
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_DEVICE_H_
-111
View File
@@ -1,111 +0,0 @@
// 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 "fastpair/common/fast_pair_device.h"
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/protocol.h"
#include "fastpair/proto/fastpair_rpcs.proto.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(FastPairDevice, GetAndSetAccountKey) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
AccountKey firstKey = AccountKey::CreateRandomKey();
device.SetAccountKey(firstKey);
EXPECT_EQ(device.GetAccountKey(), firstKey);
// Test that overriding works.
AccountKey secondKey = AccountKey::CreateRandomKey();
device.SetAccountKey(secondKey);
EXPECT_EQ(device.GetAccountKey(), secondKey);
}
TEST(FastPairDevice, GetAndSetName) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
// Test that name returns null before any sets.
EXPECT_FALSE(device.GetDisplayName().has_value());
// Test that name returns the set value.
std::string test_name = "test_name";
device.SetDisplayName(test_name);
EXPECT_EQ(device.GetDisplayName().value(), test_name);
// Test that overriding works.
std::string new_test_name = "new_test_name";
device.SetDisplayName(new_test_name);
EXPECT_EQ(device.GetDisplayName().value(), new_test_name);
}
TEST(FastPairDevice, GetAndPublicAddress) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
// Test that public address returns null before any sets.
EXPECT_FALSE(device.GetPublicAddress().has_value());
// Test that name returns the set value.
std::string test_GetPublicAddress = "test_GetPublicAddress ";
device.SetPublicAddress(test_GetPublicAddress);
EXPECT_EQ(device.GetPublicAddress().value(), test_GetPublicAddress);
// Test that overriding works.
std::string new_test_GetPublicAddress = "new_test_GetPublicAddress ";
device.SetPublicAddress(new_test_GetPublicAddress);
EXPECT_EQ(device.GetPublicAddress().value(), new_test_GetPublicAddress);
}
TEST(FastPairDevice, GetVersionUnset) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
EXPECT_FALSE(device.GetVersion());
}
TEST(FastPairDevice, GetVersionV1) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
proto::GetObservedDeviceResponse response;
device.SetMetadata(DeviceMetadata(response));
EXPECT_EQ(device.GetVersion(), DeviceFastPairVersion::kV1);
}
TEST(FastPairDevice, GetVersionHigherThanV1) {
FastPairDevice device("model_id", "ble_address",
Protocol::kFastPairInitialPairing);
proto::GetObservedDeviceResponse response;
std::string anti_spoofing_key(kPublicKeyByteSize, 0);
response.mutable_device()->mutable_anti_spoofing_key_pair()->set_public_key(
anti_spoofing_key);
device.SetMetadata(DeviceMetadata(response));
EXPECT_EQ(device.GetVersion(), DeviceFastPairVersion::kHigherThanV1);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-147
View File
@@ -1,147 +0,0 @@
// 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 "fastpair/common/fast_pair_http_result.h"
#include <ostream>
#include <string>
#include "absl/status/status.h"
namespace nearby {
namespace fastpair {
FastPairHttpError FastPairHttpErrorForHttpResponseCode(absl::Status status) {
switch (status.code()) {
case absl::StatusCode::kOk:
return FastPairHttpError::kSuccess;
case absl::StatusCode::kInvalidArgument:
return FastPairHttpError::kHttpErrorInvalidArgument;
case absl::StatusCode::kUnauthenticated:
return FastPairHttpError::kHttpErrorUnauthenticated;
case absl::StatusCode::kPermissionDenied:
return FastPairHttpError::kHttpErrorPermissionDenied;
case absl::StatusCode::kDeadlineExceeded:
return FastPairHttpError::kHttpErrorDeadlineExceeded;
case absl::StatusCode::kUnavailable:
return FastPairHttpError::kHttpErrorUnavailable;
case absl::StatusCode::kUnknown:
return FastPairHttpError::kHttpErrorUnknown;
case absl::StatusCode::kInternal:
return FastPairHttpError::kHttpErrorInternal;
case absl::StatusCode::kCancelled:
case absl::StatusCode::kUnimplemented:
case absl::StatusCode::kOutOfRange:
case absl::StatusCode::kAborted:
case absl::StatusCode::kNotFound:
return FastPairHttpError::kHttpErrorOtherFailure;
default:
break;
}
return FastPairHttpError::kHttpErrorUnknown;
}
FastPairHttpStatus::FastPairHttpStatus(const absl::Status& absl_status)
: absl_status_(absl_status) {
if (absl_status_.ok()) {
status_ = Status::kSuccess;
} else {
if (absl_status_.code() == absl::StatusCode::kFailedPrecondition) {
status_ = Status::kNetworkFailure;
} else {
status_ = Status::kHttpFailure;
}
}
}
FastPairHttpStatus::FastPairHttpStatus(const FastPairHttpStatus& status) =
default;
FastPairHttpStatus::~FastPairHttpStatus() = default;
bool FastPairHttpStatus::IsSuccess() const {
return status_ == Status::kSuccess;
}
std::string FastPairHttpStatus::ToString() const {
std::string status;
switch (status_) {
case Status::kSuccess:
status = "kSuccess";
break;
case Status::kNetworkFailure:
status = "kNetworkFailure";
break;
case Status::kHttpFailure:
status = "kHttpFailure";
break;
}
return "status=" + status;
}
std::ostream& operator<<(std::ostream& stream, const FastPairHttpError& error) {
switch (error) {
case FastPairHttpError::kSuccess:
stream << "[Success]";
break;
case FastPairHttpError::kTimeout:
stream << "[Timeout]";
break;
case FastPairHttpError::kUnknown:
stream << "[Unknown]";
break;
case FastPairHttpError::kAuthenticationError:
stream << "[Authentication]";
break;
case FastPairHttpError::kHttpErrorUnknown:
stream << "[HTTP Error: Unknown]";
break;
case FastPairHttpError::kHttpErrorDeadlineExceeded:
stream << "[HTTP Error: Deadline exceeded]";
break;
case FastPairHttpError::kHttpErrorPermissionDenied:
stream << "[HTTP Error: Permission denied]";
break;
case FastPairHttpError::kHttpErrorUnavailable:
stream << "[HTTP Error: Unavailable]";
break;
case FastPairHttpError::kHttpErrorUnauthenticated:
stream << "[HTTP Error: Unauthenticated]";
break;
case FastPairHttpError::kHttpErrorInvalidArgument:
stream << "[HTTP Error: Invalid argument]";
break;
case FastPairHttpError::kHttpErrorOffline:
stream << "[HTTP Error: offline]";
break;
case FastPairHttpError::kHttpErrorInternal:
stream << "[HTTP Error: Internal server error]";
break;
case FastPairHttpError::kHttpErrorOtherFailure:
stream << "[HTTP Error: Other failure]";
break;
}
return stream;
}
std::ostream& operator<<(std::ostream& stream,
const FastPairHttpStatus& status) {
stream << status.ToString();
return stream;
}
} // namespace fastpair
} // namespace nearby
-65
View File
@@ -1,65 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_HTTP_RESULT_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_HTTP_RESULT_H_
#include <ostream>
#include <string>
#include "absl/status/status.h"
namespace nearby {
namespace fastpair {
enum class FastPairHttpError {
kSuccess,
kTimeout,
kUnknown,
kAuthenticationError,
kHttpErrorUnknown,
kHttpErrorDeadlineExceeded,
kHttpErrorPermissionDenied,
kHttpErrorUnavailable,
kHttpErrorUnauthenticated,
kHttpErrorInvalidArgument,
kHttpErrorOffline,
kHttpErrorInternal,
kHttpErrorOtherFailure
};
class FastPairHttpStatus {
public:
explicit FastPairHttpStatus(const absl::Status& absl_status);
FastPairHttpStatus(const FastPairHttpStatus& status);
~FastPairHttpStatus();
bool IsSuccess() const;
std::string ToString() const;
private:
enum class Status { kSuccess, kNetworkFailure, kHttpFailure } status_;
absl::Status absl_status_;
};
FastPairHttpError FastPairHttpErrorForHttpResponseCode(absl::Status status);
std::ostream& operator<<(std::ostream& stream, const FastPairHttpError& error);
std::ostream& operator<<(std::ostream& stream,
const FastPairHttpStatus& status);
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_HTTP_RESULT_H_
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2023 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 "fastpair/common/fast_pair_prefs.h"
namespace nearby {
namespace fastpair {
namespace prefs {
namespace {
using json = ::nlohmann::json;
}
const char kNearbyFastPairUsersName[] = "nearby_fastpair.users";
void RegisterNearbyFastPairPrefs(
preferences::PreferencesManager* preferences_manager) {
preferences_manager->Set(kNearbyFastPairUsersName, json::object());
}
} // namespace prefs
} // namespace fastpair
} // namespace nearby
-34
View File
@@ -1,34 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_PREFS_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_PREFS_H_
#include "absl/base/attributes.h"
#include "internal/preferences/preferences_manager.h"
namespace nearby {
namespace fastpair {
namespace prefs {
ABSL_CONST_INIT extern const char kNearbyFastPairUsersName[];
void RegisterNearbyFastPairPrefs(
preferences::PreferencesManager* preferences_manager);
} // namespace prefs
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_PREFS_H_
-49
View File
@@ -1,49 +0,0 @@
// Copyright 2023 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 "fastpair/common/fast_pair_prefs.h"
#include <memory>
#include <string>
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace prefs {
namespace {
using json = ::nlohmann::json;
constexpr char kPreferencesFilePath[] = "Google/Nearby/Preferences";
TEST(FastPairPreference, RegisterNearbyFastPairPrefs) {
auto preferences_manager =
std::make_unique<preferences::PreferencesManager>(kPreferencesFilePath);
RegisterNearbyFastPairPrefs(preferences_manager.get());
EXPECT_TRUE(
preferences_manager->Get(kNearbyFastPairUsersName, json()).empty());
json value = {{"current_user", "abc@gmail.com"}};
preferences_manager->Set(kNearbyFastPairUsersName, value);
auto result = preferences_manager->Get(kNearbyFastPairUsersName, json());
ASSERT_FALSE(result.empty());
auto val = result["current_user"];
EXPECT_EQ(val.get<std::string>(), "abc@gmail.com");
}
} // namespace
} // namespace prefs
} // namespace fastpair
} // namespace nearby
-45
View File
@@ -1,45 +0,0 @@
// Copyright 2023 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 "fastpair/common/fast_pair_switches.h"
#include <string>
namespace nearby {
namespace fastpair {
namespace switches {
namespace {
// Switch value for nearby fast pair global host.
int global_host_size = 0;
char global_host[256];
} // namespace
void SetNearbyFastPairHttpHost(const std::string& host) {
if (host.size() > 256) {
return;
}
global_host_size = host.size();
memcpy(global_host, host.c_str(), global_host_size);
}
std::string GetNearbyFastPairHttpHost() {
return std::string(global_host, global_host_size);
}
} // namespace switches
} // namespace fastpair
} // namespace nearby
-37
View File
@@ -1,37 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_SWITCHES_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_SWITCHES_H_
#include <string>
#include "fastpair/common/fast_pair_switches.h"
namespace nearby {
namespace fastpair {
namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
// Setter and Getter for Nearby Fast Pair http host.
void SetNearbyFastPairHttpHost(const std::string& host);
std::string GetNearbyFastPairHttpHost();
} // namespace switches
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FASTPAIR_SWITCHES_H_
@@ -1,51 +0,0 @@
// Copyright 2023 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 "fastpair/common/fast_pair_switches.h"
#include <string>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace switches {
namespace {
TEST(FastPairSwitches, DefautEmptyHttpHost) {
EXPECT_THAT(GetNearbyFastPairHttpHost(), testing::IsEmpty());
}
TEST(FastPairSwitches, SetLongSizedHttpHostSkipped) {
std::string s(5000, '*');
SetNearbyFastPairHttpHost(s);
EXPECT_THAT(GetNearbyFastPairHttpHost(), testing::IsEmpty());
}
TEST(FastPairSwitches, SetNonEmptyHttpHost) {
SetNearbyFastPairHttpHost("fakehost.com");
EXPECT_THAT(GetNearbyFastPairHttpHost(), "fakehost.com");
}
TEST(FastPairSwitches, SetEmptyHttpHost) {
SetNearbyFastPairHttpHost("");
EXPECT_THAT(GetNearbyFastPairHttpHost(), testing::IsEmpty());
}
} // namespace
} // namespace switches
} // namespace fastpair
} // namespace nearby
-29
View File
@@ -1,29 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_VERSION_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_VERSION_H_
namespace nearby {
namespace fastpair {
enum class DeviceFastPairVersion {
kV1,
kHigherThanV1,
};
}
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_FAST_PAIR_VERSION_H_
@@ -1,59 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
#include <cstdint>
#include <optional>
#include <utility>
#include <vector>
#include "fastpair/common/battery_notification.h"
namespace nearby {
namespace fastpair {
// Fast Pair 'Not Discoverable' advertisement. See
// https://developers.google.com/nearby/fast-pair/specifications/service/provider#AdvertisingWhenNotDiscoverable
struct NonDiscoverableAdvertisement {
// Represents showing UI indication
enum class Type {
kShowUi = 0, /* Show UI indication: 0b0000*/
kNone = 1,
kHideUi = 2, /* Hide UI indication: 0b0010*/
};
NonDiscoverableAdvertisement() = default;
NonDiscoverableAdvertisement(
std::vector<uint8_t> account_key_filter, Type type,
std::vector<uint8_t> salt,
std::optional<BatteryNotification> battery_notification)
: account_key_filter(std::move(account_key_filter)),
type(type),
salt(std::move(salt)),
battery_notification(std::move(battery_notification)) {}
~NonDiscoverableAdvertisement() = default;
std::vector<uint8_t> account_key_filter;
Type type = Type::kNone;
std::vector<uint8_t> salt;
std::optional<BatteryNotification> battery_notification;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
-117
View File
@@ -1,117 +0,0 @@
// 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 "fastpair/common/pair_failure.h"
#include <ostream>
namespace nearby {
namespace fastpair {
std::ostream& operator<<(std::ostream& stream, PairFailure failure) {
switch (failure) {
case PairFailure::kUnknown:
stream << "[Failed with unknown reason]";
break;
case PairFailure::kCreateGattConnection:
stream << "[Failed to create a GATT connection to the device]";
break;
case PairFailure::kGattServiceDiscovery:
stream << "[Failed to find the expected GATT service]";
break;
case PairFailure::kGattServiceDiscoveryTimeout:
stream << "[Timed out while starting discovery of GATT service]";
break;
case PairFailure::kDataEncryptorRetrieval:
stream << "[Failed to retrieve the data encryptor]";
break;
case PairFailure::kKeyBasedPairingCharacteristicDiscovery:
stream << "[Failed to find the Key-based pairing GATT characteristic]";
break;
case PairFailure::kPasskeyCharacteristicDiscovery:
stream << "[Failed to find the Passkey GATT characteristic]";
break;
case PairFailure::kAccountKeyCharacteristicDiscovery:
stream << "[Failed to find the Account Key GATT characteristic]";
break;
case PairFailure::kKeyBasedPairingCharacteristicSubscription:
stream << "[Failed to start a subscription on the Key-based pairing "
"GATT characteristic]";
break;
case PairFailure::kPasskeyCharacteristicSubscription:
stream << "[Failed to start a subscription on the Passkey GATT "
"characteristic]";
break;
case PairFailure::kKeyBasedPairingCharacteristicSubscriptionTimeout:
stream << "[Timed out while starting a subscription on the Key-based "
"pairing GATT characteristic]";
break;
case PairFailure::kPasskeyCharacteristicSubscriptionTimeout:
stream << "[Timed out while starting a subscription on the Passkey "
"GATT characteristic]";
break;
case PairFailure::kKeyBasedPairingCharacteristicWrite:
stream
<< "[Failed to write to the Key-based pairing GATT characteristic]";
break;
case PairFailure::kPasskeyPairingCharacteristicWrite:
stream << "[Failed to write to the Passkey GATT characteristic]";
break;
case PairFailure::kAccountKeyCharacteristicWrite:
stream << "[Failed to write to the Account Key GATT characteristic]";
break;
case PairFailure::kKeyBasedPairingResponseTimeout:
stream << "[Timed out while waiting for the Key-based Pairing response]";
break;
case PairFailure::kPasskeyResponseTimeout:
stream << "[Timed out while waiting for the Passkey response]";
break;
case PairFailure::kKeybasedPairingResponseDecryptFailure:
stream << "[Failed to decrypt Key-based Pairing response]";
break;
case PairFailure::kIncorrectKeyBasedPairingResponseType:
stream << "[Incorrect Key-based response message type]";
break;
case PairFailure::kPasskeyDecryptFailure:
stream << "[Failed to decrypt Passkey response]";
break;
case PairFailure::kIncorrectPasskeyResponseType:
stream << "[Incorrect Passkey response message type]";
break;
case PairFailure::kPasskeyMismatch:
stream << "[Passkeys did not match]";
break;
case PairFailure::kPairingDeviceLostBetweenGattConnectionAttempts:
stream
<< "[Potential pairing device lost between GATT connection attempts]";
break;
case PairFailure::kDeviceLostMidPairing:
stream << "[Potential pairing device lost during pairing.]";
break;
case PairFailure::kPairingAndConnect:
stream << "[Failed to pair with discovered device.]";
break;
case PairFailure::kPairingTimeout:
stream << "[Potential pairing failed with timeout.]";
break;
case PairFailure::kWriteAccountKeyToFootprints:
stream << "[Failed to write Account Key to Footprints.]";
break;
}
return stream;
}
} // namespace fastpair
} // namespace nearby
-89
View File
@@ -1,89 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PAIR_FAILURE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PAIR_FAILURE_H_
#include <ostream>
namespace nearby {
namespace fastpair {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class PairFailure {
kUnknown = 0,
// Failed to create a GATT connection to the device.
kCreateGattConnection = 1,
// Failed to find the expected GATT service.
kGattServiceDiscovery = 2,
// Timed out while starting discovery of GATT service.
kGattServiceDiscoveryTimeout = 3,
// Failed to retrieve the data encryptor.
kDataEncryptorRetrieval = 4,
// Failed to find the Key-based pairing GATT characteristic.
kKeyBasedPairingCharacteristicDiscovery = 5,
// Failed to find the Passkey GATT characteristic.
kPasskeyCharacteristicDiscovery = 6,
// Failed to find the Account Key GATT characteristic.
kAccountKeyCharacteristicDiscovery = 7,
// Failed to subscribe the notification on the Key-based pairing GATT
// characteristic.
kKeyBasedPairingCharacteristicSubscription = 8,
// Failed to start a notify session on the Passkey GATT characteristic.
kPasskeyCharacteristicSubscription = 9,
// Timed out while waiting to start a notify session on the Key-based pairing
// GATT characteristic.
kKeyBasedPairingCharacteristicSubscriptionTimeout = 10,
// / Timed out while waiting to start a notify session on the Passkey GATT
// characteristic.
kPasskeyCharacteristicSubscriptionTimeout = 11,
// Failed to write to the Key-based pairing GATT characteristic.
kKeyBasedPairingCharacteristicWrite = 12,
// Failed to write to the Passkey GATT characteristic.
kPasskeyPairingCharacteristicWrite = 13,
// Failed to write to the AccountKey GATT characteristic.
kAccountKeyCharacteristicWrite = 14,
// Timed out while waiting for the Key-based Pairing response.
kKeyBasedPairingResponseTimeout = 15,
// Timed out while waiting for the Passkey response.
kPasskeyResponseTimeout = 16,
// Failed to decrypt Key-based response message.
kKeybasedPairingResponseDecryptFailure = 17,
// Incorrect Key-based response message type.
kIncorrectKeyBasedPairingResponseType = 18,
// Failed to decrypt Passkey response message.
kPasskeyDecryptFailure = 19,
// Incorrect Passkey response message type.
kIncorrectPasskeyResponseType = 20,
// Passkeys did not match.
kPasskeyMismatch = 21,
// Potential pairing device lost between GATT connection attempts.
kPairingDeviceLostBetweenGattConnectionAttempts = 22,
// Potential pairing device lost during pairing.
kDeviceLostMidPairing = 23,
// Failed to pair and connect with discovered device.
kPairingAndConnect = 24,
// Potential pairing timeout.
kPairingTimeout = 25,
kWriteAccountKeyToFootprints = 26,
kMaxValue = kWriteAccountKeyToFootprints,
};
std::ostream& operator<<(std::ostream& stream, PairFailure failure);
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PAIR_FAILURE_H_
-71
View File
@@ -1,71 +0,0 @@
// Copyright 2023 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 "fastpair/common/pair_failure.h"
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(PairFailureTest, PairFailureValue) {
EXPECT_EQ(static_cast<int>(PairFailure::kUnknown), 0);
EXPECT_EQ(static_cast<int>(PairFailure::kCreateGattConnection), 1);
EXPECT_EQ(static_cast<int>(PairFailure::kGattServiceDiscovery), 2);
EXPECT_EQ(static_cast<int>(PairFailure::kGattServiceDiscoveryTimeout), 3);
EXPECT_EQ(static_cast<int>(PairFailure::kDataEncryptorRetrieval), 4);
EXPECT_EQ(
static_cast<int>(PairFailure::kKeyBasedPairingCharacteristicDiscovery),
5);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyCharacteristicDiscovery), 6);
EXPECT_EQ(static_cast<int>(PairFailure::kAccountKeyCharacteristicDiscovery),
7);
EXPECT_EQ(
static_cast<int>(PairFailure::kKeyBasedPairingCharacteristicSubscription),
8);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyCharacteristicSubscription),
9);
EXPECT_EQ(static_cast<int>(
PairFailure::kKeyBasedPairingCharacteristicSubscriptionTimeout),
10);
EXPECT_EQ(
static_cast<int>(PairFailure::kPasskeyCharacteristicSubscriptionTimeout),
11);
EXPECT_EQ(static_cast<int>(PairFailure::kKeyBasedPairingCharacteristicWrite),
12);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyPairingCharacteristicWrite),
13);
EXPECT_EQ(static_cast<int>(PairFailure::kAccountKeyCharacteristicWrite), 14);
EXPECT_EQ(static_cast<int>(PairFailure::kKeyBasedPairingResponseTimeout), 15);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyResponseTimeout), 16);
EXPECT_EQ(
static_cast<int>(PairFailure::kKeybasedPairingResponseDecryptFailure),
17);
EXPECT_EQ(
static_cast<int>(PairFailure::kIncorrectKeyBasedPairingResponseType), 18);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyDecryptFailure), 19);
EXPECT_EQ(static_cast<int>(PairFailure::kIncorrectPasskeyResponseType), 20);
EXPECT_EQ(static_cast<int>(PairFailure::kPasskeyMismatch), 21);
EXPECT_EQ(static_cast<int>(
PairFailure::kPairingDeviceLostBetweenGattConnectionAttempts),
22);
EXPECT_EQ(static_cast<int>(PairFailure::kDeviceLostMidPairing), 23);
EXPECT_EQ(static_cast<int>(PairFailure::kPairingAndConnect), 24);
EXPECT_EQ(static_cast<int>(PairFailure::kPairingTimeout), 25);
EXPECT_EQ(static_cast<int>(PairFailure::kWriteAccountKeyToFootprints), 26);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-39
View File
@@ -1,39 +0,0 @@
// 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 "fastpair/common/protocol.h"
#include <ostream>
namespace nearby {
namespace fastpair {
std::ostream& operator<<(std::ostream& stream, Protocol protocol) {
switch (protocol) {
case Protocol::kFastPairInitialPairing:
stream << "[Fast Pair Initial Pairing]";
break;
case Protocol::kFastPairRetroactivePairing:
stream << "[Fast Pair Retroactive Pairing]";
break;
case Protocol::kFastPairSubsequentPairing:
stream << "[Fast Pair Subsequent Pairing]";
break;
}
return stream;
}
} // namespace fastpair
} // namespace nearby
-36
View File
@@ -1,36 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PROTOCOL_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PROTOCOL_H_
#include <ostream>
namespace nearby {
namespace fastpair {
// Pairing scenarios
enum class Protocol {
// Google Fast Pair
kFastPairInitialPairing = 0,
kFastPairRetroactivePairing = 1,
kFastPairSubsequentPairing = 2,
};
std::ostream& operator<<(std::ostream& stream, Protocol protocol);
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_PROTOCOL_H_
-134
View File
@@ -1,134 +0,0 @@
# Copyright 2023 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.
cc_library(
name = "crypto",
srcs = [
"fast_pair_decryption.cc",
"fast_pair_encryption.cc",
"fast_pair_message_type.cc",
],
hdrs = [
"decrypted_passkey.h",
"decrypted_response.h",
"fast_pair_decryption.h",
"fast_pair_encryption.h",
"fast_pair_key_pair.h",
"fast_pair_message_type.h",
],
visibility = [
"//:__subpackages__",
"//fastpair:__subpackages__",
],
deps = [
"//fastpair/common",
"//internal/base:bluetooth_address",
"//internal/platform:base",
"//internal/platform:types",
"@boringssl//:crypto",
"@com_google_absl//absl/log:check",
],
)
cc_test(
name = "decrypted_passkey_test",
size = "small",
srcs = [
"decrypted_passkey_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "decrypted_response_test",
size = "small",
srcs = [
"decrypted_response_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_key_pair_test",
size = "small",
srcs = [
"fast_pair_key_pair_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_encryption_test",
size = "small",
srcs = [
"fast_pair_encryption_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//fastpair/common",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_decryption_test",
size = "small",
srcs = [
"fast_pair_decryption_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_message_type_test",
size = "small",
srcs = [
"fast_pair_message_type_test.cc",
],
shard_count = 1,
deps = [
":crypto",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
-45
View File
@@ -1,45 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_PASSKEY_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_PASSKEY_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include "fastpair/common/constant.h"
#include "fastpair/crypto/fast_pair_message_type.h"
namespace nearby {
namespace fastpair {
// Thin structure which is used by the higher level components of the Fast Pair
// system to represent a decrypted account passkey.
struct DecryptedPasskey {
DecryptedPasskey(
FastPairMessageType message_type, uint32_t passkey,
const std::array<uint8_t, kDecryptedPasskeySaltByteSize>& salt)
: message_type(message_type), passkey(passkey), salt(salt) {}
FastPairMessageType message_type;
uint32_t passkey;
std::array<uint8_t, kDecryptedPasskeySaltByteSize> salt;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_PASSKEY_H_
-45
View File
@@ -1,45 +0,0 @@
// 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 "fastpair/crypto/decrypted_passkey.h"
#include <array>
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(DecryptedPasskeyTest, CreateDecryptedPasskey) {
// Message type
FastPairMessageType messgaeType = FastPairMessageType::kSeekersPasskey;
// Passkey bytes.
std::array<uint8_t, 3> passkey_bytes = {0x02, 0x03, 0x04};
uint32_t passkey = passkey_bytes[2];
passkey += passkey_bytes[1] << 8;
passkey += passkey_bytes[0] << 16;
// Random salt
std::array<uint8_t, 12> salt = {0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E,
0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
DecryptedPasskey decryptedPasskey(messgaeType, passkey, salt);
EXPECT_EQ(decryptedPasskey.message_type, messgaeType);
EXPECT_EQ(decryptedPasskey.passkey, passkey);
EXPECT_EQ(decryptedPasskey.salt, salt);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-47
View File
@@ -1,47 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_RESPONSE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_RESPONSE_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include "fastpair/common/constant.h"
#include "fastpair/crypto/fast_pair_message_type.h"
namespace nearby {
namespace fastpair {
// Thin structure which is used by the higher level components of the Fast Pair
// system to represent a decrypted response.
struct DecryptedResponse {
DecryptedResponse(
FastPairMessageType message_type,
const std::array<uint8_t, kDecryptedResponseAddressByteSize>&
address_bytes,
const std::array<uint8_t, kDecryptedResponseSaltByteSize>& salt)
: message_type(message_type), address_bytes(address_bytes), salt(salt) {}
FastPairMessageType message_type;
std::array<uint8_t, kDecryptedResponseAddressByteSize> address_bytes;
std::array<uint8_t, kDecryptedResponseSaltByteSize> salt;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_DECRYPTED_RESPONSE_H_
@@ -1,42 +0,0 @@
// 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 "fastpair/crypto/decrypted_response.h"
#include <array>
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(DecryptedResponseTest, CreateDecryptedResponse) {
constexpr std::array<uint8_t, 6> address_bytes = {0x02, 0x03, 0x04,
0x05, 0x06, 0x07};
constexpr std::array<uint8_t, 9> salt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x00};
DecryptedResponse decryptedResponse(
FastPairMessageType::kKeyBasedPairingResponse, address_bytes, salt);
EXPECT_EQ(decryptedResponse.message_type,
FastPairMessageType::kKeyBasedPairingResponse);
EXPECT_EQ(decryptedResponse.address_bytes, address_bytes);
EXPECT_EQ(decryptedResponse.salt, salt);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-116
View File
@@ -1,116 +0,0 @@
// 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 "fastpair/crypto/fast_pair_decryption.h"
#include <algorithm>
#include <array>
#include <optional>
#ifdef NEARBY_CHROMIUM
#include "base/check.h"
#elif defined(NEARBY_SWIFTPM)
#include "internal/platform/logging.h"
#else
#include "absl/log/check.h" // nogncheck
#endif
#include "fastpair/common/constant.h"
#include "fastpair/crypto/decrypted_passkey.h"
#include "fastpair/crypto/decrypted_response.h"
#include <openssl/aes.h>
namespace nearby {
namespace fastpair {
namespace {
std::array<uint8_t, kAesBlockByteSize> DecryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
const std::array<uint8_t, kAesBlockByteSize>& encrypted_bytes) {
AES_KEY aes_key;
int aes_key_was_set = AES_set_decrypt_key(aes_key_bytes.data(),
aes_key_bytes.size() * 8, &aes_key);
CHECK(aes_key_was_set == 0) << "Invalid AES key size.";
std::array<uint8_t, kAesBlockByteSize> decrypted_bytes;
// Encrypted_bytes is less than 16 bytes and can be guaranteed to be a
// single block, so we encrypt/decrypt it using AES ECB mode (Approved by:
// b/73360609)
AES_decrypt(encrypted_bytes.data(), decrypted_bytes.data(), &aes_key);
return decrypted_bytes;
}
} // namespace
// Decrypts the encrypted response
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.4)
// and returns the parsed decrypted response
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.3)
std::optional<DecryptedResponse> FastPairDecryption::ParseDecryptResponse(
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
const std::array<uint8_t, kAesBlockByteSize>& encrypted_response_bytes) {
std::array<uint8_t, kAesBlockByteSize> decrypted_response_bytes =
DecryptBytes(aes_key_bytes, encrypted_response_bytes);
uint8_t message_type = decrypted_response_bytes[kMessageTypeIndex];
// If the message type index is not the expected fast pair message type, then
// this is not a valid fast pair response.
if (message_type != kKeybasedPairingResponseType) {
return std::nullopt;
}
std::array<uint8_t, kDecryptedResponseAddressByteSize> address_bytes;
std::copy(decrypted_response_bytes.begin() + kResponseAddressStartIndex,
decrypted_response_bytes.begin() + kResponseSaltStartIndex,
address_bytes.begin());
std::array<uint8_t, kDecryptedResponseSaltByteSize> salt;
std::copy(decrypted_response_bytes.begin() + kResponseSaltStartIndex,
decrypted_response_bytes.end(), salt.begin());
return DecryptedResponse(FastPairMessageType::kKeyBasedPairingResponse,
address_bytes, salt);
}
// Decrypts the encrypted passkey
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table2.1)
// and returns the parsed decrypted passkey
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table2.2)
// TODO(b/263400788) Add unit test to cover this function and fix all Mutants
// warning
std::optional<DecryptedPasskey> FastPairDecryption::ParseDecryptPasskey(
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
const std::array<uint8_t, kAesBlockByteSize>& encrypted_passkey_bytes) {
std::array<uint8_t, kAesBlockByteSize> decrypted_passkey_bytes =
DecryptBytes(aes_key_bytes, encrypted_passkey_bytes);
FastPairMessageType message_type;
if (decrypted_passkey_bytes[kMessageTypeIndex] == kSeekerPasskeyType) {
message_type = FastPairMessageType::kSeekersPasskey;
} else if (decrypted_passkey_bytes[kMessageTypeIndex] ==
kProviderPasskeyType) {
message_type = FastPairMessageType::kProvidersPasskey;
} else {
return std::nullopt;
}
uint32_t passkey = decrypted_passkey_bytes[3];
passkey += decrypted_passkey_bytes[2] << 8;
passkey += decrypted_passkey_bytes[1] << 16;
std::array<uint8_t, kDecryptedPasskeySaltByteSize> salt;
std::copy(decrypted_passkey_bytes.begin() + kPasskeySaltStartIndex,
decrypted_passkey_bytes.end(), salt.begin());
return DecryptedPasskey(message_type, passkey, salt);
}
} // namespace fastpair
} // namespace nearby
-44
View File
@@ -1,44 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_DECRYPTION_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_DECRYPTION_H_
#include <array>
#include <string>
#include <optional>
#include "fastpair/crypto/decrypted_passkey.h"
#include "fastpair/crypto/decrypted_response.h"
namespace nearby {
namespace fastpair {
/** Utilities used for encrypting and decrypting Fast Pair packets. */
class FastPairDecryption {
public:
static constexpr int kAesBlockByteSize = 16;
static std::optional<DecryptedResponse> ParseDecryptResponse(
const std::array<uint8_t, 16>& aes_key_bytes,
const std::array<uint8_t, 16>& encrypted_response_bytes);
static std::optional<DecryptedPasskey> ParseDecryptPasskey(
const std::array<uint8_t, 16>& aes_key_bytes,
const std::array<uint8_t, 16>& encrypted_passkey_bytes);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DECRYPTION_H_
@@ -1,157 +0,0 @@
// 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 "fastpair/crypto/fast_pair_decryption.h"
#include <algorithm>
#include <array>
#include <iterator>
#include <vector>
#include "gtest/gtest.h"
#include "fastpair/crypto/fast_pair_encryption.h"
namespace nearby {
namespace fastpair {
namespace {
// All test data comes from
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
constexpr std::array<uint8_t, kAesBlockByteSize> aes_key_bytes = {
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6,
0xCF, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
TEST(FastPairDecryptionTest, ParseDecryptResponseSuccess) {
std::vector<uint8_t> response_bytes;
// Message type.
response_bytes.push_back(0x01);
// Address bytes.
std::array<uint8_t, 6> address_bytes = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
std::copy(address_bytes.begin(), address_bytes.end(),
std::back_inserter(response_bytes));
// Random salt
std::array<uint8_t, 9> salt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x00};
std::copy(salt.begin(), salt.end(), std::back_inserter(response_bytes));
std::array<uint8_t, kAesBlockByteSize> response_bytes_array;
std::copy_n(response_bytes.begin(), kAesBlockByteSize,
response_bytes_array.begin());
auto encrypted_bytes =
FastPairEncryption::EncryptBytes(aes_key_bytes, response_bytes_array);
auto response =
FastPairDecryption::ParseDecryptResponse(aes_key_bytes, encrypted_bytes);
EXPECT_TRUE(response.has_value());
EXPECT_EQ(response->message_type,
FastPairMessageType::kKeyBasedPairingResponse);
EXPECT_EQ(response->address_bytes, address_bytes);
EXPECT_EQ(response->salt, salt);
}
TEST(FastPairDecryptionTest, ParseDecryptResponseFailure) {
constexpr std::array<uint8_t, kAesBlockByteSize> response_bytes = {
/*message_type=*/0x02,
/*address_bytes=*/0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
/*salt=*/0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x00};
auto encrypted_bytes =
FastPairEncryption::EncryptBytes(aes_key_bytes, response_bytes);
auto response =
FastPairDecryption::ParseDecryptResponse(aes_key_bytes, encrypted_bytes);
EXPECT_FALSE(response.has_value());
}
TEST(FastPairDecryptionTest, ParseDecryptPasskeySuccess) {
std::vector<uint8_t> passkey_bytes;
// Message type.
passkey_bytes.push_back(0x02);
// Passkey bytes.
uint32_t passkey = 5;
passkey_bytes.push_back(passkey >> 16);
passkey_bytes.push_back(passkey >> 8);
passkey_bytes.push_back(passkey);
// Random salt
std::array<uint8_t, 12> salt = {0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E,
0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
std::copy(salt.begin(), salt.end(), std::back_inserter(passkey_bytes));
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
std::copy_n(passkey_bytes.begin(), kAesBlockByteSize,
passkey_bytes_array.begin());
auto encrypted_bytes =
FastPairEncryption::EncryptBytes(aes_key_bytes, passkey_bytes_array);
auto decrypted_passkey =
FastPairDecryption::ParseDecryptPasskey(aes_key_bytes, encrypted_bytes);
EXPECT_TRUE(decrypted_passkey.has_value());
EXPECT_EQ(decrypted_passkey->message_type,
FastPairMessageType::kSeekersPasskey);
EXPECT_EQ(decrypted_passkey->passkey, passkey);
EXPECT_EQ(decrypted_passkey->salt, salt);
}
TEST(FastPairDecryptionTest, ParseDecryptPasskeyFailure) {
constexpr std::array<uint8_t, kAesBlockByteSize> passkey_bytes = {
/*message_type=*/0x04,
/*passkey=*/0x02,
0x03,
0x04,
/*salt=*/0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x0E};
auto encrypted_bytes =
FastPairEncryption::EncryptBytes(aes_key_bytes, passkey_bytes);
auto passkey =
FastPairDecryption::ParseDecryptPasskey(aes_key_bytes, encrypted_bytes);
EXPECT_FALSE(passkey.has_value());
}
} // namespace
} // namespace fastpair
} // namespace nearby
-166
View File
@@ -1,166 +0,0 @@
// 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 "fastpair/crypto/fast_pair_encryption.h"
#include <algorithm>
#include <array>
#include <iterator>
#include <optional>
#include <string_view>
#include <vector>
#ifdef NEARBY_CHROMIUM
#include "base/check.h"
#elif defined(NEARBY_SWIFTPM)
#include "internal/platform/logging.h"
#else
#include "absl/log/check.h" // nogncheck
#endif
#include "fastpair/common/constant.h"
#include "fastpair/crypto/fast_pair_key_pair.h"
#include "fastpair/crypto/fast_pair_message_type.h"
#include "internal/platform/logging.h"
#include <openssl/aes.h>
#include <openssl/base.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdh.h>
#include <openssl/nid.h>
#include <openssl/sha.h>
namespace nearby {
namespace fastpair {
namespace {
// Converts the public anti-spoofing key into an EC_Point.
bssl::UniquePtr<EC_POINT> GetEcPointFromPublicAntiSpoofingKey(
const bssl::UniquePtr<EC_GROUP>& ec_group,
std::string_view decoded_public_anti_spoofing) {
std::array<uint8_t, kPublicKeyByteSize + 1> buffer;
buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
std::copy(decoded_public_anti_spoofing.begin(),
decoded_public_anti_spoofing.end(), buffer.begin() + 1);
bssl::UniquePtr<EC_POINT> new_ec_point(EC_POINT_new(ec_group.get()));
if (!EC_POINT_oct2point(ec_group.get(), new_ec_point.get(), buffer.data(),
buffer.size(), nullptr)) {
return nullptr;
}
return new_ec_point;
}
// Key derivation function to be used in hashing the generated secret key.
void* KDF(const void* in, size_t inlen, void* out, size_t* outlen) {
// Set this to 16 since that's the amount of bytes we want to use
// for the key, even though more will be written by SHA256 below.
*outlen = kSharedSecretKeyByteSize;
return SHA256(static_cast<const uint8_t*>(in), inlen,
static_cast<uint8_t*>(out));
}
} // namespace
// TODO(b/263400788) Add unit test to cover this function and fix all Mutants
// warning
std::optional<KeyPair> FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
std::string_view decoded_public_anti_spoofing) {
if (decoded_public_anti_spoofing.size() != kPublicKeyByteSize) {
NEARBY_LOGS(INFO) << "Expected " << kPublicKeyByteSize
<< " byte value for anti-spoofing key. Got:"
<< decoded_public_anti_spoofing.size();
return std::nullopt;
}
// Generate the secp256r1 key-pair.
bssl::UniquePtr<EC_GROUP> ec_group(
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
bssl::UniquePtr<EC_KEY> ec_key(
EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
if (!EC_KEY_generate_key(ec_key.get())) {
NEARBY_LOGS(INFO) << __func__ << ": Failed to generate ec key";
return std::nullopt;
}
// The ultimate goal here is to get a 64-byte public key. We accomplish this
// by converting the generated public key into the uncompressed X9.62 format,
// which is 0x04 followed by padded x and y coordinates.
std::array<uint8_t, kPublicKeyByteSize + 1> uncompressed_private_key;
int point_bytes_written = EC_POINT_point2oct(
ec_group.get(), EC_KEY_get0_public_key(ec_key.get()),
POINT_CONVERSION_UNCOMPRESSED, uncompressed_private_key.data(),
uncompressed_private_key.size(), nullptr);
if (point_bytes_written != uncompressed_private_key.size()) {
NEARBY_LOGS(INFO) << __func__
<< ": EC_POINT_point2oct failed to convert public key "
"to uncompressed x9.62 format.";
return std::nullopt;
}
bssl::UniquePtr<EC_POINT> public_anti_spoofing_point =
GetEcPointFromPublicAntiSpoofingKey(ec_group,
decoded_public_anti_spoofing);
if (!public_anti_spoofing_point) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Failed to convert Public Anti-Spoofing key to EC_POINT";
return std::nullopt;
}
uint8_t secret[SHA256_DIGEST_LENGTH];
int computed_key_size =
ECDH_compute_key(secret, SHA256_DIGEST_LENGTH,
public_anti_spoofing_point.get(), ec_key.get(), &KDF);
if (computed_key_size != kSharedSecretKeyByteSize) {
NEARBY_LOGS(INFO) << __func__ << ": ECDH_compute_key failed.";
return std::nullopt;
}
// Take first 16 bytes from secret as the shared secret key.
std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key;
std::copy(secret, secret + kSharedSecretKeyByteSize,
std::begin(shared_secret_key));
// Ignore the first byte since it is 0x04, from the above uncompressed X9 .62
// format.
std::array<uint8_t, kPublicKeyByteSize> public_key;
std::copy(uncompressed_private_key.begin() + 1,
uncompressed_private_key.end(), public_key.begin());
return KeyPair(shared_secret_key, public_key);
}
std::array<uint8_t, kAesBlockByteSize> FastPairEncryption::EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt) {
AES_KEY aes_key;
int aes_key_was_set = AES_set_encrypt_key(aes_key_bytes.data(),
aes_key_bytes.size() * 8, &aes_key);
DCHECK(aes_key_was_set == 0) << "Invalid AES key size.";
std::array<uint8_t, kAesBlockByteSize> encrypted_bytes;
// Bytes_to_encrypt is less than 16 bytes and can be guaranteed to be a
// single block, so we encrypt it using AES ECB mode (Approved by: b/73360609)
AES_encrypt(bytes_to_encrypt.data(), encrypted_bytes.data(), &aes_key);
return encrypted_bytes;
}
} // namespace fastpair
} // namespace nearby
-46
View File
@@ -1,46 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_ENCRYPTION_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_ENCRYPTION_H_
#include <stdint.h>
#include <array>
#include <string>
#include <string_view>
#include <optional>
#include "fastpair/common/constant.h"
#include "fastpair/crypto/fast_pair_key_pair.h"
namespace nearby {
namespace fastpair {
/** Utilities used for generating Ecdh key agreement and
* encrypting Fast Pair packets. */
class FastPairEncryption {
public:
static std::optional<KeyPair> GenerateKeysWithEcdhKeyAgreement(
std::string_view decoded_public_anti_spoofing);
static std::array<uint8_t, kAesBlockByteSize> EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_ENCRYPTION_H_
@@ -1,84 +0,0 @@
// 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 "fastpair/crypto/fast_pair_encryption.h"
#include <algorithm>
#include <array>
#include <iterator>
#include <string>
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
namespace nearby {
namespace fastpair {
namespace {
// All test data comes from
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
constexpr std::array<uint8_t, kAesBlockByteSize> aes_key_bytes = {
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6,
0xCF, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
std::string DecodeKey(const std::string& encoded_key) {
std::string key;
absl::Base64Unescape(encoded_key, &key);
return key;
}
class FastPairEncryptionTest : public testing::Test {};
TEST(FastPairEncryptionTest, EncryptBytes_Success) {
constexpr std::array<uint8_t, kAesBlockByteSize> input = {
0xF3, 0x0F, 0x4E, 0x78, 0x6C, 0x59, 0xA7, 0xBB,
0xF3, 0x87, 0x3B, 0x5A, 0x49, 0xBA, 0x97, 0xEA};
constexpr std::array<uint8_t, kAesBlockByteSize> expected = {
0xAC, 0x9A, 0x16, 0xF0, 0x95, 0x3A, 0x3F, 0x22,
0x3D, 0xD1, 0x0C, 0xF5, 0x36, 0xE0, 0x9E, 0x9C};
EXPECT_EQ(FastPairEncryption::EncryptBytes(aes_key_bytes, input), expected);
}
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_EmptyKey) {
EXPECT_FALSE(
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement("").has_value());
}
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_ShortKey) {
EXPECT_FALSE(FastPairEncryption::GenerateKeysWithEcdhKeyAgreement("too_short")
.has_value());
}
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_InvalidKey) {
EXPECT_FALSE(
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
DecodeKey("U2PWc3FHTxah/o0YT9n1VRvtm57SNIRSXOEBXm4fdtMo+06tNoFlt8D0/"
"2BsN8auolz5ikwLRvQh+MiQ6oYveg=="))
.has_value());
}
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_ValidKey) {
EXPECT_TRUE(
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
DecodeKey("U2PWc3FHTxah/o0YU9n1VRvtm57SNIRSXOEBXm4fdtMo+06tNoFlt8D0/"
"2BsN8auolz5ikwLRvQh+MiQ6oYveg=="))
.has_value());
}
} // namespace
} // namespace fastpair
} // namespace nearby
-46
View File
@@ -1,46 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_KEY_PAIR_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_KEY_PAIR_H_
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <array>
#include <utility>
#include "fastpair/common/constant.h"
namespace nearby {
namespace fastpair {
// Key pair structure to represent public and private keys used for encryption/
// decryption.
struct KeyPair {
KeyPair(
const std::array<uint8_t, kSharedSecretKeyByteSize>& shared_secret_key,
const std::array<uint8_t, kPublicKeyByteSize>& public_key)
: shared_secret_key(std::move(shared_secret_key)),
public_key(std::move(public_key)) {}
const std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key;
const std::array<uint8_t, kPublicKeyByteSize> public_key;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_KEY_PAIR_H_
@@ -1,53 +0,0 @@
// 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 "fastpair/crypto/fast_pair_key_pair.h"
#include <array>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
// Test data comes from
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
TEST(KeyPairTest, CreateKeyPair) {
// Shared secret key bytes.
constexpr std::array<uint8_t, kSharedSecretKeyByteSize>
shared_secret_key_bytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
// Public key bytes.
constexpr std::array<uint8_t, kPublicKeyByteSize> public_key_bytes = {
0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67,
0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34,
0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6,
0x50, 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56,
0xfb, 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27,
0xc5, 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25};
KeyPair keyPair(shared_secret_key_bytes, public_key_bytes);
EXPECT_EQ(keyPair.shared_secret_key, shared_secret_key_bytes);
EXPECT_EQ(keyPair.public_key, public_key_bytes);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-45
View File
@@ -1,45 +0,0 @@
// 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 "fastpair/crypto/fast_pair_message_type.h"
#include <ostream>
namespace nearby {
namespace fastpair {
std::ostream& operator<<(std::ostream& stream,
FastPairMessageType message_type) {
switch (message_type) {
case FastPairMessageType::kKeyBasedPairingRequest:
stream << "[Key-Based Pairing Request]";
break;
case FastPairMessageType::kKeyBasedPairingResponse:
stream << "[Key-Based Pairing Response]";
break;
case FastPairMessageType::kSeekersPasskey:
stream << "[Seeker's Passkey]";
break;
case FastPairMessageType::kProvidersPasskey:
stream << "[Providers' Passkey]";
break;
default:
stream << "[Unknown]";
}
return stream;
}
} // namespace fastpair
} // namespace nearby
-43
View File
@@ -1,43 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_MESSAGE_TYPE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_MESSAGE_TYPE_H_
#include <ostream>
namespace nearby {
namespace fastpair {
// Type values for Fast Pair messages.
enum class FastPairMessageType {
// Unknown message type.
kUnknown = 0,
// Key-based Pairing Request.
kKeyBasedPairingRequest = 1,
// Key-based Pairing Response.
kKeyBasedPairingResponse = 2,
// Seeker's passkey.
kSeekersPasskey = 3,
// Provider's passkey.
kProvidersPasskey = 4,
};
std::ostream& operator<<(std::ostream& stream,
FastPairMessageType message_type);
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_MESSAGE_TYPE_H_
@@ -1,32 +0,0 @@
// Copyright 2023 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 "fastpair/crypto/fast_pair_message_type.h"
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(FastPairMessageTypeTest, FastPairMessageTypeValue) {
EXPECT_EQ(static_cast<int>(FastPairMessageType::kUnknown), 0);
EXPECT_EQ(static_cast<int>(FastPairMessageType::kKeyBasedPairingRequest), 1);
EXPECT_EQ(static_cast<int>(FastPairMessageType::kKeyBasedPairingResponse), 2);
EXPECT_EQ(static_cast<int>(FastPairMessageType::kSeekersPasskey), 3);
EXPECT_EQ(static_cast<int>(FastPairMessageType::kProvidersPasskey), 4);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-93
View File
@@ -1,93 +0,0 @@
# Copyright 2023 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.
licenses(["notice"])
cc_library(
name = "dataparser",
srcs = [
"fast_pair_data_parser.cc",
],
hdrs = [
"fast_pair_data_parser.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
":decoder",
"//fastpair/common",
"//fastpair/crypto",
"//internal/base:bluetooth_address",
"//internal/platform:base",
"//internal/platform:types",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "decoder",
srcs = [
"fast_pair_decoder.cc",
],
hdrs = [
"fast_pair_decoder.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
"@com_google_absl//absl/strings",
],
)
cc_test(
name = "fast_pair_data_parser_test",
size = "small",
srcs = [
"fast_pair_data_parser_test.cc",
],
shard_count = 16,
deps = [
":dataparser",
"//fastpair/common",
"//fastpair/crypto",
"//fastpair/testing",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@boringssl//:crypto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_decoder_test",
size = "small",
srcs = [
"fast_pair_decoder_test.cc",
],
shard_count = 16,
deps = [
":decoder",
"//fastpair/testing",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
@@ -1,231 +0,0 @@
// 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 "fastpair/dataparser/fast_pair_data_parser.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <optional>
#include <utility>
#include <vector>
#include "third_party/nearby//fastpair/crypto/fast_pair_decryption.h"
#include "fastpair/common/battery_notification.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "fastpair/dataparser/fast_pair_decoder.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr int kHeaderIndex = 0;
constexpr int kFieldTypeBitmask = 0b00001111;
constexpr int kFieldLengthBitmask = 0b11110000;
constexpr int kHeaderLength = 1;
constexpr int kFieldLengthOffset = 4;
constexpr int kFieldTypeAccountKeyFilter = 0;
constexpr int kFieldTypeAccountKeyFilterSalt = 1;
constexpr int kFieldTypeAccountKeyFilterNoNotification = 2;
constexpr int kFieldTypeBattery = 3;
constexpr int kFieldTypeBatteryNoNotification = 4;
constexpr int kAddressByteSize = 6;
constexpr int kMaxLengthOfSaltBytes = 2;
bool ValidateInputSizes(const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_bytes) {
if (aes_key_bytes.size() != kAesBlockByteSize) {
NEARBY_LOGS(WARNING) << __func__
<< ": AES key should have size = " << kAesBlockByteSize
<< ", actual = " << aes_key_bytes.size();
return false;
}
if (encrypted_bytes.size() != kEncryptedDataByteSize) {
NEARBY_LOGS(WARNING) << __func__ << ": Encrypted bytes should have size = "
<< kEncryptedDataByteSize
<< ", actual = " << encrypted_bytes.size();
return false;
}
return true;
}
void ConvertVectorsToArrays(
const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_bytes,
std::array<uint8_t, kAesBlockByteSize>& out_aes_key_bytes,
std::array<uint8_t, kEncryptedDataByteSize>& out_encrypted_bytes) {
std::copy(aes_key_bytes.begin(), aes_key_bytes.end(),
out_aes_key_bytes.begin());
std::copy(encrypted_bytes.begin(), encrypted_bytes.end(),
out_encrypted_bytes.begin());
}
std::vector<uint8_t> CopyFieldBytesToVector(
const std::vector<uint8_t>& service_data,
const absl::flat_hash_map<size_t, std::pair<size_t, size_t>>& field_indices,
size_t key) {
std::vector<uint8_t> out;
DCHECK(field_indices.contains(key));
auto indices = field_indices.find(key)->second;
for (size_t i = indices.first; i < indices.second; i++) {
out.push_back(service_data[i]);
}
return out;
}
} // namespace
void FastPairDataParser::GetHexModelIdFromServiceData(
const std::vector<uint8_t>& service_data,
GetHexModelIdFromServiceDataCallback callback) {
callback(FastPairDecoder::HasModelId(&service_data)
? FastPairDecoder::GetHexModelIdFromServiceData(&service_data)
: std::nullopt);
}
void FastPairDataParser::ParseDecryptedResponse(
const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_response_bytes,
ParseDecryptResponseCallback callback) {
if (!ValidateInputSizes(aes_key_bytes, encrypted_response_bytes)) {
callback(std::nullopt);
return;
}
std::array<uint8_t, kAesBlockByteSize> key;
std::array<uint8_t, kEncryptedDataByteSize> bytes;
ConvertVectorsToArrays(aes_key_bytes, encrypted_response_bytes, key, bytes);
callback(FastPairDecryption::ParseDecryptResponse(key, bytes));
}
void FastPairDataParser::ParseDecryptedPasskey(
const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_passkey_bytes,
ParseDecryptPasskeyCallback callback) {
if (!ValidateInputSizes(aes_key_bytes, encrypted_passkey_bytes)) {
callback(std::nullopt);
return;
}
std::array<uint8_t, kAesBlockByteSize> key;
std::array<uint8_t, kEncryptedDataByteSize> bytes;
ConvertVectorsToArrays(aes_key_bytes, encrypted_passkey_bytes, key, bytes);
callback(FastPairDecryption::ParseDecryptPasskey(key, bytes));
}
void FastPairDataParser::ParseNotDiscoverableAdvertisement(
absl::string_view fast_pair_service_data, absl::string_view address,
ParseNotDiscoverableAdvertisementCallback callback) {
std::vector<uint8_t> service_data;
std::move(std::begin(fast_pair_service_data),
std::end(fast_pair_service_data), std::back_inserter(service_data));
if (service_data.empty() || FastPairDecoder::GetVersion(&service_data) != 0) {
NEARBY_LOGS(WARNING) << " Invalid service data.";
callback(std::nullopt);
return;
}
absl::flat_hash_map<size_t, std::pair<size_t, size_t>> field_indices;
size_t headerIndex = kHeaderIndex + kHeaderLength +
FastPairDecoder::GetIdLength(&service_data);
while (headerIndex < service_data.size()) {
size_t type = service_data[headerIndex] & kFieldTypeBitmask;
size_t length =
(service_data[headerIndex] & kFieldLengthBitmask) >> kFieldLengthOffset;
size_t index = headerIndex + kHeaderLength;
size_t end = index + length;
if (end <= service_data.size()) {
field_indices[type] = std::make_pair(index, end);
}
headerIndex = end;
}
// Account key filter bytes
std::vector<uint8_t> account_key_filter_bytes;
NonDiscoverableAdvertisement::Type show_ui =
NonDiscoverableAdvertisement::Type::kNone;
if (field_indices.contains(kFieldTypeAccountKeyFilter)) {
account_key_filter_bytes = CopyFieldBytesToVector(
service_data, field_indices, kFieldTypeAccountKeyFilter);
show_ui = NonDiscoverableAdvertisement::Type::kShowUi;
} else if (field_indices.contains(kFieldTypeAccountKeyFilterNoNotification)) {
account_key_filter_bytes = CopyFieldBytesToVector(
service_data, field_indices, kFieldTypeAccountKeyFilterNoNotification);
show_ui = NonDiscoverableAdvertisement::Type::kHideUi;
}
if (account_key_filter_bytes.empty()) {
NEARBY_LOGS(WARNING) << " Service data doesn't contain account key filter.";
callback(std::nullopt);
return;
}
// Salt bytes
std::vector<uint8_t> salt_bytes;
if (field_indices.contains(kFieldTypeAccountKeyFilterSalt)) {
salt_bytes = CopyFieldBytesToVector(service_data, field_indices,
kFieldTypeAccountKeyFilterSalt);
}
// https://developers.devsite.corp.google.com/nearby/fast-pair/specifications/service/provider#AccountKeyFilter
if (salt_bytes.size() > kMaxLengthOfSaltBytes) {
NEARBY_LOGS(WARNING) << " Parsed a salt field larger than two bytes: "
<< salt_bytes.size();
callback(std::nullopt);
return;
}
if (salt_bytes.empty()) {
NEARBY_LOGS(INFO)
<< __func__
<< ": missing salt field from device. Using device address instead.";
std::array<uint8_t, kAddressByteSize> address_bytes;
device::ParseBluetoothAddress(
address, absl::MakeSpan(address_bytes.data(), kAddressByteSize));
salt_bytes =
std::vector<uint8_t>(address_bytes.begin(), address_bytes.end());
}
// Battery info bytes
std::vector<uint8_t> battery_bytes;
BatteryNotification::Type show_ui_for_battery =
BatteryNotification::Type::kNone;
if (field_indices.contains(kFieldTypeBattery)) {
battery_bytes =
CopyFieldBytesToVector(service_data, field_indices, kFieldTypeBattery);
show_ui_for_battery = BatteryNotification::Type::kShowUi;
} else if (field_indices.contains(kFieldTypeBatteryNoNotification)) {
battery_bytes = CopyFieldBytesToVector(service_data, field_indices,
kFieldTypeBatteryNoNotification);
show_ui_for_battery = BatteryNotification::Type::kHideUi;
}
callback(NonDiscoverableAdvertisement(
std::move(account_key_filter_bytes), show_ui, std::move(salt_bytes),
BatteryNotification::FromBytes(battery_bytes, show_ui_for_battery)));
}
} // namespace fastpair
} // namespace nearby
@@ -1,84 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DATA_PARSER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DATA_PARSER_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <functional>
#include <optional>
#include <string>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "fastpair/crypto/decrypted_passkey.h"
#include "fastpair/crypto/decrypted_response.h"
namespace nearby {
namespace fastpair {
// This class is responsible for parsing the untrusted bytes for Fast Pair.
class FastPairDataParser {
using GetHexModelIdFromServiceDataCallback =
absl::AnyInvocable<void(std::optional<absl::string_view>)>;
using ParseDecryptResponseCallback =
absl::AnyInvocable<void(std::optional<DecryptedResponse>)>;
using ParseDecryptPasskeyCallback =
absl::AnyInvocable<void(std::optional<DecryptedPasskey>)>;
using ParseNotDiscoverableAdvertisementCallback =
absl::AnyInvocable<void(std::optional<NonDiscoverableAdvertisement>)>;
public:
// Gets the hex string representation of the device's model ID from the
// service data.
static void GetHexModelIdFromServiceData(
const std::vector<uint8_t>& fast_pair_service_data,
GetHexModelIdFromServiceDataCallback callback);
// Decrypts |encrypted_response_bytes| using |aes_key| and returns a parsed
// DecryptedResponse instance if possible.
static void ParseDecryptedResponse(
const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_response_bytes,
ParseDecryptResponseCallback callback);
// Decrypts |encrypted_passkey_bytes| using |aes_key| and returns a parsed
// DecryptedPasskey instance if possible.
static void ParseDecryptedPasskey(
const std::vector<uint8_t>& aes_key_bytes,
const std::vector<uint8_t>& encrypted_passkey_bytes,
ParseDecryptPasskeyCallback callback);
// Parses a 'Non Discoverable' advertisement from |service_data|.
// If the advertisement does not contain information about salt, use the
// |address| as salt instead.
static void ParseNotDiscoverableAdvertisement(
absl::string_view fast_pair_service_data, absl::string_view address,
ParseNotDiscoverableAdvertisementCallback callback);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DATA_PARSER_H_
@@ -1,720 +0,0 @@
// 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 "fastpair/dataparser/fast_pair_data_parser.h"
#include <stdint.h>
#include <algorithm>
#include <array>
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/non_discoverable_advertisement.h"
#include "fastpair/crypto/fast_pair_encryption.h"
#include "fastpair/testing/fast_pair_service_data_creator.h"
#include "internal/platform/count_down_latch.h"
namespace nearby {
namespace fastpair {
namespace {
// Test data comes from:
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
constexpr absl::string_view kModelId("aabbcc");
constexpr absl::string_view kInvalidModelId("aabb");
constexpr absl::string_view kDeviceAddress("11:12:13:14:15:16");
constexpr absl::string_view kAccountKeyFilter("112233445566");
constexpr absl::string_view kSalt("01");
constexpr absl::string_view kBattery("01048F");
constexpr int kBatteryHeader = 0b00110011;
constexpr std::array<uint8_t, kAesBlockByteSize> kAeskeyarray = {
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6,
0xCF, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
constexpr int kNotDiscoverableAdvHeader = 0b00000110;
constexpr int kAccountKeyFilterHeader = 0b01100000;
constexpr int kSaltHeader = 0b00010001;
TEST(FastPairDataParserTest, GetHexModelIdFromServiceDataUnsucessfully) {
const std::vector<uint8_t> service_data =
FastPairServiceDataCreator::Builder()
.SetModelId(kInvalidModelId)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::GetHexModelIdFromServiceData(
service_data, [&](std::optional<absl::string_view> model_id) {
EXPECT_EQ(model_id, std::nullopt);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, GetHexModelIdFromServiceDataSuccessfully) {
const std::vector<uint8_t> service_data =
FastPairServiceDataCreator::Builder()
.SetModelId(kModelId)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::GetHexModelIdFromServiceData(
service_data, [&](std::optional<absl::string_view> model_id) {
EXPECT_EQ(model_id, kModelId);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptResponseUnsuccessfullyWithInvalidAesKey) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95,
0x1F, 0xF7, 0xB6, 0xCF, 0x5E,
0x3F, 0x45, 0x61, 0xC3, 0x32};
const std::vector<uint8_t> kResponseBytes = {/*message_type=*/0x02,
/*address_bytes=*/0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
/*salt=*/0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x00};
std::array<uint8_t, kAesBlockByteSize> response_bytes_array;
std::copy(kResponseBytes.begin(), kResponseBytes.end(),
response_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, response_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end());
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedResponse(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedResponse> response) {
EXPECT_FALSE(response.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptResponseUnsuccessfullyWithInvalidResponse) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
const std::vector<uint8_t> kResponseBytes = {/*message_type=*/0x02,
/*address_bytes=*/0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
/*salt=*/0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x00};
std::array<uint8_t, kAesBlockByteSize> response_bytes_array;
std::copy(kResponseBytes.begin(), kResponseBytes.end(),
response_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, response_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end() - 1);
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedResponse(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedResponse> response) {
EXPECT_FALSE(response.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptResponseSuccessfully) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
std::vector<uint8_t> response_bytes;
// Message type.
constexpr uint8_t kMessageType = 0x01;
response_bytes.push_back(kMessageType);
// Address bytes.
constexpr std::array<uint8_t, 6> kAddressBytes = {0x02, 0x03, 0x04,
0x05, 0x06, 0x07};
std::copy(kAddressBytes.begin(), kAddressBytes.end(),
std::back_inserter(response_bytes));
// Random salt
constexpr std::array<uint8_t, 9> kSalt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x00};
std::copy(kSalt.begin(), kSalt.end(), std::back_inserter(response_bytes));
std::array<uint8_t, kAesBlockByteSize> response_bytes_array;
std::copy(response_bytes.begin(), response_bytes.end(),
response_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, response_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end());
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedResponse(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedResponse> response) {
ASSERT_TRUE(response.has_value());
EXPECT_EQ(response.value().message_type,
FastPairMessageType::kKeyBasedPairingResponse);
EXPECT_EQ(response.value().address_bytes, kAddressBytes);
EXPECT_EQ(response.value().salt, kSalt);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptPasskeyUnsuccessfullyWithInvalidAesKey) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95,
0x1F, 0xF7, 0xB6, 0xCF, 0x5E,
0x3F, 0x45, 0x61, 0xC3, 0x32};
const std::vector<uint8_t> kPasskeyBytes = {/*message_type=*/0x02,
/*address_bytes=*/0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
/*salt=*/0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x00};
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
std::copy(kPasskeyBytes.begin(), kPasskeyBytes.end(),
passkey_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, passkey_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end());
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedPasskey(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedPasskey> decrypted_passkey) {
EXPECT_FALSE(decrypted_passkey.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptPasskeyUnsuccessfullyWithInvalidPasskey) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
const std::vector<uint8_t> kPasskeyBytes = {/*message_type=*/0x04,
/*passkey=*/0x02,
0x03,
0x04,
/*salt=*/0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F};
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
std::copy(kPasskeyBytes.begin(), kPasskeyBytes.end(),
passkey_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, passkey_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end() - 1);
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedPasskey(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedPasskey> decrypted_passkey) {
EXPECT_FALSE(decrypted_passkey.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptSeekerPasskeySuccessfully) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
std::vector<uint8_t> passkey_bytes;
// Message type.
constexpr uint8_t kMessageType = 0x02;
passkey_bytes.push_back(kMessageType);
// Passkey bytes.
constexpr uint32_t kPasskey = 5;
passkey_bytes.push_back(kPasskey >> 16);
passkey_bytes.push_back(kPasskey >> 8);
passkey_bytes.push_back(kPasskey);
// Random salt
constexpr std::array<uint8_t, 12> kSalt = {
0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E, 0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
std::copy(kSalt.begin(), kSalt.end(), std::back_inserter(passkey_bytes));
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
std::copy(passkey_bytes.begin(), passkey_bytes.end(),
passkey_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, passkey_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end());
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedPasskey(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedPasskey> decrypted_passkey) {
ASSERT_TRUE(decrypted_passkey.has_value());
EXPECT_EQ(decrypted_passkey.value().message_type,
FastPairMessageType::kSeekersPasskey);
EXPECT_EQ(decrypted_passkey.value().passkey, kPasskey);
EXPECT_EQ(decrypted_passkey.value().salt, kSalt);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, DecryptProviderPasskeySuccessfully) {
const std::vector<uint8_t> kAesKeyBytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D};
std::vector<uint8_t> passkey_bytes;
// Message type.
constexpr uint8_t kMessageType = 0x03;
passkey_bytes.push_back(kMessageType);
// Passkey bytes.
constexpr uint32_t kPasskey = 5;
passkey_bytes.push_back(kPasskey >> 16);
passkey_bytes.push_back(kPasskey >> 8);
passkey_bytes.push_back(kPasskey);
// Random salt
constexpr std::array<uint8_t, 12> kSalt = {
0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E, 0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
std::copy(kSalt.begin(), kSalt.end(), std::back_inserter(passkey_bytes));
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
std::copy(passkey_bytes.begin(), passkey_bytes.end(),
passkey_bytes_array.begin());
auto encrypted_bytes_array =
FastPairEncryption::EncryptBytes(kAeskeyarray, passkey_bytes_array);
std::vector<uint8_t> encrypted_bytes(encrypted_bytes_array.begin(),
encrypted_bytes_array.end());
CountDownLatch latch(1);
FastPairDataParser::ParseDecryptedPasskey(
kAesKeyBytes, encrypted_bytes,
[&](std::optional<DecryptedPasskey> decrypted_passkey) {
ASSERT_TRUE(decrypted_passkey.has_value());
EXPECT_EQ(decrypted_passkey.value().message_type,
FastPairMessageType::kProvidersPasskey);
EXPECT_EQ(decrypted_passkey.value().passkey, kPasskey);
EXPECT_EQ(decrypted_passkey.value().salt, kSalt);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementEmpty) {
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
"", kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest,
ParseNotDiscoverableAdvertisementNoApplicibleData) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest,
ParseNotDiscoverableAdvertisementAccountKeyFilter) {
const std::vector<uint8_t> kSaltBytes = {0x01};
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kSaltBytes);
EXPECT_EQ(advertisement->type,
NonDiscoverableAdvertisement::Type::kShowUi);
EXPECT_FALSE(advertisement->battery_notification.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest,
ParseNotDiscoverableAdvertisementAccountKeyFilterNoNotification) {
const std::vector<uint8_t> kSaltBytes = {0x01};
std::vector<uint8_t> bytes =
FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(
/*accountKeyFilterNoNotificationHeader*/ 0b01100010)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kSaltBytes);
EXPECT_EQ(advertisement->type,
NonDiscoverableAdvertisement::Type::kHideUi);
EXPECT_FALSE(advertisement->battery_notification.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementWrongVersion) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(/*InvalidHeader*/ 0b00100000)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest,
ParseNotDiscoverableAdvertisementZeroLengthExtraField) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField("")
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementWrongType) {
std::vector<uint8_t> bytes =
FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader /*InvalidType*/ (0b01100001)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementSaltTwoBytes) {
const std::vector<uint8_t> kLargeSaltBytes = {0xC7, 0xC8};
std::vector<uint8_t> bytes =
FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(/*SaltTwoBytes*/ 0b00100001)
.AddExtraField(/*LargeSalt*/ "C7C8")
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kLargeSaltBytes);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementSaltTooLarge) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(0b00110001)
.AddExtraField(/*invalidSalt*/ "C7C8C9")
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
EXPECT_FALSE(advertisement.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementWithBattery) {
const std::vector<uint8_t> kSaltBytes = {0x01};
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.AddExtraFieldHeader(kBatteryHeader)
.AddExtraField(kBattery)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kSaltBytes);
EXPECT_EQ(advertisement->type,
NonDiscoverableAdvertisement::Type::kShowUi);
ASSERT_TRUE(advertisement->battery_notification.has_value());
EXPECT_EQ(advertisement->battery_notification->type,
BatteryNotification::Type::kShowUi);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(0)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(0).percentage,
1);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(1)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(1).percentage,
4);
ASSERT_TRUE(advertisement->battery_notification->battery_infos.at(2)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(2).percentage,
15);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementMissingSalt) {
const std::vector<uint8_t> kDeviceAddressBytes = {17, 18, 19, 20, 21, 22};
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kBatteryHeader)
.AddExtraField(kBattery)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kDeviceAddressBytes);
EXPECT_EQ(advertisement->type,
NonDiscoverableAdvertisement::Type::kShowUi);
ASSERT_TRUE(advertisement->battery_notification.has_value());
EXPECT_EQ(advertisement->battery_notification->type,
BatteryNotification::Type::kShowUi);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(0)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(0).percentage,
1);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(1)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(1).percentage,
4);
ASSERT_TRUE(advertisement->battery_notification->battery_infos.at(2)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(2).percentage,
15);
latch.CountDown();
});
latch.Await();
}
TEST(FastPairDataParserTest, ParseNotDiscoverableAdvertisementWithBatteryNoUi) {
const std::vector<uint8_t> kSaltBytes = {0x01};
std::vector<uint8_t> bytes =
FastPairServiceDataCreator::Builder()
.SetHeader(kNotDiscoverableAdvHeader)
.SetModelId(kModelId)
.AddExtraFieldHeader(kAccountKeyFilterHeader)
.AddExtraField(kAccountKeyFilter)
.AddExtraFieldHeader(kSaltHeader)
.AddExtraField(kSalt)
.AddExtraFieldHeader(/*batterHeaderNoNotification*/ 0b00110100)
.AddExtraField(kBattery)
.Build()
->CreateServiceData();
CountDownLatch latch(1);
FastPairDataParser::ParseNotDiscoverableAdvertisement(
std::string(bytes.begin(), bytes.end()), kDeviceAddress,
[&](const std::optional<NonDiscoverableAdvertisement> advertisement) {
ASSERT_TRUE(advertisement.has_value());
EXPECT_EQ(absl::BytesToHexString(
std::string(advertisement->account_key_filter.begin(),
advertisement->account_key_filter.end())),
kAccountKeyFilter);
EXPECT_EQ(advertisement->salt, kSaltBytes);
EXPECT_EQ(advertisement->type,
NonDiscoverableAdvertisement::Type::kShowUi);
ASSERT_TRUE(advertisement->battery_notification.has_value());
EXPECT_EQ(advertisement->battery_notification->type,
BatteryNotification::Type::kHideUi);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(0)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(0).percentage,
1);
EXPECT_FALSE(advertisement->battery_notification->battery_infos.at(1)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(1).percentage,
4);
ASSERT_TRUE(advertisement->battery_notification->battery_infos.at(2)
.is_charging);
EXPECT_EQ(
advertisement->battery_notification->battery_infos.at(2).percentage,
15);
latch.CountDown();
});
latch.Await();
}
} // namespace
} // namespace fastpair
} // namespace nearby
-104
View File
@@ -1,104 +0,0 @@
// 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 "fastpair/dataparser/fast_pair_decoder.h"
#include <algorithm>
#include <array>
#include <iterator>
#include <optional>
#include <string>
#include <vector>
#include "absl/strings/escaping.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr int kHeaderIndex = 0;
constexpr int kHeaderLength = 1;
constexpr int kHeaderLengthBitmask = 0b00011110;
constexpr int kHeaderLengthOffset = 1;
constexpr int kHeaderVersionBitmask = 0b11100000;
constexpr int kHeaderVersionOffset = 5;
constexpr int kMinModelIdLength = 3;
constexpr int kMaxModelIdLength = 14;
} // namespace
int FastPairDecoder::GetIdLength(const std::vector<uint8_t>* service_data) {
return service_data->size() == kMinModelIdLength
? kMinModelIdLength
: ((*service_data)[kHeaderIndex] & kHeaderLengthBitmask) >>
kHeaderLengthOffset;
}
int FastPairDecoder::GetVersion(const std::vector<uint8_t>* service_data) {
return service_data->size() == kMinModelIdLength
? 0
: ((*service_data)[kHeaderIndex] & kHeaderVersionBitmask) >>
kHeaderVersionOffset;
}
bool IsIdLengthValid(const std::vector<uint8_t>* service_data) {
int id_length = FastPairDecoder::GetIdLength(service_data);
return kMinModelIdLength <= id_length && id_length <= kMaxModelIdLength &&
id_length + kHeaderLength <= static_cast<int>(service_data->size());
}
bool FastPairDecoder::HasModelId(const std::vector<uint8_t>* service_data) {
return service_data != nullptr &&
(service_data->size() == kMinModelIdLength ||
// Header byte exists. We support only format version 0. (A different
// version indicates a breaking change in the format.)
(service_data->size() > kMinModelIdLength &&
GetVersion(service_data) == 0 && IsIdLengthValid(service_data)));
}
std::optional<std::string> FastPairDecoder::GetHexModelIdFromServiceData(
const std::vector<uint8_t>* service_data) {
if (service_data == nullptr || service_data->size() < kMinModelIdLength) {
return std::nullopt;
}
if (service_data->size() == kMinModelIdLength) {
// If the size is 3, all the bytes are the ID,
std::vector<uint8_t> bytes = *service_data;
std::string model_id(bytes.begin(), bytes.end());
return absl::BytesToHexString(model_id);
}
// Otherwise, the first byte is a header which contains the length of the
// big-endian model ID that follows. The model ID will be trimmed if it
// contains leading zeros.
int id_index = 1;
int end = id_index + GetIdLength(service_data);
// Ignore leading zeros.
while ((*service_data)[id_index] == 0 && end - id_index > kMinModelIdLength) {
id_index++;
}
// Copy appropriate bytes to new array.
int bytes_size = end - id_index;
std::vector<uint8_t> bytes;
bytes.reserve(bytes_size);
for (int i = 0; i < bytes_size; i++) {
bytes.push_back((*service_data)[i + id_index]);
}
std::string model_id(bytes.begin(), bytes.end());
return absl::BytesToHexString(model_id);
}
} // namespace fastpair
} // namespace nearby
-38
View File
@@ -1,38 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DECODER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DECODER_H_
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
namespace nearby {
namespace fastpair {
class FastPairDecoder {
public:
static int GetVersion(const std::vector<uint8_t>* service_data);
static int GetIdLength(const std::vector<uint8_t>* service_data);
static bool HasModelId(const std::vector<uint8_t>* service_data);
static std::optional<std::string> GetHexModelIdFromServiceData(
const std::vector<uint8_t>* service_data);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_DATAPARSER_FAST_PAIR_DECODER_H_
@@ -1,143 +0,0 @@
// 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 "fastpair/dataparser/fast_pair_decoder.h"
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
#include "fastpair/testing/fast_pair_service_data_creator.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr char kModelId[7] = "aabbcc";
constexpr char kLongModelId[17] = "1122334455667788";
constexpr char kPaddedModelId[9] = "00001111";
constexpr char kTrimmedModelId[7] = "001111";
constexpr uint8_t kLongModelIdHeader = 0b00010000;
constexpr uint8_t kPaddedLongModelIdHeader = 0b00001000;
bool HasModelIdString(std::string model_id) {
std::string bytes_str = absl::HexStringToBytes(model_id);
std::vector<uint8_t> model_id_bytes;
std::move(std::begin(bytes_str), std::end(bytes_str),
std::back_inserter(model_id_bytes));
return FastPairDecoder::HasModelId(&model_id_bytes);
}
TEST(FastPairDecoderTest, HasModelIdThreeByteFormat) {
EXPECT_TRUE(HasModelIdString(kModelId));
}
TEST(FastPairDecoderTest, HasModelIdTooShort) {
EXPECT_FALSE(HasModelIdString("11"));
}
TEST(FastPairDecoderTest, HasModelIdLongFormat) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(0b00001000)
.SetModelId("11223344")
.Build()
->CreateServiceData();
EXPECT_TRUE(FastPairDecoder::HasModelId(&bytes));
bytes = FastPairServiceDataCreator::Builder()
.SetHeader(0b00001010)
.SetModelId("1122334455")
.Build()
->CreateServiceData();
EXPECT_TRUE(FastPairDecoder::HasModelId(&bytes));
}
TEST(FastPairDecoderTest, HasModelIdLongInvalidVersion) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(0b00101000)
.SetModelId("11223344")
.Build()
->CreateServiceData();
EXPECT_FALSE(FastPairDecoder::HasModelId(&bytes));
}
TEST(FastPairDecoderTest, HasModelIdLongInvalidLength) {
std::vector<uint8_t> bytes = FastPairServiceDataCreator::Builder()
.SetHeader(0b00001010)
.SetModelId("11223344")
.Build()
->CreateServiceData();
EXPECT_FALSE(FastPairDecoder::HasModelId(&bytes));
bytes = FastPairServiceDataCreator::Builder()
.SetHeader(0b00000010)
.SetModelId("11223344")
.Build()
->CreateServiceData();
EXPECT_FALSE(FastPairDecoder::HasModelId(&bytes));
}
TEST(FastPairDecoderTest, GetHexModelIdFromServiceDataNoResultForNullData) {
EXPECT_EQ(FastPairDecoder::GetHexModelIdFromServiceData(nullptr),
absl::nullopt);
}
TEST(FastPairDecoderTest, GetHexModelIdFromServiceDataNoResultForEmptyData) {
std::vector<uint8_t> empty;
EXPECT_EQ(FastPairDecoder::GetHexModelIdFromServiceData(&empty),
absl::nullopt);
}
TEST(FastPairDecoderTest, GetHexModelIdFromServiceDataThreeByteData) {
std::vector<uint8_t> service_data = FastPairServiceDataCreator::Builder()
.SetModelId(kModelId)
.Build()
->CreateServiceData();
EXPECT_EQ(FastPairDecoder::GetHexModelIdFromServiceData(&service_data),
kModelId);
}
TEST(FastPairDecoderTest, GetHexModelIdFromServiceDataLongModelId) {
std::vector<uint8_t> service_data = FastPairServiceDataCreator::Builder()
.SetHeader(kLongModelIdHeader)
.SetModelId(kLongModelId)
.Build()
->CreateServiceData();
EXPECT_EQ(FastPairDecoder::GetHexModelIdFromServiceData(&service_data),
kLongModelId);
}
TEST(FastPairDecoderTest, GetHexModelIdFromServiceDataLongModelIdTrimmed) {
std::vector<uint8_t> service_data = FastPairServiceDataCreator::Builder()
.SetHeader(kPaddedLongModelIdHeader)
.SetModelId(kPaddedModelId)
.Build()
->CreateServiceData();
EXPECT_EQ(FastPairDecoder::GetHexModelIdFromServiceData(&service_data),
kTrimmedModelId);
}
} // namespace
} // namespace fastpair
} // namespace nearby
-190
View File
@@ -1,190 +0,0 @@
// Copyright 2023 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 "fastpair/fast_pair_controller.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "fastpair/common/protocol.h"
#include "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include "fastpair/message_stream/message_stream.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
FastPairController::FastPairController(Mediums* mediums, FastPairDevice* device,
SingleThreadExecutor* executor)
: mediums_(mediums), device_(device), executor_(executor) {}
absl::Status FastPairController::OpenMessageStream() {
message_stream_ = std::make_unique<MessageStream>(
*device_, &mediums_->GetBluetoothClassic().GetMedium(), *this);
return message_stream_->OpenRfcomm();
}
void FastPairController::AddMessageStreamConnectionObserver(
MessageStreamConnectionObserver* observer) {
connection_observers_.AddObserver(observer);
if (message_stream_status_.ok() && observer->on_connected != nullptr) {
observer->on_connected(*device_);
} else if (!message_stream_status_.ok() &&
observer->on_disconnected != nullptr) {
observer->on_disconnected(*device_, message_stream_status_);
}
}
void FastPairController::RemoveMessageStreamConnectionObserver(
MessageStreamConnectionObserver* observer) {
connection_observers_.RemoveObserver(observer);
}
void FastPairController::AddAddressRotationObserver(
BleAddressRotationObserver* observer) {
address_rotation_observers_.AddObserver(observer);
if (!device_->GetBleAddress().empty()) {
observer->on_ble_address_rotated(*device_, device_->GetBleAddress());
}
}
void FastPairController::RemoveAddressRotationObserver(
BleAddressRotationObserver* observer) {
address_rotation_observers_.RemoveObserver(observer);
}
void FastPairController::AddModelIdObserver(ModelIdObserver* observer) {
model_id_observers_.AddObserver(observer);
if (!device_->GetModelId().empty()) {
observer->on_model_id(*device_);
}
}
void FastPairController::RemoveModelIdObserver(ModelIdObserver* observer) {
model_id_observers_.RemoveObserver(observer);
}
Future<std::shared_ptr<FastPairDataEncryptor>>
FastPairController::GetDataEncryptor() {
if (!encryptor_) {
encryptor_ =
std::make_unique<Future<std::shared_ptr<FastPairDataEncryptor>>>();
if (device_->GetMetadata()) {
CreateDataEncryptor();
} else {
FastPairRepository::Get()->GetDeviceMetadata(
device_->GetModelId(),
[this](std::optional<DeviceMetadata> metadata) {
if (!metadata.has_value()) {
NEARBY_LOGS(WARNING)
<< __func__ << ": Failed to get device metadata";
return;
}
device_->SetMetadata(metadata.value());
CreateDataEncryptor();
});
}
}
return *encryptor_;
}
void FastPairController::CreateDataEncryptor() {
FastPairDataEncryptorImpl::Factory::CreateAsync(
*device_, [borrowable = lender_.GetBorrowable()](
std::unique_ptr<FastPairDataEncryptor> encryptor) mutable {
auto borrowed = borrowable.Borrow();
if (borrowed) {
(*borrowed)->SetDataEncryptor(std::move(encryptor));
}
});
}
Future<FastPairController::GattClientRef>
FastPairController::GetGattClientRef() {
Future<FastPairController::GattClientRef> result;
if (gatt_client_ == nullptr) {
gatt_client_ref_count_ = 0;
gatt_client_ = FastPairGattServiceClientImpl::Factory::Create(
*device_, *mediums_, executor_);
gatt_client_->InitializeGattConnection(
[](std::optional<PairFailure> result) {
if (result.has_value()) {
NEARBY_LOGS(INFO) << "InitializeGattConnection: " << result.value();
} else {
NEARBY_LOGS(INFO) << "InitializeGattConnection: OK";
}
});
}
result.Set(GattClientRef(this));
return result;
}
// MessageStream::Observer callbacks
void FastPairController::OnConnectionResult(absl::Status result) {
NEARBY_LOGS(INFO) << "OnConnectionResult " << result;
message_stream_status_ = result;
if (!result.ok()) {
NEARBY_LOGS(INFO) << "Connection attempt failed with " << result;
return;
}
for (auto* observer : connection_observers_.GetObservers()) {
if (observer->on_connected != nullptr) {
observer->on_connected(*device_);
}
}
}
void FastPairController::OnDisconnected(absl::Status status) {
NEARBY_LOGS(INFO) << "OnDisconnected " << status;
message_stream_status_ = status;
for (auto* observer : connection_observers_.GetObservers()) {
if (observer->on_disconnected != nullptr) {
observer->on_disconnected(*device_, status);
}
}
}
void FastPairController::OnEnableSilenceMode(bool enable) {}
void FastPairController::OnLogBufferFull() {}
void FastPairController::OnModelId(absl::string_view model_id) {
device_->SetModelId(absl::BytesToHexString(model_id));
NEARBY_LOGS(INFO) << "Setting model id: " << device_->GetModelId();
for (auto* observer : model_id_observers_.GetObservers()) {
observer->on_model_id(*device_);
}
}
void FastPairController::OnBleAddressUpdated(absl::string_view address) {
std::string old_address = std::string(device_->GetBleAddress());
device_->SetBleAddress(address);
for (auto* observer : address_rotation_observers_.GetObservers()) {
observer->on_ble_address_rotated(*device_, old_address);
}
}
void FastPairController::OnBatteryUpdated(
std::vector<MessageStream::BatteryInfo> battery_levels) {}
void FastPairController::OnRemainingBatteryTime(absl::Duration duration) {}
bool FastPairController::OnRing(uint8_t components, absl::Duration duration) {
return false;
}
} // namespace fastpair
} // namespace nearby
-201
View File
@@ -1,201 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_CONTROLLER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_CONTROLLER_H_
#include <atomic>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_gatt_service_client_impl.h"
#include "fastpair/message_stream/message_stream.h"
#include "internal/base/observer_list.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/borrowable.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
class FastPairController : public MessageStream::Observer {
public:
struct MessageStreamConnectionObserver {
// Callback triggered when a Message Stream connection is opened.
absl::AnyInvocable<void(const FastPairDevice& device)> on_connected;
// Callback triggered when a Message Stream connection is terminated.
absl::AnyInvocable<void(const FastPairDevice& device, absl::Status status)>
on_disconnected;
};
struct BleAddressRotationObserver {
absl::AnyInvocable<void(const FastPairDevice& device,
absl::string_view old_address)>
on_ble_address_rotated;
};
struct ModelIdObserver {
absl::AnyInvocable<void(const FastPairDevice& device)> on_model_id;
};
// RAII accessor to GattClient
class GattClientRef {
public:
GattClientRef() = default;
explicit GattClientRef(FastPairController* controller)
: controller_(controller) {
CHECK(controller_ != nullptr);
controller_->AcquireGattClient();
}
GattClientRef(const GattClientRef& other) {
controller_ = other.controller_;
if (controller_ != nullptr) {
controller_->AcquireGattClient();
}
}
GattClientRef(GattClientRef&& other) {
controller_ = other.controller_;
other.controller_ = nullptr;
}
GattClientRef& operator=(const GattClientRef& other) {
if (controller_ != nullptr) {
controller_->ReleaseGattClient();
}
controller_ = other.controller_;
if (controller_ != nullptr) {
controller_->AcquireGattClient();
}
return *this;
}
GattClientRef& operator=(GattClientRef&& other) {
if (controller_ != nullptr) {
controller_->ReleaseGattClient();
}
controller_ = other.controller_;
other.controller_ = nullptr;
return *this;
}
~GattClientRef() {
if (controller_ != nullptr) {
controller_->ReleaseGattClient();
}
}
FastPairGattServiceClient* operator->() {
CHECK(controller_ != nullptr);
return controller_->GetGattClient();
}
private:
FastPairController* controller_ = nullptr;
};
// Creates a device controller in retroactive pairing path.
FastPairController(Mediums* mediums, FastPairDevice* device,
SingleThreadExecutor* executor);
~FastPairController() override {
NEARBY_LOGS(INFO) << "Destroy FastPairController";
lender_.Release();
connection_observers_.Clear();
address_rotation_observers_.Clear();
model_id_observers_.Clear();
message_stream_.reset();
NEARBY_LOGS(INFO) << "Destroyed FastPairController";
}
absl::Status OpenMessageStream();
// Registers an observer for connection events. The observer must stay alive
// until it is removed.
// The callback is also called during registration with the current state
// of the connection.
void AddMessageStreamConnectionObserver(
MessageStreamConnectionObserver* observer);
void RemoveMessageStreamConnectionObserver(
MessageStreamConnectionObserver* observer);
// Registers an observer for BLE address rotation.
// The callback is also called during registration with the current BLE
// address unless FP does not know the device's address.
void AddAddressRotationObserver(BleAddressRotationObserver* observer);
void RemoveAddressRotationObserver(BleAddressRotationObserver* observer);
void AddModelIdObserver(ModelIdObserver* observer);
void RemoveModelIdObserver(ModelIdObserver* observer);
Future<std::shared_ptr<FastPairDataEncryptor>> GetDataEncryptor();
Future<GattClientRef> GetGattClientRef();
// MessageStream::Observer callbacks
void OnConnectionResult(absl::Status result) override;
void OnDisconnected(absl::Status status) override;
void OnEnableSilenceMode(bool enable) override;
void OnLogBufferFull() override;
void OnModelId(absl::string_view model_id) override;
void OnBleAddressUpdated(absl::string_view address) override;
void OnBatteryUpdated(
std::vector<MessageStream::BatteryInfo> battery_levels) override;
void OnRemainingBatteryTime(absl::Duration duration) override;
bool OnRing(uint8_t components, absl::Duration duration) override;
FastPairDevice& GetDevice() { return *device_; }
std::string GetSeekerMacAddress() const {
return mediums_->GetBluetoothClassic().GetMedium().GetMacAddress();
}
private:
void SetDataEncryptor(std::unique_ptr<FastPairDataEncryptor> encryptor) {
if (encryptor != nullptr) {
encryptor_->Set(std::move(encryptor));
} else {
encryptor_->SetException({Exception::kFailed});
}
}
void AcquireGattClient() { ++gatt_client_ref_count_; }
void ReleaseGattClient() {
if (--gatt_client_ref_count_ == 0) {
gatt_client_.reset();
}
}
FastPairGattServiceClient* GetGattClient() {
CHECK(gatt_client_ != nullptr);
return gatt_client_.get();
}
void CreateDataEncryptor();
Mediums* mediums_;
FastPairDevice* device_;
SingleThreadExecutor* executor_;
std::unique_ptr<Future<std::shared_ptr<FastPairDataEncryptor>>> encryptor_;
std::unique_ptr<MessageStream> message_stream_;
absl::Status message_stream_status_ =
absl::FailedPreconditionError("not connected");
ObserverList<MessageStreamConnectionObserver> connection_observers_;
ObserverList<BleAddressRotationObserver> address_rotation_observers_;
ObserverList<ModelIdObserver> model_id_observers_;
// TODO(jsobczak): Improve locking around gatt_client_
std::unique_ptr<FastPairGattServiceClient> gatt_client_;
std::atomic_int gatt_client_ref_count_;
Lender<FastPairController*> lender_{this};
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_CONTROLLER_H_
-83
View File
@@ -1,83 +0,0 @@
// Copyright 2023 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 "fastpair/fast_pair_controller.h"
#include <memory>
#include <string>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
#include "fastpair/message_stream/fake_provider.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
class FastPairControllerTest : public testing::Test {
protected:
void SetUp() override {
BluetoothClassicMedium& seeker_medium =
mediums_.GetBluetoothClassic().GetMedium();
provider_.DiscoverProvider(seeker_medium);
std::string address = provider_.GetMacAddress();
NEARBY_LOGS(INFO) << "Provider address: " << address;
remote_device_ = seeker_medium.GetRemoteDevice(provider_.GetMacAddress());
ASSERT_TRUE(remote_device_.IsValid());
fast_pair_device_ =
std::make_unique<FastPairDevice>(Protocol::kFastPairRetroactivePairing);
fast_pair_device_->SetPublicAddress(remote_device_.GetMacAddress());
}
void TearDown() override {
executor_.Shutdown();
provider_.Shutdown();
MediumEnvironment::Instance().Stop();
}
// The medium environment must be initialized (started) before adding
// adapters.
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
Mediums mediums_;
FakeProvider provider_;
BluetoothDevice remote_device_;
std::unique_ptr<FastPairDevice> fast_pair_device_;
};
TEST_F(FastPairControllerTest, Constructor) {
FastPairController controller(&mediums_, &*fast_pair_device_, &executor_);
}
TEST_F(FastPairControllerTest, OpenMessageStream) {
FastPairController controller(&mediums_, &*fast_pair_device_, &executor_);
EXPECT_OK(controller.OpenMessageStream());
}
} // namespace
} // namespace fastpair
} // namespace nearby
-43
View File
@@ -1,43 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_EVENTS_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_EVENTS_H_
#include <optional>
namespace nearby {
namespace fastpair {
// Fast Pair plugins receive notifications from the FP service about various
// system events. The structures below provide details about the events.
struct InitialDiscoveryEvent {};
struct SubsequentDiscoveryEvent {};
struct PairEvent {
bool is_paired;
};
struct ScreenEvent {
std::optional<bool> is_locked;
};
struct BatteryEvent {};
struct RingEvent {};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_EVENTS_H_
-58
View File
@@ -1,58 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_PLUGIN_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_PLUGIN_H_
#include <memory>
#include "fastpair/fast_pair_events.h"
#include "fastpair/fast_pair_seeker.h"
namespace nearby {
namespace fastpair {
class FastPairPlugin {
public:
virtual ~FastPairPlugin() = default;
// All functions below are synchronous.
virtual void OnInitialDiscoveryEvent(const InitialDiscoveryEvent& event) {}
virtual void OnSubsequentDiscoveryEvent(
const SubsequentDiscoveryEvent& event) {}
// Handles pair, unpair events.
virtual void OnPairEvent(const PairEvent& event) {}
virtual void OnScreenEvent(const ScreenEvent& event) {}
virtual void OnBatteryEvent(const BatteryEvent& event) {}
virtual void OnRingEvent(const RingEvent& event) {}
};
class FastPairPluginProvider {
public:
virtual ~FastPairPluginProvider() = default;
// Returns an instance of `FastPairPlugin`.
//
// The plugin can use the `seeker` to communicate with the Fast Pair Seeker
// Service. `seeker` is always non-null and has a lifetime at least as long as
// the plugin returned by this call.
// `device` is a non-null.
virtual std::unique_ptr<FastPairPlugin> GetPlugin(
FastPairSeeker* seeker, const FastPairDevice* device) = 0;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_PLUGIN_H_
-102
View File
@@ -1,102 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SEEKER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SEEKER_H_
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "fastpair/common/fast_pair_device.h"
namespace nearby {
namespace fastpair {
// Pairing result callback.
struct PairingCallback {
absl::AnyInvocable<void(const FastPairDevice&, absl::Status)>
on_pairing_result =
[](const FastPairDevice& device, absl::Status status) {};
};
// Initial Pairing parameters.
struct InitialPairingParam {};
// Subsequent Pairing parameters.
struct SubsequentPairingParam {};
// Retroactive Pairing parameters.
struct RetroactivePairingParam {};
// Finish Retroactive Pairing parameters.
struct FinishRetroactivePairingParam {
// Save the negotiated Account Key or abandon it and forget the Fast Pair
// Device.
bool save_account_key = false;
};
// Fast Pair Seeker API available to plugins.
class FastPairSeeker {
public:
virtual ~FastPairSeeker() = default;
// Starts asynchronous initial pairing flow. This pairing flow is used with
// devices that we see for the first time.
//
// Returns an error if pairing flow could not be started. Otherwise, the
// pairing result will be returned via the `callback`.
virtual absl::Status StartInitialPairing(const FastPairDevice& device,
const InitialPairingParam& params,
PairingCallback callback) = 0;
// Starts asynchronous subsequent pairing flow. This pairing flow is used when
// device is an already known peripheral. The user paired with that device in
// the past, perhaps using a different seeker and `device` already has an
// Account Key.
//
// Returns an error if pairing flow could not be started. Otherwise, the
// pairing result will be returned via the `callback`.
virtual absl::Status StartSubsequentPairing(
const FastPairDevice& device, const SubsequentPairingParam& params,
PairingCallback callback) = 0;
// Starts asynchronous retroactive pairing flow. This pairing flow is used
// when the user has paired manually with a new device and we want to
// retroactively exchange an Account Key. See:
// https://developers.google.com/nearby/fast-pair/specifications/extensions/retroactiveacctkey
// The retroactive pairing flow should be started immediately after the
// pairing event, before we had a chance to ask for the user for permission.
// Therefore, the retroactive is split into two stages. The client should call
// `StartRetroactivePairing()` first. When the pairing result returned via
// `callback` is successful, the client should ask the user for permission to
// save the account key. Finally, the client should call
// `FinishRetroactivePairing()` with the user's decision to complete the
// retroactive pairing flow.
//
// Returns an error if pairing flow could not be started. Otherwise, the
// pairing result will be returned via the `callback`.
virtual absl::Status StartRetroactivePairing(
const FastPairDevice& device, const RetroactivePairingParam& param,
PairingCallback callback) = 0;
// Finishes the retroactive pairing flow.
//
// Returns an error if the flow could not be started. Otherwise, the
// result will be returned via the `callback`.
virtual absl::Status FinishRetroactivePairing(
const FastPairDevice& device, const FinishRetroactivePairingParam& param,
PairingCallback callback) = 0;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SEEKER_H_
-210
View File
@@ -1,210 +0,0 @@
// Copyright 2023 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 "fastpair/fast_pair_service.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "fastpair/common/fast_pair_prefs.h"
#include "fastpair/fast_pair_plugin.h"
#include "fastpair/internal/fast_pair_seeker_impl.h"
#include "fastpair/repository/fast_pair_repository_impl.h"
#include "fastpair/server_access/fast_pair_client_impl.h"
#include "fastpair/server_access/fast_pair_http_notifier.h"
#include "internal/account/account_manager_impl.h"
#include "internal/auth/authentication_manager_impl.h"
#include "internal/flags/nearby_flags.h"
#include "internal/network/http_client_impl.h"
#include "internal/platform/device_info_impl.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/flags/nearby_platform_feature_flags.h"
#include "internal/platform/logging.h"
#include "internal/platform/task_runner_impl.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr char kFastPairPreferencesFilePath[] = "Google/Nearby/FastPair";
constexpr FeatureFlags::Flags fast_pair_feature_flags = FeatureFlags::Flags{
.enable_scan_for_fast_pair_advertisement = true,
.skip_service_discovery_before_connecting_to_rfcomm = true,
};
constexpr absl::Duration kTimeout = absl::Seconds(3);
} // namespace
FastPairService::FastPairService()
: FastPairService(std::make_unique<auth::AuthenticationManagerImpl>(),
std::make_unique<network::NearbyHttpClient>(),
std::make_unique<DeviceInfoImpl>()) {}
FastPairService::FastPairService(
std::unique_ptr<auth::AuthenticationManager> authentication_manager,
std::unique_ptr<network::HttpClient> http_client,
std::unique_ptr<DeviceInfo> device_info)
: authentication_manager_(std::move(authentication_manager)),
http_client_(std::move(http_client)),
device_info_(std::move(device_info)),
task_runner_(std::make_unique<TaskRunnerImpl>(1)),
preferences_manager_(std::make_unique<preferences::PreferencesManager>(
kFastPairPreferencesFilePath)),
account_manager_(AccountManagerImpl::Factory::Create(
preferences_manager_.get(), prefs::kNearbyFastPairUsersName,
authentication_manager_.get(), task_runner_.get())),
fast_pair_client_(std::make_unique<FastPairClientImpl>(
authentication_manager_.get(), account_manager_.get(),
http_client_.get(), &fast_pair_http_notifier_, device_info_.get())),
fast_pair_repository_(
std::make_unique<FastPairRepositoryImpl>(fast_pair_client_.get())),
on_device_destroyed_callback_(
[this](const FastPairDevice& device) { OnDeviceDestroyed(device); }) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
platform::config_package_nearby::nearby_platform_feature::
kEnableBleV2Gatt,
true);
const_cast<FeatureFlags&>(FeatureFlags::GetInstance())
.SetFlags(fast_pair_feature_flags);
devices_.AddObserver(&on_device_destroyed_callback_);
seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
[this](const FastPairDevice& device,
InitialDiscoveryEvent event) {
OnInitialDiscoveryEvent(device, std::move(event));
},
.on_subsequent_discovery =
[this](const FastPairDevice& device,
SubsequentDiscoveryEvent event) {
OnSubsequentDiscoveryEvent(device, std::move(event));
},
.on_pair_event =
[this](const FastPairDevice& device, PairEvent event) {
OnPairEvent(device, std::move(event));
},
.on_screen_event =
[this](ScreenEvent event) { OnScreenEvent(std::move(event)); },
.on_battery_event =
[this](const FastPairDevice& device, BatteryEvent event) {
OnBatteryEvent(device, std::move(event));
},
.on_ring_event =
[this](const FastPairDevice& device, RingEvent event) {
OnRingEvent(device, std::move(event));
}},
&executor_, account_manager_.get(), &devices_,
fast_pair_repository_.get());
}
FastPairService::~FastPairService() { executor_.Shutdown(); }
absl::Status FastPairService::RegisterPluginProvider(
absl::string_view name, std::unique_ptr<FastPairPluginProvider> provider) {
Future<absl::Status> result;
executor_.Execute("register-plugin", [&]() {
bool success = plugin_states_
.insert({std::string(name),
PluginState{.provider = std::move(provider)}})
.second;
absl::Status status = success
? absl::OkStatus()
: absl::AlreadyExistsError(absl::StrFormat(
"Plugin '%s' already registered", name));
result.Set(status);
});
ExceptionOr<absl::Status> status = result.Get(kTimeout);
return status.ok() ? status.GetResult()
: absl::DeadlineExceededError("Register plugin timeout");
}
absl::Status FastPairService::UnregisterPluginProvider(absl::string_view name) {
Future<absl::Status> result;
executor_.Execute("unregister-plugin", [&]() {
bool success = success = plugin_states_.erase(name);
absl::Status status = success
? absl::OkStatus()
: absl::NotFoundError(absl::StrFormat(
"Plugin '%s' already registered", name));
result.Set(status);
});
ExceptionOr<absl::Status> status = result.Get(kTimeout);
return status.ok() ? status.GetResult()
: absl::DeadlineExceededError("Unregister plugin timeout");
}
void FastPairService::OnInitialDiscoveryEvent(const FastPairDevice& device,
InitialDiscoveryEvent event) {
executor_.Execute("on-initial-discovery", [this, device = &device,
event = std::move(event)]() {
NEARBY_LOGS(INFO) << "OnInitialDiscoveryEvent " << *device;
for (auto& entry : plugin_states_) {
auto plugin = entry.second.GetPlugin(seeker_.get(), device);
plugin->OnInitialDiscoveryEvent(event);
}
});
}
void FastPairService::OnSubsequentDiscoveryEvent(
const FastPairDevice& device, SubsequentDiscoveryEvent event) {}
void FastPairService::OnPairEvent(const FastPairDevice& device,
PairEvent event) {
executor_.Execute(
"on-pair-event", [this, device = &device, event = std::move(event)]() {
NEARBY_LOGS(INFO) << "OnPairEvent " << *device;
for (auto& entry : plugin_states_) {
auto plugin = entry.second.GetPlugin(seeker_.get(), device);
plugin->OnPairEvent(event);
}
});
}
void FastPairService::OnScreenEvent(ScreenEvent event) {
executor_.Execute("on-screen-event", [this, event = std::move(event)]() {
NEARBY_LOGS(INFO) << "OnScreenEvent ";
for (auto& entry : plugin_states_) {
for (auto& plugin : entry.second.plugins) {
plugin.second->OnScreenEvent(event);
}
}
});
}
void FastPairService::OnBatteryEvent(const FastPairDevice& device,
BatteryEvent event) {}
void FastPairService::OnRingEvent(const FastPairDevice& device,
RingEvent event) {}
void FastPairService::OnDeviceDestroyed(const FastPairDevice& device) {
NEARBY_LOGS(INFO) << "OnDeviceDestroyed " << device;
for (auto& entry : plugin_states_) {
entry.second.plugins.erase(&device);
}
}
FastPairPlugin* FastPairService::PluginState::GetPlugin(
FastPairSeeker* seeker, const FastPairDevice* device) {
auto it = plugins.find(device);
if (it != plugins.end()) {
return it->second.get();
}
auto result = plugins.insert({device, provider->GetPlugin(seeker, device)});
DCHECK(result.second);
return result.first->second.get();
}
} // namespace fastpair
} // namespace nearby
-117
View File
@@ -1,117 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SERVICE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SERVICE_H_
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "fastpair/fast_pair_plugin.h"
#include "fastpair/fast_pair_seeker.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/server_access/fast_pair_client.h"
#include "fastpair/server_access/fast_pair_http_notifier.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/auth/authentication_manager.h"
#include "internal/network/http_client.h"
#include "internal/platform/device_info.h"
#include "internal/platform/implementation/account_manager.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/task_runner.h"
#include "internal/preferences/preferences_manager.h"
namespace nearby {
namespace fastpair {
// Fast Pair Seeker Service. There should be only one instance of the service
// running on the system.
class FastPairService {
public:
FastPairService();
// Constructor for tests. Allows us to inject a serverless metadata
// repository.
FastPairService(
std::unique_ptr<auth::AuthenticationManager> authentication_manager,
std::unique_ptr<network::HttpClient> http_client,
std::unique_ptr<DeviceInfo> device_info);
~FastPairService();
// Registers a plugin provider. `name` must be a unique.
// Returns an error if a provider with the same `name` is already registered.
absl::Status RegisterPluginProvider(
absl::string_view name, std::unique_ptr<FastPairPluginProvider> provider);
// Unregisters a plugin provider and removes all plugins created by that
// provider. Returns an error if there is no plugin provider registered with
// `name`.
absl::Status UnregisterPluginProvider(absl::string_view name);
// Returns a `FastPairSeeker` implementation. The returned object has the
// same lifetime as this `FastPairService` instance.
FastPairSeeker* GetSeeker() const { return seeker_.get(); }
// Returns a `AccountManager` implementation. The returned object has the
// same lifetime as this `FastPairService` instance.
AccountManager* GetAccountManager() { return account_manager_.get(); }
// Returns a `FastPairRepository` implementation. The returned object has the
// same lifetime as this `FastPairService` instance.
FastPairRepository* GetFastPairRepository() {
return fast_pair_repository_.get();
}
private:
struct PluginState {
// Gets the plugin for `device`. Creates the plugin if it does not exist.
FastPairPlugin* GetPlugin(FastPairSeeker* seeker,
const FastPairDevice* device);
std::unique_ptr<FastPairPluginProvider> provider;
absl::flat_hash_map<const FastPairDevice*, std::unique_ptr<FastPairPlugin>>
plugins;
};
void OnInitialDiscoveryEvent(const FastPairDevice& device,
InitialDiscoveryEvent event);
void OnSubsequentDiscoveryEvent(const FastPairDevice& device,
SubsequentDiscoveryEvent event);
void OnPairEvent(const FastPairDevice& device, PairEvent event);
void OnScreenEvent(ScreenEvent event);
void OnBatteryEvent(const FastPairDevice& device, BatteryEvent event);
void OnRingEvent(const FastPairDevice& device, RingEvent event);
void OnDeviceDestroyed(const FastPairDevice& device);
SingleThreadExecutor executor_;
FastPairHttpNotifier fast_pair_http_notifier_;
std::unique_ptr<FastPairSeeker> seeker_;
// Plugin name is the key.
absl::flat_hash_map<std::string, PluginState> plugin_states_;
FastPairDeviceRepository devices_{&executor_};
std::unique_ptr<auth::AuthenticationManager> authentication_manager_;
std::unique_ptr<network::HttpClient> http_client_;
std::unique_ptr<DeviceInfo> device_info_;
std::unique_ptr<TaskRunner> task_runner_;
std::unique_ptr<preferences::PreferencesManager> preferences_manager_;
std::unique_ptr<AccountManager> account_manager_;
std::unique_ptr<FastPairClient> fast_pair_client_;
std::unique_ptr<FastPairRepository> fast_pair_repository_;
FastPairDeviceRepository::RemoveDeviceCallback on_device_destroyed_callback_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_FAST_PAIR_SERVICE_H_
-185
View File
@@ -1,185 +0,0 @@
// Copyright 2023 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 "fastpair/fast_pair_service.h"
#include <memory>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "fastpair/fast_pair_events.h"
#include "fastpair/internal/fast_pair_seeker_impl.h"
#include "fastpair/message_stream/fake_provider.h"
#include "fastpair/plugins/fake_fast_pair_plugin.h"
#include "internal/account/account_manager_impl.h"
#include "internal/network/http_client.h"
#include "internal/platform/device_info.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/test/fake_account_manager.h"
#include "internal/test/fake_device_info.h"
#include "internal/test/fake_http_client.h"
#include "internal/test/google3_only/fake_authentication_manager.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::string_view kPluginName = "my plugin";
constexpr absl::string_view kModelId{"718c17"};
constexpr absl::string_view kPublicAntiSpoof =
"Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+"
"0wVcljfT3XPoiy1fntlneziyLD5knDVAJSE+RM/zlPRP/Jg==";
using ::testing::status::StatusIs;
class FastPairServiceTest : public ::testing::Test {
protected:
FastPairServiceTest() {
AccountManagerImpl::Factory::SetFactoryForTesting([]() {
return std::make_unique<nearby::FakeAccountManager>();
});
http_client_ = std::make_unique<network::FakeHttpClient>();
device_info_ = std::make_unique<FakeDeviceInfo>();
authentication_manager_ =
std::make_unique<nearby::FakeAuthenticationManager>();
}
void SetUp() override {
MediumEnvironment::Instance().Start();
GetAuthManager()->EnableSyncMode();
}
void TearDown() override {
AccountManagerImpl::Factory::SetFactoryForTesting(nullptr);
MediumEnvironment::Instance().Stop();
}
nearby::FakeAuthenticationManager* GetAuthManager() {
return reinterpret_cast<nearby::FakeAuthenticationManager*>(
authentication_manager_.get());
}
network::FakeHttpClient* GetHttpClient() {
return reinterpret_cast<network::FakeHttpClient*>(http_client_.get());
}
void SetUpDeviceMetadata() {
proto::GetObservedDeviceResponse response_proto;
auto* device = response_proto.mutable_device();
int64_t device_id;
CHECK(absl::SimpleHexAtoi(kModelId, &device_id));
device->set_id(device_id);
network::HttpResponse response;
response.SetStatusCode(network::HttpStatusCode::kHttpOk);
response.SetBody(response_proto.SerializeAsString());
GetHttpClient()->SetResponseForSyncRequest(response);
}
std::unique_ptr<auth::AuthenticationManager> authentication_manager_;
std::unique_ptr<network::HttpClient> http_client_;
std::unique_ptr<DeviceInfo> device_info_;
};
TEST(FastPairService, RegisterUnregister) {
FastPairService service;
EXPECT_OK(service.RegisterPluginProvider(
kPluginName, std::make_unique<FakeFastPairPluginProvider>()));
EXPECT_OK(service.UnregisterPluginProvider(kPluginName));
}
TEST(FastPairService, RegisterTwiceFails) {
FastPairService service;
EXPECT_OK(service.RegisterPluginProvider(
kPluginName, std::make_unique<FakeFastPairPluginProvider>()));
EXPECT_THAT(service.RegisterPluginProvider(
kPluginName, std::make_unique<FakeFastPairPluginProvider>()),
StatusIs(absl::StatusCode::kAlreadyExists));
}
TEST(FastPairService, UnregisterTwiceFails) {
FastPairService service;
EXPECT_OK(service.RegisterPluginProvider(
kPluginName, std::make_unique<FakeFastPairPluginProvider>()));
EXPECT_OK(service.UnregisterPluginProvider(kPluginName));
EXPECT_THAT(service.UnregisterPluginProvider(kPluginName),
StatusIs(absl::StatusCode::kNotFound));
}
TEST_F(FastPairServiceTest, InitialDiscoveryEvent) {
FakeProvider provider;
SetUpDeviceMetadata();
FastPairService service(std::move(authentication_manager_),
std::move(http_client_), std::move(device_info_));
CountDownLatch latch(1);
auto plugin_provider = std::make_unique<FakeFastPairPluginProvider>();
plugin_provider->on_initial_discovery_event_ =
[&](const FastPairDevice* device, const InitialDiscoveryEvent& event) {
NEARBY_LOGS(INFO) << "Initial discovery: " << device;
EXPECT_EQ(device->GetModelId(), kModelId);
latch.CountDown();
};
EXPECT_OK(
service.RegisterPluginProvider(kPluginName, std::move(plugin_provider)));
FastPairSeekerExt* seeker =
static_cast<FastPairSeekerExt*>(service.GetSeeker());
EXPECT_OK(seeker->StartFastPairScan());
provider.StartDiscoverableAdvertisement(kModelId);
latch.Await();
EXPECT_OK(seeker->StopFastPairScan());
EXPECT_OK(service.UnregisterPluginProvider(kPluginName));
}
TEST_F(FastPairServiceTest, ScreenEvent) {
FakeProvider provider;
SetUpDeviceMetadata();
FastPairService service(std::move(authentication_manager_),
std::move(http_client_), std::move(device_info_));
CountDownLatch latch(1);
auto plugin_provider = std::make_unique<FakeFastPairPluginProvider>();
plugin_provider->on_initial_discovery_event_ =
[&](const FastPairDevice* device, const InitialDiscoveryEvent& event) {
NEARBY_LOGS(INFO) << "Initial discovery: " << device;
EXPECT_EQ(device->GetModelId(), kModelId);
latch.CountDown();
};
plugin_provider->on_screen_event_ = [&](ScreenEvent event) {
EXPECT_TRUE(event.is_locked);
latch.CountDown();
};
EXPECT_OK(
service.RegisterPluginProvider(kPluginName, std::move(plugin_provider)));
FastPairSeekerExt* seeker =
static_cast<FastPairSeekerExt*>(service.GetSeeker());
EXPECT_OK(seeker->StartFastPairScan());
provider.StartDiscoverableAdvertisement(kModelId);
seeker->SetIsScreenLocked(true);
latch.Await();
EXPECT_OK(seeker->StopFastPairScan());
EXPECT_OK(service.UnregisterPluginProvider(kPluginName));
}
} // namespace
} // namespace fastpair
} // namespace nearby
-172
View File
@@ -1,172 +0,0 @@
# 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.
licenses(["notice"])
cc_library(
name = "handshake",
srcs = [
"fast_pair_data_encryptor_impl.cc",
"fast_pair_gatt_service_client_impl.cc",
"fast_pair_handshake_impl.cc",
"fast_pair_handshake_lookup.cc",
],
hdrs = [
"fast_pair_data_encryptor.h",
"fast_pair_data_encryptor_impl.h",
"fast_pair_gatt_service_client.h",
"fast_pair_gatt_service_client_impl.h",
"fast_pair_handshake.h",
"fast_pair_handshake_impl.h",
"fast_pair_handshake_lookup.h",
],
visibility = [
"//:__subpackages__",
"//fastpair:__subpackages__",
],
deps = [
"//fastpair/common",
"//fastpair/crypto",
"//fastpair/dataparser",
"//fastpair/internal/mediums",
"//fastpair/repository",
"//internal/base:bluetooth_address",
"//internal/platform:comm",
"//internal/platform:types",
"//internal/platform:uuid",
"@boringssl//:crypto",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
],
)
cc_library(
name = "test_support",
hdrs = [
"fake_fast_pair_data_encryptor.h",
"fake_fast_pair_gatt_service_client.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
":handshake",
"//fastpair/common",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
],
)
cc_test(
name = "fast_pair_data_encryptor_impl_test",
size = "small",
srcs = [
"fast_pair_data_encryptor_impl_test.cc",
],
shard_count = 16,
deps = [
":handshake",
"//fastpair/common",
"//fastpair/crypto",
"//fastpair/dataparser",
"//fastpair/internal/mediums",
"//fastpair/repository:test_support",
"//fastpair/testing",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_gatt_service_client_impl_test",
size = "small",
srcs = [
"fast_pair_gatt_service_client_impl_test.cc",
],
shard_count = 16,
deps = [
":handshake",
":test_support",
"//fastpair/common",
"//fastpair/internal/mediums",
"//fastpair/testing",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/test",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_handshake_impl_test",
size = "small",
srcs = [
"fast_pair_handshake_impl_test.cc",
],
shard_count = 16,
deps = [
":handshake",
":test_support",
"//fastpair/common",
"//fastpair/crypto",
"//fastpair/proto:fastpair_cc_proto",
"//internal/platform:base",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "fast_pair_handshake_lookup_test",
size = "small",
srcs = [
"fast_pair_handshake_lookup_test.cc",
],
shard_count = 16,
deps = [
":handshake",
"//fastpair/common",
"//fastpair/internal/mediums",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
@@ -1,85 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
#include <array>
#include <optional>
#include <utility>
#include <vector>
#include "fastpair/common/constant.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
namespace nearby {
namespace fastpair {
class FakeFastPairDataEncryptor : public FastPairDataEncryptor {
public:
FakeFastPairDataEncryptor() = default;
void SetPublickey(std::optional<std::array<uint8_t, 64>> public_key) {
public_key_ = std::move(public_key);
}
void SetEncryptedBytes(
std::array<uint8_t, kAesBlockByteSize> encrypted_bytes) {
encrypted_bytes_ = std::move(encrypted_bytes);
}
void SetResponse(std::optional<DecryptedResponse> response) {
response_ = std::move(response);
}
void SetPasskey(std::optional<DecryptedPasskey> passkey) {
passkey_ = std::move(passkey);
}
// FastPairDataEncryptor:
std::array<uint8_t, kAesBlockByteSize> EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt)
const override {
return encrypted_bytes_;
}
std::optional<std::array<uint8_t, 64>> GetPublicKey() const override {
return public_key_;
}
void ParseDecryptResponse(
const std::vector<uint8_t>& encrypted_response_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedResponse>)> callback)
override {
callback(response_);
}
void ParseDecryptPasskey(
const std::vector<uint8_t>& encrypted_passkey_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedPasskey>)> callback)
override {
callback(passkey_);
}
private:
std::optional<std::array<uint8_t, 64>> public_key_;
std::array<uint8_t, kAesBlockByteSize> encrypted_bytes_;
std::optional<DecryptedResponse> response_;
std::optional<DecryptedPasskey> passkey_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
@@ -1,80 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
#include <optional>
#include <utility>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
namespace nearby {
namespace fastpair {
// This class fakes FastPairGattServiceClient and permits setting which
// PairFailure, if any, is run with the callback.
class FakeFastPairGattServiceClient : public FastPairGattServiceClient {
public:
void InitializeGattConnection(
absl::AnyInvocable<void(std::optional<PairFailure>)>
on_gatt_initialized_callback) override {
on_initialized_callback_ = std::move(on_gatt_initialized_callback);
}
void WriteRequestAsync(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) override {
key_based_write_response_callback_ = std::move(write_response_callback);
}
void WritePasskeyAsync(
uint8_t message_type, uint32_t passkey,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) override {
passkey_write_response_callback_ = std::move(write_response_callback);
}
void RunOnGattClientInitializedCallback(
std::optional<PairFailure> failure = std::nullopt) {
std::move(on_initialized_callback_)(failure);
}
void RunWriteResponseCallback(
absl::string_view value,
std::optional<PairFailure> failure = std::nullopt) {
std::move(key_based_write_response_callback_)(value, failure);
}
void RunWritePasskeyCallback(
absl::string_view value,
std::optional<PairFailure> failure = std::nullopt) {
std::move(passkey_write_response_callback_)(value, failure);
}
private:
absl::AnyInvocable<void(std::optional<PairFailure>)> on_initialized_callback_;
WriteResponseCallback key_based_write_response_callback_;
WriteResponseCallback passkey_write_response_callback_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
@@ -1,63 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <functional>
#include <optional>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "fastpair/common/constant.h"
#include "fastpair/crypto/decrypted_passkey.h"
#include "fastpair/crypto/decrypted_response.h"
namespace nearby {
namespace fastpair {
// Holds a secret key for a device and has methods to encrypt bytes, decrypt
// response and decrypt passkey.
class FastPairDataEncryptor {
public:
virtual ~FastPairDataEncryptor() = default;
// Encrypts bytes with the stored secret key.
virtual std::array<uint8_t, kAesBlockByteSize> EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt) const = 0;
// Return stored PublicKey
virtual std::optional<std::array<uint8_t, 64>> GetPublicKey() const = 0;
// Decrypt and parse decrypted response bytes with the stored secret key.
virtual void ParseDecryptResponse(
const std::vector<uint8_t>& encrypted_response_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedResponse>)>
callback) = 0;
// Decrypt and parse decrypted passkey bytes with the stored secret key.
virtual void ParseDecryptPasskey(
const std::vector<uint8_t>& encrypted_passkey_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedPasskey>)>
callback) = 0;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_H_
@@ -1,172 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iterator>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/protocol.h"
#include "fastpair/crypto/decrypted_passkey.h"
#include "fastpair/crypto/decrypted_response.h"
#include "fastpair/crypto/fast_pair_encryption.h"
#include "fastpair/crypto/fast_pair_key_pair.h"
#include "fastpair/dataparser/fast_pair_data_parser.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
namespace {
FastPairDataEncryptorImpl::Factory* g_test_factory_ = nullptr;
bool ValidateInputSize(const std::vector<uint8_t>& encrypted_bytes) {
if (encrypted_bytes.size() != kAesBlockByteSize) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Encrypted bytes should have size = "
<< kAesBlockByteSize
<< ", actual = " << encrypted_bytes.size();
return false;
}
return true;
}
} // namespace
// FastPairDataEncryptorImpl::Factory
void FastPairDataEncryptorImpl::Factory::SetFactoryForTesting(
Factory* g_test_factory) {
g_test_factory_ = g_test_factory;
}
FastPairDataEncryptorImpl::Factory::~Factory() = default;
void FastPairDataEncryptorImpl::Factory::CreateAsync(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback) {
if (g_test_factory_) {
g_test_factory_->CreateInstance(device,
std::move(on_get_instance_callback));
return;
}
if (device.GetProtocol() == Protocol::kFastPairInitialPairing ||
device.GetProtocol() == Protocol::kFastPairRetroactivePairing) {
CreateAsyncWithKeyExchange(device, std::move(on_get_instance_callback));
} else {
CreateAsyncWithAccountKey(device, std::move(on_get_instance_callback));
}
}
void FastPairDataEncryptorImpl::Factory::CreateAsyncWithKeyExchange(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback) {
NEARBY_LOGS(VERBOSE) << __func__;
auto& metadata = device.GetMetadata();
DCHECK(metadata);
std::optional<KeyPair> key_pair =
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
metadata->GetDetails().anti_spoofing_key_pair().public_key());
if (!key_pair.has_value()) {
NEARBY_LOGS(INFO) << "Fail to generate key pair";
std::move(on_get_instance_callback)(nullptr);
return;
}
auto data_encryptor =
std::make_unique<FastPairDataEncryptorImpl>(key_pair.value());
std::move(on_get_instance_callback)(std::move(data_encryptor));
}
void FastPairDataEncryptorImpl::Factory::CreateAsyncWithAccountKey(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback) {
NEARBY_LOGS(INFO) << __func__;
absl::string_view account_key = device.GetAccountKey().GetAsBytes();
CHECK_EQ(account_key.size(), static_cast<size_t>(kSharedSecretKeyByteSize));
std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key;
std::copy_n(account_key.begin(), kSharedSecretKeyByteSize,
shared_secret_key.begin());
std::move(on_get_instance_callback)(
std::make_unique<FastPairDataEncryptorImpl>(
std::move(shared_secret_key)));
}
// FastPairDataEncryptorImpl
FastPairDataEncryptorImpl::FastPairDataEncryptorImpl(const KeyPair& key_pair)
: shared_secret_key_(key_pair.shared_secret_key),
public_key_(key_pair.public_key) {}
FastPairDataEncryptorImpl::FastPairDataEncryptorImpl(
const std::array<uint8_t, kSharedSecretKeyByteSize>& shared_secret_key)
: shared_secret_key_(shared_secret_key) {}
FastPairDataEncryptorImpl::~FastPairDataEncryptorImpl() = default;
std::array<uint8_t, kAesBlockByteSize> FastPairDataEncryptorImpl::EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt) const {
return FastPairEncryption::EncryptBytes(shared_secret_key_, bytes_to_encrypt);
}
std::optional<std::array<uint8_t, kPublicKeyByteSize>>
FastPairDataEncryptorImpl::GetPublicKey() const {
return public_key_;
}
void FastPairDataEncryptorImpl::ParseDecryptResponse(
const std::vector<uint8_t>& encrypted_response_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedResponse>)> callback) {
if (!ValidateInputSize(encrypted_response_bytes)) {
callback(std::nullopt);
return;
}
FastPairDataParser::ParseDecryptedResponse(
std::vector<uint8_t>(shared_secret_key_.begin(),
shared_secret_key_.end()),
encrypted_response_bytes, std::move(callback));
}
void FastPairDataEncryptorImpl::ParseDecryptPasskey(
const std::vector<uint8_t>& encrypted_passkey_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedPasskey>)> callback) {
if (!ValidateInputSize(encrypted_passkey_bytes)) {
callback(std::nullopt);
return;
}
FastPairDataParser::ParseDecryptedPasskey(
std::vector<uint8_t>(shared_secret_key_.begin(),
shared_secret_key_.end()),
encrypted_passkey_bytes, std::move(callback));
}
} // namespace fastpair
} // namespace nearby
@@ -1,103 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
#include <stdint.h>
#include <array>
#include <functional>
#include <memory>
#include <optional>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/crypto/fast_pair_key_pair.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
namespace nearby {
namespace fastpair {
// Holds a secret key for a device and has methods to encrypt bytes, decrypt
// response and decrypt passkey.
class FastPairDataEncryptorImpl : public FastPairDataEncryptor {
public:
class Factory {
public:
static void CreateAsync(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback);
static void SetFactoryForTesting(Factory* test_factory);
protected:
virtual ~Factory();
virtual void CreateInstance(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback) = 0;
private:
static void CreateAsyncWithKeyExchange(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback);
static void CreateAsyncWithAccountKey(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback);
};
std::array<uint8_t, kAesBlockByteSize> EncryptBytes(
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt)
const override;
std::optional<std::array<uint8_t, kPublicKeyByteSize>> GetPublicKey()
const override;
void ParseDecryptResponse(
const std::vector<uint8_t>& encrypted_response_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedResponse>)> callback)
override;
void ParseDecryptPasskey(
const std::vector<uint8_t>& encrypted_passkey_bytes,
absl::AnyInvocable<void(const std::optional<DecryptedPasskey>)> callback)
override;
explicit FastPairDataEncryptorImpl(const KeyPair& key_pair);
explicit FastPairDataEncryptorImpl(
const std::array<uint8_t, kSharedSecretKeyByteSize>& secret_key);
~FastPairDataEncryptorImpl() override;
private:
const std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key_;
// The public key is only required during initial pairing and optional during
// communication with paired devices.
const std::optional<std::array<uint8_t, kPublicKeyByteSize>> public_key_ =
std::nullopt;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
@@ -1,323 +0,0 @@
// 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 "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include <array>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
#include "absl/functional/bind_front.h"
#include "absl/strings/escaping.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/protocol.h"
#include "fastpair/crypto/fast_pair_encryption.h"
#include "fastpair/dataparser/fast_pair_data_parser.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "internal/platform/count_down_latch.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr std::array<uint8_t, kAesBlockByteSize> kResponseBytes = {
0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D,
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6};
constexpr std::array<uint8_t, kAesBlockByteSize> kPasskeyBytes = {
0x02, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D,
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6};
constexpr char kPublicAntiSpoof[] =
"Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+"
"0wVcljfT3XPoiy1fntlneziyLD5knDVAJSE+RM/zlPRP/Jg==";
constexpr char kInvalidPublicAntiSpoof[] = "InvalidPublicAntiSpoof";
constexpr char kValidModelId[] = "718c17";
constexpr char kTestAddress[] = "test_address";
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200);
class FastPairDataEncryptorImplTest : public testing::Test {
public:
void TearDown() override { data_encryptor_.reset(); }
void FailedSetUpDeviceWithNoPublicKey() {
proto::GetObservedDeviceResponse response;
std::string decoded_key;
absl::Base64Unescape(kInvalidPublicAntiSpoof, &decoded_key);
response.mutable_device()->mutable_anti_spoofing_key_pair()->set_public_key(
decoded_key);
FastPairDevice device(kValidModelId, kTestAddress,
Protocol::kFastPairInitialPairing);
device.SetMetadata(DeviceMetadata(response));
CountDownLatch latch(1);
FastPairDataEncryptorImpl::Factory::CreateAsync(
device, absl::bind_front(
&FastPairDataEncryptorImplTest::OnDataEncryptorCreateAsync,
this, latch));
latch.Await();
}
void SuccessCreateFastPairDataEncryptorWithKeyExchange() {
proto::GetObservedDeviceResponse response;
std::string decoded_key;
absl::Base64Unescape(kPublicAntiSpoof, &decoded_key);
response.mutable_device()->mutable_anti_spoofing_key_pair()->set_public_key(
decoded_key);
FastPairDevice device(kValidModelId, kTestAddress,
Protocol::kFastPairInitialPairing);
device.SetMetadata(DeviceMetadata(response));
CountDownLatch latch(1);
FastPairDataEncryptorImpl::Factory::CreateAsync(
device, absl::bind_front(
&FastPairDataEncryptorImplTest::OnDataEncryptorCreateAsync,
this, latch));
latch.Await();
}
void SuccessCreateFastPairDataEncryptorWithAccountKey() {
FastPairDevice device(kValidModelId, kTestAddress,
Protocol::kFastPairSubsequentPairing);
const std::vector<uint8_t> kAccountKey{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
device.SetAccountKey(
AccountKey(std::string(kAccountKey.begin(), kAccountKey.end())));
CountDownLatch latch(1);
FastPairDataEncryptorImpl::Factory::CreateAsync(
device, absl::bind_front(
&FastPairDataEncryptorImplTest::OnDataEncryptorCreateAsync,
this, latch));
latch.Await();
}
void OnDataEncryptorCreateAsync(
CountDownLatch latch,
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
data_encryptor_ = std::move(fast_pair_data_encryptor);
latch.CountDown();
}
std::array<uint8_t, kAesBlockByteSize> EncryptBytes() {
return data_encryptor_->EncryptBytes(kResponseBytes);
}
void ParseDecryptedResponse() {
const std::array<uint8_t, kAesBlockByteSize> bytes =
data_encryptor_->EncryptBytes(kResponseBytes);
CountDownLatch latch(1);
data_encryptor_->ParseDecryptResponse(
std::vector<uint8_t>(bytes.begin(), bytes.end()),
absl::bind_front(
&FastPairDataEncryptorImplTest::ParseDecryptedResponseCallback,
this, latch));
latch.Await();
}
void ParseDecryptedResponseInvalidBytes() {
const std::array<uint8_t, kAesBlockByteSize> bytes =
data_encryptor_->EncryptBytes(kResponseBytes);
CountDownLatch latch(1);
data_encryptor_->ParseDecryptResponse(
std::vector<uint8_t>(bytes.begin() + 3, bytes.end()),
absl::bind_front(
&FastPairDataEncryptorImplTest::ParseDecryptedResponseCallback,
this, latch));
latch.Await();
}
void ParseDecryptedResponseCallback(
CountDownLatch latch, const std::optional<DecryptedResponse>& response) {
response_ = response;
latch.CountDown();
}
void ParseDecryptedPasskey() {
const std::array<uint8_t, kAesBlockByteSize> bytes =
data_encryptor_->EncryptBytes(kPasskeyBytes);
CountDownLatch latch(1);
data_encryptor_->ParseDecryptPasskey(
std::vector<uint8_t>(bytes.begin(), bytes.end()),
absl::bind_front(
&FastPairDataEncryptorImplTest::ParseDecryptPasskeyCallback, this,
latch));
latch.Await();
}
void ParseDecryptedPasskeyWithAccountKey() {
const std::array<uint8_t, kSharedSecretKeyByteSize> kAccountKey{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
auto bytes = FastPairEncryption::EncryptBytes(kAccountKey, kPasskeyBytes);
CountDownLatch latch(1);
data_encryptor_->ParseDecryptPasskey(
std::vector<uint8_t>(bytes.begin(), bytes.end()),
absl::bind_front(
&FastPairDataEncryptorImplTest::ParseDecryptPasskeyCallback, this,
latch));
latch.Await();
}
void ParseDecryptedPasskeyInvalidBytes() {
const std::array<uint8_t, kAesBlockByteSize> bytes =
data_encryptor_->EncryptBytes(kPasskeyBytes);
CountDownLatch latch(1);
data_encryptor_->ParseDecryptPasskey(
std::vector<uint8_t>(bytes.begin() + 3, bytes.end()),
absl::bind_front(
&FastPairDataEncryptorImplTest::ParseDecryptPasskeyCallback, this,
latch));
latch.Await();
}
void ParseDecryptResponseCallback(
CountDownLatch latch, const std::optional<DecryptedResponse>& response) {
response_ = response;
}
void ParseDecryptPasskeyCallback(
CountDownLatch latch, const std::optional<DecryptedPasskey>& passkey) {
passkey_ = passkey;
latch.CountDown();
}
protected:
std::unique_ptr<FastPairDataEncryptor> data_encryptor_;
std::optional<DecryptedResponse> response_ = std::nullopt;
std::optional<DecryptedPasskey> passkey_ = std::nullopt;
std::unique_ptr<FastPairDataParser> data_parser_;
private:
std::unique_ptr<FastPairDevice> device_;
};
TEST_F(FastPairDataEncryptorImplTest, NoKeyPair) {
FailedSetUpDeviceWithNoPublicKey();
EXPECT_FALSE(data_encryptor_);
}
TEST_F(FastPairDataEncryptorImplTest,
SuccessCreateFastPairDataEncryptorWithKeyExchange) {
EXPECT_FALSE(data_encryptor_);
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
}
TEST_F(FastPairDataEncryptorImplTest,
SuccessCreateFastPairDataEncryptorWithAccountKey) {
EXPECT_FALSE(data_encryptor_);
SuccessCreateFastPairDataEncryptorWithAccountKey();
EXPECT_TRUE(data_encryptor_);
}
TEST_F(FastPairDataEncryptorImplTest, GetPublicKey) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
EXPECT_NE(data_encryptor_->GetPublicKey(), std::nullopt);
}
TEST_F(FastPairDataEncryptorImplTest, GetNoPublicKey) {
SuccessCreateFastPairDataEncryptorWithAccountKey();
EXPECT_TRUE(data_encryptor_);
EXPECT_EQ(data_encryptor_->GetPublicKey(), std::nullopt);
}
TEST_F(FastPairDataEncryptorImplTest, EncryptBytesWithKeyExchange) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
EXPECT_FALSE(EncryptBytes().empty());
}
TEST_F(FastPairDataEncryptorImplTest, EncryptBytesWithAccountKey) {
SuccessCreateFastPairDataEncryptorWithAccountKey();
EXPECT_TRUE(data_encryptor_);
EXPECT_FALSE(EncryptBytes().empty());
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedResponseWithKeyExchange) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedResponse();
EXPECT_TRUE(response_);
const std::array<uint8_t, kDecryptedResponseAddressByteSize> kAddressBytes = {
0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32};
EXPECT_EQ(response_->address_bytes, kAddressBytes);
EXPECT_EQ(response_->message_type,
FastPairMessageType::kKeyBasedPairingResponse);
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedResponseWithAccountKey) {
SuccessCreateFastPairDataEncryptorWithAccountKey();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedResponse();
EXPECT_TRUE(response_);
const std::array<uint8_t, kDecryptedResponseAddressByteSize> kAddressBytes = {
0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32};
EXPECT_EQ(response_->address_bytes, kAddressBytes);
EXPECT_EQ(response_->message_type,
FastPairMessageType::kKeyBasedPairingResponse);
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedResponseInvalidInputSize) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedResponseInvalidBytes();
EXPECT_FALSE(response_);
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedPasskeyWithKeyExchange) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedPasskey();
EXPECT_TRUE(passkey_);
// Passkey bytes.
std::array<uint8_t, 3> passkey_bytes = {0x5E, 0x3F, 0x45};
uint32_t passkey = passkey_bytes[2];
passkey += passkey_bytes[1] << 8;
passkey += passkey_bytes[0] << 16;
EXPECT_EQ(passkey_->passkey, passkey);
EXPECT_EQ(passkey_->message_type, FastPairMessageType::kSeekersPasskey);
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedPasskeyWithAccountKey) {
SuccessCreateFastPairDataEncryptorWithAccountKey();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedPasskeyWithAccountKey();
EXPECT_TRUE(passkey_);
// Passkey bytes.
std::array<uint8_t, 3> passkey_bytes = {0x5E, 0x3F, 0x45};
uint32_t passkey = passkey_bytes[2];
passkey += passkey_bytes[1] << 8;
passkey += passkey_bytes[0] << 16;
EXPECT_EQ(passkey_->passkey, passkey);
EXPECT_EQ(passkey_->message_type, FastPairMessageType::kSeekersPasskey);
}
TEST_F(FastPairDataEncryptorImplTest, ParseDecryptedPasskeyInvalidInputSize) {
SuccessCreateFastPairDataEncryptorWithKeyExchange();
EXPECT_TRUE(data_encryptor_);
ParseDecryptedPasskeyInvalidBytes();
EXPECT_FALSE(passkey_);
}
} // namespace
} // namespace fastpair
} // namespace nearby
@@ -1,76 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
#include <array>
#include <optional>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "internal/platform/ble_v2.h"
namespace nearby {
namespace fastpair {
using WriteResponseCallback = absl::AnyInvocable<void(
absl::string_view value, std::optional<PairFailure> failure)>;
using WriteAccountkeyCallback = absl::AnyInvocable<void(
std::optional<AccountKey> account_key, std::optional<PairFailure> failure)>;
// This class is responsible for connecting to the Fast Pair GATT service for a
// device and invoking a callback when ready, or when an error is discovered
// during initialization.
class FastPairGattServiceClient {
public:
virtual ~FastPairGattServiceClient() = default;
virtual void InitializeGattConnection(
absl::AnyInvocable<void(std::optional<PairFailure>)>
on_gatt_initialized_callback) = 0;
// Constructs a data vector based on the message type, flags, provider
// address, and seekers address.
// Subscribe a notification for key based Pairing.
// Once the notification subscribed successfully, the message data will be
// written to the key based characteristic.
virtual void WriteRequestAsync(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) = 0;
// Constructs a data vector based on the message type and passkey.
// Subscribe a notification for the passkey.
// Once the notification subscribed successfully, the passkey data will be
// written to the passkey characteristic.
virtual void WritePasskeyAsync(
uint8_t message_type, uint32_t passkey,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) = 0;
// Writes the account key to the account key characteristic.
virtual void WriteAccountKey(
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteAccountkeyCallback write_accountkey_callback) = 0;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_H_
@@ -1,401 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_gatt_service_client_impl.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/functional/bind_front.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
#include "fastpair/internal/mediums/mediums.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
#include <openssl/rand.h>
namespace nearby {
namespace fastpair {
namespace {
// We have two UUID possibilities for each characteristic because they changed
// across different Fast Pair versions.
constexpr Uuid kFastPairServiceUuid(0x0000FE2C00001000, 0x800000805F9B34FB);
constexpr Uuid kKeyBasedCharacteristicUuidV1(0x0000123400001000,
0x800000805F9B34FB);
constexpr Uuid kKeyBasedCharacteristicUuidV2(0xFE2C123483664814,
0x8EB001DE32100BEA);
constexpr Uuid kPasskeyCharacteristicUuidV1(0x0000123500001000,
0x800000805F9B34FB);
constexpr Uuid kPasskeyCharacteristicUuidV2(0xFE2C123583664814,
0x8EB001DE32100BEA);
constexpr Uuid kAccountKeyCharacteristicUuidV1(0x0000123600001000,
0x800000805F9B34FB);
constexpr Uuid kAccountKeyCharacteristicUuidV2(0xFE2C123683664814,
0x8EB001DE32100BEA);
constexpr int kKeyBasedCharacteristicIndex = 0;
constexpr int kPasskeyCharacteristicIndex = 1;
constexpr int kAccountKeyCharacteristicIndex = 2;
constexpr int kNumCharacteristics = 3;
constexpr absl::Duration kGattOperationTimeout = absl::Seconds(15);
constexpr int kMaxNumGattConnectionAttempts = 3;
} // namespace
// FastPairGattServiceClientImpl::Factory
// static
FastPairGattServiceClientImpl::Factory*
FastPairGattServiceClientImpl::Factory::g_test_factory_ = nullptr;
// static
std::unique_ptr<FastPairGattServiceClient>
FastPairGattServiceClientImpl::Factory::Create(const FastPairDevice& device,
Mediums& mediums,
SingleThreadExecutor* executor) {
if (g_test_factory_) {
return g_test_factory_->CreateInstance();
}
return std::make_unique<FastPairGattServiceClientImpl>(device, mediums,
executor);
}
// static
void FastPairGattServiceClientImpl::Factory::SetFactoryForTesting(
Factory* g_test_factory) {
g_test_factory_ = g_test_factory;
}
FastPairGattServiceClientImpl::Factory::~Factory() = default;
FastPairGattServiceClientImpl::FastPairGattServiceClientImpl(
const FastPairDevice& device, Mediums& mediums,
SingleThreadExecutor* executor)
: device_address_(device.GetBleAddress()),
mediums_(mediums),
executor_(executor) {
gatt_connection_params_.service_uuid = kFastPairServiceUuid;
gatt_connection_params_.characteristic_uuids.resize(kNumCharacteristics);
gatt_connection_params_.characteristic_uuids[kKeyBasedCharacteristicIndex] = {
kKeyBasedCharacteristicUuidV2, kKeyBasedCharacteristicUuidV1};
gatt_connection_params_.characteristic_uuids[kPasskeyCharacteristicIndex] = {
kPasskeyCharacteristicUuidV2, kPasskeyCharacteristicUuidV1};
gatt_connection_params_.characteristic_uuids[kAccountKeyCharacteristicIndex] =
{kAccountKeyCharacteristicUuidV2, kAccountKeyCharacteristicUuidV1};
}
void FastPairGattServiceClientImpl::InitializeGattConnection(
absl::AnyInvocable<void(std::optional<PairFailure>)>
on_gatt_initialized_callback) {
NEARBY_LOGS(INFO) << __func__
<< ": Starting the GATT connection to the device.";
on_gatt_initialized_callback_ = std::move(on_gatt_initialized_callback);
AttemptGattConnection();
}
void FastPairGattServiceClientImpl::AttemptGattConnection() {
NEARBY_LOGS(INFO) << __func__ << ": Attempt to connect to the device.";
ClearCurrentState();
CreateGattConnection();
}
void FastPairGattServiceClientImpl::CreateGattConnection() {
NEARBY_LOGS(INFO) << __func__ << " : Create Gatt Connection to the device.";
MutexLock lock(&mutex_);
if (mediums_.GetBluetoothRadio().Enable() &&
mediums_.GetBleV2().IsAvailable()) {
gatt_client_ = mediums_.GetBleV2().ConnectToGattServer(
device_address_, gatt_connection_params_, [this](absl::Status status) {
NEARBY_LOGS(INFO) << "Gatt connection status: " << status;
if (status.ok()) {
executor_->Execute("init-success", [this]() {
if (on_gatt_initialized_callback_) {
std::move(on_gatt_initialized_callback_)(std::nullopt);
}
});
} else {
NotifyInitializedError(PairFailure::kCreateGattConnection);
}
});
}
if (gatt_client_) {
is_initialized_ = true;
} else {
// The device must have been lost between connection attempts.
NotifyInitializedError(
PairFailure::kPairingDeviceLostBetweenGattConnectionAttempts);
return;
}
}
std::array<uint8_t, kAesBlockByteSize>
FastPairGattServiceClientImpl::CreateRequest(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address) {
std::array<uint8_t, kAesBlockByteSize> data_to_write;
RAND_bytes(data_to_write.data(), kAesBlockByteSize);
data_to_write[0] = message_type;
data_to_write[1] = flags;
std::array<uint8_t, 6> provider_address_bytes;
device::ParseBluetoothAddress(provider_address,
absl::MakeSpan(provider_address_bytes.data(),
provider_address_bytes.size()));
std::copy(provider_address_bytes.begin(), provider_address_bytes.end(),
std::begin(data_to_write) + kProviderAddressStartIndex);
// Seekers address can be empty, in which we would just have the bytes be
// the salt.
if (!seekers_address.empty()) {
std::array<uint8_t, 6> seeker_address_bytes;
device::ParseBluetoothAddress(seekers_address,
absl::MakeSpan(seeker_address_bytes.data(),
seeker_address_bytes.size()));
std::copy(seeker_address_bytes.begin(), seeker_address_bytes.end(),
std::begin(data_to_write) + kSeekerAddressStartIndex);
}
return data_to_write;
}
std::array<uint8_t, kAesBlockByteSize>
FastPairGattServiceClientImpl::CreatePasskeyBlock(uint8_t message_type,
uint32_t passkey) {
std::array<uint8_t, kAesBlockByteSize> data_to_write;
RAND_bytes(data_to_write.data(), kAesBlockByteSize);
data_to_write[0] = message_type;
// Need to convert the uint_32 to uint_8 to use in our data vector.
data_to_write[1] = (passkey & 0x00ff0000) >> 16;
data_to_write[2] = (passkey & 0x0000ff00) >> 8;
data_to_write[3] = passkey & 0x000000ff;
return data_to_write;
}
std::array<uint8_t, kAesBlockByteSize>
FastPairGattServiceClientImpl::CreateAccountKeyBlock() {
std::array<uint8_t, 16> account_key;
RAND_bytes(account_key.data(), account_key.size());
account_key[0] = 0x04;
return account_key;
}
void FastPairGattServiceClientImpl::WriteRequestAsync(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback callback) {
CHECK(!key_based_write_response_callback_);
key_based_write_response_callback_ = std::move(callback);
const std::array<uint8_t, kAesBlockByteSize> data_to_write =
fast_pair_data_encryptor.EncryptBytes(CreateRequest(
message_type, flags, provider_address, seekers_address));
std::vector<uint8_t> data_to_write_vec(data_to_write.begin(),
data_to_write.end());
// Append the public version of the private key to the message so the device
// can generate the shared secret to decrypt the message.
const std::optional<std::array<uint8_t, 64>> public_key =
fast_pair_data_encryptor.GetPublicKey();
if (public_key) {
const std::vector<uint8_t> public_key_vec = std::vector<uint8_t>(
public_key.value().begin(), public_key.value().end());
data_to_write_vec.insert(data_to_write_vec.end(), public_key_vec.begin(),
public_key_vec.end());
}
// Write public address request to the keybased characteristic and get
// response.
WriteKeyBasedCharacteristic(
std::string(data_to_write_vec.begin(), data_to_write_vec.end()));
}
void FastPairGattServiceClientImpl::WriteKeyBasedCharacteristic(
absl::string_view request) {
NEARBY_LOGS(INFO) << __func__ << " :Start to write keybased characteristic.";
MutexLock lock(&mutex_);
gatt_client_->CallRemoteFunction(
kKeyBasedCharacteristicIndex, request,
[this](absl::StatusOr<absl::string_view> response) {
if (response.ok()) {
NEARBY_LOGS(INFO)
<< __func__ << ": key based characteristic value changed.";
NotifyWriteRequestResult(*response);
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the key based characteristic: "
<< response.status();
PairFailure failure =
absl::IsDeadlineExceeded(response.status())
? PairFailure::kKeyBasedPairingResponseTimeout
: PairFailure::kKeyBasedPairingCharacteristicWrite;
NotifyWriteRequestError(failure);
}
});
}
void FastPairGattServiceClientImpl::WritePasskeyAsync(
uint8_t message_type, uint32_t passkey,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback callback) {
CHECK(is_initialized_);
CHECK(message_type == kSeekerPasskey);
passkey_write_response_callback_ = std::move(callback);
const std::array<uint8_t, kAesBlockByteSize> data_to_write =
fast_pair_data_encryptor.EncryptBytes(
CreatePasskeyBlock(message_type, passkey));
std::vector<uint8_t> data_to_write_vec(data_to_write.begin(),
data_to_write.end());
// Write passkey confirmation request to the passkey characteristic
WritePasskeyCharacteristic(
std::string(data_to_write_vec.begin(), data_to_write_vec.end()));
}
void FastPairGattServiceClientImpl::WritePasskeyCharacteristic(
absl::string_view request) {
MutexLock lock(&mutex_);
gatt_client_->CallRemoteFunction(
kPasskeyCharacteristicIndex, request,
[this](absl::StatusOr<absl::string_view> response) {
if (response.ok()) {
NEARBY_LOGS(INFO)
<< __func__ << ": Passkey characteristic value changed.";
NotifyWritePasskeyResult(*response);
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the passkey characteristic "
<< response.status();
PairFailure failure =
absl::IsDeadlineExceeded(response.status())
? PairFailure::kPasskeyResponseTimeout
: PairFailure::kPasskeyPairingCharacteristicWrite;
NotifyWritePasskeyError(failure);
}
});
}
void FastPairGattServiceClientImpl::WriteAccountKey(
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteAccountkeyCallback write_accountkey_callback) {
MutexLock lock(&mutex_);
CHECK(is_initialized_);
account_key_write_callback_ = std::move(write_accountkey_callback);
std::array<uint8_t, kAesBlockByteSize> raw_account_key =
CreateAccountKeyBlock();
const std::array<uint8_t, kAesBlockByteSize> data_to_write =
fast_pair_data_encryptor.EncryptBytes(raw_account_key);
gatt_client_->WriteCharacteristic(
kAccountKeyCharacteristicIndex,
std::string(data_to_write.begin(), data_to_write.end()),
api::ble_v2::GattClient::WriteType::kWithResponse,
[this, account_key =
std::string(raw_account_key.begin(), raw_account_key.end())](
absl::Status status) {
if (status.ok()) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Successfully write the accoutkey characteristic.";
NotifyWriteAccountKeyResult(AccountKey(account_key));
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the passkey characteristic ";
NotifyWriteAccountKeyError(
PairFailure::kAccountKeyCharacteristicWrite);
}
});
}
void FastPairGattServiceClientImpl::NotifyInitializedError(
PairFailure failure) {
NEARBY_LOGS(VERBOSE) << __func__ << failure;
ClearCurrentState();
executor_->Execute("init-error", [this, failure]() {
if (on_gatt_initialized_callback_) {
NEARBY_LOGS(VERBOSE) << __func__ << "Executing initialized callback";
std::move(on_gatt_initialized_callback_)(failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWriteRequestResult(
absl::string_view value, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
executor_->Execute(
"key-based-response", [this, value = std::string(value), failure]() {
if (key_based_write_response_callback_) {
std::move(key_based_write_response_callback_)(value, failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWritePasskeyResult(
absl::string_view value, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
executor_->Execute(
"passkey-response", [this, value = std::string(value), failure]() {
if (passkey_write_response_callback_) {
std::move(passkey_write_response_callback_)(value, failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWriteAccountKeyResult(
std::optional<AccountKey> account_key, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
executor_->Execute("passkey-response", [this, account_key, failure]() {
if (account_key_write_callback_) {
std::move(account_key_write_callback_)(account_key, failure);
}
});
}
void FastPairGattServiceClientImpl::ClearCurrentState() {
MutexLock lock(&mutex_);
executor_->Execute("clear-current-state",
[this, gatt_client = std::move(gatt_client_)]() mutable {
if (gatt_client != nullptr) {
gatt_client->Stop();
defunct_gatt_client_ = std::move(gatt_client);
}
});
}
} // namespace fastpair
} // namespace nearby
@@ -1,164 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_
#include <array>
#include <memory>
#include <optional>
#include <string>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/internal/mediums/robust_gatt_client.h"
#include "internal/platform/mutex.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
// This class is responsible for connecting to the Fast Pair GATT service for a
// device and invoking a callback when ready, or when an error is discovered
// during initialization.
class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
public:
class Factory {
public:
static std::unique_ptr<FastPairGattServiceClient> Create(
const FastPairDevice& device, Mediums& mediums,
SingleThreadExecutor* executor);
static void SetFactoryForTesting(Factory* test_factory);
protected:
virtual ~Factory();
virtual std::unique_ptr<FastPairGattServiceClient> CreateInstance() = 0;
private:
static Factory* g_test_factory_;
};
explicit FastPairGattServiceClientImpl(const FastPairDevice& device,
Mediums& mediums,
SingleThreadExecutor* executor);
FastPairGattServiceClientImpl(const FastPairGattServiceClientImpl&) = delete;
FastPairGattServiceClientImpl& operator=(
const FastPairGattServiceClientImpl&) = delete;
~FastPairGattServiceClientImpl() override = default;
void InitializeGattConnection(
absl::AnyInvocable<void(std::optional<PairFailure>)>
on_gatt_initialized_callback) override;
void WriteRequestAsync(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) override;
void WritePasskeyAsync(
uint8_t message_type, uint32_t passkey,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback write_response_callback) override;
void WriteAccountKey(
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteAccountkeyCallback write_accountkey_callback) override;
// Allows tests to modify GATT operation timeouts.
RobustGattClient::ConnectionParams& GetConnectionParams() {
return gatt_connection_params_;
}
private:
// Attempt to create a GATT connection with the device. This method may be
// called multiple times.
void AttemptGattConnection();
void CreateGattConnection();
// Operations on KeyBased Characteristic
// Creates a data vector based on parameter information.
std::array<uint8_t, kAesBlockByteSize> CreateRequest(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address);
// Write request to KeyBased Characteristic
void WriteKeyBasedCharacteristic(absl::string_view request);
// Operations on Passkey Characteristic
// Creates a data vector based on parameter information.
std::array<uint8_t, kAesBlockByteSize> CreatePasskeyBlock(
uint8_t message_type, uint32_t passkey);
// Write request to Passkey Characteristic
void WritePasskeyCharacteristic(absl::string_view request);
// Operations on Account Key Characteristic
// Creates an Account key.
std::array<uint8_t, kAesBlockByteSize> CreateAccountKeyBlock();
// Invokes the initialized callback with the proper PairFailure and clears
// local state.
void NotifyInitializedError(PairFailure failure);
// Invokes the write response callback with the proper PairFailure on a
// write error.
void NotifyWriteRequestError(PairFailure failure) {
NotifyWriteRequestResult("", failure);
}
void NotifyWriteRequestResult(absl::string_view value,
std::optional<PairFailure> = std::nullopt);
void NotifyWritePasskeyError(PairFailure failure) {
NotifyWritePasskeyResult("", failure);
}
void NotifyWritePasskeyResult(absl::string_view value,
std::optional<PairFailure> = std::nullopt);
void NotifyWriteAccountKeyError(PairFailure failure) {
NotifyWriteAccountKeyResult(std::nullopt, failure);
}
void NotifyWriteAccountKeyResult(
std::optional<AccountKey> account_key,
std::optional<PairFailure> failure = std::nullopt);
void ClearCurrentState();
// Timers
TimerImpl passkey_subscription_timer_;
TimerImpl key_based_write_request_timer_;
TimerImpl passkey_write_request_timer_;
TimerImpl account_key_write_request_timer_;
void OnGattServiceDiscoveryTimeout();
// Callback
absl::AnyInvocable<void(std::optional<PairFailure>)>
on_gatt_initialized_callback_;
WriteResponseCallback key_based_write_response_callback_;
WriteResponseCallback passkey_write_response_callback_;
WriteAccountkeyCallback account_key_write_callback_;
Mutex mutex_;
bool is_initialized_ = false;
std::string device_address_;
std::unique_ptr<RobustGattClient> gatt_client_ ABSL_GUARDED_BY(mutex_);
std::unique_ptr<RobustGattClient> defunct_gatt_client_;
RobustGattClient::ConnectionParams gatt_connection_params_;
Mediums& mediums_;
SingleThreadExecutor* executor_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_
@@ -1,416 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_gatt_service_client_impl.h"
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/common/protocol.h"
#include "fastpair/handshake/fake_fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
#include "fastpair/internal/mediums/mediums.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
using Property = nearby::api::ble_v2::GattCharacteristic::Property;
using Permission = nearby::api::ble_v2::GattCharacteristic::Permission;
using GattCharacteristic = nearby::api::ble_v2::GattCharacteristic;
using WriteType = nearby::api::ble_v2::GattClient::WriteType;
constexpr absl::Duration kGattOperationTimeout = absl::Seconds(15);
constexpr absl::string_view kMetadataId("test_id");
constexpr absl::string_view kSeekerAddress("AA:BB:CC:DD:EE:00");
constexpr Uuid kFastPairServiceUuid(0x0000FE2C00001000, 0x800000805F9B34FB);
constexpr Uuid kKeyBasedCharacteristicUuidV2(0xFE2C123483664814,
0x8EB001DE32100BEA);
constexpr Uuid kPasskeyCharacteristicUuidV2(0xFE2C123583664814,
0x8EB001DE32100BEA);
constexpr Uuid kAccountKeyCharacteristicUuidV2(0xFE2C123683664814,
0x8EB001DE32100BEA);
// Length of advertisement byte should be 16
constexpr absl::string_view kKeyBasedCharacteristicAdvertisementByte =
"keyBasedCharacte";
constexpr absl::string_view kPasskeyharacteristicAdvertisementByte =
"passkeyCharacter";
constexpr Uuid kWrongServiceId(0x0000FE2B00001000, 0x800000805F9B34FB);
constexpr uint8_t kMessageType = 0x00;
constexpr uint8_t kFlags = 0x00;
constexpr uint32_t kPasskey = 123456;
constexpr std::array<uint8_t, 64> kPublicKey = {
0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D, 0x01, 0x5E, 0x3F,
0x45, 0x61, 0xC3, 0x32, 0x1D, 0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3,
0x32, 0x1D, 0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D, 0x01,
0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D, 0x01, 0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32, 0x1D, 0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32,
0x1D, 0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
} // namespace
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
struct CharacteristicData {
// Write result returned to the gatt client.
absl::Status write_result;
std::optional<std::string> notify_response;
};
class FastPairGattServiceClientTest : public testing::Test {
public:
FastPairGattServiceClientTest() {
fast_pair_data_encryptor_ = std::make_unique<FakeFastPairDataEncryptor>();
fast_pair_data_encryptor_->SetPublickey(kPublicKey);
}
void SetUp() override {
gatt_server_ =
provider_ble_.StartGattServer(/*ServerGattConnectionCallback=*/{
.on_characteristic_write_cb =
[&](const api::ble_v2::BlePeripheral& remote_device,
const api::ble_v2::GattCharacteristic& characteristic,
int offset, absl::string_view data,
BleV2Medium::ServerGattConnectionCallback::
WriteValueCallback callback) {
auto it = characteristics_.find(characteristic);
if (it == characteristics_.end()) {
callback(absl::NotFoundError("characteristic not found"));
return;
}
callback(it->second.write_result);
if (it->second.notify_response.has_value()) {
NEARBY_LOGS(INFO) << "Notify seeker";
auto ignored = gatt_server_->NotifyCharacteristicChanged(
characteristic, false,
ByteArray(*it->second.notify_response));
}
}});
provider_address_ = *gatt_server_->GetBlePeripheral().GetAddress();
device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
}
void TearDown() override {
executor_.Shutdown();
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
accountkey_characteristic_ = std::nullopt;
characteristics_.clear();
initalized_failure_ = std::nullopt;
write_failure_ = std::nullopt;
gatt_client_.reset();
gatt_server_->Stop();
gatt_server_.reset();
}
void InsertCorrectGattCharacteristics() {
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kKeyBasedCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*key_based_characteristic_].write_result =
absl::OkStatus();
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kPasskeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*passkey_characteristic_].write_result = absl::OkStatus();
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kAccountKeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*accountkey_characteristic_].write_result =
absl::OkStatus();
}
void InsertCharacteristicsWithWrongServiceId() {
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
kWrongServiceId, kKeyBasedCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*key_based_characteristic_].write_result =
absl::OkStatus();
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
kWrongServiceId, kPasskeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*passkey_characteristic_].write_result = absl::OkStatus();
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
kWrongServiceId, kAccountKeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*accountkey_characteristic_].write_result =
absl::OkStatus();
}
void InitializeFastPairGattServiceClient(bool short_timeouts = false) {
CountDownLatch latch(1);
gatt_client_ = FastPairGattServiceClientImpl::Factory::Create(
*device_, mediums_, &executor_);
if (short_timeouts) {
FastPairGattServiceClientImpl* impl =
dynamic_cast<FastPairGattServiceClientImpl*>(gatt_client_.get());
auto& params = impl->GetConnectionParams();
params.gatt_operation_timeout = absl::Seconds(1);
params.gatt_operation_timeout = absl::Seconds(1);
params.max_back_off = absl::Milliseconds(500);
}
gatt_client_->InitializeGattConnection(
[&](std::optional<PairFailure> failure) {
initalized_failure_ = failure;
latch.CountDown();
});
latch.Await();
}
std::optional<PairFailure> GetInitializedCallbackResult() {
return initalized_failure_;
}
void WriteTestCallback(std::optional<PairFailure> failure) {
write_failure_ = failure;
}
std::optional<PairFailure> GetWriteCallbackResult() { return write_failure_; }
void WriteRequestToKeyBased() {
CountDownLatch latch(1);
gatt_client_->WriteRequestAsync(
kMessageType, kFlags, provider_address_, /* Seeker Address*/ "",
*fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
EXPECT_FALSE(response.empty());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
}
void WriteRequestToPasskey() {
CountDownLatch latch(1);
gatt_client_->WritePasskeyAsync(
kSeekerPasskey, kPasskey, *fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
EXPECT_FALSE(response.empty());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
}
void WriteRequestToAccountkey() {
CountDownLatch latch(1);
gatt_client_->WriteAccountKey(*fast_pair_data_encryptor_,
[&](std::optional<AccountKey> account_key,
std::optional<PairFailure> failure) {
EXPECT_TRUE(account_key.has_value());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
}
void SetKeyBaseCharacteristicsWriteResultToFailure() {
auto it = characteristics_.find(*key_based_characteristic_);
it->second.write_result = absl::UnknownError("Failed to write account key");
}
void SetPasskeyCharacteristicsWriteResultToFailure() {
auto it = characteristics_.find(*passkey_characteristic_);
it->second.write_result = absl::UnknownError("Failed to write account key");
}
void SetAccountkeyCharacteristicsWriteResultToFailure() {
auto it = characteristics_.find(*accountkey_characteristic_);
it->second.write_result = absl::UnknownError("Failed to write account key");
}
protected:
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
BluetoothAdapter provider_adapter_;
BleV2Medium provider_ble_{provider_adapter_};
std::unique_ptr<GattClient> internal_gatt_client_;
std::unique_ptr<FastPairGattServiceClient> gatt_client_;
std::unique_ptr<GattServer> gatt_server_;
std::string provider_address_;
std::unique_ptr<FakeFastPairDataEncryptor> fast_pair_data_encryptor_;
std::unique_ptr<FastPairDevice> device_;
Mediums mediums_;
std::optional<PairFailure> initalized_failure_ = PairFailure::kUnknown;
std::optional<PairFailure> write_failure_ = PairFailure::kUnknown;
Property properties_ = Property::kWrite | Property::kNotify;
Permission permissions_ = Permission::kWrite;
std::optional<GattCharacteristic> key_based_characteristic_;
std::optional<GattCharacteristic> passkey_characteristic_;
std::optional<GattCharacteristic> accountkey_characteristic_;
absl::flat_hash_map<GattCharacteristic, CharacteristicData> characteristics_;
};
TEST_F(FastPairGattServiceClientTest, SuccessInitializeGattConnection) {
EXPECT_EQ(GetInitializedCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
EXPECT_EQ(GetInitializedCallbackResult(), std::nullopt);
}
TEST_F(FastPairGattServiceClientTest, FailedDiscoverServiceAndCharacteristics) {
EXPECT_EQ(GetInitializedCallbackResult(), PairFailure::kUnknown);
InsertCharacteristicsWithWrongServiceId();
InitializeFastPairGattServiceClient();
EXPECT_EQ(GetInitializedCallbackResult(), PairFailure::kCreateGattConnection);
}
TEST_F(FastPairGattServiceClientTest, SuccessfulWriteKeyBaseCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
characteristics_[*key_based_characteristic_].notify_response =
std::string(kKeyBasedCharacteristicAdvertisementByte);
WriteRequestToKeyBased();
EXPECT_EQ(GetWriteCallbackResult(), std::nullopt);
}
TEST_F(FastPairGattServiceClientTest, SuccessfulWritePasskeyCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
characteristics_[*passkey_characteristic_].notify_response =
std::string(kPasskeyharacteristicAdvertisementByte);
WriteRequestToPasskey();
EXPECT_EQ(GetWriteCallbackResult(), std::nullopt);
}
TEST_F(FastPairGattServiceClientTest,
SuccessfulWriteAccountKeyCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
WriteRequestToAccountkey();
EXPECT_EQ(GetWriteCallbackResult(), std::nullopt);
}
TEST_F(FastPairGattServiceClientTest, FailedToWriteKeyBaseCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
SetKeyBaseCharacteristicsWriteResultToFailure();
CountDownLatch latch(1);
gatt_client_->WriteRequestAsync(
kMessageType, kFlags, provider_address_, kSeekerAddress,
*fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
EXPECT_EQ(GetWriteCallbackResult(),
PairFailure::kKeyBasedPairingCharacteristicWrite);
}
TEST_F(FastPairGattServiceClientTest, FailedToWritePasskeyCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
SetPasskeyCharacteristicsWriteResultToFailure();
CountDownLatch latch(1);
gatt_client_->WritePasskeyAsync(
kSeekerPasskey, kPasskey, *fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
EXPECT_EQ(GetWriteCallbackResult(),
PairFailure::kPasskeyPairingCharacteristicWrite);
}
TEST_F(FastPairGattServiceClientTest, FailedToWriteAccountKey) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
SetAccountkeyCharacteristicsWriteResultToFailure();
CountDownLatch latch(1);
gatt_client_->WriteAccountKey(*fast_pair_data_encryptor_,
[&](std::optional<AccountKey> account_key,
std::optional<PairFailure> failure) {
EXPECT_FALSE(account_key.has_value());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
EXPECT_EQ(GetWriteCallbackResult(),
PairFailure::kAccountKeyCharacteristicWrite);
}
TEST_F(FastPairGattServiceClientTest, KeyBasedPairingResponseTimeout) {
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient(/*short_timeouts=*/true);
CountDownLatch latch(1);
// Seeker writes to Key based pairing characteristic but the provider does not
// respond.
gatt_client_->WriteRequestAsync(
kMessageType, kFlags, provider_address_, kSeekerAddress,
*fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
EXPECT_EQ(failure, PairFailure::kKeyBasedPairingResponseTimeout);
latch.CountDown();
});
latch.Await();
}
TEST_F(FastPairGattServiceClientTest, PasskeyResponseTimeout) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
CountDownLatch latch(1);
gatt_client_->WritePasskeyAsync(
kSeekerPasskey, kPasskey, *fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
WriteTestCallback(failure);
latch.CountDown();
});
SystemClock::Sleep(kGattOperationTimeout);
latch.Await();
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kPasskeyResponseTimeout);
}
} // namespace fastpair
} // namespace nearby
-83
View File
@@ -1,83 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_H_
#include <memory>
#include <optional>
#include <utility>
#include "absl/functional/any_invocable.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
namespace nearby {
namespace fastpair {
// This class performs the Fast Pair handshake procedure upon creation and
// calls |on_complete| once finished. It also exposes the
// |FastPairDataEncryptor| and |FastPairGattServiceClient| instances that were
// used during the handshake.
//
// The procedure steps are as follows:
// 1. Create a GATT connection to the device.
// 2. Create a data encryptor instance with the generated keys.
// 3. Write the Key-Based Pairing Request to the characteristic
// (https://developers.google.com/nearby/fast-pair/spec#table1.1)
// 4. Decrypt the response.
// 5. Validate response.
// 6. Set classic address field on |FastPairDevice| instance.
// 7. Complete.
class FastPairHandshake {
public:
using OnCompleteCallback = absl::AnyInvocable<void(
FastPairDevice& device, std::optional<PairFailure> failure)>;
FastPairHandshake(
OnCompleteCallback on_complete_cb,
std::unique_ptr<FastPairDataEncryptor> data_encryptor,
std::unique_ptr<FastPairGattServiceClient> gatt_service_client)
: on_complete_callback_(std::move(on_complete_cb)),
fast_pair_data_encryptor_(std::move(data_encryptor)),
fast_pair_gatt_service_client_(std::move(gatt_service_client)) {}
FastPairHandshake(const FastPairHandshake&) = delete;
FastPairHandshake& operator=(const FastPairHandshake&) = delete;
virtual ~FastPairHandshake() = default;
bool completed_successfully() { return completed_successfully_; }
FastPairDataEncryptor* fast_pair_data_encryptor() {
return fast_pair_data_encryptor_.get();
}
FastPairGattServiceClient* fast_pair_gatt_service_client() {
return fast_pair_gatt_service_client_.get();
}
protected:
bool completed_successfully_ = false;
OnCompleteCallback on_complete_callback_;
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor_;
std::unique_ptr<FastPairGattServiceClient> fast_pair_gatt_service_client_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_H_
@@ -1,138 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_handshake_impl.h"
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "absl/functional/bind_front.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include "fastpair/handshake/fast_pair_gatt_service_client_impl.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/logging.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
FastPairHandshakeImpl::FastPairHandshakeImpl(FastPairDevice& device,
Mediums& mediums,
OnCompleteCallback on_complete,
SingleThreadExecutor* executor)
: FastPairHandshake(std::move(on_complete), nullptr, nullptr) {
fast_pair_gatt_service_client_ =
FastPairGattServiceClientImpl::Factory::Create(device, mediums, executor);
fast_pair_gatt_service_client_->InitializeGattConnection(
[&](std::optional<PairFailure> failure) {
OnGattClientInitializedCallback(device, failure);
});
}
void FastPairHandshakeImpl::OnGattClientInitializedCallback(
FastPairDevice& device, std::optional<PairFailure> failure) {
if (failure.has_value()) {
NEARBY_LOGS(WARNING) << __func__
<< ": Failed to init gatt client with failure = "
<< failure.value();
std::move(on_complete_callback_)(device, failure.value());
return;
}
NEARBY_LOGS(INFO)
<< __func__
<< ": Fast Pair GATT service client initialization successful.";
FastPairDataEncryptorImpl::Factory::CreateAsync(
device,
[&](std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
OnDataEncryptorCreateAsync(device, std::move(fast_pair_data_encryptor));
});
}
void FastPairHandshakeImpl::OnDataEncryptorCreateAsync(
FastPairDevice& device,
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
if (!fast_pair_data_encryptor) {
NEARBY_LOGS(WARNING) << __func__
<< ": Failed to create Fast Pair Data Encryptor.";
std::move(on_complete_callback_)(device,
PairFailure::kDataEncryptorRetrieval);
return;
}
fast_pair_data_encryptor_ = std::move(fast_pair_data_encryptor);
NEARBY_LOGS(INFO) << __func__ << ": Beginning key-based pairing protocol";
fast_pair_gatt_service_client_->WriteRequestAsync(
/*message_type=*/kKeyBasedPairingType,
/*flags=*/kInitialOrSubsequentFlags,
/*provider_address=*/device.GetBleAddress(),
/*seekers_address=*/"", *fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
OnWriteResponse(device, response, failure);
});
}
void FastPairHandshakeImpl::OnWriteResponse(
FastPairDevice& device, absl::string_view response,
std::optional<PairFailure> failure) {
if (failure.has_value()) {
NEARBY_LOGS(WARNING)
<< __func__
<< ": Failed during key-based pairing protocol with failure = "
<< failure.value();
std::move(on_complete_callback_)(device, failure.value());
return;
}
NEARBY_LOGS(INFO) << __func__ << ": Successfully wrote response.";
if (response.size() != kAesBlockByteSize) {
NEARBY_LOGS(WARNING)
<< __func__ << ": Handshake failed because of incorrect response size.";
std::move(on_complete_callback_)(
device, PairFailure::kKeybasedPairingResponseDecryptFailure);
return;
}
std::vector<uint8_t> response_bytes(response.begin(), response.end());
fast_pair_data_encryptor_->ParseDecryptResponse(
response_bytes, [&](std::optional<DecryptedResponse> response) {
OnParseDecryptedResponse(device, response);
});
}
void FastPairHandshakeImpl::OnParseDecryptedResponse(
FastPairDevice& device, std::optional<DecryptedResponse>& response) {
if (!response.has_value()) {
NEARBY_LOGS(WARNING) << __func__
<< ": Missing decrypted response from parse.";
std::move(on_complete_callback_)(
device, PairFailure::kKeybasedPairingResponseDecryptFailure);
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Successfully decrypted and parsed response.";
device.SetPublicAddress(
device::CanonicalizeBluetoothAddress(response->address_bytes));
completed_successfully_ = true;
std::move(on_complete_callback_)(device, std::nullopt);
}
} // namespace fastpair
} // namespace nearby
@@ -1,53 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_IMPL_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_IMPL_H_
#include <memory>
#include <optional>
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/crypto/decrypted_response.h"
#include "fastpair/handshake/fast_pair_handshake.h"
#include "fastpair/internal/mediums/mediums.h"
namespace nearby {
namespace fastpair {
class FastPairHandshakeImpl : public FastPairHandshake {
public:
explicit FastPairHandshakeImpl(FastPairDevice& device, Mediums& mediums,
OnCompleteCallback on_complete,
SingleThreadExecutor* executor);
FastPairHandshakeImpl(const FastPairHandshakeImpl&) = delete;
FastPairHandshakeImpl& operator=(const FastPairHandshakeImpl&) = delete;
private:
void OnGattClientInitializedCallback(FastPairDevice& device,
std::optional<PairFailure> failure);
void OnDataEncryptorCreateAsync(
FastPairDevice& device,
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor);
void OnWriteResponse(FastPairDevice& device, absl::string_view response,
std::optional<PairFailure> failure);
void OnParseDecryptedResponse(FastPairDevice& device,
std::optional<DecryptedResponse>& response);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_IMPL_H_
@@ -1,325 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_handshake_impl.h"
#include <array>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/common/protocol.h"
#include "fastpair/crypto/decrypted_response.h"
#include "fastpair/handshake/fake_fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_data_encryptor.h"
#include "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
using Property = nearby::api::ble_v2::GattCharacteristic::Property;
using Permission = nearby::api::ble_v2::GattCharacteristic::Permission;
using ::nearby::api::ble_v2::GattCharacteristic;
constexpr absl::string_view kMetadataId("718c17");
constexpr absl::string_view kPublicAddress("5E:3F:45:61:C3:32");
constexpr absl::string_view kKeyBasedResponse("keybasedresponse");
constexpr absl::string_view kWrongResponse("wrongresponse");
constexpr Uuid kFastPairServiceUuid(0x0000FE2C00001000, 0x800000805F9B34FB);
constexpr Uuid kKeyBasedCharacteristicUuidV2(0xFE2C123483664814,
0x8EB001DE32100BEA);
constexpr Uuid kPasskeyCharacteristicUuidV2(0xFE2C123583664814,
0x8EB001DE32100BEA);
constexpr Uuid kAccountKeyCharacteristicUuidV2(0xFE2C123683664814,
0x8EB001DE32100BEA);
constexpr std::array<uint8_t, 6> address_bytes = {0x5E, 0x3F, 0x45,
0x61, 0xC3, 0x32};
constexpr std::array<uint8_t, 9> salt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x00};
} // namespace
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
class FastPairFakeDataEncryptorImplFactory
: public FastPairDataEncryptorImpl::Factory {
public:
void CreateInstance(
const FastPairDevice& device,
absl::AnyInvocable<void(std::unique_ptr<FastPairDataEncryptor>)>
on_get_instance_callback) override {
if (!successful_retrieval_) {
std::move(on_get_instance_callback)(nullptr);
return;
}
auto data_encryptor = std::make_unique<FakeFastPairDataEncryptor>();
data_encryptor_ = data_encryptor.get();
data_encryptor->SetResponse(response_);
std::move(on_get_instance_callback)(std::move(data_encryptor));
}
FakeFastPairDataEncryptor* data_encryptor() { return data_encryptor_; }
void SetFailedRetrieval() { successful_retrieval_ = false; }
void SetResponse(std::optional<DecryptedResponse> response) {
response_ = std::move(response);
}
private:
FakeFastPairDataEncryptor* data_encryptor_ = nullptr;
bool successful_retrieval_ = true;
std::optional<DecryptedResponse> response_;
};
struct CharacteristicData {
// Write result returned to the gatt client.
absl::Status write_result;
std::optional<std::string> notify_response;
};
class FastPairHandshakeImplTest : public testing::Test {
public:
FastPairHandshakeImplTest() {
FastPairDataEncryptorImpl::Factory::SetFactoryForTesting(
&fake_data_encryptor_factory_);
}
void TearDown() override {
executor_.Shutdown();
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
handshake_.reset();
gatt_server_->Stop();
gatt_server_.reset();
}
void StartGattServer() {
gatt_server_ =
provider_ble_.StartGattServer(/*ServerGattConnectionCallback=*/{
.on_characteristic_write_cb =
[&](const api::ble_v2::BlePeripheral& remote_device,
const api::ble_v2::GattCharacteristic& characteristic,
int offset, absl::string_view data,
BleV2Medium::ServerGattConnectionCallback::
WriteValueCallback callback) mutable {
MutexLock lock(&mutex_);
auto it = characteristics_.find(characteristic);
if (it == characteristics_.end()) {
callback(absl::NotFoundError("characteristic not found"));
return;
}
callback(it->second.write_result);
if (it->second.notify_response.has_value()) {
auto ignored = gatt_server_->NotifyCharacteristicChanged(
characteristic, false,
ByteArray(*it->second.notify_response));
}
}});
provider_address_ = *gatt_server_->GetBlePeripheral().GetAddress();
}
void InsertCorrectGattCharacteristics() {
MutexLock lock(&mutex_);
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kKeyBasedCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*key_based_characteristic_].write_result =
absl::OkStatus();
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kPasskeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*passkey_characteristic_].write_result = absl::OkStatus();
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kAccountKeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*accountkey_characteristic_].write_result =
absl::OkStatus();
}
void SetNotifyResponse(GattCharacteristic characteristic,
absl::string_view response) {
MutexLock lock(&mutex_);
CHECK(characteristics_.find(characteristic) != characteristics_.end());
characteristics_[characteristic].notify_response = response;
}
void SetDecryptedResponse() {
DecryptedResponse decrypted_response(
FastPairMessageType::kKeyBasedPairingResponse, address_bytes, salt);
fake_data_encryptor_factory_.SetResponse(std::move(decrypted_response));
}
protected:
MediumEnvironmentStarter env_;
Mutex mutex_;
SingleThreadExecutor executor_;
std::unique_ptr<FastPairHandshake> handshake_;
BluetoothAdapter provider_adapter_;
BleV2Medium provider_ble_{provider_adapter_};
std::string provider_address_;
Mediums mediums_;
std::unique_ptr<FastPairDevice> fast_pair_device_;
absl::flat_hash_map<GattCharacteristic, CharacteristicData> characteristics_
ABSL_GUARDED_BY(mutex_);
std::optional<GattCharacteristic> key_based_characteristic_;
std::optional<GattCharacteristic> passkey_characteristic_;
std::optional<GattCharacteristic> accountkey_characteristic_;
FastPairFakeDataEncryptorImplFactory fake_data_encryptor_factory_;
private:
std::unique_ptr<GattServer> gatt_server_;
Property properties_ = Property::kWrite | Property::kNotify;
Permission permissions_ = Permission::kWrite;
};
TEST_F(FastPairHandshakeImplTest, Success) {
StartGattServer();
InsertCorrectGattCharacteristics();
SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
SetDecryptedResponse();
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(fast_pair_device_->GetPublicAddress(), kPublicAddress);
EXPECT_FALSE(failure.has_value());
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_TRUE(handshake_->completed_successfully());
}
TEST_F(FastPairHandshakeImplTest, GattError) {
StartGattServer();
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
SetDecryptedResponse();
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(), PairFailure::kCreateGattConnection);
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
TEST_F(FastPairHandshakeImplTest, DataEncryptorCreateError) {
StartGattServer();
InsertCorrectGattCharacteristics();
SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
fake_data_encryptor_factory_.SetFailedRetrieval();
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(), PairFailure::kDataEncryptorRetrieval);
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
TEST_F(FastPairHandshakeImplTest, WriteResponseError) {
StartGattServer();
InsertCorrectGattCharacteristics();
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
SetDecryptedResponse();
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeyBasedPairingResponseTimeout);
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
TEST_F(FastPairHandshakeImplTest, WriteResponseWrongSize) {
StartGattServer();
InsertCorrectGattCharacteristics();
SetNotifyResponse(*key_based_characteristic_, kWrongResponse);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
SetDecryptedResponse();
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeybasedPairingResponseDecryptFailure);
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
TEST_F(FastPairHandshakeImplTest, ParseResponseError) {
StartGattServer();
InsertCorrectGattCharacteristics();
SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
handshake_ = std::make_unique<FastPairHandshakeImpl>(
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeybasedPairingResponseDecryptFailure);
latch.CountDown();
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
} // namespace fastpair
} // namespace nearby
@@ -1,104 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_handshake_lookup.h"
#include <memory>
#include <optional>
#include <utility>
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "fastpair/handshake/fast_pair_handshake_impl.h"
namespace nearby {
namespace fastpair {
FastPairHandshakeLookup* FastPairHandshakeLookup::instance_ = nullptr;
absl::Mutex FastPairHandshakeLookup::mutex_(absl::kConstInit);
namespace {
absl::optional<FastPairHandshakeLookup::CreateFunction> g_test_create_function =
std::nullopt;
}
// static
FastPairHandshakeLookup* FastPairHandshakeLookup::GetInstance() {
absl::MutexLock lock(&mutex_);
if (!instance_) {
instance_ = new FastPairHandshakeLookup();
}
return instance_;
}
// static Create function override which can be set by tests.
void FastPairHandshakeLookup::SetCreateFunctionForTesting(
CreateFunction create_function) {
g_test_create_function = std::move(create_function);
}
FastPairHandshake* FastPairHandshakeLookup::Get(FastPairDevice* device) {
absl::MutexLock lock(&mutex_);
auto it = fast_pair_handshakes_.find(device);
return it != fast_pair_handshakes_.end() ? it->second.get() : nullptr;
}
FastPairHandshake* FastPairHandshakeLookup::Get(absl::string_view address) {
absl::MutexLock lock(&mutex_);
for (const auto& pair : fast_pair_handshakes_) {
if (pair.first->GetPublicAddress() == address ||
pair.first->GetBleAddress() == address) {
return pair.second.get();
}
}
return nullptr;
}
bool FastPairHandshakeLookup::Erase(FastPairDevice* device) {
absl::MutexLock lock(&mutex_);
return fast_pair_handshakes_.erase(device) == 1;
}
bool FastPairHandshakeLookup::Erase(absl::string_view address) {
absl::MutexLock lock(&mutex_);
for (const auto& pair : fast_pair_handshakes_) {
if (pair.first->GetPublicAddress() == address ||
pair.first->GetBleAddress() == address) {
fast_pair_handshakes_.erase(pair.first);
return true;
}
}
return false;
}
void FastPairHandshakeLookup::Clear() {
absl::MutexLock lock(&mutex_);
fast_pair_handshakes_.clear();
}
FastPairHandshake* FastPairHandshakeLookup::Create(
FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete,
SingleThreadExecutor* executor) {
absl::MutexLock lock(&mutex_);
auto it = fast_pair_handshakes_.emplace(
&device, g_test_create_function.has_value()
? g_test_create_function.value()(device, mediums,
std::move(on_complete))
: std::make_unique<FastPairHandshakeImpl>(
device, mediums, std::move(on_complete), executor));
DCHECK(it.second);
return it.first->second.get();
}
} // namespace fastpair
} // namespace nearby
@@ -1,94 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_
#include <functional>
#include <memory>
#include <optional>
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_handshake.h"
#include "fastpair/internal/mediums/mediums.h"
namespace nearby {
namespace fastpair {
// This Singletonclass creates, deletes and exposes FastPairHandshake instances.
class FastPairHandshakeLookup {
public:
using OnCompleteCallback = absl::AnyInvocable<void(
FastPairDevice& device, std::optional<PairFailure> failure)>;
using CreateFunction = absl::AnyInvocable<std::unique_ptr<FastPairHandshake>(
FastPairDevice& device, Mediums& mediums, OnCompleteCallback callback)>;
// This is the static method that controls the access to the singleton
// instance. On the first run, it creates a singleton object and places it
// into the static field. On subsequent runs, it returns the existing object
// stored in the static field.
static FastPairHandshakeLookup* GetInstance();
static void SetCreateFunctionForTesting(CreateFunction create_function);
// Singletons should not be cloneable.
FastPairHandshakeLookup(const FastPairHandshakeLookup&) = delete;
// Singletons should not be assignable.
FastPairHandshakeLookup& operator=(const FastPairHandshakeLookup&) = delete;
// Get an existing instance for |FastPairdevice|.
FastPairHandshake* Get(FastPairDevice* device);
// Get an existing instance for |address|.
FastPairHandshake* Get(absl::string_view address);
// Erases the FastPairHandshake instance for |FastPairdevice| if it exists.
bool Erase(FastPairDevice* device);
// Erases the FastPairHandshake instance for |FastPairdevice| if it exists.
bool Erase(absl::string_view address);
// Deletes all existing FastPairHandshake instances.
void Clear();
// Creates and returns a new instance for |FastPairdevice| if no instance
// already exists.
// Returns the existing instance if there is one.
FastPairHandshake* Create(FastPairDevice& device, Mediums& mediums,
OnCompleteCallback on_complete,
SingleThreadExecutor* executor);
protected:
// Constructor/destructor of singleton object should not be public
// for which the destructor will never be called.
// and constructor will be invoked once from GetInstance() static method.
FastPairHandshakeLookup() = default;
~FastPairHandshakeLookup() = default;
private:
static absl::Mutex mutex_;
static FastPairHandshakeLookup* instance_ ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<FastPairDevice*, std::unique_ptr<FastPairHandshake>>
fast_pair_handshakes_ ABSL_GUARDED_BY(mutex_);
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_
@@ -1,150 +0,0 @@
// Copyright 2023 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 "fastpair/handshake/fast_pair_handshake_lookup.h"
#include <memory>
#include <optional>
#include <string>
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
#include "fastpair/common/protocol.h"
#include "fastpair/internal/mediums/mediums.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::string_view kValidModelId("718c17");
constexpr absl::string_view kPubliceAddress("public_address");
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
class FastPairHandshakeLookupTest : public ::testing::Test {
public:
FastPairHandshakeLookupTest() {
provider_address_ = adapter_.GetMacAddress();
device_ = new FastPairDevice(kValidModelId, provider_address_,
Protocol::kFastPairInitialPairing);
device_->SetPublicAddress(kPubliceAddress);
}
~FastPairHandshakeLookupTest() override { delete device_; }
void TearDown() override { executor_.Shutdown(); }
void CreateFastPairHandshkeInstanceForDevice(FastPairDevice& device) {
CountDownLatch latch(1);
Mediums mediums;
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Create(
device, mediums,
[&](FastPairDevice& cb_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &cb_device);
EXPECT_TRUE(failure.has_value());
latch.CountDown();
},
&executor_));
latch.Await();
}
protected:
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
BluetoothAdapter adapter_;
BleV2Medium ble_{adapter_};
std::string provider_address_;
FastPairDevice* device_ = nullptr;
};
TEST_F(FastPairHandshakeLookupTest, CreateFastPairHandshkeInstanceForDevice) {
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(provider_address_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(kPubliceAddress));
CreateFastPairHandshkeInstanceForDevice(*device_);
// GetFastPairHandshakeWithDevicePtr
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
// GetFastPairHandshakeWithBLEAddress
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(provider_address_));
// GetFastPairHandshakeWithPublicAddress
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(kPubliceAddress));
// GetFastPairHandshakeWithDevicePtr
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
// GetFastPairHandshakeWithWrongAddress
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(""));
}
TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithDevicePtr) {
CreateFastPairHandshkeInstanceForDevice(*device_);
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(device_));
// Already Erased
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_FALSE(
FastPairHandshakeLookup::GetInstance()->Erase(provider_address_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress));
}
TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithBLEAddress) {
CreateFastPairHandshkeInstanceForDevice(*device_);
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
// Erase Wrong Address
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(""));
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(provider_address_));
// Already Erased
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(device_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress));
}
TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithPublicAddress) {
CreateFastPairHandshkeInstanceForDevice(*device_);
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress));
// Already Erased
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_));
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(device_));
EXPECT_FALSE(
FastPairHandshakeLookup::GetInstance()->Erase(provider_address_));
}
TEST_F(FastPairHandshakeLookupTest, ClearAllFastPairHandshakeInstances) {
CreateFastPairHandshkeInstanceForDevice(*device_);
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_));
FastPairHandshakeLookup::GetInstance()->Clear();
EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_));
}
} // namespace
} // namespace fastpair
} // namespace nearby
-69
View File
@@ -1,69 +0,0 @@
# Copyright 2023 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.
licenses(["notice"])
cc_library(
name = "internal",
srcs = ["fast_pair_seeker_impl.cc"],
hdrs = [
"fast_pair_seeker_impl.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
"//fastpair:fast_pair_controller",
"//fastpair:fast_pair_events",
"//fastpair:fast_pair_seeker",
"//fastpair/common",
"//fastpair/internal/mediums",
"//fastpair/pairing",
"//fastpair/repository",
"//fastpair/repository:device_repository",
"//fastpair/retroactive",
"//fastpair/scanning:scanner",
"//internal/platform:types",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:str_format",
],
)
cc_test(
name = "fast_pair_seeker_impl_test",
size = "small",
srcs = [
"fast_pair_seeker_impl_test.cc",
],
deps = [
":internal",
"//fastpair:fast_pair_events",
"//fastpair:fast_pair_seeker",
"//fastpair/common",
"//fastpair/message_stream:fake_gatt_callbacks",
"//fastpair/message_stream:fake_provider",
"//fastpair/proto:fastpair_cc_proto",
"//fastpair/repository",
"//fastpair/repository:device_repository",
"//fastpair/repository:test_support",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/test",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
-327
View File
@@ -1,327 +0,0 @@
// Copyright 2023 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 "fastpair/internal/fast_pair_seeker_impl.h"
#include <ios>
#include <memory>
#include <optional>
#include <utility>
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "fastpair/common/account_key.h"
#include "fastpair/fast_pair_controller.h"
#include "fastpair/fast_pair_events.h"
#include "fastpair/pairing/pairer_broker_impl.h"
#include "fastpair/scanning/scanner_broker_impl.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/logging.h"
#include "internal/platform/pending_job_registry.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::Duration kCleanupTimeout = absl::Seconds(3);
} // namespace
FastPairSeekerImpl::FastPairSeekerImpl(ServiceCallbacks callbacks,
SingleThreadExecutor* executor,
AccountManager* account_manager,
FastPairDeviceRepository* devices,
FastPairRepository* repository)
: callbacks_(std::move(callbacks)),
executor_(executor),
account_manager_(account_manager),
devices_(devices),
repository_(repository) {
pairer_broker_ =
std::make_unique<PairerBrokerImpl>(mediums_, executor_, account_manager_);
pairer_broker_->AddObserver(this);
mediums_.GetBluetoothClassic().AddObserver(this);
retro_detector_ = std::make_unique<RetroactivePairingDetectorImpl>(
mediums_, devices, account_manager_, executor);
retro_detector_->AddObserver(this);
}
FastPairSeekerImpl::~FastPairSeekerImpl() {
NEARBY_LOGS(INFO) << "~FastPairSeekerImpl start";
pairer_broker_->RemoveObserver(this);
mediums_.GetBluetoothClassic().RemoveObserver(this);
auto unused = StopFastPairScan();
CountDownLatch latch(1);
executor_->Execute("~FastPairSeekerImpl", [this, latch]() mutable {
FinishPairing(absl::AbortedError("Pairing terminated"));
pairer_broker_.reset();
executor_->Execute("sync", [latch]() mutable { latch.CountDown(); });
});
if (!latch.Await(kCleanupTimeout)) {
NEARBY_LOGS(WARNING) << "Cleanup didn't finish in " << kCleanupTimeout;
}
PendingJobRegistry::GetInstance().ListAllJobs();
NEARBY_LOGS(INFO) << "~FastPairSeekerImpl done";
}
absl::Status FastPairSeekerImpl::StartInitialPairing(
const FastPairDevice& device, const InitialPairingParam& params,
PairingCallback callback) {
if (pairer_broker_->IsPairing()) {
return absl::AlreadyExistsError("Already pairing");
}
pairing_callback_ = std::make_unique<PairingCallback>(std::move(callback));
device_under_pairing_ = &const_cast<FastPairDevice&>(device);
device_under_pairing_->StartedPairing(true);
pairer_broker_->PairDevice(*device_under_pairing_);
return absl::OkStatus();
}
absl::Status FastPairSeekerImpl::StartSubsequentPairing(
const FastPairDevice& device, const SubsequentPairingParam& params,
PairingCallback callback) {
return absl::UnimplementedError("StartSubsequentPairing");
}
absl::Status FastPairSeekerImpl::StartRetroactivePairing(
const FastPairDevice& device, const RetroactivePairingParam& param,
PairingCallback callback) {
if (pairer_broker_->IsPairing()) {
return absl::AlreadyExistsError("Already pairing");
}
device_under_pairing_ = &const_cast<FastPairDevice&>(device);
device_under_pairing_->StartedPairing(true);
controller_ = std::make_unique<FastPairController>(
&mediums_, device_under_pairing_, executor_);
retroactive_pair_ = std::make_unique<Retroactive>(controller_.get());
pairing_callback_ = std::make_unique<PairingCallback>(std::move(callback));
retroactive_pair_->Pair().AddListener(
[this](ExceptionOr<absl::Status> result) {
// TODO(jsobczak): We could/should keep controller_ alive until the
// client calls FinishRetroactivePairing(), verify that they called
// Finish for the correct device, and if the user has given consent, we
// should keep the MessageStream connection open.
retroactive_pair_.reset();
controller_.reset();
FinishPairing(result.result());
},
executor_);
return absl::OkStatus();
}
absl::Status FastPairSeekerImpl::FinishRetroactivePairing(
const FastPairDevice& device, const FinishRetroactivePairingParam& param,
PairingCallback callback) {
if (device.GetProtocol() != Protocol::kFastPairRetroactivePairing) {
return absl::InvalidArgumentError(
"Fast Pair Device is not a retroactive pairing device");
}
if (!device.GetAccountKey()) {
return absl::InvalidArgumentError(
"Fast Pair Device does not have an account key");
}
if (!param.save_account_key) {
executor_->Execute(
"abandon retro device",
[this, &device, callback = std::move(callback)]() mutable {
NEARBY_LOGS(INFO) << "Abandon device on retroactive pairing path";
callback.on_pairing_result(device, absl::OkStatus());
devices_->RemoveDevice(&device);
});
} else {
executor_->Execute(
"save account key",
[this, &device, callback = std::move(callback)]() mutable {
NEARBY_LOGS(INFO) << "Save account key for " << device;
repository_->WriteAccountAssociationToFootprints(
const_cast<FastPairDevice&>(device),
[&device,
callback = std::move(callback)](absl::Status status) mutable {
callback.on_pairing_result(device, status);
});
});
}
return absl::OkStatus();
}
absl::Status FastPairSeekerImpl::StartFastPairScan() {
if (scanning_session_ != nullptr) {
return absl::AlreadyExistsError("already scanning");
}
scanner_ = std::make_unique<ScannerBrokerImpl>(mediums_, executor_, devices_);
scanner_->AddObserver(this);
scanning_session_ =
scanner_->StartScanning(Protocol::kFastPairInitialPairing);
return absl::OkStatus();
}
absl::Status FastPairSeekerImpl::StopFastPairScan() {
if (scanning_session_ == nullptr) {
return absl::NotFoundError("scanner is not running");
}
scanning_session_.reset();
scanner_->RemoveObserver(this);
DestroyOnExecutor(std::move(scanner_), executor_);
return absl::OkStatus();
}
// ScannerBroker::Observer::OnDeviceFound
void FastPairSeekerImpl::OnDeviceFound(FastPairDevice& device) {
NEARBY_LOGS(INFO) << "Device found: " << device;
callbacks_.on_initial_discovery(device, InitialDiscoveryEvent{});
}
// ScannerBroker::Observer::OnDeviceLost
void FastPairSeekerImpl::OnDeviceLost(FastPairDevice& device) {
NEARBY_LOGS(INFO) << "Device lost: " << device;
if (IsDeviceUnderPairing(device)) {
FinishPairing(absl::UnavailableError("Device lost during pairing"));
}
}
// PairerBroker:Observer::OnDevicePaired
void FastPairSeekerImpl::OnDevicePaired(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": " << device;
}
// PairerBroker:Observer::OnAccountKeyWrite
void FastPairSeekerImpl::OnAccountKeyWrite(FastPairDevice& device,
std::optional<PairFailure> error) {
if (error.has_value()) {
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device
<< ",Error=" << error.value();
return;
}
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device;
if (device.GetProtocol() == Protocol::kFastPairRetroactivePairing) {
// TODO: UI ShowAssociateAccount
}
}
// PairerBroker:Observer::OnPairingComplete
void FastPairSeekerImpl::OnPairingComplete(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": " << device;
if (!IsDeviceUnderPairing(device)) {
NEARBY_LOGS(WARNING) << "unexpected on pair complete callback";
return;
}
FinishPairing(absl::OkStatus());
}
// PairerBroker:Observer::OnPairFailure
void FastPairSeekerImpl::OnPairFailure(FastPairDevice& device,
PairFailure failure) {
NEARBY_LOGS(INFO) << __func__ << ": " << device
<< " with PairFailure: " << failure;
if (!IsDeviceUnderPairing(device)) {
NEARBY_LOGS(WARNING) << "unexpected on pair failure callback";
return;
}
FinishPairing(
absl::InternalError(absl::StrFormat("Pairing failed with %v", failure)));
}
bool FastPairSeekerImpl::IsDeviceUnderPairing(const FastPairDevice& device) {
return device_under_pairing_ == &device;
}
void FastPairSeekerImpl::FinishPairing(absl::Status result) {
if (pairing_callback_ && device_under_pairing_ != nullptr) {
pairing_callback_->on_pairing_result(*device_under_pairing_, result);
}
pairing_callback_.reset();
device_under_pairing_ = nullptr;
}
void FastPairSeekerImpl::SetIsScreenLocked(bool locked) {
NEARBY_LOGS(INFO) << __func__ << ": Screen lock state changed. ( "
<< std::boolalpha << locked << ")";
is_screen_locked_ = locked;
callbacks_.on_screen_event(ScreenEvent{.is_locked = locked});
}
void FastPairSeekerImpl::InvalidateScanningState() {
// Stop scanning when screen is off.
if (is_screen_locked_) {
absl::Status status = StopFastPairScan();
NEARBY_LOGS(VERBOSE) << __func__
<< ": Stopping scanning because the screen is locked.";
return;
}
// TODO(b/275452353): Check if bluetooth and fast pair is enabled
// Screen is on, Bluetooth is enabled, and Fast Pair is enabled, start
// scanning.
absl::Status status = StartFastPairScan();
}
void FastPairSeekerImpl::DeviceAdded(BluetoothDevice& device) {
NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ")";
}
void FastPairSeekerImpl::DeviceRemoved(BluetoothDevice& device) {
NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ")";
}
void FastPairSeekerImpl::DeviceAddressChanged(BluetoothDevice& device,
absl::string_view old_address) {
NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", "
<< old_address << ")";
}
void FastPairSeekerImpl::DevicePairedChanged(BluetoothDevice& device,
bool new_paired_status) {
NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", "
<< new_paired_status << ")";
// Note, the FP service will be notified about paired events from the
// retroactive pairing path if `device` is an FP device.
// TODO(jsobczak): Notify service about unpair events if `device` is a known
// FP device.
}
void FastPairSeekerImpl::DeviceConnectedStateChanged(BluetoothDevice& device,
bool connected) {
NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", "
<< connected << ")";
}
void FastPairSeekerImpl::OnRetroactivePairFound(FastPairDevice& device) {
NEARBY_LOGS(VERBOSE) << __func__ << ": " << device;
callbacks_.on_pair_event(device, PairEvent{.is_paired = true});
}
void FastPairSeekerImpl::ForgetDeviceByAccountKey(
const AccountKey& account_key) {
NEARBY_LOGS(VERBOSE) << __func__;
auto opt_device = devices_->FindDevice(account_key);
if (!opt_device.has_value()) {
NEARBY_LOGS(INFO) << __func__ << "No FP device matching the account key.";
} else {
devices_->RemoveDevice(opt_device.value());
}
repository_->DeleteAssociatedDeviceByAccountKey(
account_key, [&](absl::Status success) {
if (!success.ok()) return;
NEARBY_LOGS(VERBOSE) << "Deleted associated devcie by account key";
// Temporary solution to refresh the saved_devices_sheet.
repository_->GetUserSavedDevices();
});
}
} // namespace fastpair
} // namespace nearby
-148
View File
@@ -1,148 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_
#include <memory>
#include <optional>
#include <utility>
#include "fastpair/fast_pair_controller.h"
#include "fastpair/fast_pair_events.h"
#include "fastpair/fast_pair_seeker.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/pairing/pairer_broker_impl.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "fastpair/retroactive/retroactive.h"
#include "fastpair/retroactive/retroactive_pairing_detector_impl.h"
#include "fastpair/scanning/scanner_broker_impl.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
// Fast Pair Seeker Extended interface.
// The methods in this interface are available only to FP internal plugins.
class FastPairSeekerExt : public FastPairSeeker {
public:
virtual absl::Status StartFastPairScan() = 0;
virtual absl::Status StopFastPairScan() = 0;
// Handle the state changes of screen lock.
virtual void SetIsScreenLocked(bool is_locked) = 0;
virtual void ForgetDeviceByAccountKey(const AccountKey& account_key) = 0;
};
class FastPairSeekerImpl : public FastPairSeekerExt,
ScannerBrokerImpl::Observer,
PairerBroker::Observer,
BluetoothClassicMedium::Observer,
RetroactivePairingDetector::Observer {
public:
struct ServiceCallbacks {
absl::AnyInvocable<void(const FastPairDevice&, InitialDiscoveryEvent)>
on_initial_discovery;
absl::AnyInvocable<void(const FastPairDevice&, SubsequentDiscoveryEvent)>
on_subsequent_discovery;
absl::AnyInvocable<void(const FastPairDevice&, PairEvent)> on_pair_event;
absl::AnyInvocable<void(ScreenEvent)> on_screen_event;
absl::AnyInvocable<void(const FastPairDevice&, BatteryEvent)>
on_battery_event;
absl::AnyInvocable<void(const FastPairDevice&, RingEvent)> on_ring_event;
};
FastPairSeekerImpl(ServiceCallbacks callbacks, SingleThreadExecutor* executor,
AccountManager* account_manager,
FastPairDeviceRepository* devices,
FastPairRepository* repository);
~FastPairSeekerImpl() override;
// From FastPairSeeker.
absl::Status StartInitialPairing(const FastPairDevice& device,
const InitialPairingParam& params,
PairingCallback callback) override;
absl::Status StartSubsequentPairing(const FastPairDevice& device,
const SubsequentPairingParam& params,
PairingCallback callback) override;
absl::Status StartRetroactivePairing(const FastPairDevice& device,
const RetroactivePairingParam& param,
PairingCallback callback) override;
absl::Status FinishRetroactivePairing(
const FastPairDevice& device, const FinishRetroactivePairingParam& param,
PairingCallback callback) override;
// From FastPairSeekerExt.
absl::Status StartFastPairScan() override;
absl::Status StopFastPairScan() override;
void SetIsScreenLocked(bool is_locked) override;
void ForgetDeviceByAccountKey(const AccountKey& account_key) override;
// From BluetoothClassicMedium::Observer.
void DeviceAdded(BluetoothDevice& device) override;
void DeviceRemoved(BluetoothDevice& device) override;
void DeviceAddressChanged(BluetoothDevice& device,
absl::string_view old_address) override;
void DevicePairedChanged(BluetoothDevice& device,
bool new_paired_status) override;
void DeviceConnectedStateChanged(BluetoothDevice& device,
bool connected) override;
// From RetroactivePairingDetector::Observer.
void OnRetroactivePairFound(FastPairDevice& device) override;
// Internal methods, not exported to plugins.
private:
// From ScannerBrokerImpl::Observer.
void OnDeviceFound(FastPairDevice& device) override;
void OnDeviceLost(FastPairDevice& device) override;
// From PairerBroker:Observer
void OnDevicePaired(FastPairDevice& device) override;
void OnAccountKeyWrite(FastPairDevice& device,
std::optional<PairFailure> error) override;
void OnPairingComplete(FastPairDevice& device) override;
void OnPairFailure(FastPairDevice& device, PairFailure failure) override;
void InvalidateScanningState() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
bool IsDeviceUnderPairing(const FastPairDevice& device);
void FinishPairing(absl::Status result);
ServiceCallbacks callbacks_;
SingleThreadExecutor* executor_;
AccountManager* account_manager_;
FastPairDeviceRepository* devices_;
FastPairRepository* repository_;
Mediums mediums_;
std::unique_ptr<ScannerBrokerImpl> scanner_;
std::unique_ptr<ScannerBrokerImpl::ScanningSession> scanning_session_;
std::unique_ptr<PairerBrokerImpl> pairer_broker_;
std::unique_ptr<PairingCallback> pairing_callback_;
std::unique_ptr<RetroactivePairingDetectorImpl> retro_detector_;
std::unique_ptr<FastPairController> controller_;
std::unique_ptr<Retroactive> retroactive_pair_;
FastPairDevice* device_under_pairing_ = nullptr;
FastPairDevice* test_device_ = nullptr;
bool is_screen_locked_ = false;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_DEFAULT_FAST_PAIR_SEEKER_H_
@@ -1,382 +0,0 @@
// Copyright 2023 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 "fastpair/internal/fast_pair_seeker_impl.h"
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/fast_pair_events.h"
#include "fastpair/fast_pair_seeker.h"
#include "fastpair/message_stream/fake_gatt_callbacks.h"
#include "fastpair/message_stream/fake_provider.h"
#include "fastpair/proto/data.proto.h"
#include "fastpair/proto/enum.proto.h"
#include "fastpair/repository/fake_fast_pair_repository.h"
#include "fastpair/repository/fast_pair_device_repository.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/test/fake_account_manager.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr absl::string_view kServiceID{"Fast Pair"};
constexpr absl::string_view kFastPairServiceUuid{
"0000FE2C-0000-1000-8000-00805F9B34FB"};
constexpr absl::string_view kModelId{"718c17"};
constexpr absl::string_view kBobPrivateKey =
"02B437B0EDD6BBD429064A4E529FCBF1C48D0D624924D592274B7ED81193D763";
constexpr absl::string_view kBobPublicKey =
"F7D496A62ECA416351540AA343BC690A6109F551500666B83B1251FB84FA2860795EBD63D3"
"B8836F44A9A3E28BB34017E015F5979305D849FDF8DE10123B61D2";
constexpr absl::string_view kPasskey = "123456";
constexpr absl::string_view kTestAccountId = "test_account_id";
using ::testing::status::StatusIs;
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
class FastPairRepositoryObserver : public FastPairRepository::Observer {
public:
explicit FastPairRepositoryObserver(CountDownLatch* latch) { latch_ = latch; }
void OnGetUserSavedDevices(
const proto::OptInStatus& opt_in_status,
const std::vector<proto::FastPairDevice>& devices) override {
latch_->CountDown();
}
CountDownLatch* latch_ = nullptr;
};
class FastPairSeekerImplTest : public testing::Test {
protected:
FastPairSeekerImplTest() = default;
void SetUp() override {
NEARBY_LOG_SET_SEVERITY(VERBOSE);
repository_ = FakeFastPairRepository::Create(
kModelId, absl::HexStringToBytes(kBobPublicKey));
repository_->SetResultOfIsDeviceSavedToAccount(
absl::NotFoundError("not found"));
account_manager_ = std::make_unique<FakeAccountManager>();
AccountManager::Account account;
account.id = kTestAccountId;
account_manager_->SetAccount(account);
}
void TearDown() override { executor_.Shutdown(); }
void WaitForBackgroundTasks() {
CountDownLatch latch(1);
executor_.Execute([&]() { latch.CountDown(); });
latch.Await();
}
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
std::unique_ptr<FakeAccountManager> account_manager_;
FastPairDeviceRepository devices_{&executor_};
std::unique_ptr<FakeFastPairRepository> repository_;
std::unique_ptr<FastPairSeekerImpl> fast_pair_seeker_;
FakeGattCallbacks fake_gatt_callbacks_;
};
TEST_F(FastPairSeekerImplTest, StartAndStopFastPairScan) {
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{}, &executor_,
account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
EXPECT_OK(fast_pair_seeker_->StopFastPairScan());
}
TEST_F(FastPairSeekerImplTest, DISABLED_DiscoverDevice) {
FakeProvider provider;
CountDownLatch latch(1);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
[&](const FastPairDevice& device, InitialDiscoveryEvent event) {
EXPECT_EQ(device.GetModelId(), kModelId);
latch.CountDown();
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
provider.StartDiscoverableAdvertisement(kModelId);
// Waits for the device to be discovered
latch.Await();
}
TEST_F(FastPairSeekerImplTest, StartFastPairScanTwiceFails) {
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{}, &executor_,
account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
EXPECT_THAT(fast_pair_seeker_->StartFastPairScan(),
StatusIs(absl::StatusCode::kAlreadyExists));
}
TEST_F(FastPairSeekerImplTest, StopFastPairScanTwiceFails) {
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{}, &executor_,
account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
EXPECT_OK(fast_pair_seeker_->StopFastPairScan());
EXPECT_THAT(fast_pair_seeker_->StopFastPairScan(),
StatusIs(absl::StatusCode::kNotFound));
}
TEST_F(FastPairSeekerImplTest, ScreenLocksDuringAdvertising) {
CountDownLatch latch(2);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
[&](const FastPairDevice& device, InitialDiscoveryEvent event) {
latch.CountDown();
},
.on_screen_event =
[&](ScreenEvent event) {
EXPECT_TRUE(event.is_locked);
latch.CountDown();
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
// Create Advertiser and startAdvertising
Mediums mediums_2;
std::string service_id(kServiceID);
ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
mediums_2.GetBle().GetMedium().StartAdvertising(
service_id, advertisement_bytes, fast_pair_service_uuid);
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
fast_pair_seeker_->SetIsScreenLocked(true);
EXPECT_TRUE(latch.Await().Ok());
}
TEST_F(FastPairSeekerImplTest, InitialPairing) {
NEARBY_LOG_SET_SEVERITY(VERBOSE);
FakeProvider provider;
CountDownLatch discover_latch(1);
CountDownLatch pair_latch(1);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
[&](const FastPairDevice& device, InitialDiscoveryEvent event) {
EXPECT_EQ(device.GetModelId(), kModelId);
EXPECT_OK(fast_pair_seeker_->StartInitialPairing(
device, {},
{.on_pairing_result = [&](const FastPairDevice& device,
absl::Status status) {
EXPECT_EQ(device.GetBleAddress(),
provider.GetMacAddress());
EXPECT_OK(status);
pair_latch.CountDown();
}}));
discover_latch.CountDown();
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
provider.PrepareForInitialPairing(
{
.private_key = absl::HexStringToBytes(kBobPrivateKey),
.public_key = absl::HexStringToBytes(kBobPublicKey),
.model_id = std::string(kModelId),
.pass_key = std::string(kPasskey),
},
&fake_gatt_callbacks_);
discover_latch.Await();
pair_latch.Await();
auto fp_device = devices_.FindDevice(provider.GetMacAddress());
ASSERT_TRUE(fp_device.has_value());
EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey());
fast_pair_seeker_.reset();
}
TEST_F(FastPairSeekerImplTest, ForgetDeviceByAccountKey) {
NEARBY_LOG_SET_SEVERITY(VERBOSE);
FakeProvider provider;
CountDownLatch discover_latch(1);
CountDownLatch pair_latch(1);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
[&](const FastPairDevice& device, InitialDiscoveryEvent event) {
EXPECT_EQ(device.GetModelId(), kModelId);
EXPECT_OK(fast_pair_seeker_->StartInitialPairing(
device, {},
{.on_pairing_result = [&](const FastPairDevice& device,
absl::Status status) {
EXPECT_EQ(device.GetBleAddress(),
provider.GetMacAddress());
EXPECT_OK(status);
pair_latch.CountDown();
}}));
discover_latch.CountDown();
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
EXPECT_OK(fast_pair_seeker_->StartFastPairScan());
provider.PrepareForInitialPairing(
{
.private_key = absl::HexStringToBytes(kBobPrivateKey),
.public_key = absl::HexStringToBytes(kBobPublicKey),
.model_id = std::string(kModelId),
.pass_key = std::string(kPasskey),
},
&fake_gatt_callbacks_);
discover_latch.Await();
pair_latch.Await();
auto fp_device = devices_.FindDevice(provider.GetMacAddress());
ASSERT_TRUE(fp_device.has_value());
EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey());
// Adds FastPairRepository observer.
CountDownLatch repository_latch(1);
FastPairRepositoryObserver observer(&repository_latch);
repository_->AddObserver(&observer);
// Adds FastPairDeviceRepository observer.
CountDownLatch devices_latch(1);
FastPairDeviceRepository::RemoveDeviceCallback callback =
[&](const FastPairDevice& device) { devices_latch.CountDown(); };
devices_.AddObserver(&callback);
fast_pair_seeker_->ForgetDeviceByAccountKey(
fp_device.value()->GetAccountKey());
repository_latch.Await();
devices_latch.Await();
EXPECT_FALSE(devices_.FindDevice(provider.GetMacAddress()).has_value());
fast_pair_seeker_.reset();
}
TEST_F(FastPairSeekerImplTest, RetroactivePairingWithUserConsent) {
NEARBY_LOG_SET_SEVERITY(VERBOSE);
FakeProvider provider;
CountDownLatch pair_latch(1);
CountDownLatch retro_latch(1);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_pair_event =
[&](const FastPairDevice& device, PairEvent event) {
NEARBY_LOGS(INFO) << "Pair callback";
pair_latch.CountDown();
EXPECT_OK(fast_pair_seeker_->StartRetroactivePairing(
device, RetroactivePairingParam{},
{.on_pairing_result = [&](const FastPairDevice&,
absl::Status status) {
EXPECT_OK(status);
retro_latch.CountDown();
}}));
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
provider.PrepareForRetroactivePairing(
{.private_key = absl::HexStringToBytes(kBobPrivateKey),
.public_key = absl::HexStringToBytes(kBobPublicKey),
.model_id = std::string(kModelId)},
&fake_gatt_callbacks_);
EXPECT_TRUE(pair_latch.Await().Ok());
EXPECT_TRUE(retro_latch.Await().Ok());
auto fp_device = devices_.FindDevice(provider.GetMacAddress());
ASSERT_TRUE(fp_device.has_value());
EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey());
// The client asks the user for consent, the user grants it.
CountDownLatch finish_latch(1);
EXPECT_OK(fast_pair_seeker_->FinishRetroactivePairing(
**fp_device, FinishRetroactivePairingParam{.save_account_key = true},
{.on_pairing_result = [&](const FastPairDevice&, absl::Status status) {
EXPECT_OK(status);
finish_latch.CountDown();
}}));
EXPECT_TRUE(finish_latch.Await());
}
TEST_F(FastPairSeekerImplTest, RetroactivePairingNoUserConsent) {
NEARBY_LOG_SET_SEVERITY(VERBOSE);
FakeProvider provider;
CountDownLatch pair_latch(1);
CountDownLatch retro_latch(1);
fast_pair_seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_pair_event =
[&](const FastPairDevice& device, PairEvent event) {
NEARBY_LOGS(INFO) << "Pair callback";
pair_latch.CountDown();
EXPECT_OK(fast_pair_seeker_->StartRetroactivePairing(
device, RetroactivePairingParam{},
{.on_pairing_result = [&](const FastPairDevice&,
absl::Status status) {
EXPECT_OK(status);
retro_latch.CountDown();
}}));
}},
&executor_, account_manager_.get(), &devices_, repository_.get());
provider.PrepareForRetroactivePairing(
{.private_key = absl::HexStringToBytes(kBobPrivateKey),
.public_key = absl::HexStringToBytes(kBobPublicKey),
.model_id = std::string(kModelId)},
&fake_gatt_callbacks_);
EXPECT_TRUE(pair_latch.Await().Ok());
EXPECT_TRUE(retro_latch.Await().Ok());
auto fp_device = devices_.FindDevice(provider.GetMacAddress());
ASSERT_TRUE(fp_device.has_value());
EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey());
// The client asks the user for consent, the user rejects it.
CountDownLatch finish_latch(1);
EXPECT_OK(fast_pair_seeker_->FinishRetroactivePairing(
**fp_device, FinishRetroactivePairingParam{.save_account_key = false},
{.on_pairing_result = [&](const FastPairDevice&, absl::Status status) {
EXPECT_OK(status);
finish_latch.CountDown();
}}));
EXPECT_TRUE(finish_latch.Await());
// The device should be deleted.
WaitForBackgroundTasks();
EXPECT_FALSE(devices_.FindDevice(provider.GetMacAddress()).has_value());
}
} // namespace
} // namespace fastpair
} // namespace nearby
-38
View File
@@ -1,38 +0,0 @@
# 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.
licenses(["notice"])
cc_library(
name = "platform_windows_libs",
linkopts = [
"wininet.lib",
"kernel32.lib",
"user32.lib",
"gdi32.lib",
"winspool.lib",
"comdlg32.lib",
"advapi32.lib",
"shell32.lib",
"ole32.lib",
"oleaut32.lib",
"uuid.lib",
"odbc32.lib",
"odbccp32.lib",
"wbemuuid.lib",
"wtsapi32.lib",
"version.lib",
],
visibility = ["//visibility:private"],
)
-151
View File
@@ -1,151 +0,0 @@
# 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.
licenses(["notice"])
cc_library(
name = "mediums",
srcs = [
"ble.cc",
"ble_v2.cc",
"bluetooth_classic.cc",
"bluetooth_radio.cc",
"robust_gatt_client.cc",
],
hdrs = [
"ble.h",
"ble_v2.h",
"bluetooth_classic.h",
"bluetooth_radio.h",
"mediums.h",
"robust_gatt_client.h",
],
visibility = [
"//fastpair:__subpackages__",
],
deps = [
"//fastpair/common",
"//internal/platform:comm",
"//internal/platform:types",
"//internal/platform/implementation:comm",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
)
cc_test(
name = "bluetooth_radio_test",
size = "small",
srcs = [
"bluetooth_radio_test.cc",
],
shard_count = 16,
deps = [
":mediums",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "mediums_test",
size = "small",
srcs = [
"mediums_test.cc",
],
shard_count = 16,
deps = [
":mediums",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "ble_test",
size = "small",
srcs = [
"ble_test.cc",
],
shard_count = 16,
deps = [
":mediums",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "ble_v2_test",
size = "small",
srcs = [
"ble_v2_test.cc",
],
shard_count = 16,
deps = [
":mediums",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "bluetooth_classic_test",
size = "small",
srcs = [
"bluetooth_classic_test.cc",
],
shard_count = 16,
deps = [
":mediums",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "robust_gatt_client_test",
size = "small",
srcs = [
"robust_gatt_client_test.cc",
],
deps = [
":mediums",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
-127
View File
@@ -1,127 +0,0 @@
// 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 "fastpair/internal/mediums/ble.h"
#include <string>
#include <utility>
#include "fastpair/internal/mediums/bluetooth_radio.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
namespace nearby {
namespace fastpair {
Ble::Ble(BluetoothRadio& radio) : radio_(radio) {}
bool Ble::IsAvailable() const {
MutexLock lock(&mutex_);
return IsAvailableLocked();
}
bool Ble::IsAvailableLocked() const {
return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled();
}
bool Ble::StartScanning(const std::string& service_id,
const std::string& fast_pair_service_uuid,
DiscoveredPeripheralCallback callback) {
MutexLock lock(&mutex_);
discovered_peripheral_callback_ = std::move(callback);
if (service_id.empty()) {
NEARBY_LOGS(INFO)
<< "Refusing to start BLE scanning with empty service id.";
return false;
}
if (IsScanningLocked()) {
NEARBY_LOGS(INFO) << "Refusing to start BLE scanning because "
"another scanning is already in-progress.";
return false;
}
if (!radio_.IsEnabled()) {
NEARBY_LOGS(INFO)
<< "Can't start BLE scanning because Bluetooth was NOT enabled";
return false;
}
if (!IsAvailableLocked()) {
NEARBY_LOGS(INFO) << "Can't scan BLE scanning because BLE isn't available.";
return false;
}
if (!medium_.StartScanning(
service_id, fast_pair_service_uuid,
{
.peripheral_discovered_cb =
[this](BlePeripheral& peripheral,
const std::string& service_id,
const ByteArray& medium_advertisement_bytes,
bool fast_advertisement) {
// Don't bother trying to parse zero byte advertisements.
if (medium_advertisement_bytes.size() == 0) {
NEARBY_LOGS(INFO) << "Skipping zero byte advertisement "
<< "with service_id: " << service_id;
return;
}
discovered_peripheral_callback_.peripheral_discovered_cb(
peripheral, service_id, medium_advertisement_bytes,
fast_advertisement);
},
.peripheral_lost_cb =
[this](BlePeripheral& peripheral,
const std::string& service_id) {
discovered_peripheral_callback_.peripheral_lost_cb(
peripheral, service_id);
},
})) {
NEARBY_LOGS(INFO) << "Failed to start BLE scanning";
return false;
}
NEARBY_LOGS(INFO) << "Start BLE scanning with service id=" << service_id;
// Mark the fact that we're currently performing a BLE scanning.
is_scanning_ = true;
return true;
}
bool Ble::StopScanning(const std::string& service_id) {
MutexLock lock(&mutex_);
if (!IsScanningLocked()) {
NEARBY_LOGS(INFO) << "Can't stop BLE scanning because we never "
"started scanning.";
return false;
}
NEARBY_LOGS(INFO) << "Stop BLE scanning with service id=" << service_id;
bool ret = medium_.StopScanning(service_id);
is_scanning_ = false;
return ret;
}
bool Ble::IsScanning() {
NEARBY_LOGS(INFO) << __func__;
MutexLock lock(&mutex_);
return IsScanningLocked();
}
bool Ble::IsScanningLocked() { return is_scanning_; }
} // namespace fastpair
} // namespace nearby
-78
View File
@@ -1,78 +0,0 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_BLE_BLE_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_BLE_BLE_H_
#include <string>
#include "fastpair/internal/mediums/bluetooth_radio.h"
#include "internal/platform/ble.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/mutex.h"
namespace nearby {
namespace fastpair {
// Provides the operations that can be performed on the Bluetooth Low Energy
// (BLE) medium.
class Ble {
public:
using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback;
explicit Ble(BluetoothRadio& bluetooth_radio);
Ble(Ble&&) = delete;
Ble& operator=(Ble&&) = delete;
~Ble() = default;
// Returns true, if Ble communications are supported by a platform.
bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_);
// Enables Ble scanning mode. Will report any discoverable peripherals in
// range through a callback. Returns true, if scanning mode was enabled,
// false otherwise.
bool StartScanning(const std::string& service_id,
const std::string& fast_pair_service_uuid,
DiscoveredPeripheralCallback callback)
ABSL_LOCKS_EXCLUDED(mutex_);
// Disables Ble discovery mode.
bool StopScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_);
// Return true if Ble is currenlty scanning.
bool IsScanning() ABSL_LOCKS_EXCLUDED(mutex_);
// Return BleMedium
BleMedium& GetMedium() { return medium_; }
private:
// Same as IsAvailable(), but must be called with mutex_ held.
bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Same as IsDiscovering(), but must be called with mutex_ held.
bool IsScanningLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable Mutex mutex_;
DiscoveredPeripheralCallback discovered_peripheral_callback_;
BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){
radio_.GetBluetoothAdapter()};
BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_};
bool is_scanning_ = false;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_BLE_BLE_H_
-80
View File
@@ -1,80 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/ble.h"
#include <string>
#include "gtest/gtest.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
namespace nearby {
namespace fastpair {
namespace {
using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback;
constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"};
constexpr absl::string_view kAdvertisementString{"96C12E"};
constexpr absl::string_view kFastPairServiceUuid{"\x2c\xfe"};
TEST(BleTest, ConstructorDestructorWorks) {
BluetoothRadio radio;
Ble ble(radio);
EXPECT_TRUE(ble.IsAvailable());
EXPECT_FALSE(ble.IsScanning());
}
TEST(BleTest, CanStartDiscovery) {
MediumEnvironment::Instance().Start();
BluetoothRadio radio_a;
BluetoothRadio radio_b;
Ble ble_a{radio_a};
Ble ble_b{radio_b};
radio_a.Enable();
radio_b.Enable();
std::string service_id(kServiceID);
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
std::string fast_pair_service_uuid(kFastPairServiceUuid);
CountDownLatch accept_latch(1);
CountDownLatch lost_latch(1);
ble_b.GetMedium().StartAdvertising(service_id, advertisement_bytes,
fast_pair_service_uuid);
EXPECT_TRUE(ble_a.StartScanning(
service_id, fast_pair_service_uuid,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&accept_latch](
BlePeripheral& peripheral, const std::string& service_id,
const ByteArray& advertisement_bytes,
bool fast_advertisement) { accept_latch.CountDown(); },
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
}));
EXPECT_TRUE(ble_a.IsScanning());
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
ble_b.GetMedium().StopAdvertising(service_id);
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
EXPECT_TRUE(ble_a.StopScanning(service_id));
EXPECT_FALSE(ble_a.IsScanning());
MediumEnvironment::Instance().Stop();
}
} // namespace
} // namespace fastpair
} // namespace nearby
-60
View File
@@ -1,60 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/ble_v2.h"
#include <memory>
#include <string>
#include <utility>
#include "internal/platform/mutex_lock.h"
namespace nearby {
namespace fastpair {
BleV2::BleV2(BluetoothRadio& radio) : radio_(radio) {}
bool BleV2::IsAvailable() const {
MutexLock lock(&mutex_);
return IsAvailableLocked();
}
bool BleV2::IsAvailableLocked() const {
return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled();
}
std::unique_ptr<RobustGattClient> BleV2::ConnectToGattServer(
absl::string_view ble_address, RobustGattClient::ConnectionParams params,
RobustGattClient::ConnectionStatusCallback connection_status_callback) {
MutexLock lock(&mutex_);
if (!radio_.IsEnabled()) {
NEARBY_LOGS(INFO)
<< "Can't connect to GattServer because Bluetooth was NOT enabled";
return nullptr;
}
if (!IsAvailableLocked()) {
NEARBY_LOGS(VERBOSE)
<< __func__
<< "Can't connect to GattServer because BleV2 isn't available.";
return nullptr;
}
BleV2Peripheral v2_peripheral =
medium_.GetRemotePeripheral(std::string(ble_address));
return std::make_unique<RobustGattClient>(
medium_, v2_peripheral, std::move(params),
std::move(connection_status_callback));
}
} // namespace fastpair
} // namespace nearby
-60
View File
@@ -1,60 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_
#include <memory>
#include <string>
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/internal/mediums/bluetooth_radio.h"
#include "fastpair/internal/mediums/robust_gatt_client.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
namespace nearby {
namespace fastpair {
// Provides the operations that can be performed on the Bluetooth Low Energy
// (BLE_V2) medium.
class BleV2 {
public:
explicit BleV2(BluetoothRadio& bluetooth_radio);
~BleV2() = default;
// Returns true, if BleV2 communications are supported by a platform.
bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns a new GattClient connection to a gatt server.
std::unique_ptr<RobustGattClient> ConnectToGattServer(
absl::string_view ble_address, RobustGattClient::ConnectionParams params,
RobustGattClient::ConnectionStatusCallback connection_status_callback);
private:
// Same as IsAvailable(), but must be called with mutex_ held.
bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable Mutex mutex_;
BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){
radio_.GetBluetoothAdapter()};
BleV2Medium medium_ ABSL_GUARDED_BY(mutex_){adapter_};
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_
-46
View File
@@ -1,46 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/ble_v2.h"
#include "gtest/gtest.h"
namespace nearby {
namespace fastpair {
namespace {
TEST(BleV2Test, IsAvailable) {
BluetoothRadio radio;
BleV2 bleV2(radio);
EXPECT_TRUE(bleV2.IsAvailable());
EXPECT_TRUE(radio.Disable());
EXPECT_FALSE(bleV2.IsAvailable());
}
TEST(BleV2Test, CanConnectToGattServer) {
BluetoothRadio radio;
BleV2 bleV2(radio);
EXPECT_TRUE(bleV2.ConnectToGattServer("bleaddress", {}, nullptr));
}
TEST(BleV2Test, CannotConnectToGattServer) {
BluetoothRadio radio;
BleV2 bleV2(radio);
EXPECT_TRUE(radio.Disable());
EXPECT_FALSE(bleV2.ConnectToGattServer("bleaddress", {}, nullptr));
}
} // namespace
} // namespace fastpair
} // namespace nearby
@@ -1,115 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/bluetooth_classic.h"
#include <memory>
#include <string>
#include "absl/strings/escaping.h"
#include "internal/platform/bluetooth_adapter.h"
namespace nearby {
namespace fastpair {
BluetoothClassic::BluetoothClassic(BluetoothRadio& radio) : radio_(radio) {}
bool BluetoothClassic::IsAvailable() const {
MutexLock lock(&mutex_);
return IsAvailableLocked();
}
bool BluetoothClassic::IsAvailableLocked() const {
return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled();
}
void BluetoothClassic::AddObserver(BluetoothClassicMedium::Observer* observer) {
MutexLock lock(&mutex_);
medium_.AddObserver(observer);
}
void BluetoothClassic::RemoveObserver(
BluetoothClassicMedium::Observer* observer) {
MutexLock lock(&mutex_);
medium_.RemoveObserver(observer);
}
bool BluetoothClassic::StartDiscovery() {
MutexLock lock(&mutex_);
if (!radio_.IsEnabled()) {
NEARBY_LOGS(INFO) << "Can't discover BT devices because BT isn't enabled.";
return false;
}
if (!IsAvailableLocked()) {
NEARBY_LOGS(INFO)
<< "Can't discover BT devices because BT isn't available.";
return false;
}
if (!medium_.StartDiscovery({})) {
NEARBY_LOGS(INFO) << "Failed to start discovery of BT devices.";
return false;
}
// Mark the fact that we're currently performing a Bluetooth scan.
is_scanning = true;
return true;
}
bool BluetoothClassic::StopDiscovery() {
MutexLock lock(&mutex_);
if (!IsDiscovering()) {
NEARBY_LOGS(INFO)
<< "Can't stop discovery of BT devices because it never started.";
return false;
}
if (!medium_.StopDiscovery()) {
NEARBY_LOGS(INFO) << "Failed to stop discovery of Bluetooth devices.";
return false;
}
is_scanning = false;
return true;
}
bool BluetoothClassic::IsDiscovering() const { return is_scanning; }
std::unique_ptr<BluetoothPairing> BluetoothClassic::CreatePairing(
absl::string_view public_address) {
MutexLock lock(&mutex_);
if (!radio_.IsEnabled()) {
NEARBY_LOGS(INFO)
<< __func__
<< "Can't create bluetooth pairing because Bluetooth was NOT enabled";
return nullptr;
}
if (!IsAvailableLocked()) {
NEARBY_LOGS(VERBOSE) << __func__
<< "Can't create bluetooth pairing because "
"BluetoothClassic isn't available.";
return nullptr;
}
BluetoothDevice device = medium_.GetRemoteDevice(std::string(public_address));
if (!device.IsValid()) {
NEARBY_LOGS(INFO) << __func__
<< "Can't create bluetooth pairing because Bluetooth "
"device was NOT found";
return nullptr;
}
return medium_.CreatePairing(device);
}
BluetoothClassicMedium& BluetoothClassic::GetMedium() { return medium_; }
} // namespace fastpair
} // namespace nearby
@@ -1,71 +0,0 @@
// Copyright 2023 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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_
#include <memory>
#include "absl/strings/string_view.h"
#include "fastpair/internal/mediums/bluetooth_radio.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/mutex.h"
namespace nearby {
namespace fastpair {
class BluetoothClassic {
public:
explicit BluetoothClassic(BluetoothRadio& bluetooth_radio);
~BluetoothClassic() = default;
// Returns true, if BT communications are supported by a platform.
bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_);
void AddObserver(BluetoothClassicMedium::Observer* observer);
void RemoveObserver(BluetoothClassicMedium::Observer* observer);
// Enables BT discovery mode to observer any discoverable device in range.
// Returns true, if discovery mode was enabled, false otherwise.
bool StartDiscovery() ABSL_LOCKS_EXCLUDED(mutex_);
// Disables BT discovery mode.
// Returns true, if discovery mode was previously enabled, false otherwise.
bool StopDiscovery() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns a new BluetoothPairing instance to handle the pairing process
// with the remote device.
std::unique_ptr<BluetoothPairing> CreatePairing(
absl::string_view public_address);
BluetoothClassicMedium& GetMedium() ABSL_LOCKS_EXCLUDED(mutex_);
private:
// Same as IsAvailable(), but must be called with mutex_ held.
bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if device is currently in discovery mode.
bool IsDiscovering() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable Mutex mutex_;
BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){
radio_.GetBluetoothAdapter()};
BluetoothClassicMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_};
bool is_scanning ABSL_GUARDED_BY(mutex_) = false;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_
@@ -1,154 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/bluetooth_classic.h"
#include "gtest/gtest.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
namespace nearby {
namespace fastpair {
namespace {
class BluetoothClassicMediumObserver
: public BluetoothClassicMedium ::Observer {
public:
explicit BluetoothClassicMediumObserver(
BluetoothClassic* bluetooth_classic, CountDownLatch* device_added_latch,
CountDownLatch* device_removed_latch,
CountDownLatch* device_paired_changed_latch)
: bluetooth_classic_(bluetooth_classic),
device_added_latch_(device_added_latch),
device_removed_latch_(device_removed_latch),
device_paired_changed_latch_(device_paired_changed_latch) {
bluetooth_classic_->AddObserver(this);
}
~BluetoothClassicMediumObserver() override {
bluetooth_classic_->RemoveObserver(this);
}
void DeviceAdded(BluetoothDevice& device) override {
if (!device_added_latch_) return;
device_added_latch_->CountDown();
}
void DeviceRemoved(BluetoothDevice& device) override {
if (!device_removed_latch_) return;
device_removed_latch_->CountDown();
}
void DevicePairedChanged(BluetoothDevice& device,
bool new_paired_status) override {
if (!device_paired_changed_latch_) return;
device_paired_changed_latch_->CountDown();
}
BluetoothClassic* bluetooth_classic_;
CountDownLatch* device_added_latch_;
CountDownLatch* device_removed_latch_;
CountDownLatch* device_paired_changed_latch_;
};
TEST(BluetoothClassicTest, CanStartAndStopDiscovery) {
MediumEnvironment::Instance().Start();
BluetoothRadio radio;
BluetoothClassic bluetooth_classic(radio);
BluetoothAdapter provider_adapter;
provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled);
provider_adapter.SetScanMode(
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
BluetoothClassicMedium bt_provider(provider_adapter);
CountDownLatch device_added_latch(1);
CountDownLatch device_removed_latch(1);
BluetoothClassicMediumObserver observer(
&bluetooth_classic, &device_added_latch, &device_removed_latch, nullptr);
EXPECT_TRUE(bluetooth_classic.StartDiscovery());
device_added_latch.Await();
provider_adapter.SetStatus(BluetoothAdapter::Status::kDisabled);
device_removed_latch.Await();
EXPECT_TRUE(bluetooth_classic.StopDiscovery());
MediumEnvironment::Instance().Stop();
}
TEST(BluetoothClassicTest, CanCreatePairing) {
MediumEnvironment::Instance().Start();
BluetoothRadio radio;
BluetoothClassic bluetooth_classic(radio);
BluetoothAdapter provider_adapter;
provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled);
BluetoothClassicMedium bt_provider(provider_adapter);
EXPECT_TRUE(bluetooth_classic.IsAvailable());
EXPECT_TRUE(
bluetooth_classic.CreatePairing(provider_adapter.GetMacAddress()));
MediumEnvironment::Instance().Stop();
}
TEST(BluetoothClassicTest, FailedToCreatePairingDueToRemoteDeviceNotFound) {
MediumEnvironment::Instance().Start();
BluetoothRadio radio;
BluetoothClassic bluetooth_classic(radio);
BluetoothAdapter provider_adapter;
provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled);
BluetoothClassicMedium bt_provider(provider_adapter);
EXPECT_TRUE(bluetooth_classic.IsAvailable());
EXPECT_FALSE(bluetooth_classic.CreatePairing("bleaddress"));
MediumEnvironment::Instance().Stop();
}
TEST(BluetoothClassicTest, RadioDisable) {
BluetoothRadio radio;
BluetoothClassic bluetooth_classic(radio);
BluetoothAdapter provider_adapter;
provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled);
BluetoothClassicMedium bt_provider(provider_adapter);
radio.Disable();
EXPECT_FALSE(bluetooth_classic.IsAvailable());
EXPECT_FALSE(
bluetooth_classic.CreatePairing(provider_adapter.GetMacAddress()));
EXPECT_FALSE(bluetooth_classic.StartDiscovery());
EXPECT_FALSE(bluetooth_classic.StopDiscovery());
}
TEST(BluetoothClassicTest, BluetoothAdapterDisable) {
BluetoothRadio radio;
radio.GetBluetoothAdapter().SetStatus(BluetoothAdapter::Status::kDisabled);
BluetoothClassic bluetooth_classic(radio);
BluetoothAdapter adapter_provider;
adapter_provider.SetStatus(BluetoothAdapter::Status::kEnabled);
BluetoothClassicMedium bt_provider(adapter_provider);
EXPECT_FALSE(bluetooth_classic.IsAvailable());
EXPECT_FALSE(
bluetooth_classic.CreatePairing(adapter_provider.GetMacAddress()));
EXPECT_FALSE(bluetooth_classic.StartDiscovery());
EXPECT_FALSE(bluetooth_classic.StopDiscovery());
}
TEST(BluetoothClassicTest, GetMedium) {
BluetoothRadio radio;
BluetoothClassic bluetooth_classic(radio);
EXPECT_TRUE(bluetooth_classic.GetMedium().IsValid());
}
} // namespace
} // namespace fastpair
} // namespace nearby
@@ -1,87 +0,0 @@
// Copyright 2023 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 "fastpair/internal/mediums/bluetooth_radio.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace fastpair {
BluetoothRadio::BluetoothRadio() {
if (!IsAdapterValid()) {
NEARBY_LOGS(ERROR) << "Bluetooth adapter is not valid: BT is not supported";
}
}
BluetoothRadio::~BluetoothRadio() {
NEARBY_LOGS(VERBOSE) << "~BluetoothRadio start";
// We never enabled Bluetooth, nothing to do.
if (!ever_saved_state_.Get()) {
NEARBY_LOGS(INFO) << "BT adapter was not used. Not touching HW.";
return;
}
NEARBY_LOGS(INFO) << "Bring BT adapter to original state";
if (!SetBluetoothState(originally_enabled_.Get())) {
NEARBY_LOGS(INFO) << "Failed to restore BT adapter original state.";
}
NEARBY_LOGS(VERBOSE) << "~BluetoothRadio done";
}
bool BluetoothRadio::Enable() {
NEARBY_LOGS(INFO) << __func__;
if (!SaveOriginalState()) {
return false;
}
return SetBluetoothState(true);
}
bool BluetoothRadio::Disable() {
if (!SaveOriginalState()) {
return false;
}
return SetBluetoothState(false);
}
bool BluetoothRadio::IsEnabled() const {
return IsAdapterValid() && IsInDesiredState(true);
}
bool BluetoothRadio::SetBluetoothState(bool enable) {
return bluetooth_adapter_.SetStatus(
enable ? BluetoothAdapter::Status::kEnabled
: BluetoothAdapter::Status::kDisabled);
}
bool BluetoothRadio::IsInDesiredState(bool should_be_enabled) const {
return bluetooth_adapter_.IsEnabled() == should_be_enabled;
}
bool BluetoothRadio::SaveOriginalState() {
if (!IsAdapterValid()) {
return false;
}
// If we haven't saved the original state of the radio, save it.
if (!ever_saved_state_.Set(true)) {
originally_enabled_.Set(bluetooth_adapter_.IsEnabled());
}
return true;
}
} // namespace fastpair
} // namespace nearby

Some files were not shown because too many files have changed in this diff Show More