| // 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_service_client.h" |
| |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.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/common/extensions/api/networking_private.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/utility_process_host.h" |
| |
| using content::BrowserThread; |
| using extensions::api::networking_private::VerificationProperties; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| const char kNetworkingPrivateServiceClient[] = "NetworkingPrivateServiceClient"; |
| const char kNetworkingPrivateSequenceTokenName[] = "NetworkingPrivate"; |
| |
| // Implementation of Verify* methods using NetworkingPrivateCrypto. |
| // TODO(mef): Move this into NetworkingPrivateCrypto class. |
| class CryptoVerifyImpl : public NetworkingPrivateServiceClient::CryptoVerify { |
| bool VerifyDestination(const VerificationProperties& properties) { |
| 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 void VerifyDestination(scoped_ptr<base::ListValue> args, |
| bool* verified, |
| std::string* error) OVERRIDE { |
| using extensions::api::networking_private::VerifyDestination::Params; |
| scoped_ptr<Params> params = Params::Create(*args); |
| *verified = VerifyDestination(params->properties); |
| } |
| |
| virtual void VerifyAndEncryptData(scoped_ptr<base::ListValue> args, |
| std::string* base64_encoded_ciphertext, |
| std::string* error) OVERRIDE { |
| using extensions::api::networking_private::VerifyAndEncryptData::Params; |
| scoped_ptr<Params> params = Params::Create(*args); |
| |
| if (!VerifyDestination(params->properties)) { |
| *error = "VerifyError"; |
| return; |
| } |
| |
| std::string public_key; |
| if (!base::Base64Decode(params->properties.public_key, &public_key)) { |
| *error = "DecodeError"; |
| return; |
| } |
| |
| NetworkingPrivateCrypto crypto; |
| std::string ciphertext; |
| if (!crypto.EncryptByteString(public_key, params->data, &ciphertext)) { |
| *error = "EncryptError"; |
| return; |
| } |
| |
| if (!base::Base64Encode(ciphertext, base64_encoded_ciphertext)) { |
| *error = "EncodeError"; |
| return; |
| } |
| } |
| }; |
| |
| // Deletes WiFiService and CryptoVerify objects on worker thread. |
| void ShutdownServicesOnWorkerThread( |
| scoped_ptr<wifi::WiFiService> wifi_service, |
| scoped_ptr<NetworkingPrivateServiceClient::CryptoVerify> crypto_verify) { |
| DCHECK(wifi_service.get()); |
| DCHECK(crypto_verify.get()); |
| } |
| |
| } // namespace |
| |
| NetworkingPrivateServiceClient::NetworkingPrivateServiceClient( |
| wifi::WiFiService* wifi_service, |
| CryptoVerify* crypto_verify) |
| : crypto_verify_(crypto_verify), |
| wifi_service_(wifi_service), |
| weak_factory_(this) { |
| sequence_token_ = BrowserThread::GetBlockingPool()-> |
| GetNamedSequenceToken(kNetworkingPrivateSequenceTokenName); |
| task_runner_ = BrowserThread::GetBlockingPool()-> |
| GetSequencedTaskRunnerWithShutdownBehavior( |
| sequence_token_, |
| base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &WiFiService::SetEventObservers, |
| base::Unretained(wifi_service_.get()), |
| base::MessageLoopProxy::current(), |
| base::Bind( |
| &NetworkingPrivateServiceClient::OnNetworksChangedEventOnUIThread, |
| weak_factory_.GetWeakPtr()), |
| base::Bind( |
| &NetworkingPrivateServiceClient:: |
| OnNetworkListChangedEventOnUIThread, |
| weak_factory_.GetWeakPtr()))); |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &WiFiService::Initialize, |
| base::Unretained(wifi_service_.get()), |
| task_runner_)); |
| } |
| |
| NetworkingPrivateServiceClient::~NetworkingPrivateServiceClient() { |
| // Verify that these objects were passed to ShutdownServicesOnWorkerThread to |
| // be deleted after completion of all posted tasks. |
| DCHECK(!wifi_service_.get()); |
| DCHECK(!crypto_verify_.get()); |
| } |
| |
| NetworkingPrivateServiceClient::CryptoVerify* |
| NetworkingPrivateServiceClient::CryptoVerify::Create() { |
| return new CryptoVerifyImpl(); |
| } |
| |
| NetworkingPrivateServiceClient::ServiceCallbacks::ServiceCallbacks() {} |
| |
| NetworkingPrivateServiceClient::ServiceCallbacks::~ServiceCallbacks() {} |
| |
| void NetworkingPrivateServiceClient::Shutdown() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| // Clear callbacks map to release callbacks from UI thread. |
| callbacks_map_.Clear(); |
| // Post ShutdownServicesOnWorkerThread task to delete services when all posted |
| // tasks are done. |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(&ShutdownServicesOnWorkerThread, |
| base::Passed(&wifi_service_), |
| base::Passed(&crypto_verify_))); |
| } |
| |
| void NetworkingPrivateServiceClient::AddObserver(Observer* observer) { |
| network_events_observers_.AddObserver(observer); |
| } |
| |
| void NetworkingPrivateServiceClient::RemoveObserver(Observer* observer) { |
| network_events_observers_.RemoveObserver(observer); |
| } |
| |
| NetworkingPrivateServiceClient::ServiceCallbacks* |
| NetworkingPrivateServiceClient::AddServiceCallbacks() { |
| ServiceCallbacks* service_callbacks = new ServiceCallbacks(); |
| service_callbacks->id = callbacks_map_.Add(service_callbacks); |
| return service_callbacks; |
| } |
| |
| void NetworkingPrivateServiceClient::RemoveServiceCallbacks( |
| ServiceCallbacksID callback_id) { |
| callbacks_map_.Remove(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::GetProperties( |
| const std::string& network_guid, |
| const DictionaryResultCallback& callback, |
| const ErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->error_callback = error_callback; |
| service_callbacks->get_properties_callback = callback; |
| |
| DictionaryValue* properties = new DictionaryValue(); |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&WiFiService::GetProperties, |
| base::Unretained(wifi_service_.get()), |
| network_guid, |
| properties, |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterGetProperties, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| network_guid, |
| base::Owned(properties), |
| base::Owned(error))); |
| } |
| |
| void NetworkingPrivateServiceClient::GetVisibleNetworks( |
| const std::string& network_type, |
| const ListResultCallback& callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->get_visible_networks_callback = callback; |
| |
| ListValue* networks = new ListValue(); |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&WiFiService::GetVisibleNetworks, |
| base::Unretained(wifi_service_.get()), |
| network_type, |
| networks), |
| base::Bind(&NetworkingPrivateServiceClient::AfterGetVisibleNetworks, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(networks))); |
| } |
| |
| void NetworkingPrivateServiceClient::RequestNetworkScan() { |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(&WiFiService::RequestNetworkScan, |
| base::Unretained(wifi_service_.get()))); |
| } |
| |
| void NetworkingPrivateServiceClient::SetProperties( |
| const std::string& network_guid, |
| const base::DictionaryValue& properties, |
| const base::Closure& callback, |
| const ErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->error_callback = error_callback; |
| service_callbacks->set_properties_callback = callback; |
| |
| scoped_ptr<base::DictionaryValue> properties_ptr(properties.DeepCopy()); |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&WiFiService::SetProperties, |
| base::Unretained(wifi_service_.get()), |
| network_guid, |
| base::Passed(&properties_ptr), |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterSetProperties, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(error))); |
| } |
| |
| |
| void NetworkingPrivateServiceClient::StartConnect( |
| const std::string& network_guid, |
| const base::Closure& callback, |
| const ErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->error_callback = error_callback; |
| service_callbacks->start_connect_callback = callback; |
| |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&WiFiService::StartConnect, |
| base::Unretained(wifi_service_.get()), |
| network_guid, |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterStartConnect, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(error))); |
| } |
| |
| void NetworkingPrivateServiceClient::StartDisconnect( |
| const std::string& network_guid, |
| const base::Closure& callback, |
| const ErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->error_callback = error_callback; |
| service_callbacks->start_disconnect_callback = callback; |
| |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&WiFiService::StartDisconnect, |
| base::Unretained(wifi_service_.get()), |
| network_guid, |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterStartDisconnect, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(error))); |
| } |
| |
| void NetworkingPrivateServiceClient::VerifyDestination( |
| scoped_ptr<base::ListValue> args, |
| const BoolResultCallback& callback, |
| const CryptoErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->crypto_error_callback = error_callback; |
| service_callbacks->verify_destination_callback = callback; |
| |
| bool* result = new bool; |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&CryptoVerify::VerifyDestination, |
| base::Unretained(crypto_verify_.get()), |
| base::Passed(&args), |
| result, |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterVerifyDestination, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(result), |
| base::Owned(error))); |
| } |
| |
| void NetworkingPrivateServiceClient::VerifyAndEncryptData( |
| scoped_ptr<base::ListValue> args, |
| const StringResultCallback& callback, |
| const CryptoErrorCallback& error_callback) { |
| ServiceCallbacks* service_callbacks = AddServiceCallbacks(); |
| service_callbacks->crypto_error_callback = error_callback; |
| service_callbacks->verify_and_encrypt_data_callback = callback; |
| |
| std::string* result = new std::string; |
| std::string* error = new std::string; |
| |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::Bind(&CryptoVerify::VerifyAndEncryptData, |
| base::Unretained(crypto_verify_.get()), |
| base::Passed(&args), |
| result, |
| error), |
| base::Bind(&NetworkingPrivateServiceClient::AfterVerifyAndEncryptData, |
| weak_factory_.GetWeakPtr(), |
| service_callbacks->id, |
| base::Owned(result), |
| base::Owned(error))); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterGetProperties( |
| ServiceCallbacksID callback_id, |
| const std::string& network_guid, |
| const DictionaryValue* properties, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->error_callback.is_null()); |
| service_callbacks->error_callback.Run(*error, |
| scoped_ptr<base::DictionaryValue>()); |
| } else { |
| DCHECK(!service_callbacks->get_properties_callback.is_null()); |
| service_callbacks->get_properties_callback.Run(network_guid, *properties); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterGetVisibleNetworks( |
| ServiceCallbacksID callback_id, |
| const ListValue* networks) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| DCHECK(!service_callbacks->get_visible_networks_callback.is_null()); |
| service_callbacks->get_visible_networks_callback.Run(*networks); |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterSetProperties( |
| ServiceCallbacksID callback_id, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->error_callback.is_null()); |
| service_callbacks->error_callback.Run(*error, |
| scoped_ptr<base::DictionaryValue>()); |
| } else { |
| DCHECK(!service_callbacks->set_properties_callback.is_null()); |
| service_callbacks->set_properties_callback.Run(); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterStartConnect( |
| ServiceCallbacksID callback_id, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->error_callback.is_null()); |
| service_callbacks->error_callback.Run(*error, |
| scoped_ptr<base::DictionaryValue>()); |
| } else { |
| DCHECK(!service_callbacks->start_connect_callback.is_null()); |
| service_callbacks->start_connect_callback.Run(); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterStartDisconnect( |
| ServiceCallbacksID callback_id, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->error_callback.is_null()); |
| service_callbacks->error_callback.Run(*error, |
| scoped_ptr<base::DictionaryValue>()); |
| } else { |
| DCHECK(!service_callbacks->start_disconnect_callback.is_null()); |
| service_callbacks->start_disconnect_callback.Run(); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterVerifyDestination( |
| ServiceCallbacksID callback_id, |
| const bool* result, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->crypto_error_callback.is_null()); |
| service_callbacks->crypto_error_callback.Run(*error, *error); |
| } else { |
| DCHECK(!service_callbacks->verify_destination_callback.is_null()); |
| service_callbacks->verify_destination_callback.Run(*result); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::AfterVerifyAndEncryptData( |
| ServiceCallbacksID callback_id, |
| const std::string* result, |
| const std::string* error) { |
| ServiceCallbacks* service_callbacks = callbacks_map_.Lookup(callback_id); |
| DCHECK(service_callbacks); |
| if (!error->empty()) { |
| DCHECK(!service_callbacks->crypto_error_callback.is_null()); |
| service_callbacks->crypto_error_callback.Run(*error, *error); |
| } else { |
| DCHECK(!service_callbacks->verify_and_encrypt_data_callback.is_null()); |
| service_callbacks->verify_and_encrypt_data_callback.Run(*result); |
| } |
| RemoveServiceCallbacks(callback_id); |
| } |
| |
| void NetworkingPrivateServiceClient::OnNetworksChangedEventOnUIThread( |
| const std::vector<std::string>& network_guids) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| FOR_EACH_OBSERVER(Observer, |
| network_events_observers_, |
| OnNetworksChangedEvent(network_guids)); |
| } |
| |
| void NetworkingPrivateServiceClient::OnNetworkListChangedEventOnUIThread( |
| const std::vector<std::string>& network_guids) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| FOR_EACH_OBSERVER(Observer, |
| network_events_observers_, |
| OnNetworkListChangedEvent(network_guids)); |
| } |
| |
| } // namespace extensions |