Chromium Code Reviews| Index: chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
| diff --git a/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc b/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6f2c552c607c419286c40f3b7236c84522ccce6a |
| --- /dev/null |
| +++ b/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
| @@ -0,0 +1,447 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/extensions/api/networking_private/networking_private_process_client.h" |
| + |
| +#include "base/base64.h" |
| +#include "base/bind.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/threading/worker_pool.h" |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/common/extensions/api/networking_private.h" |
| +#include "chrome/common/networking_private_messages.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/utility_process_host.h" |
| + |
| +using content::BrowserThread; |
| +using content::UtilityProcessHost; |
| +using extensions::api::networking_private::VerificationProperties; |
| + |
| +namespace extensions { |
| + |
| +namespace { |
| +// Implementation of Verify* methods using NetworkingPrivateCrypto. |
| +class CryptoVerifyImpl : public NetworkingPrivateProcessClient::CryptoVerify { |
| + virtual bool VerifyDestination( |
| + const VerificationProperties& properties) OVERRIDE { |
| + std::vector<std::string> data_parts; |
| + data_parts.push_back(properties.device_ssid); |
| + data_parts.push_back(properties.device_serial); |
| + data_parts.push_back(properties.device_bssid); |
| + data_parts.push_back(properties.public_key); |
| + data_parts.push_back(properties.nonce); |
| + std::string unsigned_data = JoinString(data_parts, ","); |
| + std::string signed_data; |
| + if (!base::Base64Decode(properties.signed_data, &signed_data)) |
| + return false; |
| + NetworkingPrivateCrypto crypto; |
| + return crypto.VerifyCredentials(properties.certificate, |
| + signed_data, |
| + unsigned_data, |
| + properties.device_bssid); |
| + } |
| + |
| + virtual bool VerifyAndEncryptData(const VerificationProperties& properties, |
| + const std::string& plain_data, |
| + std::string* encoded_data) OVERRIDE { |
| + if (!VerifyDestination(properties)) |
| + return false; |
| + |
| + std::string public_key; |
| + if (!base::Base64Decode(properties.public_key, &public_key)) |
| + return false; |
| + |
| + NetworkingPrivateCrypto crypto; |
| + std::string encrypted_data; |
| + if (!crypto.EncryptByteString(public_key, plain_data, &encrypted_data)) |
| + return false; |
| + |
| + return base::Base64Encode(encrypted_data, encoded_data); |
| + } |
| +}; |
| + |
| +} // namespace |
| + |
| +const char kNetworkingPrivateProcessClient[] = "NetworkingPrivateProcessClient"; |
| + |
| +scoped_refptr<NetworkingPrivateProcessClient> |
| +NetworkingPrivateProcessClient::GetForProfile(Profile* profile) { |
| + if (!profile->GetUserData(kNetworkingPrivateProcessClient)) { |
| + NetworkingPrivateProcessClient* client = |
| + new NetworkingPrivateProcessClient(profile); |
| + profile->SetUserData( |
| + kNetworkingPrivateProcessClient, |
| + new base::UserDataAdapter<NetworkingPrivateProcessClient>(client)); |
| + client->Start(); |
| + } |
| + |
| + return scoped_refptr<NetworkingPrivateProcessClient>( |
| + base::UserDataAdapter<NetworkingPrivateProcessClient>::Get( |
| + profile, kNetworkingPrivateProcessClient)); |
| +} |
| + |
| +NetworkingPrivateProcessClient::NetworkingPrivateProcessClient(Profile* profile) |
| + : profile_(profile), |
| + crypto_verify_(new CryptoVerifyImpl()) {} |
| + |
| +NetworkingPrivateProcessClient::~NetworkingPrivateProcessClient() {} |
| + |
| +NetworkingPrivateProcessClient::MessageCallbacks::MessageCallbacks() {} |
| + |
| +NetworkingPrivateProcessClient::MessageCallbacks::~MessageCallbacks() {} |
| + |
| +void NetworkingPrivateProcessClient::Start() { |
| + BrowserThread::ID thread_id; |
| + CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id)); |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&NetworkingPrivateProcessClient::StartProcessOnIOThread, |
| + this, |
| + thread_id)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::StartProcessOnIOThread( |
| + BrowserThread::ID thread_id) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + utility_process_host_ = UtilityProcessHost::Create( |
| + this, BrowserThread::GetMessageLoopProxyForThread(thread_id).get()) |
| + ->AsWeakPtr(); |
| + utility_process_host_->DisableSandbox(); |
| + utility_process_host_->StartBatchMode(); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::AddObserver(Observer* observer) { |
| + network_events_observers_.AddObserver(observer); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::RemoveObserver(Observer* observer) { |
| + network_events_observers_.RemoveObserver(observer); |
| + // Shutdown will occur when all remaining calls are completed. |
| + ShutdownIfDone(); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::ShutdownIfDone() { |
| + if (!network_events_observers_.might_have_observers() |
| + && callbacks_map_.IsEmpty()) { |
|
tbarzic
2013/10/21 21:54:07
nit: && to the line before
mef
2013/10/21 23:29:16
Done.
|
| + // Remove current process client from profile, so new API calls would launch |
| + // new process. |
| + profile_->RemoveUserData(kNetworkingPrivateProcessClient); |
| + BrowserThread::PostTask( |
|
cbentzel
2013/10/21 21:07:16
You should do the PostTask before RemoveUserData -
mef
2013/10/21 23:29:16
Done.
|
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&NetworkingPrivateProcessClient::ShutdownProcessOnIOThread, |
| + this)); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::ShutdownProcessOnIOThread() { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + // The utility_process_host_ will take care of deleting itself. |
| + if (utility_process_host_.get()) { |
| + utility_process_host_->EndBatchMode(); |
| + utility_process_host_.reset(); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::Send(IPC::Message* message) { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind( |
| + &NetworkingPrivateProcessClient::SendOnIOThread, this, message)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::SendOnIOThread(IPC::Message* message) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (utility_process_host_.get()) |
| + utility_process_host_->Send(message); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnProcessCrashed(int exit_code) { |
| + std::string error_code("UtilityProcessCrashed"); |
| + // Report error for all pending callbacks |
| + for (IDMap<MessageCallbacks, IDMapOwnPointer>::iterator iter(&callbacks_map_); |
| + !iter.IsAtEnd(); |
| + iter.Advance()) { |
| + if (!iter.GetCurrentValue()->error_callback.is_null()) { |
| + scoped_ptr<DictionaryValue> error_data_ptr(new DictionaryValue()); |
| + iter.GetCurrentValue()->error_callback.Run(error_code, |
| + error_data_ptr.Pass()); |
| + } |
| + } |
| + callbacks_map_.Clear(); |
| + |
| + // restart the utility process. |
| + Start(); |
|
cbentzel
2013/10/21 21:07:16
BUG: You'll need to reset utility_process_host_ in
tbarzic
2013/10/21 21:54:07
are you sure about this? shouldn't the utility pro
mef
2013/10/21 23:29:16
Done. AFAIU extra reset() here doesn't hurt anythi
cbentzel
2013/10/22 00:57:40
Not totally sure, but I took a look through the Ut
tbarzic
2013/10/22 01:33:44
I think the host is deleted synchronously after Ut
|
| +} |
| + |
| +bool NetworkingPrivateProcessClient::OnMessageReceived( |
| + const IPC::Message& message) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(NetworkingPrivateProcessClient, message) |
| + // Responses from NetworkingPrivateHandler. |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_API_Error, OnApiError) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_GetProperties_Succeeded, |
| + OnGetPropertiesSucceeded) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_StartConnect_Succeeded, |
| + OnStartConnectSucceeded) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_StartDisconnect_Succeeded, |
| + OnStartDisconnectSucceeded) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_SetProperties_Succeeded, |
| + OnSetPropertiesSucceeded) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_GetVisibleNetworksSucceeded, |
| + OnGetVisibleNetworksSucceeded) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_NetworksChanged_Event, |
| + OnNetworksChangedEvent) |
| + IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_NetworkListChanged_Event, |
| + OnNetworkListChangedEvent) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| + |
| +void NetworkingPrivateProcessClient::GetProperties( |
| + const std::string& service_path, |
| + const DictionaryResultCallback& callback, |
| + const ErrorCallback& error_callback) { |
| + MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
| + message_callbacks->error_callback = error_callback; |
| + message_callbacks->get_properties_callback = callback; |
| + |
| + Send(new NetworkingPrivateMsg_GetProperties(message_callbacks->id, |
| + service_path)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::GetVisibleNetworks( |
| + const ListResultCallback& callback) { |
| + MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
| + message_callbacks->get_visible_networks_callback = callback; |
| + |
| + Send(new NetworkingPrivateMsg_GetVisibleNetworks(message_callbacks->id)); |
| +} |
| + |
| +// Requests network scan. Broadcasts NetworkListChangedEvent upon completion. |
| +void NetworkingPrivateProcessClient::RequestNetworkScan() { |
| + Send(new NetworkingPrivateMsg_RequestNetworkScan()); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::SetProperties( |
| + const std::string& service_path, |
| + const base::DictionaryValue& properties, |
| + const VoidResultCallback& callback, |
| + const ErrorCallback& error_callback) { |
| + MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
| + message_callbacks->error_callback = error_callback; |
| + message_callbacks->set_properties_callback = callback; |
| + |
| + scoped_ptr<DictionaryValue> properties_ptr(properties.DeepCopy()); |
| + Send(new NetworkingPrivateMsg_SetProperties( |
| + message_callbacks->id, service_path, *properties_ptr)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::StartConnect( |
| + const std::string& service_path, |
| + const VoidResultCallback& callback, |
| + const ErrorCallback& error_callback) { |
| + MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
| + message_callbacks->error_callback = error_callback; |
| + message_callbacks->start_connect_callback = callback; |
| + |
| + Send(new NetworkingPrivateMsg_StartConnect(message_callbacks->id, |
| + service_path)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::StartDisconnect( |
| + const std::string& service_path, |
| + const VoidResultCallback& callback, |
| + const ErrorCallback& error_callback) { |
| + MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
| + message_callbacks->error_callback = error_callback; |
| + message_callbacks->start_disconnect_callback = callback; |
| + |
| + Send(new NetworkingPrivateMsg_StartDisconnect(message_callbacks->id, |
| + service_path)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::VerifyDestination( |
| + scoped_ptr<base::ListValue> args, |
| + const BoolResultCallback& callback, |
| + const CryptoErrorCallback& error_callback) { |
| + base::WorkerPool::PostTask( |
|
cbentzel
2013/10/21 21:07:16
Could this use PostTaskAndReply rather than depend
mef
2013/10/21 23:29:16
It could, but wouldn't it be inconsistent with Ver
|
| + FROM_HERE, |
| + base::Bind( |
| + &NetworkingPrivateProcessClient::VerifyDestinationOnWorkerThread, |
| + this, |
| + Passed(&args), |
| + callback, |
| + error_callback), |
| + false); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::VerifyDestinationOnWorkerThread( |
| + scoped_ptr<base::ListValue> args, |
| + const BoolResultCallback& callback, |
| + const CryptoErrorCallback& error_callback) { |
| + using extensions::api::networking_private::VerifyDestination::Params; |
| + scoped_ptr<Params> params = Params::Create(*args); |
| + bool result = crypto_verify_->VerifyDestination(params->properties); |
| + BrowserThread::PostTask(BrowserThread::UI, |
| + FROM_HERE, |
| + base::Bind(callback, result)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::VerifyAndEncryptData( |
| + scoped_ptr<base::ListValue> args, |
| + const StringResultCallback& callback, |
| + const CryptoErrorCallback& error_callback) { |
| + base::WorkerPool::PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &NetworkingPrivateProcessClient::VerifyAndEncryptDataOnWorkerThread, |
| + this, |
| + Passed(&args), |
| + callback, |
| + error_callback), |
| + false); |
| +} |
| + |
| + |
| +void NetworkingPrivateProcessClient::VerifyAndEncryptDataOnWorkerThread( |
| + scoped_ptr<base::ListValue> args, |
| + const StringResultCallback& callback, |
| + const CryptoErrorCallback& error_callback) { |
| + using extensions::api::networking_private::VerifyAndEncryptData::Params; |
| + scoped_ptr<Params> params = Params::Create(*args); |
| + std::string encoded_data; |
| + bool verified = crypto_verify_->VerifyAndEncryptData( |
| + params->properties, params->data, &encoded_data); |
| + if (verified) |
|
cbentzel
2013/10/21 21:07:16
Nit: I'd add braces here since these span multiple
mef
2013/10/21 23:29:16
Done.
|
| + BrowserThread::PostTask(BrowserThread::UI, |
| + FROM_HERE, |
| + base::Bind(callback, encoded_data)); |
| + else |
| + BrowserThread::PostTask(BrowserThread::UI, |
| + FROM_HERE, |
| + base::Bind(error_callback, "VerifyError", "Error")); |
| +} |
| + |
| +NetworkingPrivateProcessClient::MessageCallbacks* |
| +NetworkingPrivateProcessClient::AddMessageCallbacks() { |
| + MessageCallbacks* message_callbacks = new MessageCallbacks(); |
| + message_callbacks->process_client = this; |
| + message_callbacks->id = callbacks_map_.Add(message_callbacks); |
| + return message_callbacks; |
| +} |
| + |
| +void NetworkingPrivateProcessClient::RemoveMessageCallbacks( |
| + MessageCallbacksID message_id) { |
| + callbacks_map_.Remove(message_id); |
| + ShutdownIfDone(); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::SetupForTest( |
| + const base::DictionaryValue& parameters, |
| + CryptoVerify* crypto_verify_mock) { |
| + crypto_verify_.reset(crypto_verify_mock); |
| + if (crypto_verify_mock) { |
| + // Prevent shutdown between calls. |
| + AddMessageCallbacks(); |
| + // Pass mock parameters to utility process itself. |
| + scoped_ptr<DictionaryValue> parameters_ptr(parameters.DeepCopy()); |
| + Send(new NetworkingPrivateMsg_UseWiFiServiceMock_ForTest( |
| + *parameters_ptr.Pass())); |
| + } else { |
| + callbacks_map_.Clear(); |
|
tbarzic
2013/10/21 21:54:07
ShutdownIfDone();
I would probably be nicer to ha
mef
2013/10/21 23:29:16
Done.
|
| + } |
| +} |
| + |
| +// Message handlers |
| +void NetworkingPrivateProcessClient::OnApiError( |
| + MessageCallbacksID message_id, |
| + const std::string& error_code, |
| + const base::DictionaryValue& error_data) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + scoped_ptr<DictionaryValue> error_data_ptr(error_data.DeepCopy()); |
| + if (!message_callbacks->error_callback.is_null()) |
| + message_callbacks->error_callback.Run(error_code, error_data_ptr.Pass()); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnGetPropertiesSucceeded( |
| + MessageCallbacksID message_id, |
| + const std::string& network_guid, |
| + const base::DictionaryValue& properties) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + if (!message_callbacks->get_properties_callback.is_null()) |
| + message_callbacks->get_properties_callback.Run(network_guid, properties); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnGetVisibleNetworksSucceeded( |
| + MessageCallbacksID message_id, |
| + const base::ListValue& network_list) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + if (!message_callbacks->get_visible_networks_callback.is_null()) |
| + message_callbacks->get_visible_networks_callback.Run(network_list); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnNetworksChangedEvent( |
| + const std::vector<std::string>& network_guids) { |
| + FOR_EACH_OBSERVER(Observer, |
| + network_events_observers_, |
| + OnNetworksChangedEvent(network_guids)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnNetworkListChangedEvent( |
| + const std::vector<std::string>& network_guids) { |
| + FOR_EACH_OBSERVER(Observer, |
| + network_events_observers_, |
| + OnNetworkListChangedEvent(network_guids)); |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnSetPropertiesSucceeded( |
| + MessageCallbacksID message_id, |
| + const std::string& network_guid) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + if (!message_callbacks->set_properties_callback.is_null()) |
| + message_callbacks->set_properties_callback.Run(); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnStartConnectSucceeded( |
| + MessageCallbacksID message_id, |
| + const std::string& network_guid) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + if (!message_callbacks->start_connect_callback.is_null()) |
| + message_callbacks->start_connect_callback.Run(); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +void NetworkingPrivateProcessClient::OnStartDisconnectSucceeded( |
| + MessageCallbacksID message_id, |
| + const std::string& network_guid) { |
| + MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
| + if (message_callbacks != NULL) { |
| + if (!message_callbacks->start_disconnect_callback.is_null()) |
| + message_callbacks->start_disconnect_callback.Run(); |
| + RemoveMessageCallbacks(message_id); |
| + } |
| +} |
| + |
| +} // namespace extensions |