• 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/strings/string_util.h"
16 #include "base/sys_info.h"
17 #include "base/values.h"
18 #include "chrome/browser/chromeos/settings/cros_settings.h"
19 #include "chrome/grit/chromium_strings.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "chromeos/settings/cros_settings_names.h"
23 #include "components/crx_file/id_util.h"
24 #include "components/user_manager/user_manager.h"
25 #include "content/public/browser/web_ui.h"
26 #include "content/public/browser/web_ui_data_source.h"
27 #include "extensions/common/extension_urls.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/webui/web_ui_util.h"
30 #include "url/gurl.h"
31 
32 namespace chromeos {
33 
34 namespace {
35 
36 // Populates app info dictionary with |app_data|.
PopulateAppDict(const KioskAppManager::App & app_data,base::DictionaryValue * app_dict)37 void PopulateAppDict(const KioskAppManager::App& app_data,
38                      base::DictionaryValue* app_dict) {
39   std::string icon_url("chrome://theme/IDR_APP_DEFAULT_ICON");
40 
41   // TODO(xiyuan): Replace data url with a URLDataSource.
42   if (!app_data.icon.isNull())
43     icon_url = webui::GetBitmapDataUrl(*app_data.icon.bitmap());
44 
45   // The items which are to be written into app_dict are also described in
46   // chrome/browser/resources/extensions/chromeos/kiosk_app_list.js in @typedef
47   // for AppDict. Please update it whenever you add or remove any keys here.
48   app_dict->SetString("id", app_data.app_id);
49   app_dict->SetString("name", app_data.name);
50   app_dict->SetString("iconURL", icon_url);
51   app_dict->SetBoolean(
52       "autoLaunch",
53       KioskAppManager::Get()->GetAutoLaunchApp() == app_data.app_id &&
54       (KioskAppManager::Get()->IsAutoLaunchEnabled() ||
55           KioskAppManager::Get()->IsAutoLaunchRequested()));
56   app_dict->SetBoolean("isLoading", app_data.is_loading);
57 }
58 
59 // Sanitize app id input value and extracts app id out of it.
60 // Returns false if an app id could not be derived out of the input.
ExtractsAppIdFromInput(const std::string & input,std::string * app_id)61 bool ExtractsAppIdFromInput(const std::string& input,
62                             std::string* app_id) {
63   if (crx_file::id_util::IdIsValid(input)) {
64     *app_id = input;
65     return true;
66   }
67 
68   GURL webstore_url = GURL(input);
69   if (!webstore_url.is_valid())
70     return false;
71 
72   GURL webstore_base_url =
73       GURL(extension_urls::GetWebstoreItemDetailURLPrefix());
74 
75   if (webstore_url.scheme() != webstore_base_url.scheme() ||
76       webstore_url.host() != webstore_base_url.host() ||
77       !StartsWithASCII(
78           webstore_url.path(), webstore_base_url.path(), true)) {
79     return false;
80   }
81 
82   const std::string path = webstore_url.path();
83   const size_t last_slash = path.rfind('/');
84   if (last_slash == std::string::npos)
85     return false;
86 
87   const std::string candidate_id = path.substr(last_slash + 1);
88   if (!crx_file::id_util::IdIsValid(candidate_id))
89     return false;
90 
91   *app_id = candidate_id;
92   return true;
93 }
94 
95 }  // namespace
96 
KioskAppsHandler()97 KioskAppsHandler::KioskAppsHandler()
98     : kiosk_app_manager_(KioskAppManager::Get()),
99       initialized_(false),
100       is_kiosk_enabled_(false),
101       is_auto_launch_enabled_(false),
102       weak_ptr_factory_(this) {
103   kiosk_app_manager_->AddObserver(this);
104 }
105 
~KioskAppsHandler()106 KioskAppsHandler::~KioskAppsHandler() {
107   kiosk_app_manager_->RemoveObserver(this);
108 }
109 
RegisterMessages()110 void KioskAppsHandler::RegisterMessages() {
111   web_ui()->RegisterMessageCallback("initializeKioskAppSettings",
112       base::Bind(&KioskAppsHandler::HandleInitializeKioskAppSettings,
113                  base::Unretained(this)));
114   web_ui()->RegisterMessageCallback("getKioskAppSettings",
115       base::Bind(&KioskAppsHandler::HandleGetKioskAppSettings,
116                  base::Unretained(this)));
117   web_ui()->RegisterMessageCallback("addKioskApp",
118       base::Bind(&KioskAppsHandler::HandleAddKioskApp,
119                  base::Unretained(this)));
120   web_ui()->RegisterMessageCallback("removeKioskApp",
121       base::Bind(&KioskAppsHandler::HandleRemoveKioskApp,
122                  base::Unretained(this)));
123   web_ui()->RegisterMessageCallback("enableKioskAutoLaunch",
124       base::Bind(&KioskAppsHandler::HandleEnableKioskAutoLaunch,
125                  base::Unretained(this)));
126   web_ui()->RegisterMessageCallback("disableKioskAutoLaunch",
127       base::Bind(&KioskAppsHandler::HandleDisableKioskAutoLaunch,
128                  base::Unretained(this)));
129   web_ui()->RegisterMessageCallback("setDisableBailoutShortcut",
130       base::Bind(&KioskAppsHandler::HandleSetDisableBailoutShortcut,
131                  base::Unretained(this)));
132 }
133 
GetLocalizedValues(content::WebUIDataSource * source)134 void KioskAppsHandler::GetLocalizedValues(content::WebUIDataSource* source) {
135   source->AddString(
136       "addKioskAppButton",
137       l10n_util::GetStringUTF16(IDS_EXTENSIONS_ADD_KIOSK_APP_BUTTON));
138   source->AddString(
139       "kioskOverlayTitle",
140       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_OVERLAY_TITLE));
141   source->AddString(
142       "addKioskApp",
143       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP));
144   source->AddString(
145       "kioskAppIdEditHint",
146       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP_HINT));
147   source->AddString(
148       "enableAutoLaunchButton",
149       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ENABLE_AUTO_LAUNCH));
150   source->AddString(
151       "disableAutoLaunchButton",
152       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_DISABLE_AUTO_LAUNCH));
153   source->AddString(
154       "autoLaunch",
155       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_AUTO_LAUNCH));
156   source->AddString(
157       "invalidApp",
158       l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_INVALID_APP));
159   source->AddString(
160       "kioskDiableBailoutShortcutLabel",
161       l10n_util::GetStringUTF16(
162           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_LABEL));
163   source->AddString(
164       "kioskDisableBailoutShortcutWarningBold",
165       l10n_util::GetStringUTF16(
166           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_BOLD));
167   const base::string16 product_os_name =
168       l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
169   source->AddString(
170       "kioskDisableBailoutShortcutWarning",
171       l10n_util::GetStringFUTF16(
172           IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_FORMAT,
173           product_os_name));
174   source->AddString(
175       "kioskDisableBailoutShortcutConfirm",
176       l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
177   source->AddString(
178       "kioskDisableBailoutShortcutCancel",
179       l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
180   source->AddString("done", l10n_util::GetStringUTF16(IDS_DONE));
181   source->AddString("add", l10n_util::GetStringUTF16(IDS_ADD));
182 }
183 
OnKioskAppDataChanged(const std::string & app_id)184 void KioskAppsHandler::OnKioskAppDataChanged(const std::string& app_id) {
185   UpdateApp(app_id);
186 }
187 
OnKioskAppDataLoadFailure(const std::string & app_id)188 void KioskAppsHandler::OnKioskAppDataLoadFailure(const std::string& app_id) {
189   ShowError(app_id);
190 }
191 
OnKioskExtensionLoadedInCache(const std::string & app_id)192 void KioskAppsHandler::OnKioskExtensionLoadedInCache(
193     const std::string& app_id) {
194   UpdateApp(app_id);
195 }
196 
OnKioskExtensionDownloadFailed(const std::string & app_id)197 void KioskAppsHandler::OnKioskExtensionDownloadFailed(
198     const std::string& app_id) {
199   ShowError(app_id);
200 }
201 
OnGetConsumerKioskAutoLaunchStatus(chromeos::KioskAppManager::ConsumerKioskAutoLaunchStatus status)202 void KioskAppsHandler::OnGetConsumerKioskAutoLaunchStatus(
203     chromeos::KioskAppManager::ConsumerKioskAutoLaunchStatus status) {
204   initialized_ = true;
205   is_kiosk_enabled_ = user_manager::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 
UpdateApp(const std::string & app_id)336 void KioskAppsHandler::UpdateApp(const std::string& app_id) {
337   KioskAppManager::App app_data;
338   if (!kiosk_app_manager_->GetApp(app_id, &app_data))
339     return;
340 
341   base::DictionaryValue app_dict;
342   PopulateAppDict(app_data, &app_dict);
343 
344   web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.updateApp",
345                                    app_dict);
346 }
347 
ShowError(const std::string & app_id)348 void KioskAppsHandler::ShowError(const std::string& app_id) {
349   base::StringValue app_id_value(app_id);
350   web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.showError",
351                                    app_id_value);
352 
353   kiosk_app_manager_->RemoveApp(app_id);
354 }
355 
356 }  // namespace chromeos
357