1 // sample OTP: |
|
2 // ttttvvvvvvcurikvhjcvnlnbecbkubjvuittbifhndhn |
|
3 // charset: cbdefghijklnrtuv |
|
4 |
|
5 var yk_interval = false; |
|
6 |
|
7 var YK_SEC_NORMAL_USERNAME = 1; |
|
8 var YK_SEC_NORMAL_PASSWORD = 2; |
|
9 var YK_SEC_ELEV_USERNAME = 4; |
|
10 var YK_SEC_ELEV_PASSWORD = 8; |
|
11 |
|
12 var yubikey_otp_current = false; |
|
13 |
|
14 function yk_mb_init(fieldid, statid) |
|
15 { |
|
16 load_component(['messagebox', 'fadefilter', 'flyin', 'jquery', 'jquery-ui', 'l10n']); |
|
17 var mp = miniPrompt(yk_mb_construct); |
|
18 if ( typeof(fieldid) == 'function' ) |
|
19 { |
|
20 var input = mp.getElementsByTagName('input')[0]; |
|
21 input.submit_func = fieldid; |
|
22 } |
|
23 else if ( fieldid && statid ) |
|
24 { |
|
25 var input = mp.getElementsByTagName('input')[0]; |
|
26 input.yk_field_id = fieldid; |
|
27 input.yk_status_id = statid; |
|
28 } |
|
29 } |
|
30 |
|
31 function yk_mb_construct(mp) |
|
32 { |
|
33 mp.innerHTML = ''; |
|
34 mp.style.textAlign = 'center'; |
|
35 mp.innerHTML = '<h3>' + $lang.get('yubiauth_msg_please_touch_key') + '</h3>'; |
|
36 var progress = document.createElement('div'); |
|
37 $(progress).addClass('yubikey_bar').css('text-align', 'left'); |
|
38 var progimg = document.createElement('img'); |
|
39 progimg.src = cdnPath + '/images/spacer.gif'; |
|
40 progress.appendChild(progimg); |
|
41 mp.appendChild(progress); |
|
42 var ta = document.createElement('input'); |
|
43 ta.submitted = false; |
|
44 $(ta) |
|
45 .css('background-color', 'transparent') |
|
46 .css('border-width', '0px') |
|
47 .css('color', '#fff') |
|
48 .css('font-size', '1px') |
|
49 .css('padding', '0') |
|
50 .css('opacity', '0') |
|
51 .attr('size', '1') |
|
52 .keyup(function(e) |
|
53 { |
|
54 if ( e.keyCode == 27 ) |
|
55 { |
|
56 window.clearInterval(yk_interval); |
|
57 miniPromptDestroy(this); |
|
58 } |
|
59 // 0.3: submit only upon a keycode 13 |
|
60 else if ( e.keyCode == 13 ) |
|
61 { |
|
62 this.submitted = true; |
|
63 yk_handle_submit(this); |
|
64 } |
|
65 else |
|
66 { |
|
67 $('div.yubikey_bar > img', this.parentNode) |
|
68 .css('width', String(this.value.length * 2) + 'px') |
|
69 //.css('background-position', String((this.value.length > 44 ? 44 : this.value.length) - 44) + 'px -88px'); |
|
70 } |
|
71 e.preventDefault(); |
|
72 e.stopPropagation(); |
|
73 }); |
|
74 mp.appendChild(ta); |
|
75 setTimeout(function() |
|
76 { |
|
77 window.yk_interval = setInterval(function() |
|
78 { |
|
79 ta.focus(); |
|
80 }, 50); |
|
81 }, 750); |
|
82 var info = document.createElement('p'); |
|
83 $(info) |
|
84 .append('<span style="color: #ffffff; font-size: smaller;">' + $lang.get('yubiauth_msg_close_instructions') + '</span> ') |
|
85 .append('<a class="abutton abutton_green" href="#" onclick="miniPromptDestroy(this); return false;">' + $lang.get('etc_cancel') + '</a> ') |
|
86 //.append('<br />') |
|
87 .append('<span style="color: #909090; font-size: smaller;">' + $lang.get('yubiauth_msg_close_instructions') + '</span>') |
|
88 .css('margin-top', '0'); |
|
89 mp.appendChild(info); |
|
90 } |
|
91 |
|
92 function yk_handle_submit(ta) |
|
93 { |
|
94 if ( ta.value.length > 44 || !ta.value.match(/^[cbdefghijklnrtuv]+$/) ) |
|
95 { |
|
96 // report "invalid characters" |
|
97 setTimeout(function() |
|
98 { |
|
99 var parent = ta.parentNode; |
|
100 var tabackup = { |
|
101 field_id: ta.yk_field_id, |
|
102 status_id: ta.yk_status_id, |
|
103 submit_func: ta.submit_func |
|
104 }; |
|
105 yk_mb_construct(parent); |
|
106 var input = parent.getElementsByTagName('input')[0]; |
|
107 if ( tabackup.field_id ) |
|
108 input.yk_field_id = tabackup.field_id; |
|
109 if ( tabackup.status_id ) |
|
110 input.yk_status_id = tabackup.status_id; |
|
111 if ( tabackup.submit_func ) |
|
112 input.submit_func = tabackup.submit_func; |
|
113 }, 1000); |
|
114 $('h3', ta.parentNode).text($lang.get(ta.value.length > 44 ? 'yubiauth_msg_too_long' : 'yubiauth_msg_invalid_chars')); |
|
115 $('div.yubikey_bar > img', this.parentNode).addClass('yubikey_bar_error'); |
|
116 return false; |
|
117 } |
|
118 |
|
119 window.clearInterval(yk_interval); |
|
120 |
|
121 if ( ta.yk_field_id && ta.yk_status_id ) |
|
122 { |
|
123 var field = document.getElementById(ta.yk_field_id); |
|
124 var status = document.getElementById(ta.yk_status_id); |
|
125 if ( $(status).hasClass('empty') || $(status).hasClass('rmpending') ) |
|
126 { |
|
127 $(status) |
|
128 .next('span.yubikey_pubkey') |
|
129 .text(ta.value.substr(0, 12)) |
|
130 .next('a.yubikey_enroll') |
|
131 .text($lang.get('yubiauth_ctl_btn_change_key')) |
|
132 .addClass('abutton_green') |
|
133 .after(' <a class="abutton abutton_red yubikey_enroll" href="#yk_clear" onclick="yk_clear(\'' + ta.yk_field_id + '\', \'' + ta.yk_status_id + '\'); return false;">' |
|
134 + $lang.get('yubiauth_ctl_btn_clear') + |
|
135 '</a>'); |
|
136 } |
|
137 $(status).removeClass('empty').removeClass('enrolled').removeClass('rmpending').addClass('savepending').html($lang.get('yubiauth_ctl_status_enrolled_pending')); |
|
138 $(status).next('span.yubikey_pubkey').text(ta.value.substr(0, 12)); |
|
139 field.value = ta.value; |
|
140 miniPromptDestroy(ta); |
|
141 return true; |
|
142 } |
|
143 else if ( ta.submit_func ) |
|
144 { |
|
145 ta.submit_func(ta); |
|
146 } |
|
147 else |
|
148 { |
|
149 miniPromptDestroy(ta); |
|
150 } |
|
151 } |
|
152 |
|
153 function yk_login_validate_reqs(ta) |
|
154 { |
|
155 $(ta.parentNode).remove('p'); |
|
156 yubikey_otp_current = ta.value; |
|
157 |
|
158 miniPromptDestroy(ta, true); |
|
159 |
|
160 if ( logindata ) |
|
161 { |
|
162 if ( logindata.mb_object ) |
|
163 { |
|
164 // login window is open |
|
165 if ( user_level == USER_LEVEL_GUEST ) |
|
166 { |
|
167 // for guests, get the user's yubikey auth flags |
|
168 // we're still ok to submit, so make sure twofactor isn't enabled |
|
169 // as we are a guest, we have to get the flags for the user from the server |
|
170 var ajax = ajaxMakeXHR(); |
|
171 var uri = makeUrlNS('Special', 'Yubikey', 'get_flags=' + ta.value.substr(0, 12)); |
|
172 var flags = 0; |
|
173 try |
|
174 { |
|
175 ajax.open('GET', uri, false); |
|
176 ajax.send(null); |
|
177 |
|
178 if ( ajax.readyState == 4 && ajax.status == 200 ) |
|
179 { |
|
180 // we got it |
|
181 var response = String(ajax.responseText + ''); |
|
182 if ( check_json_response(response) ) |
|
183 { |
|
184 response = parseJSON(response); |
|
185 flags = response.flags || 0; |
|
186 } |
|
187 } |
|
188 } |
|
189 catch ( e ) |
|
190 { |
|
191 ajaxLoginSetStatus(AJAX_STATUS_ERROR); |
|
192 return false; |
|
193 } |
|
194 var show_username = flags & YK_SEC_NORMAL_USERNAME; |
|
195 var show_password = flags & YK_SEC_NORMAL_PASSWORD; |
|
196 } |
|
197 else |
|
198 { |
|
199 var show_username = window.yk_user_flags & YK_SEC_ELEV_USERNAME; |
|
200 var show_password = window.yk_user_flags & YK_SEC_ELEV_PASSWORD; |
|
201 } |
|
202 if ( !show_username ) |
|
203 $('#ajax_login_field_username').parent('td').hide().prev().hide(); |
|
204 if ( !show_password ) |
|
205 $('#ajax_login_field_password').parent('td').hide().prev().hide(); |
|
206 |
|
207 var can_submit = true; |
|
208 if ( show_username && !$('#ajax_login_field_username').attr('value') ) |
|
209 { |
|
210 $('#ajax_login_field_username').focus(); |
|
211 |
|
212 if ( !show_password ) |
|
213 $('#ajax_login_field_username').keyup(function(e) |
|
214 { |
|
215 // assign press of Enter in username field to submit |
|
216 if ( e.keyCode == 13 ) |
|
217 { |
|
218 $('#messageBoxButtons input:button:first').click(); |
|
219 } |
|
220 }); |
|
221 |
|
222 can_submit = false; |
|
223 } |
|
224 if ( show_password && !$('#ajax_login_field_password').attr('value') ) |
|
225 { |
|
226 if ( can_submit ) |
|
227 { |
|
228 // can_submit only true if show_username false |
|
229 $('#ajax_login_field_password').focus(); |
|
230 } |
|
231 can_submit = false; |
|
232 } |
|
233 |
|
234 if ( can_submit ) |
|
235 { |
|
236 $('#messageBoxButtons input:button:first').click(); |
|
237 } |
|
238 } |
|
239 } |
|
240 } |
|
241 |
|
242 function yk_clear(field_id, status_id) |
|
243 { |
|
244 var field = document.getElementById(field_id); |
|
245 var status = document.getElementById(status_id); |
|
246 |
|
247 var was_pending = $(field).hasClass('wasempty'); |
|
248 |
|
249 $(field).attr('value', ''); |
|
250 $(status) |
|
251 .removeClass('savepending') |
|
252 .removeClass('enrolled') |
|
253 .addClass( was_pending ? 'empty' : 'rmpending' ) |
|
254 .text( was_pending ? $lang.get('yubiauth_ctl_status_empty') : $lang.get('yubiauth_ctl_status_remove_pending') ) |
|
255 .next('span.yubikey_pubkey') |
|
256 .text('') |
|
257 .next('a') |
|
258 .text($lang.get('yubiauth_ctl_btn_enroll')) |
|
259 .removeClass('abutton_green') |
|
260 .next('a') |
|
261 .remove(); |
|
262 } |
|
263 |
|
264 addOnloadHook(function() |
|
265 { |
|
266 if ( is_iPhone ) |
|
267 // kinda can't plug a yubikey into an iPhone |
|
268 // ... yet? |
|
269 return; |
|
270 |
|
271 attachHook('login_build_form', 'yk_login_dlg_hook(table, data);'); |
|
272 attachHook('login_build_userinfo', 'if ( window.yubikey_otp_current ) userinfo.yubikey_otp = window.yubikey_otp_current;'); |
|
273 if ( title == namespace_list.Special + 'Preferences/Yubikey' ) |
|
274 { |
|
275 load_component(['jquery', 'jquery-ui', 'expander']); |
|
276 } |
|
277 }); |
|
278 |
|
279 function yk_login_dlg_hook(table, data) |
|
280 { |
|
281 window.yubikey_otp_current = false; |
|
282 var tr = document.createElement('tr'); |
|
283 var td = document.createElement('td'); |
|
284 $(td) |
|
285 .attr('colspan', '2') |
|
286 .css('text-align', 'center') |
|
287 .css('font-size', 'smaller') |
|
288 .css('font-weight', 'bold') |
|
289 .html('<a href="#" onclick="yk_mb_init(yk_login_validate_reqs); return false;" style="color: #6fa202">' + $lang.get('yubiauth_btn_enter_otp') + '</a>'); |
|
290 $('a', td).blur(function(e) |
|
291 { |
|
292 $('#messageBoxButtons input:button:first').focus(); |
|
293 $('#ajax_login_field_captcha').focus(); |
|
294 }); |
|
295 if ( ( window.yk_reg_require_otp || window.yk_user_enabled ) && !data.locked_out.locked_out ) |
|
296 { |
|
297 setTimeout(function() |
|
298 { |
|
299 yk_mb_init(yk_login_validate_reqs); |
|
300 }, 750); |
|
301 } |
|
302 tr.appendChild(td); |
|
303 table.appendChild(tr); |
|
304 } |
|
305 |
|