Commit 59a50b0d authored by Michael Hansen's avatar Michael Hansen Committed by Commit Bot

[Nearby] Periodically rotate Nearby Connections advertisement.

This adds a mechanism to rotate the Nearby Connections advertisement
and Bluetooth MAC address every [12, 15) minutes. This is to protect
user privacy by preventing tracking using this data.

Spec: go/nearby-chrome-bt

Bug: b:154846485
Change-Id: I841aa103fb374a4812ab928bc862af026835a03c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419692
Commit-Queue: Michael Hansen <hansenmichael@google.com>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809928}
parent 4ecf0779
......@@ -44,8 +44,8 @@ FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall::operator=(
FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall::
~GetDecryptedPublicCertificateCall() = default;
FakeNearbyShareCertificateManager::FakeNearbyShareCertificateManager() =
default;
FakeNearbyShareCertificateManager::FakeNearbyShareCertificateManager()
: next_salt_(GetNearbyShareTestSalt()) {}
FakeNearbyShareCertificateManager::~FakeNearbyShareCertificateManager() =
default;
......@@ -75,7 +75,10 @@ void FakeNearbyShareCertificateManager::OnStop() {}
base::Optional<NearbySharePrivateCertificate>
FakeNearbyShareCertificateManager::GetValidPrivateCertificate(
nearby_share::mojom::Visibility visibility) const {
return GetNearbyShareTestPrivateCertificate(visibility);
auto cert = GetNearbyShareTestPrivateCertificate(visibility);
cert.next_salts_for_testing() = base::queue<std::vector<uint8_t>>();
cert.next_salts_for_testing().push(next_salt_);
return cert;
}
void FakeNearbyShareCertificateManager::UpdatePrivateCertificateInStorage(
......
......@@ -84,6 +84,8 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
using NearbyShareCertificateManager::NotifyPrivateCertificatesChanged;
using NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded;
void set_next_salt(const std::vector<uint8_t>& salt) { next_salt_ = salt; }
size_t num_get_private_certificates_as_public_certificates_calls() {
return num_get_private_certificates_as_public_certificates_calls_;
}
......@@ -110,6 +112,7 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
size_t num_download_public_certificates_calls_ = 0;
std::vector<GetDecryptedPublicCertificateCall>
get_decrypted_public_certificate_calls_;
std::vector<uint8_t> next_salt_;
};
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_FAKE_NEARBY_SHARE_CERTIFICATE_MANAGER_H_
......@@ -24,7 +24,7 @@ void FakeNearbyConnectionsManager::StartAdvertising(
advertising_listener_ = listener;
advertising_data_usage_ = data_usage;
advertising_power_level_ = power_level;
adverting_endpoint_info_ = std::move(endpoint_info);
advertising_endpoint_info_ = std::move(endpoint_info);
std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess);
}
......@@ -35,7 +35,7 @@ void FakeNearbyConnectionsManager::StopAdvertising() {
advertising_listener_ = nullptr;
advertising_data_usage_ = DataUsage::kUnknown;
advertising_power_level_ = PowerLevel::kUnknown;
adverting_endpoint_info_.reset();
advertising_endpoint_info_.reset();
}
void FakeNearbyConnectionsManager::StartDiscovery(
......
......@@ -91,8 +91,8 @@ class FakeNearbyConnectionsManager
callback) {
send_payload_callback_ = std::move(callback);
}
const base::Optional<std::vector<uint8_t>>& adverting_endpoint_info() {
return adverting_endpoint_info_;
const base::Optional<std::vector<uint8_t>>& advertising_endpoint_info() {
return advertising_endpoint_info_;
}
base::Optional<std::vector<uint8_t>> connection_endpoint_info(
......@@ -118,7 +118,7 @@ class FakeNearbyConnectionsManager
DataUsage connected_data_usage_ = DataUsage::kUnknown;
base::RepeatingCallback<void(PayloadPtr, PayloadStatusListener*)>
send_payload_callback_;
base::Optional<std::vector<uint8_t>> adverting_endpoint_info_;
base::Optional<std::vector<uint8_t>> advertising_endpoint_info_;
std::set<std::string> disconnected_endpoints_;
// Maps endpoint_id to endpoint_info.
......
......@@ -12,6 +12,7 @@
#include "base/files/file.h"
#include "base/logging.h"
#include "base/numerics/checked_math.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h"
......@@ -48,6 +49,11 @@
namespace {
constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMin =
base::TimeDelta::FromMinutes(12);
constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMax =
base::TimeDelta::FromMinutes(15);
// Used to hash a token into a 4 digit string.
constexpr int kHashModulo = 9973;
constexpr int kHashBaseMultiplier = 31;
......@@ -1438,7 +1444,8 @@ void NearbySharingServiceImpl::InvalidateAdvertisingState() {
<< " visibility: " << settings_.GetVisibility()
<< " data usage: " << data_usage << " device name: "
<< device_name.value_or("** no device name **");
return;
ScheduleRotateBackgroundAdvertisementTimer();
}
void NearbySharingServiceImpl::StopAdvertising() {
......@@ -1511,6 +1518,32 @@ NearbySharingService::StatusCodes NearbySharingServiceImpl::StopScanning() {
return StatusCodes::kOk;
}
void NearbySharingServiceImpl::ScheduleRotateBackgroundAdvertisementTimer() {
uint64_t delayRangeMilliseconds = base::checked_cast<uint64_t>(
kBackgroundAdvertisementRotationDelayMax.InMilliseconds() -
kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
uint64_t delayMilliseconds =
base::RandGenerator(delayRangeMilliseconds) +
base::checked_cast<uint64_t>(
kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
rotate_background_advertisement_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(
base::checked_cast<uint64_t>(delayMilliseconds)),
base::BindOnce(
&NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired,
weak_ptr_factory_.GetWeakPtr()));
}
void NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired() {
if (foreground_receive_callbacks_.might_have_observers()) {
ScheduleRotateBackgroundAdvertisementTimer();
} else {
StopAdvertising();
InvalidateSurfaceState();
}
}
void NearbySharingServiceImpl::OnTransferComplete() {
is_receiving_files_ = false;
is_transferring_ = false;
......
......@@ -19,6 +19,7 @@
#include "base/scoped_observer.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "chrome/browser/nearby_sharing/attachment.h"
#include "chrome/browser/nearby_sharing/attachment_info.h"
......@@ -181,6 +182,8 @@ class NearbySharingServiceImpl
void StopAdvertising();
void StartScanning();
StatusCodes StopScanning();
void ScheduleRotateBackgroundAdvertisementTimer();
void OnRotateBackgroundAdvertisementTimerFired();
void OnTransferComplete();
void OnTransferStarted(bool is_incoming);
......@@ -328,6 +331,7 @@ class NearbySharingServiceImpl
NearbyShareSettings settings_;
NearbyFileHandler file_handler_;
bool is_screen_locked_ = false;
base::OneShotTimer rotate_background_advertisement_timer_;
// A list of service observers.
base::ObserverList<NearbySharingService::Observer> observers_;
......
......@@ -817,6 +817,16 @@ class NearbySharingServiceImplTest : public testing::Test {
success_run_loop.Run();
}
std::unique_ptr<sharing::Advertisement> GetCurrentAdvertisement() {
auto endpoint_info =
fake_nearby_connections_manager_->advertising_endpoint_info();
if (!endpoint_info)
return nullptr;
return sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->advertising_endpoint_info()));
}
protected:
FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() {
EXPECT_EQ(1u, local_device_data_manager_factory_.instances().size());
......@@ -1493,10 +1503,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kHighPower,
fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info());
auto advertisement =
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = GetCurrentAdvertisement();
ASSERT_TRUE(advertisement);
EXPECT_EQ(kDeviceName, advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
......@@ -1519,10 +1527,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kHighPower,
fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info());
auto advertisement =
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = GetCurrentAdvertisement();
ASSERT_TRUE(advertisement);
EXPECT_EQ(kDeviceName, advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
......@@ -1548,10 +1554,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kLowPower,
fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info());
auto advertisement =
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = GetCurrentAdvertisement();
ASSERT_TRUE(advertisement);
EXPECT_FALSE(advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
......@@ -3498,3 +3502,23 @@ TEST_F(NearbySharingServiceImplTest, ShutdownCallsObservers) {
// Prevent a double shutdown.
service_.reset();
}
TEST_F(NearbySharingServiceImplTest,
PeriodicallyRotateBackgroundAdvertisement) {
certificate_manager()->set_next_salt({0x00, 0x01});
SetVisibility(nearby_share::mojom::Visibility::kAllContacts);
NiceMock<MockTransferUpdateCallback> callback;
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
&callback, NearbySharingService::ReceiveSurfaceState::kBackground);
EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
auto endpoint_info_initial =
fake_nearby_connections_manager_->advertising_endpoint_info();
certificate_manager()->set_next_salt({0x00, 0x02});
task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(15));
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
auto endpoint_info_rotated =
fake_nearby_connections_manager_->advertising_endpoint_info();
EXPECT_NE(endpoint_info_initial, endpoint_info_rotated);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment