Index: components/proximity_auth/webui/proximity_auth_webui_handler.cc |
diff --git a/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/components/proximity_auth/webui/proximity_auth_webui_handler.cc |
index 4a313bea86e33a1aa7d528035727deb6ab05c56a..da5f19b1805ac50de2053b76c969e366809dcfce 100644 |
--- a/components/proximity_auth/webui/proximity_auth_webui_handler.cc |
+++ b/components/proximity_auth/webui/proximity_auth_webui_handler.cc |
@@ -11,8 +11,13 @@ |
#include "base/prefs/pref_service.h" |
#include "base/thread_task_runner_handle.h" |
#include "base/time/default_clock.h" |
+#include "base/time/default_tick_clock.h" |
#include "base/values.h" |
-#include "components/proximity_auth/bluetooth_connection.h" |
+#include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h" |
+#include "components/proximity_auth/ble/bluetooth_low_energy_device_whitelist.h" |
+#include "components/proximity_auth/ble/pref_names.h" |
+#include "components/proximity_auth/bluetooth_connection_finder.h" |
+#include "components/proximity_auth/bluetooth_throttler_impl.h" |
#include "components/proximity_auth/bluetooth_util.h" |
#include "components/proximity_auth/client_impl.h" |
#include "components/proximity_auth/cryptauth/base64url.h" |
@@ -35,8 +40,19 @@ namespace proximity_auth { |
namespace { |
-// The UUID of the Smart Lock Bluetooth service. |
-const char kBluetoothServiceUUID[] = "704EE561-3782-405A-A14B-2D47A2DDCDDF"; |
+// The UUID of the Smart Lock classic Bluetooth service. |
+const char kClassicBluetoothServiceUUID[] = |
+ "704EE561-3782-405A-A14B-2D47A2DDCDDF"; |
+ |
+// The UUID of the Bluetooth Low Energy service. |
+const char kBLESmartLockServiceUUID[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11"; |
+ |
+// The UUID of the characteristic used to send data to the peripheral. |
+const char kBLEToPeripheralCharUUID[] = "977c6674-1239-4e72-993b-502369b8bb5a"; |
+ |
+// The UUID of the characteristic used to receive data from the peripheral. |
+const char kBLEFromPeripheralCharUUID[] = |
+ "f4b904a2-a030-43b3-98a8-221c536c03cb"; |
// Keys in the JSON representation of a log message. |
const char kLogMessageTextKey[] = "text"; |
@@ -105,7 +121,6 @@ scoped_ptr<base::DictionaryValue> CreateSyncStateDictionary( |
ProximityAuthWebUIHandler::ProximityAuthWebUIHandler( |
ProximityAuthUIDelegate* delegate) |
: delegate_(delegate), |
- web_contents_initialized_(false), |
weak_ptr_factory_(this) { |
cryptauth_client_factory_ = delegate_->CreateCryptAuthClientFactory(); |
} |
@@ -313,7 +328,7 @@ void ProximityAuthWebUIHandler::ToggleConnection(const base::ListValue* args) { |
if (unlock_key.public_key() == public_key) { |
// Check if there is an existing connection to disconnect from first. |
if (connection && connection->IsConnected() && |
- connection->remote_device().public_key == public_key) { |
+ selected_remote_device_.public_key == public_key) { |
PA_LOG(INFO) << "Disconnecting from " |
<< unlock_key.friendly_device_name() << "[" |
<< unlock_key.bluetooth_address() << "]"; |
@@ -322,8 +337,8 @@ void ProximityAuthWebUIHandler::ToggleConnection(const base::ListValue* args) { |
} |
// Derive the PSK before connecting to the device. |
- PA_LOG(INFO) << "Connecting to " << unlock_key.friendly_device_name() |
- << "[" << unlock_key.bluetooth_address() << "]"; |
+ PA_LOG(INFO) << "Deriving PSK before connecting to " |
+ << unlock_key.friendly_device_name(); |
secure_message_delegate_ = delegate_->CreateSecureMessageDelegate(); |
secure_message_delegate_->DeriveKey( |
user_private_key_, unlock_key.public_key(), |
@@ -509,7 +524,7 @@ scoped_ptr<base::ListValue> ProximityAuthWebUIHandler::GetUnlockKeysList() { |
} |
Connection* ProximityAuthWebUIHandler::GetConnection() { |
- Connection* connection = bluetooth_connection_.get(); |
+ Connection* connection = connection_.get(); |
if (client_) { |
DCHECK(!connection); |
connection = client_->connection(); |
@@ -525,38 +540,65 @@ void ProximityAuthWebUIHandler::OnPSKDerived( |
return; |
} |
- RemoteDevice remote_device( |
- unlock_key.friendly_device_name(), unlock_key.public_key(), |
- unlock_key.bluetooth_address(), persistent_symmetric_key); |
- |
- bluetooth_connection_.reset(new BluetoothConnection( |
- remote_device, device::BluetoothUUID(kBluetoothServiceUUID))); |
- bluetooth_connection_->AddObserver(this); |
+ selected_remote_device_ = |
+ RemoteDevice(unlock_key.friendly_device_name(), unlock_key.public_key(), |
+ unlock_key.bluetooth_address(), persistent_symmetric_key); |
+ |
+ // TODO(tengs): We distinguish whether the unlock key uses classic Bluetooth |
+ // or BLE based on the presence of the |bluetooth_address| field. However, we |
+ // should ideally have a separate field specifying the protocol. |
+ if (selected_remote_device_.bluetooth_address.empty()) |
+ FindBluetoothLowEnergyConnection(selected_remote_device_); |
+ else |
+ FindBluetoothClassicConnection(selected_remote_device_); |
+} |
+ |
+void ProximityAuthWebUIHandler::FindBluetoothClassicConnection( |
+ const RemoteDevice& remote_device) { |
+ PA_LOG(INFO) << "Finding classic Bluetooth device " << remote_device.name |
+ << " [" << remote_device.bluetooth_address << "]."; |
+ |
+ // TODO(tengs): Set a timeout to stop the connection finder eventually. |
+ connection_finder_.reset(new BluetoothConnectionFinder( |
+ remote_device, device::BluetoothUUID(kClassicBluetoothServiceUUID), |
+ base::TimeDelta::FromSeconds(3))); |
+ connection_finder_->Find( |
+ base::Bind(&ProximityAuthWebUIHandler::OnConnectionFound, |
+ weak_ptr_factory_.GetWeakPtr())); |
- // This SeekDeviceByAddress operation is needed to connect to a device if |
- // it is not already known to the local device. |
- bluetooth_util::SeekDeviceByAddress( |
- remote_device.bluetooth_address, |
- base::Bind(&ProximityAuthWebUIHandler::OnSeekedDeviceByAddress, |
- weak_ptr_factory_.GetWeakPtr()), |
- base::Bind(&ProximityAuthWebUIHandler::OnSeekedDeviceByAddressError, |
- weak_ptr_factory_.GetWeakPtr()), |
- content::BrowserThread::GetBlockingPool() |
- ->GetTaskRunnerWithShutdownBehavior( |
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN) |
- .get()); |
+ web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
+ *GetUnlockKeysList()); |
} |
-void ProximityAuthWebUIHandler::OnSeekedDeviceByAddress() { |
- PA_LOG(INFO) << "Found Bluetooth device: " |
- << bluetooth_connection_->remote_device().bluetooth_address; |
- bluetooth_connection_->Connect(); |
-} |
+void ProximityAuthWebUIHandler::FindBluetoothLowEnergyConnection( |
+ const RemoteDevice& remote_device) { |
+ PrefService* pref_service = delegate_->GetPrefService(); |
+ if (!pref_service->FindPreference( |
+ prefs::kBluetoothLowEnergyDeviceWhitelist)) { |
+ PA_LOG(ERROR) << "Please enable the BLE experiment in chrome://flags."; |
+ return; |
+ } |
-void ProximityAuthWebUIHandler::OnSeekedDeviceByAddressError( |
- const std::string& error_message) { |
- PA_LOG(WARNING) << "Failed to seek device by address: " |
- << bluetooth_connection_->remote_device().bluetooth_address; |
+ PA_LOG(INFO) << "Finding Bluetooth Low Energy device " << remote_device.name; |
+ if (!bluetooth_throttler_) { |
+ bluetooth_throttler_.reset(new BluetoothThrottlerImpl( |
+ make_scoped_ptr(new base::DefaultTickClock()))); |
+ } |
+ |
+ ble_device_whitelist_.reset( |
+ new BluetoothLowEnergyDeviceWhitelist(delegate_->GetPrefService())); |
+ |
+ // TODO(tengs): Set a timeout to stop the connection finder eventually. |
+ connection_finder_.reset(new BluetoothLowEnergyConnectionFinder( |
+ kBLESmartLockServiceUUID, kBLEToPeripheralCharUUID, |
+ kBLEFromPeripheralCharUUID, ble_device_whitelist_.get(), |
+ bluetooth_throttler_.get(), 3)); |
+ connection_finder_->Find( |
+ base::Bind(&ProximityAuthWebUIHandler::OnConnectionFound, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ |
+ web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
+ *GetUnlockKeysList()); |
} |
void ProximityAuthWebUIHandler::OnAuthenticationResult( |
@@ -565,7 +607,7 @@ void ProximityAuthWebUIHandler::OnAuthenticationResult( |
secure_context_ = secure_context.Pass(); |
// Create the ClientImpl asynchronously. |client_| registers itself as an |
- // observer of |bluetooth_connection_|, so creating it synchronously would |
+ // observer of |connection_|, so creating it synchronously would |
// trigger |OnSendComplete()| as an observer call for |client_|. |
base::ThreadTaskRunnerHandle::Get()->PostTask( |
FROM_HERE, |
@@ -573,9 +615,29 @@ void ProximityAuthWebUIHandler::OnAuthenticationResult( |
weak_ptr_factory_.GetWeakPtr())); |
} |
+void ProximityAuthWebUIHandler::OnConnectionFound( |
+ scoped_ptr<Connection> connection) { |
+ DCHECK(connection->IsConnected()); |
+ connection_ = connection.Pass(); |
+ connection_->AddObserver(this); |
+ |
+ web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
+ *GetUnlockKeysList()); |
+ |
+ // TODO(tengs): Create an authenticator for BLE connections. |
+ if (selected_remote_device_.bluetooth_address.empty()) |
+ return; |
+ |
+ authenticator_.reset(new DeviceToDeviceAuthenticator( |
+ connection_.get(), delegate_->GetAccountId(), |
+ delegate_->CreateSecureMessageDelegate())); |
+ authenticator_->Authenticate( |
+ base::Bind(&ProximityAuthWebUIHandler::OnAuthenticationResult, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
void ProximityAuthWebUIHandler::CreateStatusUpdateClient() { |
- client_.reset( |
- new ClientImpl(bluetooth_connection_.Pass(), secure_context_.Pass())); |
+ client_.reset(new ClientImpl(connection_.Pass(), secure_context_.Pass())); |
client_->AddObserver(this); |
} |
@@ -610,19 +672,16 @@ ProximityAuthWebUIHandler::ExternalDeviceInfoToDictionary( |
return unlock_key.public_key() == public_key; |
}); |
- if (iterator == device_manager_->unlock_keys().end()) |
+ if (iterator == device_manager_->unlock_keys().end() || |
+ selected_remote_device_.public_key != device_info.public_key()) |
return dictionary; |
// Fill in the current Bluetooth connection status. |
- Connection* connection = GetConnection(); |
- if (!connection || |
- connection->remote_device().public_key != device_info.public_key()) |
- return dictionary; |
- |
std::string connection_status = kExternalDeviceDisconnected; |
- if (connection->IsConnected()) { |
+ Connection* connection = GetConnection(); |
+ if (connection && connection->IsConnected()) { |
connection_status = kExternalDeviceConnected; |
- } else if (connection->status() == Connection::IN_PROGRESS) { |
+ } else if (connection_finder_) { |
connection_status = kExternalDeviceConnecting; |
} |
dictionary->SetString(kExternalDeviceConnectionStatus, connection_status); |
@@ -665,15 +724,11 @@ void ProximityAuthWebUIHandler::OnConnectionStatusChanged( |
Connection::Status new_status) { |
PA_LOG(INFO) << "Connection status changed from " << old_status << " to " |
<< new_status; |
- if (new_status == Connection::CONNECTED) { |
- authenticator_.reset(new DeviceToDeviceAuthenticator( |
- connection, delegate_->GetAccountId(), |
- delegate_->CreateSecureMessageDelegate())); |
- authenticator_->Authenticate( |
- base::Bind(&ProximityAuthWebUIHandler::OnAuthenticationResult, |
- weak_ptr_factory_.GetWeakPtr())); |
- } else if (new_status == Connection::DISCONNECTED) { |
+ |
+ if (new_status == Connection::DISCONNECTED) { |
last_remote_status_update_.reset(); |
+ selected_remote_device_ = RemoteDevice(); |
+ connection_finder_.reset(); |
} |
scoped_ptr<base::ListValue> unlock_keys = GetUnlockKeysList(); |