• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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.
4 
5 #include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h"
6 
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/sys_info.h"
16 #include "base/values.h"
17 #include "chrome/browser/chromeos/login/users/user_manager.h"
18 #include "chrome/browser/chromeos/settings/cros_settings.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "chromeos/chromeos_switches.h"
21 #include "chromeos/settings/cros_settings_names.h"
22 #include "content/public/browser/web_ui.h"
23 #include "content/public/browser/web_ui_data_source.h"
24 #include "extensions/common/extension.h"
25 #include "grit/chromium_strings.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/webui/web_ui_util.h"
29 #include "url/gurl.h"
30 
31 namespace chromeos {
32 
33 namespace {
34 
35 // Populates app info dictionary with |app_data|.
PopulateAppDict(const KioskAppManager::App & app_data,base::DictionaryValue * app_dict)36 void PopulateAppDict(const KioskAppManager::App& app_data,
37                      base::DictionaryValue* app_dict) {
38   std::string icon_url("chrome://theme/IDR_APP_DEFAULT_ICON");
39 
40   // TODO(xiyuan): Replace data url with a URLDataSource.
41   if (!app_data.icon.isNull())
42     icon_url = webui::GetBitmapDataUrl(*app_data.icon.bitmap());
43 
44   app_dict->SetString("id", app_data.app_id);
45   app_dict->SetString("name", app_data.name);
46   app_dict->SetString("iconURL", icon_url);
47   app_dict->SetBoolean(
48       "autoLaunch",
49       KioskAppManager::Get()->GetAutoLaunchApp() == app_data.app_id &&
50       (KioskAppManager::Get()->IsAutoLaunchEnabled() ||
51           KioskAppManager::Get()->IsAutoLaunchRequested()));
52   app_dict->SetBoolean("isLoading", app_data.is_loading);
53 }
54 
55 // Sanitize app id input value and extracts app id out of it.
56 // Returns false if an app id could not be derived out of the input.
ExtractsAppIdFromInput(const std::string & input,std::string * app_id)57 bool ExtractsAppIdFromInput(const std::string& input,
58                             std::string* app_id) {
59   if (extensions::Extension::IdIsValid(input)) {
60     *app_id = input;
61     return true;
62   }
63 
64   GURL webstore_url = GURL(input);
65   if (!webstore_url.is_valid())
66     return false;
67 
68   GURL webstore_base_url =
69       GURL(extension_urls::GetWebstoreItemDetailURLPrefix());
70 
71   if (webstore_url.scheme() != webstore_base_url.scheme() ||
72       webstore_url.host() != webstore_base_url.host() ||
73       !StartsWithASCII(
74           webstore_url.path(), webstore_base_url.path(), true)) {
75     return false;
76   }
77 
78   const std::string path = webstore_url.path();
79   const size_t last_slash = path.rfind('/');
80   if (last_slash == std::string::npos)
81     return false;
82 
83   const std::string candidate_id = path.substr(last_slash + 1);
84   if (!extensions::Extension::IdIsValid(candidate_id))
85     return false;
86 
87   *app_id = candidate_id;
88   return true;
89 }
90 
91 }  // namespace
92 
KioskAppsHandler()93 KioskAppsHandler::KioskAppsHandler()
94     : kiosk_app_manager_(KioskAppManager::Get()),
95       initialized_(false),
96       is_kiosk_enabled_(false),
97       is_auto_launch_enabled_(false),
98       weak_ptr_factory_(this) {
99   kiosk_app_manager_->AddObserver(this);
100 }
101 
~KioskAppsHandler()102 KioskAppsHandler::~KioskAppsHandler() {
103   kiosk_app_manager_->RemoveObserver(this);
104 }
105 
RegisterMessages()106 void KioskAppsHandler::RegisterMessages() {
107   web_ui()->RegisterMessageCallback("initializeKioskAppSettings",
108       base::Bind(&KioskAppsHandler::HandleInitializeKioskAppSettings,
109                  base::Unretained(this)));
110   web_ui()->RegisterMessageCallback("getKioskAppSettings",
111       base::Bind(&KioskAppsHandler::HandleGetKioskAppSettings,
112                  base::Unretained(this)));
113   web_ui()->RegisterMessageCallback("addKioskApp",
114       base::Bind(&KioskAppsHandler::HandleAddKioskApp,
115                  base::Unretained(this)));
116   web_ui()->RegisterMessageCallback("removeKioskApp",
117       base::Bind(&KioskAppsHandler::HandleRemoveKioskApp,
118                  base::Unretained(this)));
119   web_ui()->RegisterMessageCallback("enableKioskAutoLaunch",
120       base::Bind(&KioskAppsHandler::HandleEnableKioskAutoLaunch,
121                  base::Unretained(this)));
122   web_ui()->RegisterMessageCallback("disableKioskAutoLaunch",
123       base::Bind(&KioskAppsHandler::HandleDisableKioskAutoLaunch,
124                  base::Unretained(this)));
125   web_ui()->RegisterMessageCallback("setDisableBailoutShortcut",
126       base::Bind(&KioskAppsHandler::HandleSetDisableBailoutShortcut,
127                  base::Unretained(this)));
128 }
129 
GetLocalizedValues(content::WebUIDataSource * source)130 void KioskAppsHandler::GetLocalizedValues(content::WebUIDataSource* source) {
131   source->AddString(
132       "addKioskAppButton",
133       l10n_util::GetStringUTF16(IDS_EXTENSIONS_ADD_KIOSK_APP_BUTTON));
134   source->AddString(
135       "kioskOverlayTitle",
136       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_OVERLAY_TITLE));
137   source->AddString(
138       "addKioskApp",
139       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP));
140   source->AddString(
141       "kioskAppIdEditHint",
142       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP_HINT));
143   source->AddString(
144       "enableAutoLaunchButton",
145       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ENABLE_AUTO_LAUNCH));
146   source->AddString(
147       "disableAutoLaunchButton",
148       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_DISABLE_AUTO_LAUNCH));
149   source->AddString(
150       "autoLaunch",
151       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_AUTO_LAUNCH));
152   source->AddString(
153       "invalidApp",
154       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_INVALID_APP));
155   source->AddString(
156       "kioskDiableBailoutShortcutLabel",
157       l10n_util::GetStringUTF16(
158           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_LABEL));
159   source->AddString(
160       "kioskDisableBailoutShortcutWarningBold",
161       l10n_util::GetStringUTF16(
162           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_BOLD));
163   const base::string16 product_os_name =
164       l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
165   source->AddString(
166       "kioskDisableBailoutShortcutWarning",
167       l10n_util::GetStringFUTF16(
168           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_FORMAT,
169           product_os_name));
170   source->AddString(
171       "kioskDisableBailoutShortcutConfirm",
172       l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
173   source->AddString(
174       "kioskDisableBailoutShortcutCancel",
175       l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
176   source->AddString("done", l10n_util::GetStringUTF16(IDS_DONE));
177   source->AddString("add", l10n_util::GetStringUTF16(IDS_ADD));
178 }
179 
OnKioskAppDataChanged(const std::string & app_id)180 void KioskAppsHandler::OnKioskAppDataChanged(const std::string& app_id) {
181   KioskAppManager::App app_data;
182   if (!kiosk_app_manager_->GetApp(app_id, &app_data))
183     return;
184 
185   base::DictionaryValue app_dict;
186   PopulateAppDict(app_data, &app_dict);
187 
188   web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.updateApp",
189                                    app_dict);
190 }
191 
OnKioskAppDataLoadFailure(const std::string & app_id)192 void KioskAppsHandler::OnKioskAppDataLoadFailure(const std::string& app_id) {
193   base::StringValue app_id_value(app_id);
194   web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.showError",
195                                    app_id_value);
196 
197   kiosk_app_manager_->RemoveApp(app_id);
198 }
199 
200 
OnGetConsumerKioskAutoLaunchStatus(chromeos::KioskAppManager::ConsumerKioskAutoLaunchStatus status)201 void KioskAppsHandler::OnGetConsumerKioskAutoLaunchStatus(
202     chromeos::KioskAppManager::ConsumerKioskAutoLaunchStatus status) {
203   initialized_ = true;
204   is_kiosk_enabled_ =
205       chromeos::UserManager::Get()->IsCurrentUserOwner() ||
206       !base::SysInfo::IsRunningOnChromeOS();
207 
208   is_auto_launch_enabled_ =
209       status == KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED ||
210       !base::SysInfo::IsRunningOnChromeOS();
211 
212   if (is_kiosk_enabled_) {
213     base::DictionaryValue kiosk_params;
214     kiosk_params.SetBoolean("kioskEnabled", is_kiosk_enabled_);
215     kiosk_params.SetBoolean("autoLaunchEnabled", is_auto_launch_enabled_);
216     web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.enableKiosk",
217                                      kiosk_params);
218   }
219 }
220 
221 
OnKioskAppsSettingsChanged()222 void KioskAppsHandler::OnKioskAppsSettingsChanged() {
223   SendKioskAppSettings();
224 }
225 
SendKioskAppSettings()226 void KioskAppsHandler::SendKioskAppSettings() {
227   if (!initialized_ || !is_kiosk_enabled_)
228     return;
229 
230   bool enable_bailout_shortcut;
231   if (!CrosSettings::Get()->GetBoolean(
232           kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled,
233           &enable_bailout_shortcut)) {
234     enable_bailout_shortcut = true;
235   }
236 
237   base::DictionaryValue settings;
238   settings.SetBoolean("disableBailout", !enable_bailout_shortcut);
239   settings.SetBoolean("hasAutoLaunchApp",
240                       !kiosk_app_manager_->GetAutoLaunchApp().empty());
241 
242   KioskAppManager::Apps apps;
243   kiosk_app_manager_->GetApps(&apps);
244 
245   scoped_ptr<base::ListValue> apps_list(new base::ListValue);
246   for (size_t i = 0; i < apps.size(); ++i) {
247     const KioskAppManager::App& app_data = apps[i];
248 
249     scoped_ptr<base::DictionaryValue> app_info(new base::DictionaryValue);
250     PopulateAppDict(app_data, app_info.get());
251     apps_list->Append(app_info.release());
252   }
253   settings.SetWithoutPathExpansion("apps", apps_list.release());
254 
255   web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.setSettings",
256                                    settings);
257 }
258 
HandleInitializeKioskAppSettings(const base::ListValue * args)259 void KioskAppsHandler::HandleInitializeKioskAppSettings(
260     const base::ListValue* args) {
261   KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(
262       base::Bind(&KioskAppsHandler::OnGetConsumerKioskAutoLaunchStatus,
263                  weak_ptr_factory_.GetWeakPtr()));
264 }
265 
HandleGetKioskAppSettings(const base::ListValue * args)266 void KioskAppsHandler::HandleGetKioskAppSettings(const base::ListValue* args) {
267   SendKioskAppSettings();
268 }
269 
270 
HandleAddKioskApp(const base::ListValue * args)271 void KioskAppsHandler::HandleAddKioskApp(const base::ListValue* args) {
272   if (!initialized_ || !is_kiosk_enabled_)
273     return;
274 
275   std::string input;
276   CHECK(args->GetString(0, &input));
277 
278   std::string app_id;
279   if (!ExtractsAppIdFromInput(input, &app_id)) {
280     OnKioskAppDataLoadFailure(input);
281     return;
282   }
283 
284   kiosk_app_manager_->AddApp(app_id);
285 }
286 
HandleRemoveKioskApp(const base::ListValue * args)287 void KioskAppsHandler::HandleRemoveKioskApp(const base::ListValue* args) {
288   if (!initialized_ || !is_kiosk_enabled_)
289     return;
290 
291   std::string app_id;
292   CHECK(args->GetString(0, &app_id));
293 
294   kiosk_app_manager_->RemoveApp(app_id);
295 }
296 
HandleEnableKioskAutoLaunch(const base::ListValue * args)297 void KioskAppsHandler::HandleEnableKioskAutoLaunch(
298     const base::ListValue* args) {
299   if (!initialized_ || !is_kiosk_enabled_ || !is_auto_launch_enabled_)
300     return;
301 
302   std::string app_id;
303   CHECK(args->GetString(0, &app_id));
304 
305   kiosk_app_manager_->SetAutoLaunchApp(app_id);
306 }
307 
HandleDisableKioskAutoLaunch(const base::ListValue * args)308 void KioskAppsHandler::HandleDisableKioskAutoLaunch(
309     const base::ListValue* args) {
310   if (!initialized_ || !is_kiosk_enabled_ || !is_auto_launch_enabled_)
311     return;
312 
313   std::string app_id;
314   CHECK(args->GetString(0, &app_id));
315 
316   std::string startup_app_id = kiosk_app_manager_->GetAutoLaunchApp();
317   if (startup_app_id != app_id)
318     return;
319 
320   kiosk_app_manager_->SetAutoLaunchApp("");
321 }
322 
HandleSetDisableBailoutShortcut(const base::ListValue * args)323 void KioskAppsHandler::HandleSetDisableBailoutShortcut(
324     const base::ListValue* args) {
325   if (!initialized_ || !is_kiosk_enabled_)
326     return;
327 
328   bool disable_bailout_shortcut;
329   CHECK(args->GetBoolean(0, &disable_bailout_shortcut));
330 
331   CrosSettings::Get()->SetBoolean(
332       kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled,
333       !disable_bailout_shortcut);
334 }
335 
336 }  // namespace chromeos
337