OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * @fileoverview | |
7 * 'settings-quick-unlock-setup-pin' is the settings page for choosing a PIN. | |
8 * | |
9 * Example: | |
10 * | |
11 * <settings-quick-unlock-setup-pin | |
12 * set-modes="[[quickUnlockSetModes]]" | |
13 * current-route="{{currentRoute}}"> | |
14 * </settings-quick-unlock-setup-pin> | |
15 */ | |
16 | |
17 (function() { | |
18 'use strict'; | |
19 | |
20 /** | |
21 * Metainformation about a problem message to pass to showProblem. |class| is | |
22 * the css class to show the problem message with. |messageId| is the i18n | |
23 * string id to use. | |
24 * @const | |
25 */ | |
26 var ProblemInfo = { | |
27 TOO_SHORT: { | |
28 messageId: 'quickUnlockConfigurePinChoosePinTooShort', | |
29 class: 'error' | |
30 }, | |
31 WEAK: { | |
32 messageId: 'quickUnlockConfigurePinChoosePinWeakPinWarning', | |
33 class: 'warning' | |
34 }, | |
35 MISMATCHED: { | |
36 messageId: 'quickUnlockConfigurePinMismatchedPins', | |
37 class: 'error' | |
38 } | |
39 }; | |
40 | |
41 /** | |
42 * A list of the top-10 most commmonly used PINs. This list is taken from | |
43 * www.datagenetics.com/blog/september32012/. | |
44 * @const | |
45 */ | |
46 var WEAK_PINS = [ | |
47 '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', | |
48 '6969' | |
49 ]; | |
50 | |
51 Polymer({ | |
52 is: 'settings-quick-unlock-setup-pin', | |
53 | |
54 behaviors: [I18nBehavior, QuickUnlockPasswordDetectBehavior], | |
55 | |
56 properties: { | |
57 /** @type {!settings.Route} */ | |
58 currentRoute: { | |
59 type: Object, | |
60 observer: 'onRouteChanged_', | |
61 }, | |
62 | |
63 /** | |
64 * The current PIN keyboard value. | |
65 * @private | |
66 */ | |
67 pinKeyboardValue_: String, | |
68 | |
69 /** | |
70 * Stores the initial PIN value so it can be confirmed. | |
71 * @private | |
72 */ | |
73 initialPin_: String, | |
74 | |
75 /** | |
76 * The actual problem message to display. | |
77 * @private | |
78 */ | |
79 problemMessage_: String, | |
80 | |
81 /** | |
82 * The type of problem class to show (warning or error). | |
83 */ | |
84 problemClass_: String, | |
85 | |
86 /** | |
87 * Should the step-specific submit button be displayed? | |
88 * @private | |
89 */ | |
90 enableSubmit_: Boolean, | |
91 | |
92 /** | |
93 * The current step/subpage we are on. | |
94 * @private | |
95 */ | |
96 isConfirmStep_: { | |
97 type: Boolean, | |
98 value: false | |
99 }, | |
100 }, | |
101 | |
102 observers: ['onSetModesChanged_(setModes)'], | |
103 | |
104 /** @override */ | |
105 attached: function() { | |
106 this.resetState_(); | |
107 | |
108 if (this.currentRoute == settings.Route.QUICK_UNLOCK_SETUP_PIN) | |
109 this.askForPasswordIfUnset(); | |
110 }, | |
111 | |
112 /** | |
113 * @param {!settings.Route} currentRoute | |
114 * @private | |
115 */ | |
116 onRouteChanged_: function(currentRoute) { | |
117 if (this.currentRoute == settings.Route.QUICK_UNLOCK_SETUP_PIN) { | |
118 this.askForPasswordIfUnset(); | |
119 } else { | |
120 // If the user hits the back button, they can leave the element | |
121 // half-completed; therefore, reset state if the element is not active. | |
122 this.resetState_(); | |
123 } | |
124 }, | |
125 | |
126 /** @private */ | |
127 onSetModesChanged_: function() { | |
128 if (this.currentRoute == settings.Route.QUICK_UNLOCK_SETUP_PIN) | |
129 this.askForPasswordIfUnset(); | |
130 }, | |
131 | |
132 /** | |
133 * Resets the element to the initial state. | |
134 * @private | |
135 */ | |
136 resetState_: function() { | |
137 this.initialPin_ = ''; | |
138 this.pinKeyboardValue_ = ''; | |
139 this.enableSubmit_ = false; | |
140 this.isConfirmStep_ = false; | |
141 this.onPinChange_(); | |
142 }, | |
143 | |
144 /** | |
145 * Returns true if the given PIN is likely easy to guess. | |
146 * @private | |
147 * @param {string} pin | |
148 * @return {boolean} | |
149 */ | |
150 isPinWeak_: function(pin) { | |
151 // Warn if it's a top-10 pin. | |
152 if (WEAK_PINS.includes(pin)) | |
153 return true; | |
154 | |
155 // Warn if the PIN is consecutive digits. | |
156 var delta = 0; | |
157 for (var i = 1; i < pin.length; ++i) { | |
158 var prev = Number(pin[i - 1]); | |
159 var num = Number(pin[i]); | |
160 if (Number.isNaN(prev) || Number.isNaN(num)) | |
161 return false; | |
162 delta = Math.max(delta, Math.abs(num - prev)); | |
163 } | |
164 | |
165 return delta <= 1; | |
166 }, | |
167 | |
168 /** | |
169 * Returns true if the given PIN matches PIN requirements, such as minimum | |
170 * length. | |
171 * @private | |
172 * @param {string|undefined} pin | |
173 * @return {boolean} | |
174 */ | |
175 isPinLongEnough_: function(pin) { | |
176 return !!pin && pin.length >= 4; | |
177 }, | |
178 | |
179 /** | |
180 * Returns true if the PIN is ready to be changed to a new value. | |
181 * @private | |
182 * @return {boolean} | |
183 */ | |
184 canSubmit_: function() { | |
185 return this.isPinLongEnough_(this.pinKeyboardValue_) && | |
186 this.initialPin_ == this.pinKeyboardValue_; | |
187 }, | |
188 | |
189 /** | |
190 * Notify the user about a problem. | |
191 * @private | |
192 * @param {!{messageId: string, class: string}} problemInfo | |
193 */ | |
194 showProblem_: function(problemInfo) { | |
195 this.problemMessage_ = this.i18n(problemInfo.messageId); | |
196 this.problemClass_ = problemInfo.class; | |
197 this.updateStyles(); | |
198 }, | |
199 | |
200 /** @private */ | |
201 hideProblem_: function() { | |
202 this.problemMessage_ = ''; | |
203 this.problemClass_ = ''; | |
204 }, | |
205 | |
206 /** @private */ | |
207 onPinChange_: function() { | |
208 if (!this.isConfirmStep_) { | |
209 var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); | |
210 var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); | |
211 | |
212 if (!isPinLongEnough && this.pinKeyboardValue_) | |
213 this.showProblem_(ProblemInfo.TOO_SHORT); | |
214 else if (isWeak) | |
215 this.showProblem_(ProblemInfo.WEAK); | |
216 else | |
217 this.hideProblem_(); | |
218 | |
219 this.enableSubmit_ = isPinLongEnough; | |
220 | |
221 } else { | |
222 var canSubmit = this.canSubmit_(); | |
223 | |
224 if (!canSubmit && this.pinKeyboardValue_) | |
225 this.showProblem_(ProblemInfo.MISMATCHED); | |
226 else | |
227 this.hideProblem_(); | |
228 | |
229 this.enableSubmit_ = canSubmit; | |
230 } | |
231 }, | |
232 | |
233 /** @private */ | |
234 onPinSubmit_: function() { | |
235 if (!this.isConfirmStep_) { | |
236 if (this.isPinLongEnough_(this.pinKeyboardValue_)) { | |
237 this.initialPin_ = this.pinKeyboardValue_; | |
238 this.pinKeyboardValue_ = ''; | |
239 this.isConfirmStep_ = true; | |
240 this.onPinChange_(); | |
241 } | |
242 } else { | |
243 // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. | |
244 // The PIN is not guaranteed to be valid in that case. | |
245 if (!this.canSubmit_()) | |
246 return; | |
247 | |
248 function onSetModesCompleted(didSet) { | |
249 if (!didSet) { | |
250 console.error('Failed to update pin'); | |
251 return; | |
252 } | |
253 | |
254 this.resetState_(); | |
255 settings.navigateTo(settings.Route.QUICK_UNLOCK_CHOOSE_METHOD); | |
256 } | |
257 | |
258 this.setModes.call( | |
259 null, | |
260 [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], | |
261 [this.pinKeyboardValue_], | |
262 onSetModesCompleted.bind(this)); | |
263 } | |
264 }, | |
265 | |
266 /** | |
267 * @private | |
268 * @param {string} problemMessage | |
269 * @return {boolean} | |
270 */ | |
271 hasProblem_: function(problemMessage) { | |
272 return !!problemMessage; | |
273 }, | |
274 | |
275 /** | |
276 * @private | |
277 * @param {boolean} isConfirmStep | |
278 * @return {string} | |
279 */ | |
280 getTitleMessage_: function(isConfirmStep) { | |
281 if (!isConfirmStep) | |
282 return this.i18n('quickUnlockConfigurePinChoosePinTitle'); | |
283 return this.i18n('quickUnlockConfigurePinConfirmPinTitle'); | |
284 }, | |
285 | |
286 /** | |
287 * @private | |
288 * @param {boolean} isConfirmStep | |
289 * @return {string} | |
290 */ | |
291 getContinueMessage_: function(isConfirmStep) { | |
292 if (!isConfirmStep) | |
293 return this.i18n('quickUnlockConfigurePinContinueButton'); | |
294 return this.i18n('save'); | |
295 }, | |
296 }); | |
297 | |
298 })(); | |
OLD | NEW |