| // Copyright 2014 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 "extensions/browser/api/vpn_provider/vpn_service.h" |
| |
| #include <stdint.h> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/containers/contains.h" |
| #include "base/guid.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #include "chromeos/dbus/shill/shill_third_party_vpn_driver_client.h" |
| #include "chromeos/dbus/shill/shill_third_party_vpn_observer.h" |
| #include "chromeos/network/network_configuration_handler.h" |
| #include "chromeos/network/network_profile.h" |
| #include "chromeos/network/network_profile_handler.h" |
| #include "chromeos/network/network_state.h" |
| #include "chromeos/network/network_state_handler.h" |
| #include "chromeos/network/network_type_pattern.h" |
| #include "content/public/browser/pepper_vpn_provider_resource_host_proxy.h" |
| #include "content/public/browser/vpn_service_proxy.h" |
| #include "crypto/sha2.h" |
| #include "extensions/browser/event_router.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/unloaded_extension_reason.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| namespace api_vpn = extensions::api::vpn_provider; |
| |
| void DoNothingFailureCallback(const std::string& error_name, |
| const std::string& error_message) { |
| LOG(ERROR) << error_name << ": " << error_message; |
| } |
| |
| } // namespace |
| |
| class VpnService::VpnConfiguration : public ShillThirdPartyVpnObserver { |
| public: |
| VpnConfiguration(const std::string& extension_id, |
| const std::string& configuration_name, |
| const std::string& key, |
| base::WeakPtr<VpnService> vpn_service); |
| |
| VpnConfiguration(const VpnConfiguration&) = delete; |
| VpnConfiguration& operator=(const VpnConfiguration&) = delete; |
| |
| ~VpnConfiguration() override; |
| |
| const std::string& extension_id() const { return extension_id_; } |
| const std::string& configuration_name() const { return configuration_name_; } |
| const std::string& key() const { return key_; } |
| const std::string& service_path() const { return service_path_; } |
| void set_service_path(const std::string& service_path) { |
| service_path_ = service_path; |
| } |
| const std::string& object_path() const { return object_path_; } |
| void set_pepper_proxy( |
| std::unique_ptr<content::PepperVpnProviderResourceHostProxy> |
| pepper_vpn_provider_proxy) { |
| pepper_vpn_provider_proxy_ = std::move(pepper_vpn_provider_proxy); |
| } |
| |
| // ShillThirdPartyVpnObserver: |
| void OnPacketReceived(const std::vector<char>& data) override; |
| void OnPlatformMessage(uint32_t message) override; |
| |
| private: |
| const std::string extension_id_; |
| const std::string configuration_name_; |
| const std::string key_; |
| const std::string object_path_; |
| |
| std::unique_ptr<content::PepperVpnProviderResourceHostProxy> |
| pepper_vpn_provider_proxy_; |
| |
| std::string service_path_; |
| |
| base::WeakPtr<VpnService> vpn_service_; |
| }; |
| |
| VpnService::VpnConfiguration::VpnConfiguration( |
| const std::string& extension_id, |
| const std::string& configuration_name, |
| const std::string& key, |
| base::WeakPtr<VpnService> vpn_service) |
| : extension_id_(extension_id), |
| configuration_name_(configuration_name), |
| key_(key), |
| object_path_(shill::kObjectPathBase + key_), |
| vpn_service_(vpn_service) {} |
| |
| VpnService::VpnConfiguration::~VpnConfiguration() {} |
| |
| void VpnService::VpnConfiguration::OnPacketReceived( |
| const std::vector<char>& data) { |
| if (!vpn_service_) { |
| return; |
| } |
| // Pass packet to the Pepper API if the connection is bound to it. |
| if (pepper_vpn_provider_proxy_) { |
| pepper_vpn_provider_proxy_->SendOnPacketReceived(data); |
| } else { |
| auto event_args = api_vpn::OnPacketReceived::Create( |
| std::vector<uint8_t>(data.begin(), data.end())); |
| vpn_service_->SendSignalToExtension( |
| extension_id_, extensions::events::VPN_PROVIDER_ON_PACKET_RECEIVED, |
| api_vpn::OnPacketReceived::kEventName, std::move(event_args)); |
| } |
| } |
| |
| void VpnService::VpnConfiguration::OnPlatformMessage(uint32_t message) { |
| if (!vpn_service_) { |
| return; |
| } |
| DCHECK_GE(api_vpn::PLATFORM_MESSAGE_LAST, message); |
| |
| api_vpn::PlatformMessage platform_message = |
| static_cast<api_vpn::PlatformMessage>(message); |
| |
| if (platform_message == api_vpn::PLATFORM_MESSAGE_CONNECTED) { |
| vpn_service_->SetActiveConfiguration(this); |
| } else if (platform_message == api_vpn::PLATFORM_MESSAGE_DISCONNECTED || |
| platform_message == api_vpn::PLATFORM_MESSAGE_ERROR) { |
| vpn_service_->SetActiveConfiguration(nullptr); |
| |
| // Disconnect Pepper-bound configuration. |
| if (pepper_vpn_provider_proxy_) { |
| pepper_vpn_provider_proxy_->SendOnUnbind(); |
| pepper_vpn_provider_proxy_.reset(); |
| } |
| } |
| |
| // TODO(kaliamoorthi): Update the lower layers to get the error message and |
| // pass in the error instead of std::string(). |
| auto event_args = api_vpn::OnPlatformMessage::Create( |
| configuration_name_, platform_message, std::string()); |
| |
| vpn_service_->SendSignalToExtension( |
| extension_id_, extensions::events::VPN_PROVIDER_ON_PLATFORM_MESSAGE, |
| api_vpn::OnPlatformMessage::kEventName, std::move(event_args)); |
| } |
| |
| class VpnService::VpnServiceProxyImpl : public content::VpnServiceProxy { |
| public: |
| explicit VpnServiceProxyImpl(base::WeakPtr<VpnService> vpn_service); |
| |
| void Bind(const std::string& extension_id, |
| const std::string& configuration_id, |
| const std::string& configuration_name, |
| SuccessCallback success, |
| FailureCallback failure, |
| std::unique_ptr<content::PepperVpnProviderResourceHostProxy> |
| pepper_vpn_provider_proxy) override; |
| void SendPacket(const std::string& extension_id, |
| const std::vector<char>& data, |
| SuccessCallback success, |
| FailureCallback failure) override; |
| |
| private: |
| base::WeakPtr<VpnService> vpn_service_; |
| |
| DISALLOW_COPY_AND_ASSIGN(VpnServiceProxyImpl); |
| }; |
| |
| VpnService::VpnServiceProxyImpl::VpnServiceProxyImpl( |
| base::WeakPtr<VpnService> vpn_service) |
| : vpn_service_(vpn_service) {} |
| |
| void VpnService::VpnServiceProxyImpl::Bind( |
| const std::string& extension_id, |
| const std::string& configuration_id, |
| const std::string& configuration_name, |
| SuccessCallback success, |
| FailureCallback failure, |
| std::unique_ptr<content::PepperVpnProviderResourceHostProxy> |
| pepper_vpn_provider_proxy) { |
| if (!vpn_service_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| vpn_service_->Bind(extension_id, configuration_id, configuration_name, |
| std::move(success), std::move(failure), |
| std::move(pepper_vpn_provider_proxy)); |
| } |
| |
| void VpnService::VpnServiceProxyImpl::SendPacket( |
| const std::string& extension_id, |
| const std::vector<char>& data, |
| SuccessCallback success, |
| FailureCallback failure) { |
| if (!vpn_service_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| vpn_service_->SendPacket(extension_id, data, std::move(success), |
| std::move(failure)); |
| } |
| |
| VpnService::VpnService( |
| content::BrowserContext* browser_context, |
| const std::string& userid_hash, |
| extensions::ExtensionRegistry* extension_registry, |
| extensions::EventRouter* event_router, |
| ShillThirdPartyVpnDriverClient* shill_client, |
| NetworkConfigurationHandler* network_configuration_handler, |
| NetworkProfileHandler* network_profile_handler, |
| NetworkStateHandler* network_state_handler) |
| : browser_context_(browser_context), |
| userid_hash_(userid_hash), |
| extension_registry_(extension_registry), |
| event_router_(event_router), |
| shill_client_(shill_client), |
| network_configuration_handler_(network_configuration_handler), |
| network_profile_handler_(network_profile_handler), |
| network_state_handler_(network_state_handler), |
| active_configuration_(nullptr) { |
| extension_registry_->AddObserver(this); |
| network_state_handler_->AddObserver(this, FROM_HERE); |
| network_configuration_handler_->AddObserver(this); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&VpnService::NetworkListChanged, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| VpnService::~VpnService() { |
| network_configuration_handler_->RemoveObserver(this); |
| network_state_handler_->RemoveObserver(this, FROM_HERE); |
| extension_registry_->RemoveObserver(this); |
| } |
| |
| void VpnService::SendShowAddDialogToExtension(const std::string& extension_id) { |
| SendSignalToExtension(extension_id, |
| extensions::events::VPN_PROVIDER_ON_UI_EVENT, |
| api_vpn::OnUIEvent::kEventName, |
| api_vpn::OnUIEvent::Create( |
| api_vpn::UI_EVENT_SHOWADDDIALOG, std::string())); |
| } |
| |
| void VpnService::SendShowConfigureDialogToExtension( |
| const std::string& extension_id, |
| const std::string& configuration_id) { |
| SendSignalToExtension( |
| extension_id, extensions::events::VPN_PROVIDER_ON_UI_EVENT, |
| api_vpn::OnUIEvent::kEventName, |
| api_vpn::OnUIEvent::Create(api_vpn::UI_EVENT_SHOWCONFIGUREDIALOG, |
| configuration_id)); |
| } |
| |
| void VpnService::SendPlatformError(const std::string& extension_id, |
| const std::string& configuration_id, |
| const std::string& error_message) { |
| SendSignalToExtension( |
| extension_id, extensions::events::VPN_PROVIDER_ON_PLATFORM_MESSAGE, |
| api_vpn::OnPlatformMessage::kEventName, |
| api_vpn::OnPlatformMessage::Create( |
| configuration_id, api_vpn::PLATFORM_MESSAGE_ERROR, error_message)); |
| } |
| |
| std::string VpnService::GetKey(const std::string& extension_id, |
| const std::string& name) { |
| const std::string key = crypto::SHA256HashString(extension_id + name); |
| return base::HexEncode(key.data(), key.size()); |
| } |
| |
| void VpnService::OnConfigurationRemoved(const std::string& service_path, |
| const std::string& guid) { |
| if (service_path_to_configuration_map_.find(service_path) == |
| service_path_to_configuration_map_.end()) { |
| // Ignore removal of a configuration unknown to VPN service, which means the |
| // configuration was created internally by the platform or already removed |
| // by the extension. |
| return; |
| } |
| |
| VpnConfiguration* configuration = |
| service_path_to_configuration_map_[service_path]; |
| auto event_args = |
| api_vpn::OnConfigRemoved::Create(configuration->configuration_name()); |
| SendSignalToExtension(configuration->extension_id(), |
| extensions::events::VPN_PROVIDER_ON_CONFIG_REMOVED, |
| api_vpn::OnConfigRemoved::kEventName, |
| std::move(event_args)); |
| |
| DestroyConfigurationInternal(configuration); |
| } |
| |
| void VpnService::OnGetShillProperties(const std::string& service_path, |
| absl::optional<base::Value> dictionary) { |
| if (!dictionary || service_path_to_configuration_map_.find(service_path) != |
| service_path_to_configuration_map_.end()) { |
| return; |
| } |
| const std::string* vpn_type = |
| dictionary->FindStringPath(shill::kProviderTypeProperty); |
| const std::string* extension_id = |
| dictionary->FindStringPath(shill::kProviderHostProperty); |
| const std::string* type = dictionary->FindStringPath(shill::kTypeProperty); |
| const std::string* configuration_name = |
| dictionary->FindStringPath(shill::kNameProperty); |
| if (!vpn_type || !extension_id || !type || !configuration_name || |
| *vpn_type != shill::kProviderThirdPartyVpn || *type != shill::kTypeVPN) { |
| return; |
| } |
| |
| if (!extension_registry_->GetExtensionById( |
| *extension_id, extensions::ExtensionRegistry::ENABLED)) { |
| // Does not belong to this instance of VpnService. |
| return; |
| } |
| |
| const std::string key = GetKey(*extension_id, *configuration_name); |
| VpnConfiguration* configuration = |
| CreateConfigurationInternal(*extension_id, *configuration_name, key); |
| configuration->set_service_path(service_path); |
| service_path_to_configuration_map_[service_path] = configuration; |
| shill_client_->AddShillThirdPartyVpnObserver(configuration->object_path(), |
| configuration); |
| } |
| |
| void VpnService::NetworkListChanged() { |
| NetworkStateHandler::NetworkStateList network_list; |
| network_state_handler_->GetVisibleNetworkListByType(NetworkTypePattern::VPN(), |
| &network_list); |
| for (auto* iter : network_list) { |
| if (service_path_to_configuration_map_.find(iter->path()) != |
| service_path_to_configuration_map_.end()) { |
| continue; |
| } |
| |
| network_configuration_handler_->GetShillProperties( |
| iter->path(), base::BindOnce(&VpnService::OnGetShillProperties, |
| weak_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void VpnService::CreateConfiguration(const std::string& extension_id, |
| const std::string& extension_name, |
| const std::string& configuration_name, |
| SuccessCallback success, |
| FailureCallback failure) { |
| if (configuration_name.empty()) { |
| std::move(failure).Run(std::string(), |
| std::string("Empty name not supported.")); |
| return; |
| } |
| |
| const std::string key = GetKey(extension_id, configuration_name); |
| if (base::Contains(key_to_configuration_map_, key)) { |
| std::move(failure).Run(std::string(), std::string("Name not unique.")); |
| return; |
| } |
| |
| const NetworkProfile* profile = |
| network_profile_handler_->GetProfileForUserhash(userid_hash_); |
| if (!profile) { |
| std::move(failure).Run( |
| std::string(), |
| std::string("No user profile for unshared network configuration.")); |
| return; |
| } |
| |
| VpnConfiguration* configuration = |
| CreateConfigurationInternal(extension_id, configuration_name, key); |
| |
| base::DictionaryValue properties; |
| properties.SetKey(shill::kTypeProperty, base::Value(shill::kTypeVPN)); |
| properties.SetKey(shill::kNameProperty, base::Value(configuration_name)); |
| properties.SetKey(shill::kProviderHostProperty, base::Value(extension_id)); |
| properties.SetKey(shill::kObjectPathSuffixProperty, |
| base::Value(configuration->key())); |
| properties.SetKey(shill::kProviderTypeProperty, |
| base::Value(shill::kProviderThirdPartyVpn)); |
| properties.SetKey(shill::kProfileProperty, base::Value(profile->path)); |
| |
| // Note: This will not create an entry in |policy_util|. TODO(pneubeck): |
| // Determine the correct thing to do here, crbug.com/459278. |
| std::string guid = base::GenerateGUID(); |
| properties.SetKey(shill::kGuidProperty, base::Value(guid)); |
| |
| network_configuration_handler_->CreateShillConfiguration( |
| properties, |
| base::BindOnce(&VpnService::OnCreateConfigurationSuccess, |
| weak_factory_.GetWeakPtr(), std::move(success), |
| configuration), |
| base::BindOnce(&VpnService::OnCreateConfigurationFailure, |
| weak_factory_.GetWeakPtr(), std::move(failure), |
| configuration)); |
| } |
| |
| void VpnService::DestroyConfiguration(const std::string& extension_id, |
| const std::string& configuration_id, |
| SuccessCallback success, |
| FailureCallback failure) { |
| // The ID is the configuration name for now. This may change in the future. |
| const std::string key = GetKey(extension_id, configuration_id); |
| if (!base::Contains(key_to_configuration_map_, key)) { |
| std::move(failure).Run(std::string(), std::string("Unauthorized access.")); |
| return; |
| } |
| |
| VpnConfiguration* configuration = key_to_configuration_map_[key].get(); |
| const std::string service_path = configuration->service_path(); |
| if (service_path.empty()) { |
| std::move(failure).Run(std::string(), std::string("Pending create.")); |
| return; |
| } |
| if (active_configuration_ == configuration) { |
| configuration->OnPlatformMessage(api_vpn::PLATFORM_MESSAGE_DISCONNECTED); |
| } |
| DestroyConfigurationInternal(configuration); |
| |
| network_configuration_handler_->RemoveConfiguration( |
| service_path, |
| /*remove_confirmer=*/absl::nullopt, |
| base::BindOnce(&VpnService::OnRemoveConfigurationSuccess, |
| weak_factory_.GetWeakPtr(), std::move(success)), |
| base::BindOnce(&VpnService::OnRemoveConfigurationFailure, |
| weak_factory_.GetWeakPtr(), std::move(failure))); |
| } |
| |
| void VpnService::SetParameters(const std::string& extension_id, |
| const base::DictionaryValue& parameters, |
| StringCallback success, |
| FailureCallback failure) { |
| if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { |
| std::move(failure).Run(std::string(), std::string("Unauthorized access.")); |
| return; |
| } |
| |
| shill_client_->SetParameters(active_configuration_->object_path(), parameters, |
| std::move(success), std::move(failure)); |
| } |
| |
| void VpnService::SendPacket(const std::string& extension_id, |
| const std::vector<char>& data, |
| SuccessCallback success, |
| FailureCallback failure) { |
| if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { |
| std::move(failure).Run(std::string(), std::string("Unauthorized access.")); |
| return; |
| } |
| |
| if (data.empty()) { |
| std::move(failure).Run(std::string(), |
| std::string("Can't send an empty packet.")); |
| return; |
| } |
| |
| shill_client_->SendPacket(active_configuration_->object_path(), data, |
| std::move(success), std::move(failure)); |
| } |
| |
| void VpnService::NotifyConnectionStateChanged(const std::string& extension_id, |
| api_vpn::VpnConnectionState state, |
| SuccessCallback success, |
| FailureCallback failure) { |
| if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { |
| std::move(failure).Run(std::string(), std::string("Unauthorized access.")); |
| return; |
| } |
| |
| shill_client_->UpdateConnectionState(active_configuration_->object_path(), |
| static_cast<uint32_t>(state), |
| std::move(success), std::move(failure)); |
| } |
| |
| bool VpnService::VerifyConfigExistsForTesting( |
| const std::string& extension_id, |
| const std::string& configuration_name) { |
| const std::string key = GetKey(extension_id, configuration_name); |
| return base::Contains(key_to_configuration_map_, key); |
| } |
| |
| bool VpnService::VerifyConfigIsConnectedForTesting( |
| const std::string& extension_id) { |
| return DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id); |
| } |
| |
| void VpnService::DestroyConfigurationsForExtension( |
| const extensions::Extension* extension) { |
| std::vector<VpnConfiguration*> to_be_destroyed; |
| for (const auto& iter : key_to_configuration_map_) { |
| if (iter.second->extension_id() == extension->id()) { |
| to_be_destroyed.push_back(iter.second.get()); |
| } |
| } |
| |
| for (auto* iter : to_be_destroyed) { |
| DestroyConfiguration(extension->id(), // Extension ID |
| iter->configuration_name(), // Configuration name |
| base::DoNothing(), |
| base::BindOnce(DoNothingFailureCallback)); |
| } |
| } |
| |
| void VpnService::OnExtensionUninstalled( |
| content::BrowserContext* browser_context, |
| const extensions::Extension* extension, |
| extensions::UninstallReason reason) { |
| if (browser_context != browser_context_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| DestroyConfigurationsForExtension(extension); |
| } |
| |
| void VpnService::OnExtensionUnloaded( |
| content::BrowserContext* browser_context, |
| const extensions::Extension* extension, |
| extensions::UnloadedExtensionReason reason) { |
| if (browser_context != browser_context_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| if (active_configuration_ && |
| active_configuration_->extension_id() == extension->id()) { |
| shill_client_->UpdateConnectionState( |
| active_configuration_->object_path(), |
| static_cast<uint32_t>(api_vpn::VPN_CONNECTION_STATE_FAILURE), |
| base::DoNothing(), base::BindOnce(DoNothingFailureCallback)); |
| } |
| if (reason == extensions::UnloadedExtensionReason::DISABLE || |
| reason == extensions::UnloadedExtensionReason::BLOCKLIST) { |
| DestroyConfigurationsForExtension(extension); |
| } |
| } |
| |
| void VpnService::OnCreateConfigurationSuccess( |
| VpnService::SuccessCallback callback, |
| VpnConfiguration* configuration, |
| const std::string& service_path, |
| const std::string& guid) { |
| configuration->set_service_path(service_path); |
| service_path_to_configuration_map_[service_path] = configuration; |
| shill_client_->AddShillThirdPartyVpnObserver(configuration->object_path(), |
| configuration); |
| std::move(callback).Run(); |
| } |
| |
| void VpnService::OnCreateConfigurationFailure( |
| VpnService::FailureCallback callback, |
| VpnConfiguration* configuration, |
| const std::string& error_name, |
| std::unique_ptr<base::DictionaryValue> error_data) { |
| DestroyConfigurationInternal(configuration); |
| std::move(callback).Run(error_name, std::string()); |
| } |
| |
| void VpnService::OnRemoveConfigurationSuccess( |
| VpnService::SuccessCallback callback) { |
| std::move(callback).Run(); |
| } |
| |
| void VpnService::OnRemoveConfigurationFailure( |
| VpnService::FailureCallback callback, |
| const std::string& error_name, |
| std::unique_ptr<base::DictionaryValue> error_data) { |
| std::move(callback).Run(error_name, std::string()); |
| } |
| |
| void VpnService::SendSignalToExtension( |
| const std::string& extension_id, |
| extensions::events::HistogramValue histogram_value, |
| const std::string& event_name, |
| std::vector<base::Value> event_args) { |
| std::unique_ptr<extensions::Event> event(new extensions::Event( |
| histogram_value, event_name, std::move(event_args), browser_context_)); |
| |
| event_router_->DispatchEventToExtension(extension_id, std::move(event)); |
| } |
| |
| void VpnService::SetActiveConfiguration( |
| VpnService::VpnConfiguration* configuration) { |
| active_configuration_ = configuration; |
| } |
| |
| VpnService::VpnConfiguration* VpnService::CreateConfigurationInternal( |
| const std::string& extension_id, |
| const std::string& configuration_name, |
| const std::string& key) { |
| VpnConfiguration* configuration = new VpnConfiguration( |
| extension_id, configuration_name, key, weak_factory_.GetWeakPtr()); |
| key_to_configuration_map_[key] = base::WrapUnique(configuration); |
| return configuration; |
| } |
| |
| void VpnService::DestroyConfigurationInternal(VpnConfiguration* configuration) { |
| std::unique_ptr<VpnConfiguration> configuration_ptr = |
| std::move(key_to_configuration_map_[configuration->key()]); |
| key_to_configuration_map_.erase(configuration->key()); |
| if (active_configuration_ == configuration) { |
| active_configuration_ = nullptr; |
| } |
| if (!configuration->service_path().empty()) { |
| shill_client_->RemoveShillThirdPartyVpnObserver( |
| configuration->object_path()); |
| service_path_to_configuration_map_.erase(configuration->service_path()); |
| } |
| } |
| |
| bool VpnService::DoesActiveConfigurationExistAndIsAccessAuthorized( |
| const std::string& extension_id) { |
| return active_configuration_ && |
| active_configuration_->extension_id() == extension_id; |
| } |
| |
| void VpnService::Bind( |
| const std::string& extension_id, |
| const std::string& configuration_id, |
| const std::string& configuration_name, |
| SuccessCallback success, |
| FailureCallback failure, |
| std::unique_ptr<content::PepperVpnProviderResourceHostProxy> |
| pepper_vpn_provider_proxy) { |
| // The ID is the configuration name for now. This may change in the future. |
| const std::string key = GetKey(extension_id, configuration_id); |
| if (!base::Contains(key_to_configuration_map_, key)) { |
| std::move(failure).Run(std::string(), |
| std::string("Unauthorized access. " |
| "The configuration does not exist.")); |
| return; |
| } |
| |
| VpnConfiguration* configuration = key_to_configuration_map_[key].get(); |
| if (active_configuration_ != configuration) { |
| std::move(failure).Run(std::string(), |
| std::string("Unauthorized access. " |
| "The configuration is not active.")); |
| return; |
| } |
| |
| if (configuration->extension_id() != extension_id || |
| configuration->configuration_name() != configuration_name) { |
| std::move(failure).Run( |
| std::string(), |
| std::string("Unauthorized access. " |
| "Configuration name or extension ID mismatch.")); |
| return; |
| } |
| |
| const std::string service_path = configuration->service_path(); |
| if (service_path.empty()) { |
| std::move(failure).Run(std::string(), std::string("Pending create.")); |
| return; |
| } |
| |
| // Connection authorized. All packets will be routed through the Pepper API. |
| configuration->set_pepper_proxy(std::move(pepper_vpn_provider_proxy)); |
| |
| std::move(success).Run(); |
| } |
| |
| std::unique_ptr<content::VpnServiceProxy> VpnService::GetVpnServiceProxy() { |
| return base::WrapUnique(new VpnServiceProxyImpl(weak_factory_.GetWeakPtr())); |
| } |
| |
| const std::string VpnService::GetSingleServicepathForTesting() { |
| if (service_path_to_configuration_map_.size() == 1) |
| return service_path_to_configuration_map_.begin()->first; |
| return std::string(); |
| } |
| |
| } // namespace chromeos |