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