Commit ab2c5eef authored by Xiqi Ruan's avatar Xiqi Ruan Committed by Commit Bot

cros: Request verification when changing timezone for child

When user with child account tries to modify timezone preference, prompt
parent access code validation dialog. Timezone changes can only be
applied if the validation success.

Bug: 997310
Change-Id: I90e1b5ebd79f5ca92dcc32223d637f37615e6699
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2210749Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: Xiqi Ruan <xiqiruan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779355}
parent 3930cf3f
...@@ -8,6 +8,7 @@ js_type_check("closure_compile") { ...@@ -8,6 +8,7 @@ js_type_check("closure_compile") {
deps = [ deps = [
":date_time_page", ":date_time_page",
":date_time_types", ":date_time_types",
":timezone_browser_proxy",
":timezone_selector", ":timezone_selector",
":timezone_subpage", ":timezone_subpage",
] ]
...@@ -17,7 +18,6 @@ js_library("date_time_page") { ...@@ -17,7 +18,6 @@ js_library("date_time_page") {
deps = [ deps = [
":date_time_types", ":date_time_types",
":timezone_selector", ":timezone_selector",
":timezone_subpage",
"..:os_route", "..:os_route",
"../..:router", "../..:router",
"../../prefs:prefs_behavior", "../../prefs:prefs_behavior",
...@@ -33,6 +33,10 @@ js_library("date_time_types") { ...@@ -33,6 +33,10 @@ js_library("date_time_types") {
deps = [ "//ui/webui/resources/js:cr" ] deps = [ "//ui/webui/resources/js:cr" ]
} }
js_library("timezone_browser_proxy") {
deps = [ "//ui/webui/resources/js:cr" ]
}
js_library("timezone_selector") { js_library("timezone_selector") {
deps = [ deps = [
":date_time_types", ":date_time_types",
...@@ -46,6 +50,7 @@ js_library("timezone_selector") { ...@@ -46,6 +50,7 @@ js_library("timezone_selector") {
js_library("timezone_subpage") { js_library("timezone_subpage") {
deps = [ deps = [
":date_time_types", ":date_time_types",
":timezone_browser_proxy",
":timezone_selector", ":timezone_selector",
"../../prefs:prefs_behavior", "../../prefs:prefs_behavior",
"//ui/webui/resources/js:cr", "//ui/webui/resources/js:cr",
...@@ -58,6 +63,7 @@ js_library("timezone_subpage") { ...@@ -58,6 +63,7 @@ js_library("timezone_subpage") {
# deps = [ # deps = [
# ":date_time_page.m", # ":date_time_page.m",
# ":date_time_types.m", # ":date_time_types.m",
# ":timezone_browser_proxy.m",
# ":timezone_selector.m", # ":timezone_selector.m",
# ":timezone_subpage.m" # ":timezone_subpage.m"
# ] # ]
...@@ -79,6 +85,14 @@ js_library("date_time_types.m") { ...@@ -79,6 +85,14 @@ js_library("date_time_types.m") {
extra_deps = [ ":date_time_types_module" ] extra_deps = [ ":date_time_types_module" ]
} }
js_library("timezone_browser_proxy.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/date_time_page/timezone_browser_proxy.m.js" ]
deps = [
# TODO: Fill those in.
]
extra_deps = [ ":modulize" ]
}
js_library("timezone_selector.m") { js_library("timezone_selector.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/date_time_page/timezone_selector.m.js" ] sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/date_time_page/timezone_selector.m.js" ]
deps = [ deps = [
...@@ -101,6 +115,7 @@ group("polymer3_elements") { ...@@ -101,6 +115,7 @@ group("polymer3_elements") {
public_deps = [ public_deps = [
":date_time_page_module", ":date_time_page_module",
":date_time_types_module", ":date_time_types_module",
":modulize",
":timezone_selector_module", ":timezone_selector_module",
":timezone_subpage_module", ":timezone_subpage_module",
] ]
...@@ -129,3 +144,9 @@ polymer_modulizer("timezone_subpage") { ...@@ -129,3 +144,9 @@ polymer_modulizer("timezone_subpage") {
html_file = "timezone_subpage.html" html_file = "timezone_subpage.html"
html_type = "dom-module" html_type = "dom-module"
} }
import("//ui/webui/resources/tools/js_modulizer.gni")
js_modulizer("modulize") {
input_files = [ "timezone_browser_proxy.js" ]
}
...@@ -56,9 +56,6 @@ Polymer({ ...@@ -56,9 +56,6 @@ Polymer({
prefs.generated.resolve_timezone_by_geolocation_method_short.value)` prefs.generated.resolve_timezone_by_geolocation_method_short.value)`
}, },
/** @private */
isChild_: {type: Boolean, value: loadTimeData.getBoolean('isChild')},
/** /**
* Whether the icon informing that this action is managed by a parent is * Whether the icon informing that this action is managed by a parent is
* displayed. * displayed.
...@@ -75,10 +72,6 @@ Polymer({ ...@@ -75,10 +72,6 @@ Polymer({
attached() { attached() {
this.addWebUIListener( this.addWebUIListener(
'can-set-date-time-changed', this.onCanSetDateTimeChanged_.bind(this)); 'can-set-date-time-changed', this.onCanSetDateTimeChanged_.bind(this));
this.addWebUIListener(
'access-code-validation-complete',
this.openTimeZoneSubpage_.bind(this));
chrome.send('dateTimePageReady'); chrome.send('dateTimePageReady');
}, },
...@@ -116,19 +109,8 @@ Polymer({ ...@@ -116,19 +109,8 @@ Polymer({
return id ? this.i18n(id) : ''; return id ? this.i18n(id) : '';
}, },
/** /** @private */
* Called when the timezone row is clicked. Child accounts need parental
* approval to modify their timezone, this method starts this process on the
* C++ side, and once it is complete the 'access-code-validation-complete'
* event is triggered which invokes openTimeZoneSubpage_. For non-child
* accounts the method is invoked immediately.
* @private
*/
onTimeZoneSettings_() { onTimeZoneSettings_() {
if (this.isChild_) {
chrome.send('handleShowParentAccessForTimeZone');
return;
}
this.openTimeZoneSubpage_(); this.openTimeZoneSubpage_();
}, },
......
<link rel="import" href="chrome://resources/html/cr.html">
<script src="timezone_browser_proxy.js"></script>
// Copyright 2020 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.
/** @fileoverview A helper object used by the time zone subpage page. */
cr.define('settings', function() {
/** @interface */
class TimeZoneBrowserProxy {
/** Notifies C++ code to show parent access code verification view. */
showParentAccessForTimeZone() {}
}
/** @implements {settings.TimeZoneBrowserProxy} */
class TimeZoneBrowserProxyImpl {
/** @override */
showParentAccessForTimeZone() {
chrome.send('handleShowParentAccessForTimeZone');
}
}
cr.addSingletonGetter(TimeZoneBrowserProxyImpl);
// #cr_define_end
return {
TimeZoneBrowserProxy: TimeZoneBrowserProxy,
TimeZoneBrowserProxyImpl: TimeZoneBrowserProxyImpl
};
});
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
<settings-dropdown-menu pref="{{prefs.cros.system.timezone}}" <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}"
label="$i18n{timeZone}" label="$i18n{timeZone}"
menu-options="[[timeZoneList_]]" menu-options="[[timeZoneList_]]"
disabled="[[prefs.generated.resolve_timezone_by_geolocation_on_off.value]]"> disabled="[[prefs.generated.resolve_timezone_by_geolocation_on_off.value ||
shouldDisableTimeZoneGeoSelector]]">
</settings-dropdown-menu> </settings-dropdown-menu>
</template> </template>
<template is="dom-if" restamp <template is="dom-if" restamp
...@@ -34,7 +35,8 @@ ...@@ -34,7 +35,8 @@
label="$i18n{timeZone}" label="$i18n{timeZone}"
menu-options="[[timeZoneList_]]" menu-options="[[timeZoneList_]]"
hidden="[[isUserTimeZoneSelectorHidden_(prefs.settings.timezone, hidden="[[isUserTimeZoneSelectorHidden_(prefs.settings.timezone,
prefs.generated.resolve_timezone_by_geolocation_on_off.value)]]"> prefs.generated.resolve_timezone_by_geolocation_on_off.value)]]"
disabled="[[shouldDisableTimeZoneGeoSelector]]">
</settings-dropdown-menu> </settings-dropdown-menu>
<settings-dropdown-menu id="systemTimezoneSelector" <settings-dropdown-menu id="systemTimezoneSelector"
pref="{{prefs.cros.system.timezone}}" pref="{{prefs.cros.system.timezone}}"
......
...@@ -23,6 +23,15 @@ Polymer({ ...@@ -23,6 +23,15 @@ Polymer({
notify: true, notify: true,
}, },
/**
* True if the account is supervised and doesn't get parent access code
* verification.
*/
shouldDisableTimeZoneGeoSelector: {
type: Boolean,
notify: true,
},
/** /**
* Initialized with the current time zone so the menu displays the * Initialized with the current time zone so the menu displays the
* correct value. The full option list is fetched lazily if necessary by * correct value. The full option list is fetched lazily if necessary by
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<link rel="import" href="../../prefs/prefs_behavior.html"> <link rel="import" href="../../prefs/prefs_behavior.html">
<link rel="import" href="../../settings_shared_css.html"> <link rel="import" href="../../settings_shared_css.html">
<link rel="import" href="date_time_types.html"> <link rel="import" href="date_time_types.html">
<link rel="import" href="timezone_browser_proxy.html">
<link rel="import" href="timezone_selector.html"> <link rel="import" href="timezone_selector.html">
<dom-module id="timezone-subpage"> <dom-module id="timezone-subpage">
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
Polymer({ Polymer({
is: 'timezone-subpage', is: 'timezone-subpage',
behaviors: [PrefsBehavior], behaviors:
[PrefsBehavior, WebUIListenerBehavior, settings.RouteObserverBehavior],
properties: { properties: {
/** /**
...@@ -21,6 +22,34 @@ Polymer({ ...@@ -21,6 +22,34 @@ Polymer({
}, },
}, },
/** @private {?settings.TimeZoneBrowserProxy} */
browserProxy_: null,
/** @override */
created() {
this.browserProxy_ = settings.TimeZoneBrowserProxyImpl.getInstance();
},
/**
* settings.RouteObserverBehavior
* Called when the timezone subpage is hit. Child accounts need parental
* approval to modify their timezone, this method starts this process on the
* C++ side, and timezone setting will be disable. Once it is complete the
* 'access-code-validation-complete' event is triggered which invokes
* enableTimeZoneSetting_.
* @param {!settings.Route} newRoute
* @protected
*/
currentRouteChanged(newRoute) {
if (this.shouldAskForParentAccessCode_(newRoute)) {
this.disableTimeZoneSetting_();
this.addWebUIListener(
'access-code-validation-complete',
this.enableTimeZoneSetting_.bind(this));
this.browserProxy_.showParentAccessForTimeZone();
}
},
/** /**
* Returns value list for timeZoneResolveMethodDropdown menu. * Returns value list for timeZoneResolveMethodDropdown menu.
* @private * @private
...@@ -62,4 +91,43 @@ Polymer({ ...@@ -62,4 +91,43 @@ Polymer({
return result; return result;
}, },
/**
* @param {!settings.Route} route
* @private
*/
shouldAskForParentAccessCode_(route) {
return route === settings.routes.DATETIME_TIMEZONE_SUBPAGE &&
loadTimeData.getBoolean('isChild');
},
/**
* Enables all dropdowns and radio buttons.
* @private
*/
enableTimeZoneSetting_() {
const radios = this.root.querySelectorAll('controlled-radio-button');
for (const radio of radios) {
radio.disabled = false;
}
this.$.timezoneSelector.shouldDisableTimeZoneGeoSelector = false;
const pref =
this.getPref('generated.resolve_timezone_by_geolocation_method_short');
if (pref.value !== settings.TimeZoneAutoDetectMethod.DISABLED) {
this.$.timeZoneResolveMethodDropdown.disabled = false;
}
},
/**
* Disables all dropdowns and radio buttons.
* @private
*/
disableTimeZoneSetting_() {
this.$.timeZoneResolveMethodDropdown.disabled = true;
this.$.timezoneSelector.shouldDisableTimeZoneGeoSelector = true;
const radios = this.root.querySelectorAll('controlled-radio-button');
for (const radio of radios) {
radio.disabled = true;
}
},
}); });
...@@ -1101,6 +1101,12 @@ ...@@ -1101,6 +1101,12 @@
<structure name="IDR_OS_SETTINGS_DATE_TIME_TYPES_JS" <structure name="IDR_OS_SETTINGS_DATE_TIME_TYPES_JS"
file="chromeos/date_time_page/date_time_types.js" file="chromeos/date_time_page/date_time_types.js"
compress="false" type="chrome_html" /> compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_TIMEZONE_BROWSER_PROXY_JS"
file="chromeos/date_time_page/timezone_browser_proxy.js"
compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_TIMEZONE_BROWSER_PROXY_HTML"
file="chromeos/date_time_page/timezone_browser_proxy.html"
compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_TIMEZONE_SELECTOR_HTML" <structure name="IDR_OS_SETTINGS_TIMEZONE_SELECTOR_HTML"
file="chromeos/date_time_page/timezone_selector.html" file="chromeos/date_time_page/timezone_selector.html"
compress="false" type="chrome_html" /> compress="false" type="chrome_html" />
......
...@@ -58,7 +58,7 @@ bool IsTimezoneAutomaticDetectionUserEditable() { ...@@ -58,7 +58,7 @@ bool IsTimezoneAutomaticDetectionUserEditable() {
if (IsSystemTimezoneAutomaticDetectionManaged()) { if (IsSystemTimezoneAutomaticDetectionManaged()) {
return GetSystemTimezoneAutomaticDetectionPolicyValue() == return GetSystemTimezoneAutomaticDetectionPolicyValue() ==
enterprise_management::SystemTimezoneProto::USERS_DECIDE; enterprise_management::SystemTimezoneProto::USERS_DECIDE;
} }
return true; return true;
...@@ -156,7 +156,7 @@ void DateTimeHandler::HandleShowParentAccessForTimeZone( ...@@ -156,7 +156,7 @@ void DateTimeHandler::HandleShowParentAccessForTimeZone(
base::BindOnce(&DateTimeHandler::OnParentAccessValidation, base::BindOnce(&DateTimeHandler::OnParentAccessValidation,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
ash::ParentAccessRequestReason::kChangeTimezone, false /* extra_dimmer */, ash::ParentAccessRequestReason::kChangeTimezone, false /* extra_dimmer */,
base::Time()); base::Time::Now());
} }
void DateTimeHandler::OnParentAccessValidation(bool success) { void DateTimeHandler::OnParentAccessValidation(bool success) {
...@@ -166,10 +166,9 @@ void DateTimeHandler::OnParentAccessValidation(bool success) { ...@@ -166,10 +166,9 @@ void DateTimeHandler::OnParentAccessValidation(bool success) {
void DateTimeHandler::NotifyTimezoneAutomaticDetectionPolicy() { void DateTimeHandler::NotifyTimezoneAutomaticDetectionPolicy() {
bool managed = !IsTimezoneAutomaticDetectionUserEditable(); bool managed = !IsTimezoneAutomaticDetectionUserEditable();
bool force_enabled = managed && bool force_enabled = managed && g_browser_process->platform_part()
g_browser_process->platform_part() ->GetTimezoneResolverManager()
->GetTimezoneResolverManager() ->ShouldApplyResolvedTimezone();
->ShouldApplyResolvedTimezone();
FireWebUIListener("time-zone-auto-detect-policy", base::Value(managed), FireWebUIListener("time-zone-auto-detect-policy", base::Value(managed),
base::Value(force_enabled)); base::Value(force_enabled));
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "chromeos/settings/cros_settings_names.h" #include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/system_settings_provider.h" #include "chromeos/settings/system_settings_provider.h"
#include "chromeos/settings/timezone_settings.h" #include "chromeos/settings/timezone_settings.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_data_source.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h" #include "ui/base/webui/web_ui_util.h"
...@@ -131,6 +132,9 @@ void DateTimeSection::AddLoadTimeData(content::WebUIDataSource* html_source) { ...@@ -131,6 +132,9 @@ void DateTimeSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
html_source->AddBoolean( html_source->AddBoolean(
"timeActionsProtectedForChild", "timeActionsProtectedForChild",
base::FeatureList::IsEnabled(features::kParentAccessCodeForTimeChange)); base::FeatureList::IsEnabled(features::kParentAccessCodeForTimeChange));
bool is_child = user_manager::UserManager::Get()->GetActiveUser()->IsChild();
html_source->AddBoolean("isChild", is_child);
} }
void DateTimeSection::AddHandlers(content::WebUI* web_ui) { void DateTimeSection::AddHandlers(content::WebUI* web_ui) {
......
...@@ -3,6 +3,18 @@ ...@@ -3,6 +3,18 @@
// found in the LICENSE file. // found in the LICENSE file.
(function() { (function() {
/** @implements {settings.TimeZoneBrowserProxy} */
class TestTimeZoneBrowserProxy extends TestBrowserProxy {
constructor() {
super(['showParentAccessForTimeZone']);
}
/** @override */
showParentAccessForTimeZone() {
this.methodCalled('showParentAccessForTimeZone');
}
}
function getFakePrefs() { function getFakePrefs() {
return { return {
cros: { cros: {
...@@ -125,6 +137,7 @@ function initializeDateTime(prefs, hasPolicy, opt_autoDetectPolicyValue) { ...@@ -125,6 +137,7 @@ function initializeDateTime(prefs, hasPolicy, opt_autoDetectPolicyValue) {
'Automatic time zone detection with WiFi AP', 'Automatic time zone detection with WiFi AP',
setTimeZoneAutomaticallyWithAllLocationInfo: setTimeZoneAutomaticallyWithAllLocationInfo:
'Automatic time zone detection with all location info', 'Automatic time zone detection with all location info',
isChild: false,
}; };
window.loadTimeData = new LoadTimeData; window.loadTimeData = new LoadTimeData;
...@@ -192,7 +205,13 @@ suite('settings-date-time-page', function() { ...@@ -192,7 +205,13 @@ suite('settings-date-time-page', function() {
let dateTimePageReadyCalled; let dateTimePageReadyCalled;
let getTimeZonesCalled; let getTimeZonesCalled;
/** @type {?TestTimeZoneBrowserProxy} */
let testBrowserProxy = null;
setup(function() { setup(function() {
testBrowserProxy = new TestTimeZoneBrowserProxy();
settings.TimeZoneBrowserProxyImpl.instance_ = testBrowserProxy;
PolymerTest.clearBody(); PolymerTest.clearBody();
CrSettingsPrefs.resetForTesting(); CrSettingsPrefs.resetForTesting();
...@@ -378,6 +397,88 @@ suite('settings-date-time-page', function() { ...@@ -378,6 +397,88 @@ suite('settings-date-time-page', function() {
}); });
}); });
test('auto-detect on supervised account', async () => {
const prefs = getFakePrefs();
dateTime = initializeDateTime(prefs, false);
// Set auto detect on.
dateTime.set(
'prefs.generated.resolve_timezone_by_geolocation_on_off.value', true);
dateTime.set(
'prefs.generated.resolve_timezone_by_geolocation_method_short.value',
settings.TimeZoneAutoDetectMethod.IP_ONLY);
// Set fake child account.
loadTimeData.overrideValues({
isChild: true,
});
await settings.Router.getInstance().navigateTo(
settings.routes.DATETIME_TIMEZONE_SUBPAGE);
const resolveMethodDropdown = dateTime.$$('#timeZoneResolveMethodDropdown');
const timezoneSelector = getTimeZoneSelector('#userTimeZoneSelector');
const timeZoneAutoDetectOn = dateTime.$$('#timeZoneAutoDetectOn');
const timeZoneAutoDetectOff = dateTime.$$('#timeZoneAutoDetectOff');
// Verify elements are disabled for child account.
assertTrue(resolveMethodDropdown.disabled);
assertTrue(timezoneSelector.disabled);
assertTrue(timeZoneAutoDetectOn.disabled);
assertTrue(timeZoneAutoDetectOff.disabled);
await testBrowserProxy.whenCalled('showParentAccessForTimeZone');
cr.webUIListenerCallback('access-code-validation-complete');
// Verify elements are enabled.
assertFalse(resolveMethodDropdown.disabled);
assertFalse(timeZoneAutoDetectOn.disabled);
assertFalse(timeZoneAutoDetectOff.disabled);
// |timezoneSelector| is hidden when auto detect on.
assertFalse(timezoneSelector.disabled);
assertTrue(timezoneSelector.hidden);
});
test('auto-detect off supervised account', async () => {
const prefs = getFakePrefs();
dateTime = initializeDateTime(prefs, false);
// Set auto detect off.
dateTime.set(
'prefs.generated.resolve_timezone_by_geolocation_on_off.value', false);
dateTime.set(
'prefs.generated.resolve_timezone_by_geolocation_method_short.value',
settings.TimeZoneAutoDetectMethod.DISABLED);
// Set fake child account.
loadTimeData.overrideValues({
isChild: true,
});
await settings.Router.getInstance().navigateTo(
settings.routes.DATETIME_TIMEZONE_SUBPAGE);
const resolveMethodDropdown = dateTime.$$('#timeZoneResolveMethodDropdown');
const timezoneSelector = getTimeZoneSelector('#userTimeZoneSelector');
const timeZoneAutoDetectOn = dateTime.$$('#timeZoneAutoDetectOn');
const timeZoneAutoDetectOff = dateTime.$$('#timeZoneAutoDetectOff');
// Verify elements are disabled for child account.
assertTrue(resolveMethodDropdown.disabled);
assertTrue(timezoneSelector.disabled);
assertTrue(timeZoneAutoDetectOn.disabled);
assertTrue(timeZoneAutoDetectOff.disabled);
await testBrowserProxy.whenCalled('showParentAccessForTimeZone');
cr.webUIListenerCallback('access-code-validation-complete');
// |resolveMethodDropdown| is disabled when auto detect off.
assertTrue(resolveMethodDropdown.disabled);
// Verify elements are enabled.
assertFalse(timeZoneAutoDetectOn.disabled);
assertFalse(timeZoneAutoDetectOff.disabled);
assertFalse(timezoneSelector.disabled);
});
test('set date and time button', function() { test('set date and time button', function() {
dateTime = initializeDateTime(getFakePrefs(), false); dateTime = initializeDateTime(getFakePrefs(), false);
......
...@@ -558,6 +558,7 @@ var OSSettingsDateTimePageTest = class extends OSSettingsBrowserTest { ...@@ -558,6 +558,7 @@ var OSSettingsDateTimePageTest = class extends OSSettingsBrowserTest {
/** @override */ /** @override */
get extraLibraries() { get extraLibraries() {
return super.extraLibraries.concat([ return super.extraLibraries.concat([
BROWSER_SETTINGS_PATH + '../test_browser_proxy.js',
'date_time_page_tests.js', 'date_time_page_tests.js',
]); ]);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment