diff --git a/sharing/advertisement.cc b/sharing/advertisement.cc index 7b1c252f..480ab75d 100644 --- a/sharing/advertisement.cc +++ b/sharing/advertisement.cc @@ -58,11 +58,6 @@ enum class TlvTypes : uint8_t { kQrCode = 1, kVendorId = 2, }; - -enum class VendorId : uint8_t { - kNone = 0, - kSamsung = 1, -}; // The length in bytes of the vendor ID in the TLV advertisement. constexpr uint8_t kVendorIdLength = 1; @@ -162,7 +157,7 @@ std::vector Advertisement::ToEndpointInfo() const { // the ID itself (1 byte). int size = kMinimumSize + (device_name_.has_value() ? 1 : 0) + (device_name_.has_value() ? device_name_->size() : 0) + - (vendor_id_ != static_cast(VendorId::kNone) + (vendor_id_ != static_cast(BlockedVendorId::kNone) ? (kTlvMinimumLength + kVendorIdLength) : 0); @@ -183,7 +178,7 @@ std::vector Advertisement::ToEndpointInfo() const { } // Add vendor ID if it is not the default |VendorId::kNone|. - if (vendor_id_ != static_cast(VendorId::kNone)) { + if (vendor_id_ != static_cast(BlockedVendorId::kNone)) { // Add vendor ID in TLV format. endpoint_info.push_back(static_cast(TlvTypes::kVendorId)); // Length is 1 byte. @@ -241,7 +236,7 @@ std::unique_ptr Advertisement::FromEndpointInfo( iter += device_name_length; } - uint8_t vendor_id = static_cast(VendorId::kNone); + uint8_t vendor_id = static_cast(BlockedVendorId::kNone); while (endpoint_info.end() - iter >= kTlvMinimumLength) { // We will parse a TLV element now. TlvTypes type = static_cast(*iter++); @@ -259,13 +254,15 @@ std::unique_ptr Advertisement::FromEndpointInfo( vendor_id = ConvertVendorId(*iter++); break; case TlvTypes::kQrCode: + NL_LOG(INFO) << "Found QR code data, skipping."; // TODO: b/341984671 - Implement handling for this TLV type. + iter += value_len; break; default: NL_LOG(ERROR) << "Unknown TLV type: " << static_cast(type); + iter += value_len; break; } - iter += value_len; } return Advertisement::NewInstance( diff --git a/sharing/advertisement.h b/sharing/advertisement.h index b7bf5a5e..3ea3dcf6 100644 --- a/sharing/advertisement.h +++ b/sharing/advertisement.h @@ -36,6 +36,13 @@ class Advertisement { public: static constexpr uint8_t kSaltSize = 2; static constexpr uint8_t kMetadataEncryptionKeyHashByteSize = 14; + // LINT.IfChange() + // Lists supported vendors for target blocking. + enum class BlockedVendorId : uint8_t { + kNone = 0, + kSamsung = 1, + }; + // LINT.ThenChange(//depot/google3/java/com/google/android/gmscore/integ/client/nearby/src/com/google/android/gms/nearby/sharing/SharingOptions.java:VendorId) static std::unique_ptr NewInstance( std::vector salt, std::vector encrypted_metadata_key, diff --git a/sharing/fake_nearby_sharing_service.cc b/sharing/fake_nearby_sharing_service.cc index e983ce27..c4e98349 100644 --- a/sharing/fake_nearby_sharing_service.cc +++ b/sharing/fake_nearby_sharing_service.cc @@ -22,6 +22,7 @@ #include "absl/strings/string_view.h" #include "internal/base/observer_list.h" +#include "sharing/advertisement.h" #include "sharing/attachment.h" #include "sharing/internal/api/sharing_rpc_notifier.h" #include "sharing/local_device_data/nearby_share_local_device_data_manager.h" @@ -87,7 +88,8 @@ void FakeNearbySharingService::UnregisterSendSurface( // Registers a receiver surface for handling payload transfer status. void FakeNearbySharingService::RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - uint8_t vendor_id, std::function status_codes_callback) { + Advertisement::BlockedVendorId vendor_id, + std::function status_codes_callback) { if (state == ReceiveSurfaceState::kForeground) { foreground_receive_transfer_callbacks_.AddObserver(transfer_callback); } else { diff --git a/sharing/fake_nearby_sharing_service.h b/sharing/fake_nearby_sharing_service.h index ea1bd4b1..492a5089 100644 --- a/sharing/fake_nearby_sharing_service.h +++ b/sharing/fake_nearby_sharing_service.h @@ -64,7 +64,7 @@ class FakeNearbySharingService : public NearbySharingService { // Registers a receiver surface for handling payload transfer status. void RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - uint8_t vendor_id, + Advertisement::BlockedVendorId vendor_id, std::function status_codes_callback) override; // Unregisters the current receive surface. diff --git a/sharing/nearby_sharing_service.h b/sharing/nearby_sharing_service.h index 2cc218ec..98050a91 100644 --- a/sharing/nearby_sharing_service.h +++ b/sharing/nearby_sharing_service.h @@ -23,6 +23,7 @@ #include "absl/strings/string_view.h" #include "internal/network/url.h" +#include "sharing/advertisement.h" #include "sharing/attachment.h" #include "sharing/internal/api/sharing_rpc_notifier.h" #include "sharing/local_device_data/nearby_share_local_device_data_manager.h" @@ -147,7 +148,7 @@ class NearbySharingService { // advertises the vendor ID specified by |vendor_id|. virtual void RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - uint8_t vendor_id, + Advertisement::BlockedVendorId vendor_id, std::function status_codes_callback) = 0; // Unregisters the current receive surface. diff --git a/sharing/nearby_sharing_service_impl.cc b/sharing/nearby_sharing_service_impl.cc index 545527b6..b58ae78e 100644 --- a/sharing/nearby_sharing_service_impl.cc +++ b/sharing/nearby_sharing_service_impl.cc @@ -16,6 +16,7 @@ #include +#include #include #include #include // NOLINT(build/c++17) @@ -112,6 +113,7 @@ namespace nearby { namespace sharing { namespace { +using BlockedVendorId = ::nearby::sharing::Advertisement::BlockedVendorId; using ::nearby::sharing::api::SharingPlatform; using ::nearby::sharing::proto::DataUsage; using ::nearby::sharing::proto::DeviceVisibility; @@ -151,6 +153,13 @@ constexpr absl::string_view kConnectionListenerName = "nearby-share-service"; constexpr absl::string_view kScreenStateListenerName = "nearby-share-service"; constexpr absl::string_view kProfileRelativePath = "Google/Nearby/Sharing"; +bool ShouldBlockSurfaceRegistration(BlockedVendorId registering_vendor_id, + BlockedVendorId blocked_vendor_id) { + return blocked_vendor_id != BlockedVendorId::kNone && + registering_vendor_id != BlockedVendorId::kNone && + registering_vendor_id != blocked_vendor_id; +} + } // namespace NearbySharingServiceImpl::NearbySharingServiceImpl( @@ -495,7 +504,8 @@ void NearbySharingServiceImpl::UnregisterSendSurface( void NearbySharingServiceImpl::RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - uint8_t vendor_id, std::function status_codes_callback) { + BlockedVendorId vendor_id, + std::function status_codes_callback) { RunOnNearbySharingServiceThread( "api_register_receive_surface", [this, transfer_callback, state, vendor_id, @@ -518,6 +528,7 @@ void NearbySharingServiceImpl::RegisterReceiveSurface( StatusCodes::kNoAvailableConnectionMedium); return; } + BlockedVendorId before_registration_vendor_id = GetVendorId(); // We specifically allow re-registering without error, so it is clear to // caller that the transfer_callback is currently registered. @@ -536,6 +547,17 @@ void NearbySharingServiceImpl::RegisterReceiveSurface( "different state."; std::move(status_codes_callback)(StatusCodes::kInvalidArgument); return; + } else if (ShouldBlockSurfaceRegistration( + vendor_id, before_registration_vendor_id)) { + // Block alternate vendor ID registration. + NL_LOG(ERROR) << __func__ + << ": disallowing registration of a receive surface " + "that has vendor_id " + << static_cast(vendor_id) + << " because the current vendor_id is " + << static_cast(GetVendorId()); + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; } // If the receive surface to be registered is a foreground surface, let @@ -1510,7 +1532,31 @@ void NearbySharingServiceImpl::SetupBluetoothAdapter() { InvalidateSurfaceState(); } -absl::flat_hash_map& +BlockedVendorId NearbySharingServiceImpl::GetVendorId() const { + // Prefer a vendor ID provided by a foreground surface. + auto fg_vendor_it = + std::find_if(foreground_receive_callbacks_map_.begin(), + foreground_receive_callbacks_map_.end(), + [](const auto& receive_callback) { + return receive_callback.second != BlockedVendorId::kNone; + }); + if (fg_vendor_it != foreground_receive_callbacks_map_.end()) { + return fg_vendor_it->second; + } + // Look through background surfaces. + auto bg_vendor_it = + std::find_if(background_receive_callbacks_map_.begin(), + background_receive_callbacks_map_.end(), + [](const auto& receive_callback) { + return receive_callback.second != BlockedVendorId::kNone; + }); + if (bg_vendor_it != foreground_receive_callbacks_map_.end()) { + return bg_vendor_it->second; + } + return BlockedVendorId::kNone; +} + +absl::flat_hash_map& NearbySharingServiceImpl::GetReceiveCallbacksMapFromState( ReceiveSurfaceState state) { switch (state) { @@ -1563,9 +1609,9 @@ NearbySharingServiceImpl::CreateEndpointInfo( ShareTargetType device_type = static_cast(device_info_.GetDeviceType()); - std::unique_ptr advertisement = - Advertisement::NewInstance(std::move(salt), std::move(encrypted_key), - device_type, device_name, /*vendor_id=*/0); + std::unique_ptr advertisement = Advertisement::NewInstance( + std::move(salt), std::move(encrypted_key), device_type, device_name, + static_cast(GetVendorId())); if (advertisement) { return advertisement->ToEndpointInfo(); } else { diff --git a/sharing/nearby_sharing_service_impl.h b/sharing/nearby_sharing_service_impl.h index 80e5e6f0..d9703636 100644 --- a/sharing/nearby_sharing_service_impl.h +++ b/sharing/nearby_sharing_service_impl.h @@ -133,7 +133,7 @@ class NearbySharingServiceImpl std::function status_codes_callback) override; void RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - uint8_t vendor_id, + Advertisement::BlockedVendorId vendor_id, std::function status_codes_callback) override; void UnregisterReceiveSurface( TransferUpdateCallback* transfer_callback, @@ -247,8 +247,12 @@ class NearbySharingServiceImpl void SetupBluetoothAdapter(); - absl::flat_hash_map& + absl::flat_hash_map& GetReceiveCallbacksMapFromState(ReceiveSurfaceState state); + // Retrieves the current vendor ID, defaulting to kNone if no surface has been + // registered with a different vendor ID. This function will always return one + // vendor ID, preferring a foreground surface vendor ID if available. + Advertisement::BlockedVendorId GetVendorId() const; bool IsVisibleInBackground(proto::DeviceVisibility visibility); std::optional> CreateEndpointInfo( proto::DeviceVisibility visibility, @@ -520,10 +524,10 @@ class NearbySharingServiceImpl // A list of service observers. ObserverList observers_; // A map of foreground receiver callbacks -> vendor ID. - absl::flat_hash_map + absl::flat_hash_map foreground_receive_callbacks_map_; // A map of background receiver callbacks -> vendor ID. - absl::flat_hash_map + absl::flat_hash_map background_receive_callbacks_map_; // A list of foreground receivers for transfer updates on the send surface. ObserverList foreground_send_transfer_callbacks_; diff --git a/sharing/nearby_sharing_service_impl_test.cc b/sharing/nearby_sharing_service_impl_test.cc index 63ca196b..87d9eb34 100644 --- a/sharing/nearby_sharing_service_impl_test.cc +++ b/sharing/nearby_sharing_service_impl_test.cc @@ -527,12 +527,14 @@ class NearbySharingServiceImplTest : public testing::Test { NearbySharingService::StatusCodes RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, - NearbySharingService::ReceiveSurfaceState state) { + NearbySharingService::ReceiveSurfaceState state, + uint8_t vendor_id = kVendorId) { NearbySharingService::StatusCodes result = NearbySharingService::StatusCodes::kError; absl::Notification notification; service_->RegisterReceiveSurface( - transfer_callback, state, kVendorId, + transfer_callback, state, + static_cast(vendor_id), [&](NearbySharingService::StatusCodes status_codes) { result = status_codes; notification.Notify(); @@ -2056,6 +2058,87 @@ TEST_F( EXPECT_FALSE(service_->IsInHighVisibility()); } +TEST_F(NearbySharingServiceImplTest, + RegisterReceiveSurfaceWithVendorId_StartAdvertisingVendorId) { + SetConnectionType(ConnectionType::kWifi); + preference_manager().SetInteger( + prefs::kNearbySharingBackgroundVisibilityName, + static_cast(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS)); + FlushTesting(); + + // Register background receive surface with vendor ID 1. + MockTransferUpdateCallback background_transfer_callback; + NearbySharingService::StatusCodes result = RegisterReceiveSurface( + &background_transfer_callback, + NearbySharingService::ReceiveSurfaceState::kBackground, + static_cast(Advertisement::BlockedVendorId::kSamsung)); + ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk); + ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); + + auto endpoint_info = + fake_nearby_connections_manager_->advertising_endpoint_info(); + auto advertisement = Advertisement::FromEndpointInfo(*endpoint_info); + EXPECT_EQ(advertisement->vendor_id(), + static_cast(Advertisement::BlockedVendorId::kSamsung)); +} + +TEST_F(NearbySharingServiceImplTest, + RegisterReceiveSurfaceWithDifferentVendorIdIsBlocked) { + SetConnectionType(ConnectionType::kWifi); + preference_manager().SetInteger( + prefs::kNearbySharingBackgroundVisibilityName, + static_cast(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS)); + FlushTesting(); + + // Register background receive surface with vendor ID 1. + MockTransferUpdateCallback background_transfer_callback; + NearbySharingService::StatusCodes result = RegisterReceiveSurface( + &background_transfer_callback, + NearbySharingService::ReceiveSurfaceState::kBackground, + static_cast(Advertisement::BlockedVendorId::kSamsung)); + ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk); + ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); + // Register foreground receive surface with different vendor ID. + MockTransferUpdateCallback foreground_transfer_callback; + result = RegisterReceiveSurface( + &foreground_transfer_callback, + NearbySharingService::ReceiveSurfaceState::kForeground, /*vendor_id=*/2); + EXPECT_EQ(result, NearbySharingService::StatusCodes::kInvalidArgument); + EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); +} + +TEST_F(NearbySharingServiceImplTest, + RegisterReceiveSurfaceWithVendorId_OkWithBgNoVendorId) { + SetConnectionType(ConnectionType::kWifi); + preference_manager().SetInteger( + prefs::kNearbySharingBackgroundVisibilityName, + static_cast(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS)); + FlushTesting(); + + // Register background receive surface with vendor ID 0. + MockTransferUpdateCallback background_transfer_callback; + NearbySharingService::StatusCodes result = RegisterReceiveSurface( + &background_transfer_callback, + NearbySharingService::ReceiveSurfaceState::kBackground, + static_cast(Advertisement::BlockedVendorId::kNone)); + ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk); + ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); + // Register foreground receive surface with vendor ID 1. + MockTransferUpdateCallback foreground_transfer_callback; + result = RegisterReceiveSurface( + &foreground_transfer_callback, + NearbySharingService::ReceiveSurfaceState::kForeground, + static_cast(Advertisement::BlockedVendorId::kSamsung)); + EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk); + EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); + // Verify endpoint info is advertising the foreground surface. + auto endpoint_info = + fake_nearby_connections_manager_->advertising_endpoint_info(); + auto advertisement = Advertisement::FromEndpointInfo(*endpoint_info); + EXPECT_EQ(advertisement->vendor_id(), + static_cast(Advertisement::BlockedVendorId::kSamsung)); +} + TEST_F(NearbySharingServiceImplTest, NoNetworkRegisterReceiveSurfaceIsAdvertising) { MockTransferUpdateCallback callback;