blob: 96f26993e7dfe84036c50624f76d0acde2385012 [file] [log] [blame]
// 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