Finish refactoring of DomCodeToUsLayoutKeyboardCode().
[chromium-blink-merge.git] / extensions / browser / api / vpn_provider / vpn_service.cc
blob5eaed3ebd9bff6f308ebb29b1fe9e94e922cedd2
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/vpn_provider/vpn_service.h"
7 #include <stdint.h>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/guid.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/values.h"
20 #include "chromeos/dbus/shill_third_party_vpn_driver_client.h"
21 #include "chromeos/dbus/shill_third_party_vpn_observer.h"
22 #include "chromeos/network/network_configuration_handler.h"
23 #include "chromeos/network/network_profile.h"
24 #include "chromeos/network/network_profile_handler.h"
25 #include "chromeos/network/network_state.h"
26 #include "chromeos/network/network_state_handler.h"
27 #include "chromeos/network/network_type_pattern.h"
28 #include "crypto/sha2.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
33 namespace chromeos {
35 namespace {
37 namespace api_vpn = extensions::core_api::vpn_provider;
39 void DoNothingFailureCallback(const std::string& error_name,
40 const std::string& error_message) {
41 LOG(ERROR) << error_name << ": " << error_message;
44 } // namespace
46 class VpnService::VpnConfiguration : public ShillThirdPartyVpnObserver {
47 public:
48 VpnConfiguration(const std::string& extension_id,
49 const std::string& configuration_name,
50 const std::string& key,
51 base::WeakPtr<VpnService> vpn_service);
52 ~VpnConfiguration() override;
54 const std::string& extension_id() const { return extension_id_; }
55 const std::string& configuration_name() const { return configuration_name_; }
56 const std::string& key() const { return key_; }
57 const std::string& service_path() const { return service_path_; }
58 void set_service_path(const std::string& service_path) {
59 service_path_ = service_path;
61 const std::string& object_path() const { return object_path_; }
63 // ShillThirdPartyVpnObserver:
64 void OnPacketReceived(const std::vector<char>& data) override;
65 void OnPlatformMessage(uint32_t message) override;
67 private:
68 const std::string extension_id_;
69 const std::string configuration_name_;
70 const std::string key_;
71 const std::string object_path_;
73 std::string service_path_;
75 base::WeakPtr<VpnService> vpn_service_;
77 DISALLOW_COPY_AND_ASSIGN(VpnConfiguration);
80 VpnService::VpnConfiguration::VpnConfiguration(
81 const std::string& extension_id,
82 const std::string& configuration_name,
83 const std::string& key,
84 base::WeakPtr<VpnService> vpn_service)
85 : extension_id_(extension_id),
86 configuration_name_(configuration_name),
87 key_(key),
88 object_path_(shill::kObjectPathBase + key_),
89 vpn_service_(vpn_service) {
92 VpnService::VpnConfiguration::~VpnConfiguration() {
95 void VpnService::VpnConfiguration::OnPacketReceived(
96 const std::vector<char>& data) {
97 if (!vpn_service_) {
98 return;
100 scoped_ptr<base::ListValue> event_args =
101 api_vpn::OnPacketReceived::Create(data);
102 vpn_service_->SendSignalToExtension(
103 extension_id_, api_vpn::OnPacketReceived::kEventName, event_args.Pass());
106 void VpnService::VpnConfiguration::OnPlatformMessage(uint32_t message) {
107 if (!vpn_service_) {
108 return;
110 DCHECK_GE(api_vpn::PLATFORM_MESSAGE_LAST, message);
112 api_vpn::PlatformMessage platform_message =
113 static_cast<api_vpn::PlatformMessage>(message);
114 vpn_service_->SetActiveConfiguration(
115 platform_message == api_vpn::PLATFORM_MESSAGE_CONNECTED ? this : nullptr);
117 // TODO(kaliamoorthi): Update the lower layers to get the error message and
118 // pass in the error instead of std::string().
119 scoped_ptr<base::ListValue> event_args = api_vpn::OnPlatformMessage::Create(
120 configuration_name_, platform_message, std::string());
122 vpn_service_->SendSignalToExtension(
123 extension_id_, api_vpn::OnPlatformMessage::kEventName, event_args.Pass());
126 VpnService::VpnService(
127 content::BrowserContext* browser_context,
128 const std::string& userid_hash,
129 extensions::ExtensionRegistry* extension_registry,
130 extensions::EventRouter* event_router,
131 ShillThirdPartyVpnDriverClient* shill_client,
132 NetworkConfigurationHandler* network_configuration_handler,
133 NetworkProfileHandler* network_profile_handler,
134 NetworkStateHandler* network_state_handler)
135 : browser_context_(browser_context),
136 userid_hash_(userid_hash),
137 extension_registry_(extension_registry),
138 event_router_(event_router),
139 shill_client_(shill_client),
140 network_configuration_handler_(network_configuration_handler),
141 network_profile_handler_(network_profile_handler),
142 network_state_handler_(network_state_handler),
143 active_configuration_(nullptr),
144 weak_factory_(this) {
145 extension_registry_->AddObserver(this);
146 network_state_handler_->AddObserver(this, FROM_HERE);
147 network_configuration_handler_->AddObserver(this);
148 base::MessageLoop::current()->PostTask(
149 FROM_HERE,
150 base::Bind(&VpnService::NetworkListChanged, weak_factory_.GetWeakPtr()));
153 VpnService::~VpnService() {
154 network_configuration_handler_->RemoveObserver(this);
155 network_state_handler_->RemoveObserver(this, FROM_HERE);
156 extension_registry_->RemoveObserver(this);
157 STLDeleteContainerPairSecondPointers(key_to_configuration_map_.begin(),
158 key_to_configuration_map_.end());
161 void VpnService::SendShowAddDialogToExtension(const std::string& extension_id) {
162 SendSignalToExtension(extension_id, api_vpn::OnUIEvent::kEventName,
163 api_vpn::OnUIEvent::Create(
164 api_vpn::UI_EVENT_SHOWADDDIALOG, std::string()));
167 void VpnService::SendShowConfigureDialogToExtension(
168 const std::string& extension_id,
169 const std::string& configuration_id) {
170 SendSignalToExtension(
171 extension_id, api_vpn::OnUIEvent::kEventName,
172 api_vpn::OnUIEvent::Create(api_vpn::UI_EVENT_SHOWCONFIGUREDIALOG,
173 configuration_id));
176 void VpnService::SendPlatformError(const std::string& extension_id,
177 const std::string& configuration_id,
178 const std::string& error_message) {
179 SendSignalToExtension(
180 extension_id, api_vpn::OnPlatformMessage::kEventName,
181 api_vpn::OnPlatformMessage::Create(
182 configuration_id, api_vpn::PLATFORM_MESSAGE_ERROR, error_message));
185 std::string VpnService::GetKey(const std::string& extension_id,
186 const std::string& name) {
187 const std::string key = crypto::SHA256HashString(extension_id + name);
188 return base::HexEncode(key.data(), key.size());
191 void VpnService::OnConfigurationCreated(const std::string& service_path,
192 const std::string& profile_path,
193 const base::DictionaryValue& properties,
194 Source source) {
197 void VpnService::OnConfigurationRemoved(const std::string& service_path,
198 const std::string& guid,
199 Source source) {
200 if (source == SOURCE_EXTENSION_INSTALL) {
201 // No need to process if the configuration was removed using an extension
202 // API since the API would have already done the cleanup.
203 return;
206 if (service_path_to_configuration_map_.find(service_path) ==
207 service_path_to_configuration_map_.end()) {
208 // Ignore removal of a configuration unknown to VPN service, which means the
209 // configuration was created internally by the platform.
210 return;
213 VpnConfiguration* configuration =
214 service_path_to_configuration_map_[service_path];
215 scoped_ptr<base::ListValue> event_args =
216 api_vpn::OnConfigRemoved::Create(configuration->configuration_name());
217 SendSignalToExtension(configuration->extension_id(),
218 api_vpn::OnConfigRemoved::kEventName,
219 event_args.Pass());
221 DestroyConfigurationInternal(configuration);
224 void VpnService::OnPropertiesSet(const std::string& service_path,
225 const std::string& guid,
226 const base::DictionaryValue& set_properties,
227 Source source) {
230 void VpnService::OnConfigurationProfileChanged(const std::string& service_path,
231 const std::string& profile_path,
232 Source source) {
235 void VpnService::OnGetPropertiesSuccess(
236 const std::string& service_path,
237 const base::DictionaryValue& dictionary) {
238 if (service_path_to_configuration_map_.find(service_path) !=
239 service_path_to_configuration_map_.end()) {
240 return;
242 std::string vpn_type;
243 std::string extension_id;
244 std::string type;
245 std::string configuration_name;
246 if (!dictionary.GetString(shill::kProviderTypeProperty, &vpn_type) ||
247 !dictionary.GetString(shill::kProviderHostProperty, &extension_id) ||
248 !dictionary.GetString(shill::kTypeProperty, &type) ||
249 !dictionary.GetString(shill::kNameProperty, &configuration_name) ||
250 vpn_type != shill::kProviderThirdPartyVpn || type != shill::kTypeVPN) {
251 return;
254 if (!extension_registry_->GetExtensionById(
255 extension_id, extensions::ExtensionRegistry::ENABLED)) {
256 // Does not belong to this instance of VpnService.
257 return;
260 const std::string key = GetKey(extension_id, configuration_name);
261 VpnConfiguration* configuration =
262 CreateConfigurationInternal(extension_id, configuration_name, key);
263 configuration->set_service_path(service_path);
264 service_path_to_configuration_map_[service_path] = configuration;
265 shill_client_->AddShillThirdPartyVpnObserver(configuration->object_path(),
266 configuration);
269 void VpnService::OnGetPropertiesFailure(
270 const std::string& error_name,
271 scoped_ptr<base::DictionaryValue> error_data) {
274 void VpnService::NetworkListChanged() {
275 NetworkStateHandler::NetworkStateList network_list;
276 network_state_handler_->GetVisibleNetworkListByType(NetworkTypePattern::VPN(),
277 &network_list);
278 for (auto& iter : network_list) {
279 if (service_path_to_configuration_map_.find(iter->path()) !=
280 service_path_to_configuration_map_.end()) {
281 continue;
284 network_configuration_handler_->GetShillProperties(
285 iter->path(), base::Bind(&VpnService::OnGetPropertiesSuccess,
286 weak_factory_.GetWeakPtr()),
287 base::Bind(&VpnService::OnGetPropertiesFailure,
288 weak_factory_.GetWeakPtr()));
292 void VpnService::CreateConfiguration(const std::string& extension_id,
293 const std::string& extension_name,
294 const std::string& configuration_name,
295 const SuccessCallback& success,
296 const FailureCallback& failure) {
297 if (configuration_name.empty()) {
298 failure.Run(std::string(), std::string("Empty name not supported."));
299 return;
302 const std::string key = GetKey(extension_id, configuration_name);
303 if (ContainsKey(key_to_configuration_map_, key)) {
304 failure.Run(std::string(), std::string("Name not unique."));
305 return;
308 const NetworkProfile* profile =
309 network_profile_handler_->GetProfileForUserhash(userid_hash_);
310 if (!profile) {
311 failure.Run(
312 std::string(),
313 std::string("No user profile for unshared network configuration."));
314 return;
317 VpnConfiguration* configuration =
318 CreateConfigurationInternal(extension_id, configuration_name, key);
320 base::DictionaryValue properties;
321 properties.SetStringWithoutPathExpansion(shill::kTypeProperty,
322 shill::kTypeVPN);
323 properties.SetStringWithoutPathExpansion(shill::kNameProperty,
324 configuration_name);
325 properties.SetStringWithoutPathExpansion(shill::kProviderHostProperty,
326 extension_id);
327 properties.SetStringWithoutPathExpansion(shill::kObjectPathSuffixProperty,
328 configuration->key());
329 properties.SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
330 shill::kProviderThirdPartyVpn);
331 properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
332 profile->path);
334 // Note: This will not create an entry in |policy_util|. TODO(pneubeck):
335 // Determine the correct thing to do here, crbug.com/459278.
336 std::string guid = base::GenerateGUID();
337 properties.SetStringWithoutPathExpansion(shill::kGuidProperty, guid);
339 network_configuration_handler_->CreateShillConfiguration(
340 properties, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL,
341 base::Bind(&VpnService::OnCreateConfigurationSuccess,
342 weak_factory_.GetWeakPtr(), success, configuration),
343 base::Bind(&VpnService::OnCreateConfigurationFailure,
344 weak_factory_.GetWeakPtr(), failure, configuration));
347 void VpnService::DestroyConfiguration(const std::string& extension_id,
348 const std::string& configuration_id,
349 const SuccessCallback& success,
350 const FailureCallback& failure) {
351 // The ID is the configuration name for now. This may change in the future.
352 const std::string key = GetKey(extension_id, configuration_id);
353 if (!ContainsKey(key_to_configuration_map_, key)) {
354 failure.Run(std::string(), std::string("Unauthorized access."));
355 return;
358 VpnConfiguration* configuration = key_to_configuration_map_[key];
359 const std::string service_path = configuration->service_path();
360 if (service_path.empty()) {
361 failure.Run(std::string(), std::string("Pending create."));
362 return;
364 if (active_configuration_ == configuration) {
365 configuration->OnPlatformMessage(api_vpn::PLATFORM_MESSAGE_DISCONNECTED);
367 DestroyConfigurationInternal(configuration);
369 network_configuration_handler_->RemoveConfiguration(
370 service_path, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL,
371 base::Bind(&VpnService::OnRemoveConfigurationSuccess,
372 weak_factory_.GetWeakPtr(), success),
373 base::Bind(&VpnService::OnRemoveConfigurationFailure,
374 weak_factory_.GetWeakPtr(), failure));
377 void VpnService::SetParameters(const std::string& extension_id,
378 const base::DictionaryValue& parameters,
379 const StringCallback& success,
380 const FailureCallback& failure) {
381 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) {
382 failure.Run(std::string(), std::string("Unauthorized access."));
383 return;
386 shill_client_->SetParameters(active_configuration_->object_path(), parameters,
387 success, failure);
390 void VpnService::SendPacket(const std::string& extension_id,
391 const std::vector<char>& data,
392 const SuccessCallback& success,
393 const FailureCallback& failure) {
394 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) {
395 failure.Run(std::string(), std::string("Unauthorized access."));
396 return;
399 if (data.empty()) {
400 failure.Run(std::string(), std::string("Can't send an empty packet."));
401 return;
404 shill_client_->SendPacket(active_configuration_->object_path(), data, success,
405 failure);
408 void VpnService::NotifyConnectionStateChanged(const std::string& extension_id,
409 api_vpn::VpnConnectionState state,
410 const SuccessCallback& success,
411 const FailureCallback& failure) {
412 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) {
413 failure.Run(std::string(), std::string("Unauthorized access."));
414 return;
417 shill_client_->UpdateConnectionState(active_configuration_->object_path(),
418 static_cast<uint32_t>(state), success,
419 failure);
422 bool VpnService::VerifyConfigExistsForTesting(
423 const std::string& extension_id,
424 const std::string& configuration_name) {
425 const std::string key = GetKey(extension_id, configuration_name);
426 return ContainsKey(key_to_configuration_map_, key);
429 bool VpnService::VerifyConfigIsConnectedForTesting(
430 const std::string& extension_id) {
431 return DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id);
434 void VpnService::DestroyConfigurationsForExtension(
435 const extensions::Extension* extension) {
436 std::vector<VpnConfiguration*> to_be_destroyed;
437 for (const auto& iter : key_to_configuration_map_) {
438 if (iter.second->extension_id() == extension->id()) {
439 to_be_destroyed.push_back(iter.second);
443 for (auto& iter : to_be_destroyed) {
444 DestroyConfiguration(extension->id(), // Extension ID
445 iter->configuration_name(), // Configuration name
446 base::Bind(base::DoNothing),
447 base::Bind(DoNothingFailureCallback));
451 void VpnService::OnExtensionUninstalled(
452 content::BrowserContext* browser_context,
453 const extensions::Extension* extension,
454 extensions::UninstallReason reason) {
455 if (browser_context != browser_context_) {
456 NOTREACHED();
457 return;
460 DestroyConfigurationsForExtension(extension);
463 void VpnService::OnExtensionUnloaded(
464 content::BrowserContext* browser_context,
465 const extensions::Extension* extension,
466 extensions::UnloadedExtensionInfo::Reason reason) {
467 if (browser_context != browser_context_) {
468 NOTREACHED();
469 return;
472 if (active_configuration_ &&
473 active_configuration_->extension_id() == extension->id()) {
474 shill_client_->UpdateConnectionState(
475 active_configuration_->object_path(),
476 static_cast<uint32_t>(api_vpn::VPN_CONNECTION_STATE_FAILURE),
477 base::Bind(base::DoNothing), base::Bind(DoNothingFailureCallback));
479 if (reason == extensions::UnloadedExtensionInfo::REASON_DISABLE ||
480 reason == extensions::UnloadedExtensionInfo::REASON_BLACKLIST) {
481 DestroyConfigurationsForExtension(extension);
485 void VpnService::OnCreateConfigurationSuccess(
486 const VpnService::SuccessCallback& callback,
487 VpnConfiguration* configuration,
488 const std::string& service_path) {
489 configuration->set_service_path(service_path);
490 service_path_to_configuration_map_[service_path] = configuration;
491 shill_client_->AddShillThirdPartyVpnObserver(configuration->object_path(),
492 configuration);
493 callback.Run();
496 void VpnService::OnCreateConfigurationFailure(
497 const VpnService::FailureCallback& callback,
498 VpnConfiguration* configuration,
499 const std::string& error_name,
500 scoped_ptr<base::DictionaryValue> error_data) {
501 DestroyConfigurationInternal(configuration);
502 callback.Run(error_name, std::string());
505 void VpnService::OnRemoveConfigurationSuccess(
506 const VpnService::SuccessCallback& callback) {
507 callback.Run();
510 void VpnService::OnRemoveConfigurationFailure(
511 const VpnService::FailureCallback& callback,
512 const std::string& error_name,
513 scoped_ptr<base::DictionaryValue> error_data) {
514 callback.Run(error_name, std::string());
517 void VpnService::SendSignalToExtension(const std::string& extension_id,
518 const std::string& event_name,
519 scoped_ptr<base::ListValue> event_args) {
520 scoped_ptr<extensions::Event> event(
521 new extensions::Event(extensions::events::UNKNOWN, event_name,
522 event_args.Pass(), browser_context_));
524 event_router_->DispatchEventToExtension(extension_id, event.Pass());
527 void VpnService::SetActiveConfiguration(
528 VpnService::VpnConfiguration* configuration) {
529 active_configuration_ = configuration;
532 VpnService::VpnConfiguration* VpnService::CreateConfigurationInternal(
533 const std::string& extension_id,
534 const std::string& configuration_name,
535 const std::string& key) {
536 VpnConfiguration* configuration = new VpnConfiguration(
537 extension_id, configuration_name, key, weak_factory_.GetWeakPtr());
538 // The object is owned by key_to_configuration_map_ henceforth.
539 key_to_configuration_map_[key] = configuration;
540 return configuration;
543 void VpnService::DestroyConfigurationInternal(VpnConfiguration* configuration) {
544 key_to_configuration_map_.erase(configuration->key());
545 if (active_configuration_ == configuration) {
546 active_configuration_ = nullptr;
548 if (!configuration->service_path().empty()) {
549 shill_client_->RemoveShillThirdPartyVpnObserver(
550 configuration->object_path());
551 service_path_to_configuration_map_.erase(configuration->service_path());
553 delete configuration;
556 bool VpnService::DoesActiveConfigurationExistAndIsAccessAuthorized(
557 const std::string& extension_id) {
558 return active_configuration_ &&
559 active_configuration_->extension_id() == extension_id;
562 } // namespace chromeos