Chromium Code Reviews| Index: chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js |
| diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js b/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..881190f41d027ad96465aecb0e51208fee7cd28d |
| --- /dev/null |
| +++ b/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js |
| @@ -0,0 +1,335 @@ |
| +// Copyright 2016 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 |
| + * 'settings-quick-unlock-setup-pin' is the settings page for choosing a PIN. |
| + * |
| + * Example: |
| + * |
| + * <settings-quick-unlock-setup-pin |
| + * set-modes="[[quickUnlockSetModes]]" |
| + * current-route="{{currentRoute}}"> |
| + * </settings-quick-unlock-setup-pin> |
| + */ |
| + |
| +(function() { |
| +'use strict'; |
| + |
| +/** |
| + * The step in the setup PIN flow. |
| + * @const |
| + */ |
| +var QuickUnlockSetupPinStep = { |
|
tommycli
2016/07/13 19:31:11
I think the confirm/choose stuff could be simplifi
jdufault
2016/07/13 20:38:13
Done.
|
| + CHOOSE_PIN: 'choose-pin', |
| + CONFIRM_PIN: 'confirm-pin' |
| +}; |
| + |
| +/** |
| + * The type of problem message to display. Each entry contains the i18n message |
| + * id and the associated css class to display the problem with. At most one |
| + * problem can be shown at a time. |
| + * @const |
| + */ |
| +var QuickUnlockSetupPinProblemType = { |
|
tommycli
2016/07/13 19:31:12
If there's not going to be more than 3 errors, I t
jdufault
2016/07/13 20:38:13
I've done some renaming, but this makes the showPr
tommycli
2016/07/13 20:57:10
Okay, sounds good. Thanks for trying it.
|
| + TOO_SHORT: { |
| + messageId: 'quickUnlockConfigurePinChoosePinTooShort', |
| + class: 'error' |
| + }, |
| + WEAK: { |
| + messageId: 'quickUnlockConfigurePinChoosePinWeakPinWarning', |
| + class: 'warning' |
| + }, |
| + MISMATCHED: { |
| + messageId: 'quickUnlockConfigurePinMismatchedPins', |
| + class: 'error' |
| + } |
| +}; |
| + |
| +/** |
| + * A list of the top-10 most commmonly used PINs. This list is taken from |
| + * www.datagenetics.com/blog/september32012/. |
| + * @const |
| + */ |
| +var WEAK_PINS = [ |
| + '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', |
| + '6969' |
| +]; |
| + |
| +/** |
| + * When the user should be shown an error/warning, wait for this long until |
| + * showing them the problem, to give them a chance to stop typing. |
| + * @const |
| + */ |
| +var SHOW_PROBLEM_DELAY_IN_MS = 500; |
|
tommycli
2016/07/13 19:31:12
Is the delay mechanism a requirement? Because othe
jdufault
2016/07/13 20:38:13
Without the delay, as you type the PIN you'll imme
|
| + |
| +Polymer({ |
| + is: 'settings-quick-unlock-setup-pin', |
| + |
| + behaviors: [ |
|
tommycli
2016/07/13 19:31:12
formatting seems odd here
jdufault
2016/07/13 20:38:13
I've added a newline. I'm not sure otherwise what
|
| + QuickUnlockPasswordDetectBehavior, I18nBehavior |
| + ], |
| + |
| + properties: { |
| + /** |
| + * The current PIN keyboard value. |
| + * @private |
| + */ |
| + pinKeyboardValue_: String, |
| + |
| + /** |
| + * Stores the initial PIN value so it can be confirmed. |
| + * @private |
| + */ |
| + initialPin_: String, |
| + |
| + /** |
| + * String content of the title element. |
| + * @private |
| + */ |
| + titleMessage_: String, |
|
tommycli
2016/07/13 19:31:11
Instead of a message variable, how about two dom-i
jdufault
2016/07/13 20:38:13
Done, I like this better.
|
| + |
| + /** |
| + * String content of the continue/save button. |
| + * @private |
| + */ |
| + continueMessage_: String, |
|
tommycli
2016/07/13 19:31:11
Ditto here.
jdufault
2016/07/13 20:38:13
Done.
|
| + |
| + /** |
| + * Should the step-specific problem message be displayed? |
| + * @private |
| + */ |
| + showProblem_: Boolean, |
|
tommycli
2016/07/13 19:31:12
I think you can axe this boolean and just make int
jdufault
2016/07/13 20:38:13
Done.
|
| + |
| + /** |
| + * The actual problem message to display. |
| + * @private |
| + */ |
| + problemMessage_: String, |
| + |
| + /** |
| + * The type of problem class to show (warning or error). |
| + */ |
| + problemClass_: String, |
| + |
| + /** |
| + * Should the step-specific submit button be displayed? |
| + * @private |
| + */ |
| + enableSubmit_: Boolean, |
| + |
| + /** |
| + * The current step/subpage we are on. |
| + * @private |
| + */ |
| + step_: { |
| + type: String, |
| + value: QuickUnlockSetupPinStep.CHOOSE_PIN, |
| + }, |
| + }, |
| + |
| + observers: [ |
| + 'onRouteChanged_(currentRoute)', |
| + 'onSetModesChanged_(setModes)' |
| + ], |
| + |
| + /** @override */ |
| + attached: function() { |
| + this.resetState_(); |
| + this.askForPasswordIfUnset(); |
| + }, |
| + |
| + /** @private */ |
| + onRouteChanged_: function(currentRoute) { |
| + if (this.isScreenActive(QuickUnlockScreen.SETUP_PIN)) { |
| + this.askForPasswordIfUnset(); |
| + } else { |
| + // If the user hits the back button, they can leave the element |
| + // half-completed; therefore, reset state if the element is not active. |
| + this.resetState_(); |
| + } |
| + }, |
| + |
| + /** @private */ |
| + onSetModesChanged_: function() { |
| + if (this.isScreenActive(QuickUnlockScreen.SETUP_PIN)) |
| + this.askForPasswordIfUnset(); |
| + }, |
| + |
| + /** |
| + * Resets the element to the initial state. |
| + * @private |
| + */ |
| + resetState_: function() { |
| + this.initialPin_ = ''; |
| + this.pinKeyboardValue_ = ''; |
| + this.showProblem_ = false; |
| + this.enableSubmit_ = false; |
| + this.setStep_(QuickUnlockSetupPinStep.CHOOSE_PIN); |
| + this.onPinChange_(); |
| + }, |
| + |
| + /** |
| + * Returns true if the given PIN is likely easy to guess. |
| + * @private |
| + */ |
| + isPinWeak_: function(pin) { |
| + // Warn if it's a top-10 pin. |
| + if (WEAK_PINS.includes(pin)) |
| + return true; |
| + |
| + // Warn if the PIN is consecutive digits. |
| + var delta = 0; |
| + for (var i = 1; i < pin.length; ++i) { |
| + var prev = Number(pin[i - 1]); |
| + var num = Number(pin[i]); |
| + if (Number.isNaN(prev) || Number.isNaN(num)) |
| + return false; |
| + delta = Math.max(delta, Math.abs(num - prev)); |
| + } |
| + |
| + return delta <= 1; |
| + }, |
| + |
| + /** |
| + * Returns true if the given PIN matches PIN requirements, such as minimum |
| + * length. |
| + * @private |
| + */ |
| + isPinLongEnough_: function(pin) { |
| + return pin.length >= 4; |
| + }, |
| + |
| + /** |
| + * Returns true if the PIN is ready to be changed to a new value. |
| + * @private |
| + */ |
| + canSubmit_: function() { |
| + return this.isPinLongEnough_(this.pinKeyboardValue_) && |
| + this.initialPin_ == this.pinKeyboardValue_; |
| + }, |
| + |
| + /** |
| + * Notify the user about a problem. The problem will be shown after |
| + * SHOW_PROBLEM_DELAY_IN_MS. The problem show can be cancelled by calling |
| + * |this.cancelPendingProblem_()|. |
| + * @private |
| + */ |
| + postProblem_: function(problemType) { |
| + function activateProblem() { |
| + this.showProblem_ = true; |
| + this.problemMessage_ = this.i18n(problemType.messageId); |
| + this.problemClass_ = problemType.class; |
| + setTimeout(this.updateStyles.bind(this)); |
|
tommycli
2016/07/13 19:31:11
Hmm... does it not work without this call? I've ne
jdufault
2016/07/13 20:38:13
The icon color is not updated without the call. I'
tommycli
2016/07/13 20:57:09
Cool. Getting rid of the setTimeout makes it much
|
| + } |
| + |
| + this.cancelPendingProblem_(); |
| + this.pendingProblem_ = setTimeout(activateProblem.bind(this), |
| + SHOW_PROBLEM_DELAY_IN_MS); |
| + }, |
| + |
| + /** @private */ |
| + cancelPendingProblem_: function() { |
| + if (this.pendingProblem_) { |
| + clearTimeout(this.pendingProblem_); |
| + delete this.pendingProblem_; |
| + } |
| + }, |
| + |
| + /** @private */ |
| + onPinChange_: function() { |
| + // If the user typed, we want to reset the show problem timeout. |
| + this.cancelPendingProblem_(); |
| + |
| + if (this.isChooseStep_()) { |
| + var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); |
| + var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); |
| + |
| + if (!isPinLongEnough && this.pinKeyboardValue_) |
| + this.postProblem_(QuickUnlockSetupPinProblemType.TOO_SHORT); |
| + else if (isWeak) |
| + this.postProblem_(QuickUnlockSetupPinProblemType.WEAK); |
| + else |
| + this.showProblem_ = false; |
| + |
| + this.enableSubmit_ = isPinLongEnough; |
| + |
| + } else if (this.isConfirmStep_()) { |
| + var canSubmit = this.canSubmit_(); |
| + |
| + if (!canSubmit && this.pinKeyboardValue_) |
| + this.postProblem_(QuickUnlockSetupPinProblemType.MISMATCHED); |
| + else |
| + this.showProblem_ = false; |
| + |
| + this.enableSubmit_ = canSubmit; |
| + } |
| + }, |
| + |
| + /** @private */ |
| + onPinSubmit_: function() { |
| + if (this.isChooseStep_()) { |
| + if (this.isPinLongEnough_(this.pinKeyboardValue_)) { |
| + this.initialPin_ = this.pinKeyboardValue_; |
| + this.pinKeyboardValue_ = ''; |
| + this.setStep_(QuickUnlockSetupPinStep.CONFIRM_PIN); |
| + this.onPinChange_(); |
| + } |
| + } else if (this.isConfirmStep_()) { |
| + // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. |
| + // The PIN is not guaranteed to be valid in that case. |
| + if (!this.canSubmit_()) |
| + return; |
| + |
| + function onSetModesCompleted(didSet) { |
| + if (!didSet) { |
| + console.error('Failed to update pin'); |
| + return; |
| + } |
| + |
| + this.resetState_(); |
| + this.currentRoute = { |
| + page: 'basic', |
| + section: 'people', |
| + subpage: [QuickUnlockScreen.CHOOSE_METHOD] |
| + }; |
| + } |
| + |
| + this.setModes.call( |
| + null, |
| + [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], |
| + [this.pinKeyboardValue_], |
| + onSetModesCompleted.bind(this)); |
| + } |
| + }, |
| + |
| + /** @private */ |
| + setStep_: function(step) { |
| + this.step_ = step; |
| + switch (this.step_) { |
| + case QuickUnlockSetupPinStep.CHOOSE_PIN: |
| + this.titleMessage_ = this.i18n('quickUnlockConfigurePinChoosePinTitle'); |
| + this.continueMessage_ = |
| + this.i18n('quickUnlockConfigurePinContinueButton'); |
| + break; |
| + case QuickUnlockSetupPinStep.CONFIRM_PIN: |
| + this.titleMessage_ = |
| + this.i18n('quickUnlockConfigurePinConfirmPinTitle'); |
| + this.continueMessage_ = this.i18n('save'); |
| + break; |
| + } |
| + }, |
| + |
| + /** @private */ |
| + isChooseStep_: function() { |
| + return this.step_ == QuickUnlockSetupPinStep.CHOOSE_PIN; |
| + }, |
| + |
| + /** @private */ |
| + isConfirmStep_: function() { |
| + return this.step_ == QuickUnlockSetupPinStep.CONFIRM_PIN; |
| + }, |
| +}); |
| + |
| +})(); |