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..54ecd6a2709f20d44faeabda354a22ba2ee0f2a5 |
| --- /dev/null |
| +++ b/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js |
| @@ -0,0 +1,279 @@ |
| +// 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'; |
| + |
| +/** |
| + * Metainformation about a problem message to pass to showProblem. |class| is |
| + * the css class to show the problem message with. |messageId| is the i18n |
| + * string id to use. |
| + * @const |
| + */ |
| +var ProblemInfo = { |
| + 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' |
| +]; |
| + |
| +Polymer({ |
| + is: 'settings-quick-unlock-setup-pin', |
| + |
| + behaviors: [ |
| + QuickUnlockPasswordDetectBehavior, |
| + I18nBehavior |
| + ], |
| + |
| + properties: { |
| + /** |
| + * The current PIN keyboard value. |
| + * @private |
| + */ |
| + pinKeyboardValue_: String, |
| + |
| + /** |
| + * Stores the initial PIN value so it can be confirmed. |
| + * @private |
| + */ |
| + initialPin_: String, |
| + |
| + /** |
| + * 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 |
| + */ |
| + isConfirmStep_: { |
| + type: Boolean, |
| + value: false |
| + }, |
| + }, |
| + |
| + 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.enableSubmit_ = false; |
| + this.isConfirmStep_ = false; |
| + 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. |
| + * @private |
| + */ |
| + showProblem_: function(problemInfo) { |
| + this.problemMessage_ = this.i18n(problemInfo.messageId); |
| + this.problemClass_ = problemInfo.class; |
| + this.updateStyles(); |
| + }, |
| + |
| + /** @private */ |
| + hideProblem_: function() { |
| + this.problemMessage_ = ''; |
| + this.problemClass_ = ''; |
| + }, |
| + |
| + /** @private */ |
| + onPinChange_: function() { |
| + if (!this.isConfirmStep_) { |
| + var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); |
| + var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); |
| + |
| + if (!isPinLongEnough && this.pinKeyboardValue_) |
| + this.showProblem_(ProblemInfo.TOO_SHORT); |
| + else if (isWeak) |
| + this.showProblem_(ProblemInfo.WEAK); |
| + else |
| + this.hideProblem_(); |
| + |
| + this.enableSubmit_ = isPinLongEnough; |
| + |
| + } else { |
| + var canSubmit = this.canSubmit_(); |
| + |
| + if (!canSubmit && this.pinKeyboardValue_) |
| + this.showProblem_(ProblemInfo.MISMATCHED); |
| + else |
| + this.hideProblem_(); |
| + |
| + this.enableSubmit_ = canSubmit; |
| + } |
| + }, |
| + |
| + /** @private */ |
| + onPinSubmit_: function() { |
| + if (!this.isConfirmStep_) { |
| + if (this.isPinLongEnough_(this.pinKeyboardValue_)) { |
| + this.initialPin_ = this.pinKeyboardValue_; |
| + this.pinKeyboardValue_ = ''; |
| + this.isConfirmStep_ = true; |
| + this.onPinChange_(); |
| + } |
| + } else { |
| + // 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 */ |
| + hasProblem_: function(problemMessage_) { |
| + return !!problemMessage_; |
| + }, |
| + |
| + /** @private */ |
| + computeTitleMessage_: function(isConfirmStep) { |
|
tommycli
2016/07/13 20:57:10
nit: Although it violates the Polymer guide, most
jdufault
2016/07/13 21:30:18
Done.
|
| + if (!isConfirmStep) |
| + return this.i18n('quickUnlockConfigurePinChoosePinTitle'); |
| + return this.i18n('quickUnlockConfigurePinConfirmPinTitle'); |
| + }, |
| + |
| + /** @private */ |
| + computeContinueMessage_: function(isConfirmStep) { |
| + if (!isConfirmStep) |
| + return this.i18n('quickUnlockConfigurePinContinueButton'); |
| + return this.i18n('save'); |
| + }, |
| +}); |
| + |
| +})(); |