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 /** | 18 /** |
19 * A list of the top-10 most commmonly used PINs. This list is taken from | 19 * Keep in sync with the string keys provided by settings. |
20 * www.datagenetics.com/blog/september32012/. | 20 * @enum {string} |
21 * @const | |
22 */ | 21 */ |
23 var WEAK_PINS = [ | 22 var MessageType = { |
24 '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', | 23 TOO_SHORT: 'configurePinTooShort', |
25 '6969' | 24 TOO_LONG: 'configurePinTooLong', |
26 ]; | 25 TOO_WEAK: 'configurePinWeakPin', |
26 MISMATCH: 'configurePinMismatched' | |
27 }; | |
28 | |
29 /** @enum {string} */ | |
30 var ProblemType = { | |
31 WARNING: 'warning', | |
32 ERROR: 'error' | |
33 }; | |
27 | 34 |
28 Polymer({ | 35 Polymer({ |
29 is: 'settings-setup-pin-dialog', | 36 is: 'settings-setup-pin-dialog', |
30 | 37 |
31 behaviors: [I18nBehavior], | 38 behaviors: [I18nBehavior], |
32 | 39 |
33 properties: { | 40 properties: { |
34 /** | 41 /** |
35 * The current PIN keyboard value. | 42 * The current PIN keyboard value. |
36 * @private | 43 * @private |
(...skipping 24 matching lines...) Expand all Loading... | |
61 enableSubmit_: Boolean, | 68 enableSubmit_: Boolean, |
62 | 69 |
63 /** | 70 /** |
64 * The current step/subpage we are on. | 71 * The current step/subpage we are on. |
65 * @private | 72 * @private |
66 */ | 73 */ |
67 isConfirmStep_: { | 74 isConfirmStep_: { |
68 type: Boolean, | 75 type: Boolean, |
69 value: false | 76 value: false |
70 }, | 77 }, |
78 | |
79 /** | |
80 * Interface for chrome.quickUnlockPrivate calls. May be overriden by tests. | |
81 * @private | |
82 */ | |
83 quickUnlockPrivate_: { | |
84 type: Object, | |
85 value: chrome.quickUnlockPrivate | |
86 }, | |
71 }, | 87 }, |
72 | 88 |
73 /** @override */ | 89 /** @override */ |
74 attached: function() { | 90 attached: function() { |
75 this.resetState_(); | 91 this.resetState_(); |
76 }, | 92 }, |
77 | 93 |
78 open: function() { | 94 open: function() { |
79 this.$.dialog.showModal(); | 95 this.$.dialog.showModal(); |
80 this.$.pinKeyboard.focus(); | 96 this.$.pinKeyboard.focus(); |
81 }, | 97 }, |
82 | 98 |
83 close: function() { | 99 close: function() { |
84 if (this.$.dialog.open) | 100 if (this.$.dialog.open) |
85 this.$.dialog.close(); | 101 this.$.dialog.close(); |
86 | 102 |
87 this.resetState_(); | 103 this.resetState_(); |
88 }, | 104 }, |
89 | 105 |
90 /** | 106 /** |
91 * Resets the element to the initial state. | 107 * Resets the element to the initial state. |
92 * @private | 108 * @private |
93 */ | 109 */ |
94 resetState_: function() { | 110 resetState_: function() { |
95 this.initialPin_ = ''; | 111 this.initialPin_ = ''; |
96 this.pinKeyboardValue_ = ''; | 112 this.pinKeyboardValue_ = ''; |
97 this.enableSubmit_ = false; | 113 this.enableSubmit_ = false; |
98 this.isConfirmStep_ = false; | 114 this.isConfirmStep_ = false; |
115 this.hideProblem_(); | |
99 this.onPinChange_(); | 116 this.onPinChange_(); |
100 }, | 117 }, |
101 | 118 |
102 /** @private */ | 119 /** @private */ |
103 onCancelTap_: function() { | 120 onCancelTap_: function() { |
104 this.resetState_(); | 121 this.resetState_(); |
105 this.$.dialog.close(); | 122 this.$.dialog.close(); |
106 }, | 123 }, |
107 | 124 |
108 /** | 125 /** |
109 * Returns true if the given PIN is likely easy to guess. | 126 * Returns true if the PIN is ready to be changed to a new value. |
110 * @private | 127 * @private |
111 * @param {string} pin | |
112 * @return {boolean} | 128 * @return {boolean} |
113 */ | 129 */ |
114 isPinWeak_: function(pin) { | 130 canSubmit_: function() { |
115 // Warn if it's a top-10 pin. | 131 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 }, | 132 }, |
131 | 133 |
132 /** | 134 /** |
133 * Returns true if the given PIN matches PIN requirements, such as minimum | 135 * Handles writting the appropriate message to |problemMessage_|. |
134 * length. | |
135 * @private | 136 * @private |
136 * @param {string|undefined} pin | 137 * @param {string} messageId |
137 * @return {boolean} | 138 * @param {chrome.quickUnlockPrivate.CredentialRequirements} requirements |
139 * The requirements received from getCredentialRequirements. | |
138 */ | 140 */ |
139 isPinLongEnough_: function(pin) { | 141 processPinRequirements_: function(messageId, requirements) { |
140 return !!pin && pin.length >= 4; | 142 var additionalInformation = ''; |
143 switch (messageId) { | |
144 case MessageType.TOO_SHORT: | |
145 additionalInformation = requirements.minLength.toString(); | |
146 break; | |
147 case MessageType.TOO_LONG: | |
148 additionalInformation = requirements.maxLength.toString(); | |
149 break; | |
150 case MessageType.TOO_WEAK: | |
151 case MessageType.MISMATCH: | |
152 break; | |
153 default: | |
154 assertNotReached(); | |
155 break; | |
156 } | |
157 this.problemMessage_ = this.i18n(messageId, additionalInformation); | |
141 }, | 158 }, |
142 | 159 |
143 /** | 160 /** |
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. | 161 * Notify the user about a problem. |
156 * @private | 162 * @private |
157 * @param {string} messageId | 163 * @param {string} messageId |
158 * @param {string} problemClass | 164 * @param {string} problemClass |
159 */ | 165 */ |
160 showProblem_: function(messageId, problemClass) { | 166 showProblem_: function(messageId, problemClass) { |
161 var previousMessage = this.problemMessage_; | 167 this.quickUnlockPrivate_.getCredentialRequirements( |
162 | 168 chrome.quickUnlockPrivate.QuickUnlockMode.PIN, |
163 // Update problem info. | 169 this.processPinRequirements_.bind(this, messageId)); |
164 this.problemMessage_ = this.i18n(messageId); | |
165 this.problemClass_ = problemClass; | 170 this.problemClass_ = problemClass; |
166 this.updateStyles(); | 171 this.updateStyles(); |
167 | 172 this.enableSubmit_ = problemClass != ProblemType.ERROR && |
168 // If the problem message has changed, fire an alert. | 173 messageId != MessageType.MISMATCH; |
169 if (previousMessage != this.problemMessage_) | 174 }, |
170 this.$.problemDiv.setAttribute('role', 'alert'); | |
171 }, | |
172 | 175 |
173 /** @private */ | 176 /** @private */ |
174 hideProblem_: function() { | 177 hideProblem_: function() { |
175 this.problemMessage_ = ''; | 178 this.problemMessage_ = ''; |
176 this.problemClass_ = ''; | 179 this.problemClass_ = ''; |
177 }, | 180 }, |
178 | 181 |
182 /** | |
183 * Processes the message received from the quick unlock api and hides/shows | |
184 * the problem based on the message. | |
185 * @private | |
186 * @param {chrome.quickUnlockPrivate.CredentialCheck} message The message | |
187 * received from checkCredential. | |
188 */ | |
189 processPinProblems_: function(message) { | |
190 if (!message.errors.length && !message.warnings.length) { | |
191 this.hideProblem_(); | |
192 this.enableSubmit_ = true; | |
193 return; | |
194 } | |
195 | |
196 if (message.warnings.length) { | |
197 switch (message.warnings[0]) { | |
198 case chrome.quickUnlockPrivate.CredentialProblem.TOO_WEAK: | |
199 this.showProblem_(MessageType.TOO_WEAK, ProblemType.WARNING); | |
200 break; | |
201 default: | |
202 assertNotReached(); | |
203 break; | |
204 } | |
stevenjb
2016/12/19 19:01:29
Simplify:
assert (message.warnings[0] == chrome.q
sammiequon
2016/12/21 07:37:07
Done.
| |
205 } | |
206 | |
207 if (message.errors.length) { | |
208 switch (message.errors[0]) { | |
209 case chrome.quickUnlockPrivate.CredentialProblem.TOO_SHORT: | |
210 this.showProblem_(MessageType.TOO_SHORT, ProblemType.ERROR); | |
211 break; | |
212 case chrome.quickUnlockPrivate.CredentialProblem.TOO_LONG: | |
213 this.showProblem_(MessageType.TOO_LONG, ProblemType.ERROR); | |
214 case chrome.quickUnlockPrivate.CredentialProblem.TOO_WEAK: | |
215 this.showProblem_(MessageType.TOO_WEAK, ProblemType.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.quickUnlockPrivate_.checkCredential( |
230 chrome.quickUnlockPrivate.QuickUnlockMode.PIN, | |
231 this.pinKeyboardValue_, | |
232 this.processPinProblems_.bind(this)); | |
233 } | |
234 return; | |
235 } | |
184 | 236 |
185 if (!isPinLongEnough) | 237 if (this.canSubmit_()) { |
186 this.showProblem_('configurePinTooShort', 'warning'); | 238 this.hideProblem_(); |
187 else if (isWeak) | 239 this.enableSubmit_ = true; |
188 this.showProblem_('configurePinWeakPin', 'warning'); | 240 return; |
189 else | 241 } |
190 this.hideProblem_(); | |
191 | 242 |
192 this.enableSubmit_ = isPinLongEnough; | 243 this.showProblem_(MessageType.MISMATCH, ProblemType.WARNING); |
193 | |
194 } else { | |
195 if (this.isPinConfirmed_()) | |
196 this.hideProblem_(); | |
197 else | |
198 this.showProblem_('configurePinMismatched', 'warning'); | |
199 | |
200 this.enableSubmit_ = true; | |
201 } | |
202 }, | 244 }, |
203 | 245 |
204 /** @private */ | 246 /** @private */ |
205 onPinSubmit_: function() { | 247 onPinSubmit_: function() { |
206 if (!this.isConfirmStep_) { | 248 if (!this.isConfirmStep_) { |
207 if (this.isPinLongEnough_(this.pinKeyboardValue_)) { | 249 this.initialPin_ = this.pinKeyboardValue_; |
208 this.initialPin_ = this.pinKeyboardValue_; | 250 this.pinKeyboardValue_ = ''; |
209 this.pinKeyboardValue_ = ''; | 251 this.isConfirmStep_ = true; |
210 this.isConfirmStep_ = true; | 252 this.onPinChange_(); |
211 this.onPinChange_(); | 253 this.$.pinKeyboard.focus(); |
212 this.$.pinKeyboard.focus(); | 254 return; |
213 } | 255 } |
214 } else { | 256 // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. |
215 // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. | 257 // The PIN is not guaranteed to be valid in that case. |
216 // The PIN is not guaranteed to be valid in that case. | 258 if (!this.canSubmit_()) { |
217 if (!this.isPinConfirmed_()) { | 259 this.showProblem_(MessageType.MISMATCH, ProblemType.ERROR); |
218 this.showProblem_('configurePinMismatched', 'error'); | 260 return; |
261 } | |
262 | |
263 function onSetModesCompleted(didSet) { | |
264 if (!didSet) { | |
265 console.error('Failed to update pin'); | |
219 return; | 266 return; |
220 } | 267 } |
221 | 268 |
222 function onSetModesCompleted(didSet) { | 269 this.resetState_(); |
223 if (!didSet) { | 270 this.fire('done'); |
224 console.error('Failed to update pin'); | 271 } |
225 return; | |
226 } | |
227 | 272 |
228 this.resetState_(); | 273 this.setModes.call( |
229 this.fire('done'); | 274 null, |
230 } | 275 [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], |
231 | 276 [this.pinKeyboardValue_], |
232 this.setModes.call( | 277 onSetModesCompleted.bind(this)); |
233 null, | |
234 [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], | |
235 [this.pinKeyboardValue_], | |
236 onSetModesCompleted.bind(this)); | |
237 } | |
238 }, | 278 }, |
239 | 279 |
240 /** | 280 /** |
241 * @private | 281 * @private |
242 * @param {string} problemMessage | 282 * @param {string} problemMessage |
243 * @return {boolean} | 283 * @return {boolean} |
244 */ | 284 */ |
245 hasProblem_: function(problemMessage) { | 285 hasProblem_: function(problemMessage) { |
246 return !!problemMessage; | 286 return !!problemMessage; |
247 }, | 287 }, |
(...skipping 12 matching lines...) Expand all Loading... | |
260 * @private | 300 * @private |
261 * @param {boolean} isConfirmStep | 301 * @param {boolean} isConfirmStep |
262 * @return {string} | 302 * @return {string} |
263 */ | 303 */ |
264 getContinueMessage_: function(isConfirmStep) { | 304 getContinueMessage_: function(isConfirmStep) { |
265 return this.i18n(isConfirmStep ? 'confirm' : 'configurePinContinueButton'); | 305 return this.i18n(isConfirmStep ? 'confirm' : 'configurePinContinueButton'); |
266 }, | 306 }, |
267 }); | 307 }); |
268 | 308 |
269 })(); | 309 })(); |
OLD | NEW |