Migrate ChromeOS lock_screen_reauth to TypeScript
Bug: https://issuetracker.google.com/315872665 Change-Id: If2e47035c38b4fd637d4fd6c07c9abcd3d594c69 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5501146 Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Manuel Gómez <mgomezch@chromium.org> Reviewed-by: Leon Masopust <lmasopust@google.com> Cr-Commit-Position: refs/heads/main@{#1341683}
This commit is contained in:
parent
35791f84aa
commit
1c890d9b6c
chrome
browser
ash/login
resources
chromeos/lock_screen_reauth
BUILD.gnlock_screen_network.htmllock_screen_network.tslock_screen_reauth.htmllock_screen_reauth.jslock_screen_reauth.tslock_screen_reauth_app.ts
gaia_auth_host
test/data/webui/inline_login
tools/typescript/definitions
@ -799,7 +799,7 @@ IN_PROC_BROWSER_TEST_F(SamlUnlockTest, ScrapedSingle) {
|
||||
// Make sure that the password is scraped correctly.
|
||||
ASSERT_TRUE(content::ExecJs(
|
||||
reauth_dialog_helper->DialogWebContents(),
|
||||
"$('main-element').authenticator_.addEventListener('authCompleted',"
|
||||
"$('main-element').authenticator.addEventListener('authCompleted',"
|
||||
" function(e) {"
|
||||
" var password = e.detail.password;"
|
||||
" window.domAutomationController.send(password);"
|
||||
|
@ -156,7 +156,7 @@ constexpr char kClientCert2Name[] = "client_2";
|
||||
constexpr char kLoadingDialog[] = "loadingDialog";
|
||||
constexpr char kSigninWebview[] = "$('gaia-signin').getSigninFrame()";
|
||||
constexpr char kSigninWebviewOnLockScreen[] =
|
||||
"$('main-element').getSigninFrame_()";
|
||||
"$('main-element').getSigninFrame()";
|
||||
constexpr char kTestCookieHost[] = "host1.com";
|
||||
constexpr char kTestCookieName[] = "TestCookie";
|
||||
constexpr char kTestCookieValue[] = "present";
|
||||
|
@ -3,125 +3,48 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//chrome/common/features.gni")
|
||||
import("//third_party/closure_compiler/compile_js.gni")
|
||||
import("//tools/grit/grit_rule.gni")
|
||||
import("//tools/grit/preprocess_if_expr.gni")
|
||||
import("//tools/polymer/html_to_js.gni")
|
||||
import("//ui/webui/resources/tools/generate_grd.gni")
|
||||
import("//ui/webui/resources/tools/build_webui.gni")
|
||||
|
||||
src_files_manifest = "$target_gen_dir/src_files_manifest.json"
|
||||
gen_files_manifest = "$target_gen_dir/gen_files_manifest.json"
|
||||
preprocess_folder = "$target_gen_dir/preprocessed"
|
||||
grd_filename = "$target_gen_dir/resources.grd"
|
||||
|
||||
grit("resources") {
|
||||
defines = chrome_grit_defines
|
||||
|
||||
# This is necessary since the GRD is generated during build time.
|
||||
enable_input_discovery_for_gn_analyze = false
|
||||
|
||||
source = grd_filename
|
||||
deps = [ ":build_grd" ]
|
||||
outputs = [
|
||||
"grit/lock_screen_reauth_resources.h",
|
||||
"grit/lock_screen_reauth_resources_map.h",
|
||||
"grit/lock_screen_reauth_resources_map.cc",
|
||||
"lock_screen_reauth_resources.pak",
|
||||
]
|
||||
output_dir = "$root_gen_dir/chrome"
|
||||
}
|
||||
|
||||
generate_grd("build_grd") {
|
||||
build_webui("build") {
|
||||
grd_prefix = "lock_screen_reauth"
|
||||
out_grd = grd_filename
|
||||
deps = [
|
||||
":preprocess_gen",
|
||||
":preprocess_src",
|
||||
]
|
||||
manifest_files = [
|
||||
src_files_manifest,
|
||||
gen_files_manifest,
|
||||
]
|
||||
}
|
||||
|
||||
preprocess_if_expr("preprocess_src") {
|
||||
out_folder = preprocess_folder
|
||||
out_manifest = src_files_manifest
|
||||
in_files = [
|
||||
static_files = [
|
||||
"lock_screen_network.html",
|
||||
"lock_screen_network.js",
|
||||
"lock_screen_reauth_app.html",
|
||||
"lock_screen_reauth_app.js",
|
||||
]
|
||||
}
|
||||
|
||||
web_component_files = [ "lock_screen_reauth.js" ]
|
||||
web_component_files = [ "lock_screen_reauth.ts" ]
|
||||
|
||||
preprocess_if_expr("preprocess_gen") {
|
||||
deps = [ ":web_components" ]
|
||||
in_folder = target_gen_dir
|
||||
out_folder = preprocess_folder
|
||||
out_manifest = gen_files_manifest
|
||||
in_files = web_component_files
|
||||
}
|
||||
|
||||
html_to_js("web_components") {
|
||||
js_files = web_component_files
|
||||
}
|
||||
|
||||
js_type_check("closure_compile") {
|
||||
is_polymer3 = true
|
||||
closure_flags =
|
||||
default_closure_args + mojom_js_args + [
|
||||
"js_module_root=" +
|
||||
rebase_path("//chrome/browser/resources/gaia_auth_host/",
|
||||
root_build_dir),
|
||||
"js_module_root=./gen/chrome/browser/resources/gaia_auth_host/",
|
||||
]
|
||||
deps = [
|
||||
":lock_screen_network",
|
||||
":lock_screen_reauth",
|
||||
":lock_screen_reauth_app",
|
||||
non_web_component_files = [
|
||||
"lock_screen_network.ts",
|
||||
"lock_screen_reauth_app.ts",
|
||||
]
|
||||
}
|
||||
|
||||
js_library("lock_screen_network") {
|
||||
deps = [
|
||||
"//ash/webui/common/resources:i18n_behavior",
|
||||
"//ash/webui/common/resources:load_time_data.m",
|
||||
"//ash/webui/common/resources/network:network_select",
|
||||
"//ash/webui/common/resources/network:onc_mojo",
|
||||
ts_definitions = [
|
||||
"//chrome/browser/resources/gaia_auth_host/authenticator.d.ts",
|
||||
"//chrome/browser/resources/gaia_auth_host/saml_password_attributes.d.ts",
|
||||
"//tools/typescript/definitions/chrome_event.d.ts",
|
||||
"//tools/typescript/definitions/chrome_send.d.ts",
|
||||
"//tools/typescript/definitions/context_menus.d.ts",
|
||||
"//tools/typescript/definitions/extension_types.d.ts",
|
||||
"//tools/typescript/definitions/tabs.d.ts",
|
||||
"//tools/typescript/definitions/web_request.d.ts",
|
||||
"//tools/typescript/definitions/webview_tag.d.ts",
|
||||
]
|
||||
externs_list = [
|
||||
"$externs_path/chrome_send.js",
|
||||
"//ash/webui/common/resources/cr_elements/cr_button/cr_button_externs.js",
|
||||
"//ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog_externs.js",
|
||||
]
|
||||
}
|
||||
|
||||
js_library("lock_screen_reauth_app") {
|
||||
sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/lock_screen_reauth/lock_screen_reauth.js" ]
|
||||
deps = [
|
||||
":lock_screen_reauth",
|
||||
"//ash/webui/common/resources:load_time_data.m",
|
||||
ts_deps = [
|
||||
"//ash/webui/common/resources:build_ts",
|
||||
"//ash/webui/common/resources/cr_elements:build_ts",
|
||||
"//third_party/polymer/v3_0:library",
|
||||
"//ui/webui/resources/cr_components/color_change_listener:build_ts",
|
||||
"//ui/webui/resources/js:build_ts",
|
||||
"//ui/webui/resources/mojo:build_ts",
|
||||
]
|
||||
extra_deps = [ ":web_components" ]
|
||||
}
|
||||
|
||||
js_library("lock_screen_reauth") {
|
||||
sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/lock_screen_reauth/lock_screen_reauth.js" ]
|
||||
deps = [
|
||||
"//ash/webui/common/resources:cr.m",
|
||||
"//ash/webui/common/resources:i18n_behavior",
|
||||
"//ash/webui/common/resources:load_time_data.m",
|
||||
"//chrome/browser/resources/gaia_auth_host:authenticator",
|
||||
]
|
||||
externs_list = [
|
||||
"$externs_path/chrome_send.js",
|
||||
"//ash/webui/common/resources/cr_elements/cr_button/cr_button_externs.js",
|
||||
"//ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog_externs.js",
|
||||
"//ash/webui/common/resources/cr_elements/cr_input/cr_input_externs.js",
|
||||
"//ash/webui/common/resources/cr_elements/policy/cr_tooltip_icon_externs.js",
|
||||
]
|
||||
extra_deps = [ ":web_components" ]
|
||||
ts_path_mappings =
|
||||
[ "//lock-reauth/gaia_auth_host/*|" +
|
||||
rebase_path("//chrome/browser/resources/gaia_auth_host/*",
|
||||
target_gen_dir) ]
|
||||
|
||||
webui_context_type = "trusted"
|
||||
}
|
||||
|
@ -102,14 +102,14 @@ found in the LICENSE file.
|
||||
<div slot="body">
|
||||
<div id="select-div">
|
||||
<network-select
|
||||
on-network-item-selected="onNetworkItemSelected_"
|
||||
on-custom-item-selected="onCustomItemSelected_">
|
||||
on-network-item-selected="onNetworkItemSelected"
|
||||
on-custom-item-selected="onCustomItemSelected">
|
||||
</network-select>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="button-container" class="flex layout horizontal">
|
||||
<cr-button id="cancelButton" class="cancel-button"
|
||||
on-click="onCloseTap_">
|
||||
on-click="onCloseClick">
|
||||
$i18n{lockScreenCancelButton}
|
||||
</cr-button>
|
||||
</div>
|
||||
|
@ -15,41 +15,40 @@ import './strings.m.js';
|
||||
|
||||
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
|
||||
import {CrosNetworkConfig, CrosNetworkConfigRemote, StartConnectResult} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
|
||||
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
|
||||
Polymer({
|
||||
is: 'lock-screen-network-ui',
|
||||
class LockScreenNetworkUi extends PolymerElement {
|
||||
static get is() {
|
||||
return 'lock-screen-network-ui' as const;
|
||||
}
|
||||
|
||||
/** @type {?CrosNetworkConfigRemote} */
|
||||
networkConfig_: null,
|
||||
private networkConfig: CrosNetworkConfigRemote =
|
||||
CrosNetworkConfig.getRemote();
|
||||
|
||||
/** @override */
|
||||
attached() {
|
||||
this.networkConfig_ = CrosNetworkConfig.getRemote();
|
||||
|
||||
const select = this.$$('network-select');
|
||||
select.customItems = [
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
const select = this.shadowRoot!.querySelector('network-select');
|
||||
select!.customItems = [
|
||||
{
|
||||
customItemName: 'addWiFiListItemName',
|
||||
polymerIcon: 'cr:add',
|
||||
customData: 'WiFi',
|
||||
},
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
ready() {
|
||||
override ready() {
|
||||
super.ready();
|
||||
chrome.send('initialize');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicks on network items in the <network-select> element by
|
||||
* attempting a connection to the selected network or requesting a password
|
||||
* if the network requires a password.
|
||||
* @param {!Event<!OncMojo.NetworkStateProperties>} event
|
||||
* @private
|
||||
*/
|
||||
onNetworkItemSelected_(event) {
|
||||
private onNetworkItemSelected(
|
||||
event: CustomEvent<OncMojo.NetworkStateProperties>) {
|
||||
const networkState = event.detail;
|
||||
|
||||
// If the network is already connected, show network details.
|
||||
@ -65,25 +64,22 @@ Polymer({
|
||||
}
|
||||
|
||||
// Otherwise, connect.
|
||||
this.networkConfig_.startConnect(networkState.guid).then(response => {
|
||||
this.networkConfig.startConnect(networkState.guid).then(response => {
|
||||
if (response.result === StartConnectResult.kSuccess) {
|
||||
return;
|
||||
}
|
||||
chrome.send('showNetworkConfig', [networkState.guid]);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Event<!{detail:{customData: string}}>} event
|
||||
* @private
|
||||
*/
|
||||
onCustomItemSelected_(event) {
|
||||
private onCustomItemSelected(event: CustomEvent<{customData: string}>) {
|
||||
chrome.send('addNetwork', [event.detail.customData]);
|
||||
},
|
||||
}
|
||||
|
||||
/** @private */
|
||||
onCloseTap_() {
|
||||
private onCloseClick() {
|
||||
chrome.send('dialogClose');
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
customElements.define(LockScreenNetworkUi.is, LockScreenNetworkUi);
|
@ -255,7 +255,7 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
<div class="content-wrapper" hidden="[[!isVerifyUser_]]" role="dialog"
|
||||
<div class="content-wrapper" hidden="[[!isVerifyUser]]" role="dialog"
|
||||
aria-modal="true" id="verifyAccountScreen"
|
||||
aria-label="$i18n{loginWelcomeMessage}">
|
||||
<div class="main-container">
|
||||
@ -276,17 +276,17 @@
|
||||
</div>
|
||||
<div class="flex layout horizontal button-container">
|
||||
<cr-button id="cancelButtonVerifyScreen" class="cancel-button"
|
||||
on-click="onCloseTap_">
|
||||
on-click="onCloseClick">
|
||||
$i18n{lockScreenCancelButton}
|
||||
</cr-button>
|
||||
<cr-button id="nextButtonVerifyScreen" class="action-button"
|
||||
on-click="onVerify_">
|
||||
on-click="onVerify">
|
||||
$i18n{lockScreenVerifyButton}
|
||||
</cr-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-wrapper" hidden="[[!isErrorDisplayed_]]" role="dialog"
|
||||
<div class="content-wrapper" hidden="[[!isErrorDisplayed]]" role="dialog"
|
||||
aria-modal="true" id="errorScreen"
|
||||
aria-label="$i18n{loginWelcomeMessageWithError}">
|
||||
<div class="main-container">
|
||||
@ -307,33 +307,33 @@
|
||||
</div>
|
||||
<div class="flex layout horizontal button-container">
|
||||
<cr-button id="cancelButtonErrorScreen" class="cancel-button"
|
||||
on-click="onCloseTap_">
|
||||
on-click="onCloseClick">
|
||||
$i18n{lockScreenCancelButton}
|
||||
</cr-button>
|
||||
<cr-button id="nextButton" class="action-button" on-click="onVerify_">
|
||||
<cr-button id="nextButton" class="action-button" on-click="onVerify">
|
||||
$i18n{lockScreenVerifyAgainButton}
|
||||
</cr-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="body" hidden="[[!isSigninFrameDisplayed_]]">
|
||||
<div id="body" hidden="[[!isSigninFrameDisplayed]]">
|
||||
<div id="samlContainer">
|
||||
<div id="policyCertIndicator"
|
||||
hidden="[[!policyProvidedTrustedAnchorsUsed_()]]">
|
||||
hidden="[[!policyProvidedTrustedAnchorsUsed()]]">
|
||||
<cr-tooltip-icon id="policyCertIcon" icon-class="cr:domain"
|
||||
tooltip-text="[[i18nDynamic(locale,
|
||||
'policyProvidedCaCertsTooltipMessage', authDomain_)]]"
|
||||
'policyProvidedCaCertsTooltipMessage', authDomain)]]"
|
||||
icon-aria-label="[[i18nDynamic(locale,
|
||||
'policyProvidedCaCertsTooltipMessage', authDomain_)]]"
|
||||
'policyProvidedCaCertsTooltipMessage', authDomain)]]"
|
||||
tooltip-position="bottom">
|
||||
</cr-tooltip-icon>
|
||||
</div>
|
||||
<div id="samlHeader" saml-notice-message$="[[isSaml_]]">
|
||||
<span id="samlNoticeMessage" hidden="[[!isSaml_]]">
|
||||
[[i18n('samlNotice', authDomain_)]]
|
||||
<div id="samlHeader" saml-notice-message$="[[isSaml]]">
|
||||
<span id="samlNoticeMessage" hidden="[[!isSaml]]">
|
||||
[[i18n('samlNotice', authDomain)]]
|
||||
</span>
|
||||
<cr-icon-button id="saml-close-button" iron-icon="cr:close"
|
||||
on-click="onCloseTap_" aria-label="$i18n{lockScreenCloseButton}">
|
||||
on-click="onCloseClick" aria-label="$i18n{lockScreenCloseButton}">
|
||||
</cr-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
@ -344,54 +344,54 @@
|
||||
<div>[[i18nDynamic(locale, 'samlChangeProviderMessage')]]</div>
|
||||
<oobe-text-button id="change-account"
|
||||
text-key="samlChangeProviderButton"
|
||||
on-click="onChangeSigninProviderClicked_">
|
||||
on-click="onChangeSigninProviderClicked">
|
||||
</oobe-text-button>
|
||||
</div>
|
||||
<div id="buttons-container" class="flex layout horizontal button-container"
|
||||
hidden="[[isSaml_]]">
|
||||
hidden="[[isSaml]]">
|
||||
<div class="action-buttons">
|
||||
<gaia-action-buttons id="gaia-buttons"
|
||||
authenticator="[[authenticator_]]"
|
||||
authenticator="[[authenticator]]"
|
||||
rounded-button="True"
|
||||
on-set-focus-to-webview="setFocusToWebview_">
|
||||
on-set-focus-to-webview="setFocusToWebview">
|
||||
</gaia-action-buttons>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="samlConfirmPasswordScreen" class="content-wrapper"
|
||||
hidden="[[!isConfirmPassword_]]">
|
||||
hidden="[[!isConfirmPassword]]">
|
||||
<div class="main-container">
|
||||
<div class="header">
|
||||
<iron-icon class="title-icon" icon="oobe-32:lock"></iron-icon>
|
||||
<div class="title">
|
||||
[[email_]]
|
||||
[[email]]
|
||||
</div>
|
||||
<div class="subtitle" hidden="[[isManualInput_]]">
|
||||
<div class="subtitle" hidden="[[isManualInput]]">
|
||||
$i18n{confirmPasswordSubtitle}
|
||||
</div>
|
||||
<div class="subtitle" hidden="[[!isManualInput_]]">
|
||||
<div class="subtitle" hidden="[[!isManualInput]]">
|
||||
$i18n{manualPasswordSubtitle}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<cr-input type="password" id="passwordInput" required
|
||||
placeholder="[[passwordPlaceholder_(locale, isManualInput_)]]"
|
||||
error-message="[[passwordErrorText_(locale, isManualInput_)]]">
|
||||
placeholder="[[passwordPlaceholder(locale, isManualInput)]]"
|
||||
error-message="[[passwordErrorText(locale, isManualInput)]]">
|
||||
</cr-input>
|
||||
<cr-input type="password" id="confirmPasswordInput" required
|
||||
placeholder="$i18n{confirmPasswordLabel}"
|
||||
error-message="$i18n{manualPasswordMismatch}"
|
||||
hidden="[[!isManualInput_]]">
|
||||
hidden="[[!isManualInput]]">
|
||||
</cr-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex layout horizontal button-container">
|
||||
<cr-button id="cancelButton" class="cancel-button" on-click="onCloseTap_">
|
||||
<cr-button id="cancelButton" class="cancel-button" on-click="onCloseClick">
|
||||
$i18n{lockScreenCancelButton}
|
||||
</cr-button>
|
||||
<cr-button id="nextButtonSamlConfirmPassword" class="action-button"
|
||||
on-click="onConfirm_">
|
||||
on-click="onConfirm">
|
||||
$i18n{lockScreenNextButton}
|
||||
<iron-icon id="arrowForward" icon="oobe-20:button-arrow-forward">
|
||||
</iron-icon>
|
||||
@ -399,7 +399,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-wrapper" hidden="[[!isPasswordChanged_]]">
|
||||
<div class="content-wrapper" hidden="[[!isPasswordChanged]]">
|
||||
<div class="main-container">
|
||||
<div class="header">
|
||||
<iron-icon class="title-icon" icon="oobe-32:lock"></iron-icon>
|
||||
@ -417,10 +417,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex layout horizontal button-container">
|
||||
<cr-button id="cancelButton" class="cancel-button" on-click="onCloseTap_">
|
||||
<cr-button id="cancelButton" class="cancel-button" on-click="onCloseClick">
|
||||
$i18n{lockScreenCancelButton}
|
||||
</cr-button>
|
||||
<cr-button id="nextButton" class="action-button" on-click="onNext_">
|
||||
<cr-button id="nextButton" class="action-button" on-click="onNext">
|
||||
$i18n{lockScreenNextButton}
|
||||
<iron-icon icon="oobe-20:button-arrow-forward"></iron-icon>
|
||||
</cr-button>
|
||||
|
@ -1,475 +0,0 @@
|
||||
// Copyright 2020 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview An UI component to let user init online re-auth flow on
|
||||
* the lock screen.
|
||||
*/
|
||||
|
||||
import 'chrome://resources/ash/common/cr.m.js';
|
||||
import 'chrome://resources/ash/common/event_target.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_input/cr_input.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/icons.html.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_shared_vars.css.js';
|
||||
import './components/buttons/oobe_text_button.js';
|
||||
import './components/oobe_icons.html.js';
|
||||
import './components/oobe_illo_icons.html.js';
|
||||
import './gaia_action_buttons/gaia_action_buttons.js';
|
||||
import '//resources/ash/common/cr_elements/policy/cr_tooltip_icon.js';
|
||||
import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
|
||||
|
||||
import {assert} from 'chrome://resources/ash/common/assert.js';
|
||||
import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
|
||||
import {sendWithPromise} from 'chrome://resources/js/cr.js';
|
||||
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
|
||||
import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
|
||||
import {Authenticator, AuthFlow, AuthMode, AuthParams, SUPPORTED_PARAMS} from '../../gaia_auth_host/authenticator.js';
|
||||
|
||||
const clearDataType = {
|
||||
appcache: true,
|
||||
cache: true,
|
||||
cookies: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {PolymerElement}
|
||||
* @implements {I18nBehaviorInterface}
|
||||
*/
|
||||
const LockReauthBase = mixinBehaviors([I18nBehavior], PolymerElement);
|
||||
|
||||
/**
|
||||
* @polymer
|
||||
*/
|
||||
class LockReauth extends LockReauthBase {
|
||||
static get is() {
|
||||
return 'lock-reauth';
|
||||
}
|
||||
|
||||
static get template() {
|
||||
return html`{__html_template__}`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* User non-canonicalized email for display
|
||||
*/
|
||||
email_: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* Auth Domain property of the authenticator. Updated via events.
|
||||
*/
|
||||
authDomain_: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the ‘verify user’ screen is shown.
|
||||
*/
|
||||
isVerifyUser_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the ‘verify user again’ screen is shown.
|
||||
*/
|
||||
isErrorDisplayed_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the webview for online sign-in is shown.
|
||||
*/
|
||||
isSigninFrameDisplayed_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the authenticator is currently showing SAML IdP page.
|
||||
* @private
|
||||
*/
|
||||
isSaml_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether default SAML IdP is shown.
|
||||
*/
|
||||
isDefaultSsoProvider: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether there is a failure to scrape the user's password.
|
||||
*/
|
||||
isConfirmPassword_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether no password is scraped or multiple passwords are scraped.
|
||||
*/
|
||||
isManualInput_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the user's password has changed.
|
||||
*/
|
||||
isPasswordChanged_: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
passwordConfirmAttempt_: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
|
||||
passwordChangeAttempt_: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* Saved authenticator load params.
|
||||
* @type {?AuthParams}
|
||||
* @private
|
||||
*/
|
||||
this.authenticatorParams_ = null;
|
||||
|
||||
/**
|
||||
* The UI component that hosts IdP pages.
|
||||
* @type {!Authenticator|undefined}
|
||||
*/
|
||||
this.authenticator_ = undefined;
|
||||
|
||||
/**
|
||||
* Webview that view IdP page
|
||||
* @type {!WebView|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.signinFrame_ = undefined;
|
||||
|
||||
/**
|
||||
* Gaia path which can serve as a fallback in reloading scenarios. Expected
|
||||
* to correspond to editable Gaia username page.
|
||||
* TODO(b/259181755): this should no longer be needed once we change the
|
||||
* implementation of the "Enter Google Account info" button to fully reload
|
||||
* the flow through cpp code.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.fallbackGaiaPath_ = '';
|
||||
}
|
||||
|
||||
/** @override */
|
||||
ready() {
|
||||
super.ready();
|
||||
this.signinFrame_ = this.getSigninFrame_();
|
||||
this.authenticator_ = new Authenticator(this.signinFrame_);
|
||||
this.authenticator_.addEventListener('authDomainChange', (e) => {
|
||||
this.authDomain_ = e.detail.newValue;
|
||||
});
|
||||
this.authenticator_.addEventListener(
|
||||
'authCompleted', (e) => void this.onAuthCompletedMessage_(e));
|
||||
this.authenticator_.addEventListener(
|
||||
'loadAbort', (e) => void this.onLoadAbortMessage_(e.detail));
|
||||
this.authenticator_.addEventListener('getDeviceId', (e) => {
|
||||
sendWithPromise('getDeviceId')
|
||||
.then(deviceId => this.authenticator_.getDeviceIdResponse(deviceId));
|
||||
});
|
||||
this.authenticator_.addEventListener('authFlowChange', (e) => {
|
||||
this.isSaml_ = e.detail.newValue === AuthFlow.SAML;
|
||||
});
|
||||
chrome.send('initialize');
|
||||
}
|
||||
|
||||
/** @private */
|
||||
resetState_() {
|
||||
this.isVerifyUser_ = false;
|
||||
this.isErrorDisplayed_ = false;
|
||||
this.isSaml_ = false;
|
||||
this.isSigninFrameDisplayed_ = false;
|
||||
this.isConfirmPassword_ = false;
|
||||
this.isManualInput_ = false;
|
||||
this.isPasswordChanged_ = false;
|
||||
this.authDomain_ = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the orientation which will be used in styling webui.
|
||||
* @param {!Object} is_horizontal whether the orientation is horizontal or
|
||||
* vertical.
|
||||
*/
|
||||
setOrientation(is_horizontal) {
|
||||
if (is_horizontal) {
|
||||
document.documentElement.setAttribute('orientation', 'horizontal');
|
||||
} else {
|
||||
document.documentElement.setAttribute('orientation', 'vertical');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width which will be used in styling webui.
|
||||
* @param {!Object} width the width of the dialog.
|
||||
*/
|
||||
setWidth(width) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--lock-screen-reauth-dialog-width', width + 'px');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the authentication parameters.
|
||||
* @param {!Object} data authenticator parameters bag.
|
||||
* @suppress {missingProperties}
|
||||
*/
|
||||
loadAuthenticator(data) {
|
||||
assert(
|
||||
'webviewPartitionName' in data,
|
||||
'ERROR: missing webview partition name');
|
||||
this.authenticator_.setWebviewPartition(data.webviewPartitionName);
|
||||
this.fallbackGaiaPath_ = data.fallbackGaiaPath;
|
||||
|
||||
const params = {};
|
||||
SUPPORTED_PARAMS.forEach(name => {
|
||||
if (data.hasOwnProperty(name)) {
|
||||
params[name] = data[name];
|
||||
}
|
||||
});
|
||||
|
||||
params.enableGaiaActionButtons = data.enableGaiaActionButtons;
|
||||
this.authenticatorParams_ = /** @type {AuthParams} */ (params);
|
||||
this.email_ = data.email;
|
||||
this.isDefaultSsoProvider = data.doSamlRedirect;
|
||||
this.isSaml_ = this.isDefaultSsoProvider;
|
||||
if (data.showVerificationNotice) {
|
||||
this.isVerifyUser_ = true;
|
||||
} else {
|
||||
this.doGaiaRedirect_();
|
||||
}
|
||||
chrome.send('authenticatorLoaded');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is used when the wrong user is verified correctly
|
||||
* It reset authenticator state and display error message.
|
||||
*/
|
||||
resetAuthenticator() {
|
||||
this.signinFrame_.clearData({since: 0}, clearDataType, () => {
|
||||
this.authenticator_.resetStates();
|
||||
this.isButtonsEnabled_ = true;
|
||||
this.isErrorDisplayed_ = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the page.
|
||||
*/
|
||||
reloadAuthenticator() {
|
||||
this.signinFrame_.clearData({since: 0}, clearDataType, () => {
|
||||
this.authenticator_.resetStates();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!WebView}
|
||||
* @private
|
||||
*/
|
||||
getSigninFrame_() {
|
||||
// Note: Can't use |this.$|, since it returns cached references to elements
|
||||
// originally present in DOM, while the signin-frame is dynamically
|
||||
// recreated (see Authenticator.setWebviewPartition()).
|
||||
const signinFrame = this.shadowRoot.getElementById('signin-frame');
|
||||
assert(signinFrame);
|
||||
return /** @type {!WebView} */ (signinFrame);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
setFocusToWebview_() {
|
||||
this.signinFrame_.focus();
|
||||
}
|
||||
|
||||
onAuthCompletedMessage_(e) {
|
||||
const credentials = e.detail;
|
||||
chrome.send('completeAuthentication', [
|
||||
credentials.gaiaId,
|
||||
credentials.email,
|
||||
credentials.password,
|
||||
credentials.scrapedSAMLPasswords,
|
||||
credentials.usingSAML,
|
||||
credentials.services,
|
||||
credentials.passwordAttributes,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when onLoadAbort message received.
|
||||
* @param {!Object} data Additional information about error event like:
|
||||
* {number} error_code Error code such as net::ERR_INTERNET_DISCONNECTED.
|
||||
* {string} src The URL that failed to load.
|
||||
* @private
|
||||
*/
|
||||
onLoadAbortMessage_(data) {
|
||||
chrome.send('webviewLoadAborted', [data.error_code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the user has successfully authenticated via SAML,
|
||||
* the Chrome Credentials Passing API was not used and the authenticator needs
|
||||
* the user to confirm the scraped password.
|
||||
* @param {number} passwordCount The number of passwords that were scraped.
|
||||
*/
|
||||
showSamlConfirmPassword(passwordCount) {
|
||||
this.resetState_();
|
||||
/**
|
||||
* This statement override resetState_ calls.
|
||||
* Thus have to be AFTER resetState_.
|
||||
*/
|
||||
this.isConfirmPassword_ = true;
|
||||
this.isManualInput_ = (passwordCount === 0);
|
||||
if (this.passwordConfirmAttempt_ > 0) {
|
||||
this.$.passwordInput.value = '';
|
||||
this.$.passwordInput.invalid = true;
|
||||
}
|
||||
this.passwordConfirmAttempt_++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the user's password doesn't match his old password.
|
||||
* @private
|
||||
*/
|
||||
passwordChanged() {
|
||||
this.resetState_();
|
||||
this.isPasswordChanged_ = true;
|
||||
this.passwordChangeAttempt_++;
|
||||
if (this.passwordChangeAttempt_ > 1) {
|
||||
this.$.oldPasswordInput.invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
onVerify_() {
|
||||
this.authenticator_.load(
|
||||
AuthMode.DEFAULT,
|
||||
/** @type {AuthParams} */ (this.authenticatorParams_));
|
||||
this.resetState_();
|
||||
/**
|
||||
* These statements override resetStates_ calls.
|
||||
* Thus have to be AFTER resetState_.
|
||||
*/
|
||||
this.isSigninFrameDisplayed_ = true;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
onConfirm_() {
|
||||
if (!this.$.passwordInput.validate()) {
|
||||
return;
|
||||
}
|
||||
if (this.isManualInput_) {
|
||||
// When using manual password entry, both passwords must match.
|
||||
const confirmPasswordInput =
|
||||
this.shadowRoot.querySelector('#confirmPasswordInput');
|
||||
if (!confirmPasswordInput.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmPasswordInput.value !== this.$.passwordInput.value) {
|
||||
this.$.passwordInput.invalid = true;
|
||||
confirmPasswordInput.invalid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chrome.send('onPasswordTyped', [this.$.passwordInput.value]);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
onCloseTap_() {
|
||||
chrome.send('dialogClose');
|
||||
}
|
||||
|
||||
/** @private */
|
||||
onNext_() {
|
||||
if (!this.$.oldPasswordInput.validate()) {
|
||||
this.$.oldPasswordInput.focusInput();
|
||||
return;
|
||||
}
|
||||
chrome.send('updateUserPassword', [this.$.oldPasswordInput.value]);
|
||||
this.$.oldPasswordInput.value = '';
|
||||
}
|
||||
|
||||
/** @private */
|
||||
doGaiaRedirect_() {
|
||||
this.authenticator_.load(
|
||||
AuthMode.DEFAULT,
|
||||
/** @type {AuthParams} */ (this.authenticatorParams_));
|
||||
this.resetState_();
|
||||
/**
|
||||
* These statements override resetStates_ calls.
|
||||
* Thus have to be AFTER resetState_.
|
||||
*/
|
||||
this.isSigninFrameDisplayed_ = true;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
passwordPlaceholder_(locale, isManualInput_) {
|
||||
return this.i18n(
|
||||
isManualInput_ ? 'manualPasswordInputLabel' : 'confirmPasswordLabel');
|
||||
}
|
||||
|
||||
/** @private */
|
||||
passwordErrorText_(locale, isManualInput_) {
|
||||
return this.i18n(
|
||||
isManualInput_ ? 'manualPasswordMismatch' :
|
||||
'passwordChangedIncorrectOldPassword');
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when "Enter Google Account info" button is pressed on SAML screen.
|
||||
* @private
|
||||
*/
|
||||
onChangeSigninProviderClicked_() {
|
||||
this.authenticatorParams_.doSamlRedirect = false;
|
||||
this.authenticatorParams_.enableGaiaActionButtons = true;
|
||||
this.isDefaultSsoProvider = false;
|
||||
this.isSaml_ = false;
|
||||
// Replace Gaia path with a fallback path to land on Gaia username page.
|
||||
assert(
|
||||
this.fallbackGaiaPath_,
|
||||
'fallback Gaia path needed when trying to switch from SAML to Gaia');
|
||||
this.authenticatorParams_.gaiaPath = this.fallbackGaiaPath_;
|
||||
this.authenticator_.load(
|
||||
AuthMode.DEFAULT,
|
||||
/** @type {AuthParams} */ (this.authenticatorParams_));
|
||||
}
|
||||
|
||||
/** @private */
|
||||
policyProvidedTrustedAnchorsUsed_() {
|
||||
return loadTimeData.getBoolean('policyProvidedCaCertsPresent');
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(LockReauth.is, LockReauth);
|
@ -0,0 +1,483 @@
|
||||
// Copyright 2020 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview An UI component to let user init online re-auth flow on
|
||||
* the lock screen.
|
||||
*/
|
||||
|
||||
import 'chrome://resources/ash/common/cr.m.js';
|
||||
import 'chrome://resources/ash/common/event_target.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_input/cr_input.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/icons.html.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_shared_vars.css.js';
|
||||
import './components/buttons/oobe_text_button.js';
|
||||
import './components/oobe_icons.html.js';
|
||||
import './components/oobe_illo_icons.html.js';
|
||||
import './gaia_action_buttons/gaia_action_buttons.js';
|
||||
import '//resources/ash/common/cr_elements/policy/cr_tooltip_icon.js';
|
||||
import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
|
||||
|
||||
import {AuthCompletedCredentials, AuthCompletedEvent, AuthDomainChangeEvent, Authenticator, AuthFlow, AuthFlowChangeEvent, AuthMode, AuthParams, LoadAbortEvent, SUPPORTED_PARAMS} from '//lock-reauth/gaia_auth_host/authenticator.js';
|
||||
import {CrInputElement} from '//resources/ash/common/cr_elements/cr_input/cr_input.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {assert} from 'chrome://resources/js/assert.js';
|
||||
import {sendWithPromise} from 'chrome://resources/js/cr.js';
|
||||
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
|
||||
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
|
||||
import {getTemplate} from './lock_screen_reauth.html.js';
|
||||
|
||||
const clearDataType: chrome.webviewTag.ClearDataTypeSet = {
|
||||
appcache: true,
|
||||
cache: true,
|
||||
cookies: true,
|
||||
};
|
||||
|
||||
interface LockReauthParams {
|
||||
fallbackGaiaPath: string;
|
||||
webviewPartitionName: string;
|
||||
showVerificationNotice: boolean;
|
||||
}
|
||||
|
||||
const LockReauthElementBase = I18nMixin(PolymerElement);
|
||||
|
||||
interface LockReauthElement {
|
||||
$: {
|
||||
confirmPasswordInput: CrInputElement,
|
||||
oldPasswordInput: CrInputElement,
|
||||
passwordInput: CrInputElement,
|
||||
};
|
||||
}
|
||||
|
||||
class LockReauthElement extends LockReauthElementBase {
|
||||
static get is() {
|
||||
return 'lock-reauth';
|
||||
}
|
||||
|
||||
static get template() {
|
||||
return getTemplate();
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* User non-canonicalized email for display
|
||||
*/
|
||||
email: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* Auth Domain property of the authenticator. Updated via events.
|
||||
*/
|
||||
authDomain: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the ‘verify user’ screen is shown.
|
||||
*/
|
||||
isVerifyUser: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the ‘verify user again’ screen is shown.
|
||||
*/
|
||||
isErrorDisplayed: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the webview for online sign-in is shown.
|
||||
*/
|
||||
isSigninFrameDisplayed: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the authenticator is currently showing SAML IdP page.
|
||||
*/
|
||||
isSaml: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether default SAML IdP is shown.
|
||||
*/
|
||||
isDefaultSsoProvider: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether there is a failure to scrape the user's password.
|
||||
*/
|
||||
isConfirmPassword: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether no password is scraped or multiple passwords are scraped.
|
||||
*/
|
||||
isManualInput: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the user's password has changed.
|
||||
*/
|
||||
isPasswordChanged: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
passwordConfirmAttempt: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
|
||||
passwordChangeAttempt: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
email: string;
|
||||
authDomain: string;
|
||||
isVerifyUser: boolean;
|
||||
isButtonsEnabled: boolean;
|
||||
isErrorDisplayed: boolean;
|
||||
isSigninFrameDisplayed: boolean;
|
||||
isSaml: boolean;
|
||||
isDefaultSsoProvider: boolean;
|
||||
isConfirmPassword: boolean;
|
||||
isManualInput: boolean;
|
||||
isPasswordChanged: boolean;
|
||||
passwordConfirmAttempt: number;
|
||||
passwordChangeAttempt: number;
|
||||
|
||||
/**
|
||||
* Saved authenticator load params.
|
||||
*/
|
||||
private authenticatorParams: null|AuthParams = null;
|
||||
|
||||
/**
|
||||
* The UI component that hosts IdP pages.
|
||||
*/
|
||||
authenticator?: Authenticator;
|
||||
|
||||
/**
|
||||
* Webview that view IdP page
|
||||
*/
|
||||
private signinFrame?: chrome.webviewTag.WebView;
|
||||
|
||||
/**
|
||||
* Gaia path which can serve as a fallback in reloading scenarios. Expected
|
||||
* to correspond to editable Gaia username page.
|
||||
* TODO(b/259181755): this should no longer be needed once we change the
|
||||
* implementation of the "Enter Google Account info" button to fully reload
|
||||
* the flow through cpp code.
|
||||
*/
|
||||
private fallbackGaiaPath?: string;
|
||||
|
||||
override ready() {
|
||||
super.ready();
|
||||
this.signinFrame = this.getSigninFrame();
|
||||
const authenticator = this.authenticator =
|
||||
new Authenticator(this.signinFrame);
|
||||
|
||||
const authenticatorEventListeners: Record<string, (e: any) => void> = {
|
||||
'authDomainChange': (e: AuthDomainChangeEvent) => {
|
||||
this.authDomain = e.detail.newValue;
|
||||
},
|
||||
'authCompleted': (e: AuthCompletedEvent) =>
|
||||
void this.onAuthCompletedMessage(e.detail),
|
||||
'loadAbort': (e: LoadAbortEvent) =>
|
||||
void this.onLoadAbortMessage(e.detail),
|
||||
'getDeviceId': (_: Event) => {
|
||||
sendWithPromise('getDeviceId')
|
||||
.then(deviceId => authenticator.getDeviceIdResponse(deviceId));
|
||||
},
|
||||
'authFlowChange': (e: AuthFlowChangeEvent) => {
|
||||
this.isSaml = e.detail.newValue === AuthFlow.SAML;
|
||||
},
|
||||
};
|
||||
|
||||
for (const eventName in authenticatorEventListeners) {
|
||||
this.authenticator.addEventListener(
|
||||
eventName, authenticatorEventListeners[eventName].bind(this));
|
||||
}
|
||||
|
||||
chrome.send('initialize');
|
||||
}
|
||||
|
||||
private resetState() {
|
||||
this.isVerifyUser = false;
|
||||
this.isErrorDisplayed = false;
|
||||
this.isSaml = false;
|
||||
this.isSigninFrameDisplayed = false;
|
||||
this.isConfirmPassword = false;
|
||||
this.isManualInput = false;
|
||||
this.isPasswordChanged = false;
|
||||
this.authDomain = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the orientation which will be used in styling webui.
|
||||
* @param isHorizontal whether the orientation is horizontal or
|
||||
* vertical.
|
||||
*/
|
||||
setOrientation(isHorizontal: boolean) {
|
||||
if (isHorizontal) {
|
||||
document.documentElement.setAttribute('orientation', 'horizontal');
|
||||
} else {
|
||||
document.documentElement.setAttribute('orientation', 'vertical');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width which will be used in styling webui.
|
||||
* @param width the width of the dialog.
|
||||
*/
|
||||
setWidth(width: number) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--lock-screen-reauth-dialog-width', width + 'px');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the authentication parameters.
|
||||
* @param data authenticator parameters bag.
|
||||
*/
|
||||
loadAuthenticator(data: LockReauthParams&AuthParams) {
|
||||
assert(
|
||||
'webviewPartitionName' in data,
|
||||
'ERROR: missing webview partition name');
|
||||
assert(this.authenticator, 'ERROR: Authenticator not yet initialized');
|
||||
this.authenticator.setWebviewPartition(data.webviewPartitionName);
|
||||
this.fallbackGaiaPath = data.fallbackGaiaPath;
|
||||
|
||||
const params: AuthParams = {} as AuthParams;
|
||||
SUPPORTED_PARAMS.forEach((name: string) => {
|
||||
if (data.hasOwnProperty(name)) {
|
||||
params[name] = data[name];
|
||||
}
|
||||
});
|
||||
|
||||
params.enableGaiaActionButtons = data.enableGaiaActionButtons;
|
||||
this.authenticatorParams = params;
|
||||
this.email = data.email;
|
||||
this.isDefaultSsoProvider = !!data.doSamlRedirect;
|
||||
this.isSaml = this.isDefaultSsoProvider;
|
||||
if (data.showVerificationNotice) {
|
||||
this.isVerifyUser = true;
|
||||
} else {
|
||||
this.doGaiaRedirect();
|
||||
}
|
||||
chrome.send('authenticatorLoaded');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is used when the wrong user is verified correctly
|
||||
* It reset authenticator state and display error message.
|
||||
*/
|
||||
resetAuthenticator() {
|
||||
this.getSigninFrame().clearData({since: 0}, clearDataType, () => {
|
||||
this.authenticator!.resetStates();
|
||||
this.isButtonsEnabled = true;
|
||||
this.isErrorDisplayed = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the page.
|
||||
*/
|
||||
reloadAuthenticator() {
|
||||
this.getSigninFrame().clearData({since: 0}, clearDataType, () => {
|
||||
this.authenticator!.resetStates();
|
||||
});
|
||||
}
|
||||
|
||||
private getSigninFrame(): chrome.webviewTag.WebView {
|
||||
// Note: Can't use |this.$|, since it returns cached references to elements
|
||||
// originally present in DOM, while the signin-frame is dynamically
|
||||
// recreated (see Authenticator.setWebviewPartition()).
|
||||
const signinFrame = this.shadowRoot!.getElementById('signin-frame');
|
||||
assert(signinFrame, 'ERROR: signin-frame not found');
|
||||
return signinFrame as chrome.webviewTag.WebView;
|
||||
}
|
||||
|
||||
private setFocusToWebview() {
|
||||
this.signinFrame!.focus();
|
||||
}
|
||||
|
||||
onAuthCompletedMessage(credentials: AuthCompletedCredentials) {
|
||||
chrome.send('completeAuthentication', [
|
||||
credentials.gaiaId,
|
||||
credentials.email,
|
||||
credentials.password,
|
||||
credentials.scrapedSAMLPasswords,
|
||||
credentials.usingSAML,
|
||||
credentials.services,
|
||||
credentials.passwordAttributes,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when onLoadAbort message received.
|
||||
* @param data Additional information about error event like:
|
||||
* {number} error_code Error code such as net::ERR_INTERNET_DISCONNECTED.
|
||||
* {string} src The URL that failed to load.
|
||||
*/
|
||||
private onLoadAbortMessage(data: LoadAbortEvent['detail']) {
|
||||
chrome.send('webviewLoadAborted', [data.error_code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the user has successfully authenticated via SAML,
|
||||
* the Chrome Credentials Passing API was not used and the authenticator needs
|
||||
* the user to confirm the scraped password.
|
||||
* @param passwordCount The number of passwords that were scraped.
|
||||
*/
|
||||
showSamlConfirmPassword(passwordCount: number) {
|
||||
this.resetState();
|
||||
/**
|
||||
* This statement override resetState calls.
|
||||
* Thus have to be AFTER resetState.
|
||||
*/
|
||||
this.isConfirmPassword = true;
|
||||
this.isManualInput = (passwordCount === 0);
|
||||
if (this.passwordConfirmAttempt > 0) {
|
||||
this.$.passwordInput.value = '';
|
||||
this.$.passwordInput.invalid = true;
|
||||
}
|
||||
this.passwordConfirmAttempt++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the user's password doesn't match his old password.
|
||||
*/
|
||||
private passwordChanged() {
|
||||
this.resetState();
|
||||
this.isPasswordChanged = true;
|
||||
this.passwordChangeAttempt++;
|
||||
if (this.passwordChangeAttempt > 1) {
|
||||
this.$.oldPasswordInput.invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
private onVerify() {
|
||||
assert(
|
||||
this.authenticatorParams,
|
||||
'ERROR: authenticator parameters not yet loaded');
|
||||
this.authenticator!.load(AuthMode.DEFAULT, this.authenticatorParams);
|
||||
this.resetState();
|
||||
/**
|
||||
* These statements override resetStates calls.
|
||||
* Thus have to be AFTER resetState.
|
||||
*/
|
||||
this.isSigninFrameDisplayed = true;
|
||||
}
|
||||
|
||||
private onConfirm() {
|
||||
if (!this.$.passwordInput.validate()) {
|
||||
return;
|
||||
}
|
||||
if (this.isManualInput) {
|
||||
// When using manual password entry, both passwords must match.
|
||||
if (!this.$.confirmPasswordInput.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$.confirmPasswordInput.value !== this.$.passwordInput.value) {
|
||||
this.$.passwordInput.invalid = true;
|
||||
this.$.confirmPasswordInput.invalid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chrome.send('onPasswordTyped', [this.$.passwordInput.value]);
|
||||
}
|
||||
|
||||
private onCloseClick() {
|
||||
chrome.send('dialogClose');
|
||||
}
|
||||
|
||||
private onNext() {
|
||||
if (!this.$.oldPasswordInput.validate()) {
|
||||
this.$.oldPasswordInput.focusInput();
|
||||
return;
|
||||
}
|
||||
chrome.send('updateUserPassword', [this.$.oldPasswordInput.value]);
|
||||
this.$.oldPasswordInput.value = '';
|
||||
}
|
||||
|
||||
private doGaiaRedirect() {
|
||||
assert(
|
||||
this.authenticatorParams,
|
||||
'ERROR: authenticator parameters not yet loaded');
|
||||
this.authenticator!.load(AuthMode.DEFAULT, this.authenticatorParams);
|
||||
this.resetState();
|
||||
/**
|
||||
* These statements override resetStates calls.
|
||||
* Thus have to be AFTER resetState.
|
||||
*/
|
||||
this.isSigninFrameDisplayed = true;
|
||||
}
|
||||
|
||||
private passwordPlaceholder(_locale: string, isManualInput: boolean) {
|
||||
return this.i18n(
|
||||
isManualInput ? 'manualPasswordInputLabel' : 'confirmPasswordLabel');
|
||||
}
|
||||
|
||||
private passwordErrorText(_locale: string, isManualInput: boolean) {
|
||||
return this.i18n(
|
||||
isManualInput ? 'manualPasswordMismatch' :
|
||||
'passwordChangedIncorrectOldPassword');
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when "Enter Google Account info" button is pressed on SAML screen.
|
||||
*/
|
||||
private onChangeSigninProviderClicked() {
|
||||
assert(
|
||||
this.authenticatorParams,
|
||||
'ERROR: authenticator parameters not yet loaded');
|
||||
this.authenticatorParams.doSamlRedirect = false;
|
||||
this.authenticatorParams.enableGaiaActionButtons = true;
|
||||
this.isDefaultSsoProvider = false;
|
||||
this.isSaml = false;
|
||||
// Replace Gaia path with a fallback path to land on Gaia username page.
|
||||
assert(
|
||||
this.fallbackGaiaPath,
|
||||
'fallback Gaia path needed when trying to switch from SAML to Gaia');
|
||||
this.authenticatorParams.gaiaPath = this.fallbackGaiaPath;
|
||||
this.authenticator!.load(AuthMode.DEFAULT, this.authenticatorParams);
|
||||
}
|
||||
|
||||
private policyProvidedTrustedAnchorsUsed() {
|
||||
return loadTimeData.getBoolean('policyProvidedCaCertsPresent');
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'lock-reauth': LockReauthElement;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(LockReauthElement.is, LockReauthElement);
|
@ -19,7 +19,7 @@ function initialize() {
|
||||
// in chrome://resources/ash/common/util.js. If this function is not exposed
|
||||
// via the global object, it would not be available to tests that inject
|
||||
// JavaScript directly into the renderer.
|
||||
window.$ = $;
|
||||
(window as any).$ = $;
|
||||
}
|
||||
|
||||
initialize();
|
@ -38,6 +38,7 @@ export interface AuthCompletedCredentials {
|
||||
trusted: boolean;
|
||||
usingSAML: boolean;
|
||||
isAvailableInArc?: boolean;
|
||||
scrapedSAMLPasswords?: string[];
|
||||
}
|
||||
|
||||
export interface AuthParams {
|
||||
@ -45,6 +46,7 @@ export interface AuthParams {
|
||||
clientId: string;
|
||||
clientVersion?: string;
|
||||
constrained: string;
|
||||
doSamlRedirect?: boolean;
|
||||
dontResizeNonEmbeddedPages: boolean;
|
||||
emailDomain: string;
|
||||
email: string;
|
||||
@ -53,6 +55,7 @@ export interface AuthParams {
|
||||
extractSamlPasswordAttributes: boolean;
|
||||
flow: string;
|
||||
forceDarkMode: boolean;
|
||||
frameUrl: URL;
|
||||
gaiaPath: string;
|
||||
gaiaUrl: string;
|
||||
hl: string;
|
||||
@ -66,9 +69,9 @@ export interface AuthParams {
|
||||
samlAclUrl: string;
|
||||
service: string;
|
||||
showTos: string;
|
||||
ssoProfile: string;
|
||||
ssoProfile?: string;
|
||||
urlParameterToAutofillSAMLUsername: string;
|
||||
frameUrl: URL;
|
||||
[key: string]: AuthParams[keyof AuthParams];
|
||||
}
|
||||
|
||||
export enum AuthMode {
|
||||
@ -84,6 +87,13 @@ export enum AuthFlow {
|
||||
|
||||
export const SUPPORTED_PARAMS: string[];
|
||||
|
||||
type ChangeEvent<T> = CustomEvent<{oldValue: T, newValue: T}>;
|
||||
|
||||
export type AuthCompletedEvent = CustomEvent<AuthCompletedCredentials>;
|
||||
export type AuthDomainChangeEvent = ChangeEvent<string>;
|
||||
export type AuthFlowChangeEvent = ChangeEvent<AuthFlow>;
|
||||
export type LoadAbortEvent = CustomEvent<{error_code: number, src: string}>;
|
||||
|
||||
export class Authenticator extends EventTarget {
|
||||
constructor(webview: HTMLElement|string);
|
||||
getAccountsResponse(accounts: string[]): void;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import type {AuthCompletedCredentials, AuthMode, AuthParams} from 'chrome://chrome-signin/gaia_auth_host/authenticator.js';
|
||||
import {type AuthCompletedCredentials, type AuthMode, type AuthParams} from 'chrome://chrome-signin/gaia_auth_host/authenticator.js';
|
||||
import type {InlineLoginBrowserProxy} from 'chrome://chrome-signin/inline_login_browser_proxy.js';
|
||||
import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
|
||||
|
||||
|
@ -266,6 +266,8 @@ declare global {
|
||||
reload(): void;
|
||||
addContentScripts(contentScriptList: ContentScriptDetails[]): void;
|
||||
removeContentScripts(scriptNameList?: string[]): void;
|
||||
clearData(options: ClearDataOptions, types: ClearDataTypeSet, callback?:
|
||||
(results: any[]) => void): void;
|
||||
executeScript(
|
||||
details: InjectDetails, callback?: (results: any[]) => void): void;
|
||||
insertCSS(details: InjectDetails,
|
||||
|
Loading…
x
Reference in New Issue
Block a user