1 // Copyright 2015 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 "chrome/browser/ui/ash/vpn_delegate_chromeos.h"
8 #include "ash/system/tray/system_tray_delegate.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/chromeos/profiles/profile_helper.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "components/user_manager/user.h"
17 #include "components/user_manager/user_manager.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h"
20 #include "extensions/browser/api/vpn_provider/vpn_service.h"
21 #include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/common/permissions/api_permission.h"
26 #include "extensions/common/permissions/permissions_data.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/chromeos/strings/grit/ui_chromeos_strings.h"
33 bool IsVPNProvider(const extensions::Extension
* extension
) {
34 return extension
->permissions_data()->HasAPIPermission(
35 extensions::APIPermission::kVpnProvider
);
38 Profile
* GetProfileForPrimaryUser() {
39 const user_manager::User
* const primary_user
=
40 user_manager::UserManager::Get()->GetPrimaryUser();
44 return chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user
);
49 VPNDelegateChromeOS::VPNDelegateChromeOS() : weak_factory_(this) {
50 if (user_manager::UserManager::Get()->GetPrimaryUser()) {
51 // If a user is logged in, start observing the primary user's extension
52 // registry immediately.
53 AttachToPrimaryUserExtensionRegistry();
55 // If no user is logged in, wait until the first user logs in (thus becoming
56 // the primary user) and a profile is created for that user.
57 registrar_
.Add(this, chrome::NOTIFICATION_PROFILE_CREATED
,
58 content::NotificationService::AllSources());
62 VPNDelegateChromeOS::~VPNDelegateChromeOS() {
63 if (extension_registry_
)
64 extension_registry_
->RemoveObserver(this);
67 bool VPNDelegateChromeOS::HaveThirdPartyVPNProviders() const {
68 for (const ash::VPNProvider
& provider
: vpn_providers_
) {
69 if (provider
.key
.third_party
)
75 const std::vector
<ash::VPNProvider
>& VPNDelegateChromeOS::GetVPNProviders()
77 return vpn_providers_
;
80 void VPNDelegateChromeOS::ShowAddPage(const ash::VPNProvider::Key
& key
) {
81 if (!key
.third_party
) {
82 // Show the "add network" dialog for the built-in OpenVPN/L2TP provider.
83 ash::Shell::GetInstance()->system_tray_delegate()->ShowOtherNetworkDialog(
88 Profile
* const profile
= GetProfileForPrimaryUser();
92 // Request that the third-party VPN provider identified by |key.extension_id|
93 // show its "add network" dialog.
94 chromeos::VpnServiceFactory::GetForBrowserContext(profile
)
95 ->SendShowAddDialogToExtension(key
.extension_id
);
98 void VPNDelegateChromeOS::OnExtensionLoaded(
99 content::BrowserContext
* browser_context
,
100 const extensions::Extension
* extension
) {
101 if (IsVPNProvider(extension
))
102 UpdateVPNProviders();
105 void VPNDelegateChromeOS::OnExtensionUnloaded(
106 content::BrowserContext
* browser_context
,
107 const extensions::Extension
* extension
,
108 extensions::UnloadedExtensionInfo::Reason reason
) {
109 if (IsVPNProvider(extension
))
110 UpdateVPNProviders();
113 void VPNDelegateChromeOS::OnShutdown(extensions::ExtensionRegistry
* registry
) {
114 DCHECK(extension_registry_
);
115 extension_registry_
->RemoveObserver(this);
116 extension_registry_
= nullptr;
119 void VPNDelegateChromeOS::Observe(int type
,
120 const content::NotificationSource
& source
,
121 const content::NotificationDetails
& details
) {
122 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_CREATED
, type
);
123 const Profile
* const profile
= content::Source
<Profile
>(source
).ptr();
124 if (!chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile
)) {
125 // If the profile that was just created does not belong to the primary user
126 // (e.g. login profile), ignore it.
130 // The first user logged in (thus becoming the primary user) and a profile was
131 // created for that user. Stop observing profile creation. Wait one message
132 // loop cycle to allow other code which observes the
133 // chrome::NOTIFICATION_PROFILE_CREATED notification to finish initializing
134 // the profile, then start observing the primary user's extension registry.
135 registrar_
.RemoveAll();
136 base::ThreadTaskRunnerHandle::Get()->PostTask(
138 base::Bind(&VPNDelegateChromeOS::AttachToPrimaryUserExtensionRegistry
,
139 weak_factory_
.GetWeakPtr()));
142 void VPNDelegateChromeOS::UpdateVPNProviders() {
143 DCHECK(extension_registry_
);
145 vpn_providers_
.clear();
146 for (const auto& extension
: extension_registry_
->enabled_extensions()) {
147 if (IsVPNProvider(extension
.get())) {
148 vpn_providers_
.push_back(ash::VPNProvider(
149 ash::VPNProvider::Key(extension
->id()), extension
->name()));
152 // Add the built-in OpenVPN/L2TP provider. The ash::VPNProvider::Key()
153 // constructor generates a key that identifies that built-in provider and has
155 vpn_providers_
.push_back(ash::VPNProvider(
156 ash::VPNProvider::Key(),
157 l10n_util::GetStringUTF8(IDS_NETWORK_VPN_BUILT_IN_PROVIDER
)));
162 void VPNDelegateChromeOS::AttachToPrimaryUserExtensionRegistry() {
163 DCHECK(!extension_registry_
);
164 extension_registry_
=
165 extensions::ExtensionRegistry::Get(GetProfileForPrimaryUser());
166 extension_registry_
->AddObserver(this);
168 UpdateVPNProviders();