mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Remove unused fastpair C++ implementation to streamline the codebase
PiperOrigin-RevId: 712639309
This commit is contained in:
committed by
Copybara-Service
parent
af790d0103
commit
f9292be707
@@ -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
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"],
|
||||
)
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
Reference in New Issue
Block a user