Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview | 6 * @fileoverview |
| 7 * 'settings-setup-pin-dialog' is the settings page for choosing a PIN. | 7 * 'settings-setup-pin-dialog' is the settings page for choosing a PIN. |
| 8 * | 8 * |
| 9 * Example: | 9 * Example: |
| 10 * | 10 * |
| 11 * <settings-setup-pin-dialog set-modes="[[quickUnlockSetModes]]"> | 11 * <settings-setup-pin-dialog set-modes="[[quickUnlockSetModes]]"> |
| 12 * </settings-setup-pin-dialog> | 12 * </settings-setup-pin-dialog> |
| 13 */ | 13 */ |
| 14 | 14 |
| 15 (function() { | 15 (function() { |
| 16 'use strict'; | 16 'use strict'; |
| 17 | 17 |
| 18 /** | |
| 19 * A list of the top-10 most commmonly used PINs. This list is taken from | |
| 20 * www.datagenetics.com/blog/september32012/. | |
| 21 * @const | |
| 22 */ | |
| 23 var WEAK_PINS = [ | |
| 24 '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', | |
| 25 '6969' | |
| 26 ]; | |
| 27 | |
| 28 Polymer({ | 18 Polymer({ |
| 29 is: 'settings-setup-pin-dialog', | 19 is: 'settings-setup-pin-dialog', |
| 30 | 20 |
| 31 behaviors: [I18nBehavior], | 21 behaviors: [I18nBehavior], |
| 32 | 22 |
| 33 properties: { | 23 properties: { |
| 34 /** | 24 /** |
| 35 * The current PIN keyboard value. | 25 * The current PIN keyboard value. |
| 36 * @private | 26 * @private |
| 37 */ | 27 */ |
| 38 pinKeyboardValue_: String, | 28 pinKeyboardValue_: String, |
| 39 | 29 |
| 40 /** | 30 /** |
| 41 * Stores the initial PIN value so it can be confirmed. | 31 * Stores the initial PIN value so it can be confirmed. |
| 42 * @private | 32 * @private |
| 43 */ | 33 */ |
| 44 initialPin_: String, | 34 initialPin_: String, |
| 45 | 35 |
| 46 /** | 36 /** |
| 47 * The actual problem message to display. | 37 * The actual problem message to display. |
| 48 * @private | 38 * @private |
| 49 */ | 39 */ |
| 50 problemMessage_: String, | 40 problemMessage_: { |
| 41 type: String, | |
| 42 value: '' | |
| 43 }, | |
| 51 | 44 |
| 52 /** | 45 /** |
| 53 * The type of problem class to show (warning or error). | 46 * The type of problem class to show (warning or error). |
| 54 */ | 47 */ |
| 55 problemClass_: String, | 48 problemClass_: String, |
| 56 | 49 |
| 57 /** | 50 /** |
| 58 * Should the step-specific submit button be displayed? | 51 * Should the step-specific submit button be displayed? |
| 59 * @private | 52 * @private |
| 60 */ | 53 */ |
| 61 enableSubmit_: Boolean, | 54 enableSubmit_: Boolean, |
| 62 | 55 |
| 63 /** | 56 /** |
| 64 * The current step/subpage we are on. | 57 * The current step/subpage we are on. |
| 65 * @private | 58 * @private |
| 66 */ | 59 */ |
| 67 isConfirmStep_: { | 60 isConfirmStep_: { |
| 68 type: Boolean, | 61 type: Boolean, |
| 69 value: false | 62 value: false |
| 70 }, | 63 }, |
| 64 | |
| 65 /** | |
| 66 * checkCredential is a function thats calls an api to check if a pin has | |
| 67 * any problems. It may be overriden for tests. | |
| 68 * | |
| 69 * @type {Function} | |
| 70 * @private | |
| 71 */ | |
| 72 checkCredential_: { | |
| 73 type: Object, | |
| 74 value: function() { return chrome.quickUnlockPrivate.checkCredential; } | |
| 75 }, | |
| 76 | |
| 77 /** | |
| 78 * getCredentialRequirements is a function thats calls an api get the pin | |
| 79 * policies. It may be overriden for tests. | |
| 80 * | |
| 81 * @type {Function} | |
| 82 * @private | |
| 83 */ | |
| 84 getCredentialRequirements_: { | |
| 85 type: Object, | |
| 86 value: function() { | |
| 87 return chrome.quickUnlockPrivate.getCredentialRequirements; | |
| 88 } | |
| 89 }, | |
|
stevenjb
2016/12/14 23:46:34
Rather than make two overridable methods here (and
sammiequon
2016/12/15 17:21:08
Done.
| |
| 71 }, | 90 }, |
| 72 | 91 |
| 73 /** @override */ | 92 /** @override */ |
| 74 attached: function() { | 93 attached: function() { |
| 75 this.resetState_(); | 94 this.resetState_(); |
| 76 }, | 95 }, |
| 77 | 96 |
| 78 open: function() { | 97 open: function() { |
| 79 this.$.dialog.showModal(); | 98 this.$.dialog.showModal(); |
| 80 this.$.pinKeyboard.focus(); | 99 this.$.pinKeyboard.focus(); |
| 81 }, | 100 }, |
| 82 | 101 |
| 83 close: function() { | 102 close: function() { |
| 84 if (this.$.dialog.open) | 103 if (this.$.dialog.open) |
| 85 this.$.dialog.close(); | 104 this.$.dialog.close(); |
| 86 | 105 |
| 87 this.resetState_(); | 106 this.resetState_(); |
| 88 }, | 107 }, |
| 89 | 108 |
| 90 /** | 109 /** |
| 91 * Resets the element to the initial state. | 110 * Resets the element to the initial state. |
| 92 * @private | 111 * @private |
| 93 */ | 112 */ |
| 94 resetState_: function() { | 113 resetState_: function() { |
| 95 this.initialPin_ = ''; | 114 this.initialPin_ = ''; |
| 96 this.pinKeyboardValue_ = ''; | 115 this.pinKeyboardValue_ = ''; |
| 97 this.enableSubmit_ = false; | 116 this.enableSubmit_ = false; |
| 98 this.isConfirmStep_ = false; | 117 this.isConfirmStep_ = false; |
| 118 this.hideProblem_(); | |
| 99 this.onPinChange_(); | 119 this.onPinChange_(); |
| 100 }, | 120 }, |
| 101 | 121 |
| 102 /** @private */ | 122 /** @private */ |
| 103 onCancelTap_: function() { | 123 onCancelTap_: function() { |
| 104 this.resetState_(); | 124 this.resetState_(); |
| 105 this.$.dialog.close(); | 125 this.$.dialog.close(); |
| 106 }, | 126 }, |
| 107 | 127 |
| 108 /** | 128 /** |
| 109 * Returns true if the given PIN is likely easy to guess. | 129 * Returns true if the PIN is ready to be changed to a new value. |
| 110 * @private | 130 * @private |
| 111 * @param {string} pin | |
| 112 * @return {boolean} | 131 * @return {boolean} |
| 113 */ | 132 */ |
| 114 isPinWeak_: function(pin) { | 133 canSubmit_: function() { |
| 115 // Warn if it's a top-10 pin. | 134 return this.initialPin_ == this.pinKeyboardValue_; |
| 116 if (WEAK_PINS.includes(pin)) | |
| 117 return true; | |
| 118 | |
| 119 // Warn if the PIN is consecutive digits. | |
| 120 var delta = 0; | |
| 121 for (var i = 1; i < pin.length; ++i) { | |
| 122 var prev = Number(pin[i - 1]); | |
| 123 var num = Number(pin[i]); | |
| 124 if (Number.isNaN(prev) || Number.isNaN(num)) | |
| 125 return false; | |
| 126 delta = Math.max(delta, Math.abs(num - prev)); | |
| 127 } | |
| 128 | |
| 129 return delta <= 1; | |
| 130 }, | 135 }, |
| 131 | 136 |
| 132 /** | 137 /** |
| 133 * Returns true if the given PIN matches PIN requirements, such as minimum | |
| 134 * length. | |
| 135 * @private | |
| 136 * @param {string|undefined} pin | |
| 137 * @return {boolean} | |
| 138 */ | |
| 139 isPinLongEnough_: function(pin) { | |
| 140 return !!pin && pin.length >= 4; | |
| 141 }, | |
| 142 | |
| 143 /** | |
| 144 * Returns true if the currently entered PIN is the same as the initially | |
| 145 * submitted PIN. | |
| 146 * @private | |
| 147 * @return {boolean} | |
| 148 */ | |
| 149 isPinConfirmed_: function() { | |
| 150 return this.isPinLongEnough_(this.pinKeyboardValue_) && | |
| 151 this.initialPin_ == this.pinKeyboardValue_; | |
| 152 }, | |
| 153 | |
| 154 /** | |
| 155 * Notify the user about a problem. | 138 * Notify the user about a problem. |
| 156 * @private | 139 * @private |
| 157 * @param {string} messageId | 140 * @param {string} messageId |
| 158 * @param {string} problemClass | 141 * @param {string} problemClass |
|
stevenjb
2016/12/14 23:46:34
This should really be a locally defined enum.
sammiequon
2016/12/15 17:21:08
Done.
| |
| 159 */ | 142 */ |
| 160 showProblem_: function(messageId, problemClass) { | 143 showProblem_: function(messageId, problemClass) { |
| 161 var previousMessage = this.problemMessage_; | 144 // Callback function which handles printing the appropriate message given |
| 145 // the |messageId|. | |
| 146 function getRequirementsCallback(requirements) { | |
| 147 var additionalInformation = ''; | |
| 148 switch (messageId) { | |
| 149 case 'configurePinTooShort': | |
| 150 additionalInformation = requirements.minLength.toString(); | |
| 151 break; | |
| 152 case 'configurePinTooLong': | |
| 153 additionalInformation = requirements.maxLength.toString(); | |
| 154 break; | |
| 155 case 'configurePinWeakPin': | |
| 156 case 'configurePinMismatched': | |
| 157 break; | |
| 158 default: | |
| 159 assertNotReached(); | |
| 160 break; | |
| 161 } | |
| 162 this.problemMessage_ = this.i18n(messageId, additionalInformation); | |
| 163 } | |
|
stevenjb
2016/12/14 23:46:34
This is probably worth breaking out into a separat
sammiequon
2016/12/15 17:21:08
Done.
| |
| 162 | 164 |
| 163 // Update problem info. | 165 this.getCredentialRequirements_( |
| 164 this.problemMessage_ = this.i18n(messageId); | 166 chrome.quickUnlockPrivate.QuickUnlockMode.PIN, |
| 167 getRequirementsCallback.bind(this)); | |
| 165 this.problemClass_ = problemClass; | 168 this.problemClass_ = problemClass; |
| 166 this.updateStyles(); | 169 this.updateStyles(); |
| 167 | 170 this.enableSubmit_ = (problemClass != 'error'); |
| 168 // If the problem message has changed, fire an alert. | 171 if (messageId == 'configurePinMismatched') |
| 169 if (previousMessage != this.problemMessage_) | 172 this.enableSubmit_ = false; |
|
stevenjb
2016/12/14 23:46:34
this.enableSubmit_ =
problemClass != 'error' &&
sammiequon
2016/12/15 17:21:08
Done.
| |
| 170 this.$.problemDiv.setAttribute('role', 'alert'); | 173 }, |
| 171 }, | |
| 172 | 174 |
| 173 /** @private */ | 175 /** @private */ |
| 174 hideProblem_: function() { | 176 hideProblem_: function() { |
| 175 this.problemMessage_ = ''; | 177 this.problemMessage_ = ''; |
| 176 this.problemClass_ = ''; | 178 this.problemClass_ = ''; |
| 177 }, | 179 }, |
| 178 | 180 |
| 181 /** | |
| 182 * Processes the message received from the quick unlock api and hides/shows | |
| 183 * the problem based on the message. | |
| 184 * @private | |
| 185 * @param {chrome.quickUnlockPrivate.CredentialCheck} message The message | |
| 186 * received from checkCredential. | |
|
stevenjb
2016/12/14 23:46:34
4 space indent from @param
sammiequon
2016/12/15 17:21:08
Done.
| |
| 187 */ | |
| 188 processPinProblems_: function(message) { | |
| 189 if (!message.errors.length && !message.warnings.length) { | |
| 190 this.hideProblem_(); | |
| 191 this.enableSubmit_ = true; | |
| 192 return; | |
| 193 } | |
| 194 | |
| 195 if (message.warnings.length) { | |
| 196 switch (message.warnings[0]) { | |
| 197 case 'TOO_WEAK': | |
|
stevenjb
2016/12/14 23:46:34
This should be defined in quick_unlock_private.idl
sammiequon
2016/12/15 17:21:08
Done.
| |
| 198 this.showProblem_('configurePinWeakPin', 'warning'); | |
| 199 break; | |
| 200 default: | |
| 201 assertNotReached(); | |
| 202 break; | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 if (message.errors.length) { | |
| 207 switch (message.errors[0]) { | |
| 208 case 'TOO_SHORT': | |
| 209 this.showProblem_('configurePinTooShort', 'error'); | |
| 210 break; | |
| 211 case 'TOO_LONG': | |
| 212 this.showProblem_('configurePinTooLong', 'error'); | |
| 213 break; | |
| 214 case 'TOO_WEAK': | |
| 215 this.showProblem_('configurePinWeakPin', 'error'); | |
| 216 break; | |
| 217 default: | |
| 218 assertNotReached(); | |
| 219 break; | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 }, | |
| 224 | |
| 179 /** @private */ | 225 /** @private */ |
| 180 onPinChange_: function() { | 226 onPinChange_: function() { |
| 181 if (!this.isConfirmStep_) { | 227 if (!this.isConfirmStep_) { |
| 182 var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); | 228 if (this.pinKeyboardValue_) { |
| 183 var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); | 229 this.checkCredential_( |
| 184 | 230 chrome.quickUnlockPrivate.QuickUnlockMode.PIN, |
| 185 if (!isPinLongEnough) | 231 this.pinKeyboardValue_, |
| 186 this.showProblem_('configurePinTooShort', 'warning'); | 232 this.processPinProblems_.bind(this)); |
| 187 else if (isWeak) | 233 } |
|
stevenjb
2016/12/14 23:46:34
early exit and elim else
sammiequon
2016/12/15 17:21:08
Done.
| |
| 188 this.showProblem_('configurePinWeakPin', 'warning'); | 234 } else { |
| 189 else | 235 if (this.canSubmit_()) { |
| 190 this.hideProblem_(); | 236 this.hideProblem_(); |
| 191 | 237 this.enableSubmit_ = true; |
| 192 this.enableSubmit_ = isPinLongEnough; | 238 } else { |
| 193 | |
| 194 } else { | |
| 195 if (this.isPinConfirmed_()) | |
| 196 this.hideProblem_(); | |
| 197 else | |
| 198 this.showProblem_('configurePinMismatched', 'warning'); | 239 this.showProblem_('configurePinMismatched', 'warning'); |
| 199 | 240 } |
| 200 this.enableSubmit_ = true; | |
| 201 } | 241 } |
| 202 }, | 242 }, |
| 203 | 243 |
| 204 /** @private */ | 244 /** @private */ |
| 205 onPinSubmit_: function() { | 245 onPinSubmit_: function() { |
| 206 if (!this.isConfirmStep_) { | 246 if (!this.isConfirmStep_) { |
| 207 if (this.isPinLongEnough_(this.pinKeyboardValue_)) { | 247 this.initialPin_ = this.pinKeyboardValue_; |
| 208 this.initialPin_ = this.pinKeyboardValue_; | 248 this.pinKeyboardValue_ = ''; |
| 209 this.pinKeyboardValue_ = ''; | 249 this.isConfirmStep_ = true; |
| 210 this.isConfirmStep_ = true; | 250 this.onPinChange_(); |
| 211 this.onPinChange_(); | 251 this.$.pinKeyboard.focus(); |
| 212 this.$.pinKeyboard.focus(); | |
| 213 } | |
| 214 } else { | 252 } else { |
| 215 // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. | 253 // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. |
| 216 // The PIN is not guaranteed to be valid in that case. | 254 // The PIN is not guaranteed to be valid in that case. |
| 217 if (!this.isPinConfirmed_()) { | 255 if (!this.canSubmit_()) { |
| 218 this.showProblem_('configurePinMismatched', 'error'); | 256 this.showProblem_('configurePinMismatched', 'error'); |
| 219 return; | 257 return; |
| 220 } | 258 } |
| 221 | 259 |
| 222 function onSetModesCompleted(didSet) { | 260 function onSetModesCompleted(didSet) { |
| 223 if (!didSet) { | 261 if (!didSet) { |
| 224 console.error('Failed to update pin'); | 262 console.error('Failed to update pin'); |
| 225 return; | 263 return; |
| 226 } | 264 } |
| 227 | 265 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 * @private | 298 * @private |
| 261 * @param {boolean} isConfirmStep | 299 * @param {boolean} isConfirmStep |
| 262 * @return {string} | 300 * @return {string} |
| 263 */ | 301 */ |
| 264 getContinueMessage_: function(isConfirmStep) { | 302 getContinueMessage_: function(isConfirmStep) { |
| 265 return this.i18n(isConfirmStep ? 'confirm' : 'configurePinContinueButton'); | 303 return this.i18n(isConfirmStep ? 'confirm' : 'configurePinContinueButton'); |
| 266 }, | 304 }, |
| 267 }); | 305 }); |
| 268 | 306 |
| 269 })(); | 307 })(); |
| OLD | NEW |