PluginProbe
Two Factor Authentication / 1.14.17
Two Factor Authentication v1.14.17
1.12.2 1.13.0 1.14.10 1.14.11 1.14.14 1.14.15 1.14.16 1.14.17 1.14.23 1.14.24 1.14.26 1.14.27 1.14.3 1.14.4 1.14.5 1.14.7 1.14.8 1.15.5 1.16.0 1.2.10 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 All 98 releases
two-factor-authentication / simba-tfa / includes / tfa.js

tfa.js in Two Factor Authentication 1.14.17, at simba-tfa/includes/tfa.js

327 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(function($) {
2
3 var username_requires_otp = [];
4
5 /**
6 * Returns the jQuery identifiers for finding the username field. Abstracted here to avoid maintaining multiple lists.
7 *
8 * @return String
9 */
10 function get_username_identifiers() {
11 // 'username' is used by WooCommerce
12 return '[name="log"], [name="username"], #user_login, #affwp-login-user-login, #affwp-user-login, #gform_fields_login input[type="text"]';
13 }
14
15 /**
16 * Process the results of a check for whether the user has TFA enabled or not
17 *
18 * @param Object form - jQuery form object
19 * @param Object response - the response from the check; must have the property (boolean) "status" and potentially user_(boolean) "can_trust" and (boolean) user_can_trust.
20 */
21 function process_user_tfa_enabled_check_results(form, response) {
22
23 if (true === response.status) {
24 // Don't bother to remove the spinner if the form is being submitted.
25 $('.simbaotp_spinner').remove();
26
27 var user_can_trust = (response.hasOwnProperty('user_can_trust') && response.user_can_trust) ? true : false;
28
29 var user_already_trusted = (response.hasOwnProperty('user_already_trusted') && response.user_can_trust) ? true : false;
30
31 console.log("Simba TFA: User has OTP enabled: showing OTP field (user_can_trust="+user_can_trust+")");
32
33 show_otp_field(form, user_can_trust, user_already_trusted);
34
35 return true;
36
37 } else {
38 console.log("Simba TFA: User does not have OTP enabled: submitting form");
39 // For some reason, .submit() stopped working with TML 7.x. N.B. Used to do this only for form_type == 2 ("TML shortcode or widget, WP Members, bbPress, Ultimate Membership Pro, WooCommerce or Elementor login form")
40 $(form).find('input[type="submit"], button[type="submit"]').first().trigger('click');
41 // $('#wp-submit').parents('form').first().trigger('submit');
42 }
43 return false;
44 }
45
46 /**
47 * Check if the user requires an OTP field and if so, display it
48 *
49 * @param String form - DOM selector string
50 * @param Boolean only_cache_the_results - if true, then nothing more will be done that caching the results (in the variable username_requires_otp will be updated)
51 *
52 * @uses show_otp_field()
53 *
54 * @return Boolean - true if we got involved
55 */
56 function check_and_possibly_show_otp_field(form, only_cache_the_results) {
57
58 // If this is a "lost password" form, then exit
59 if ($(form).attr('id') === 'lostpasswordform' || $(form).attr('id') === 'resetpasswordform') return false;
60
61 var username = $(form).find(get_username_identifiers()).first().val();
62
63 if (!username.length) return false;
64
65 // Is the result already known?
66 if ('object' === typeof username_requires_otp[username]) {
67 if (!only_cache_the_results) {
68 // Process the already-known result
69 return process_user_tfa_enabled_check_results($(form), username_requires_otp[username]);
70 }
71 // No further processing
72 return true;
73 }
74
75 var $submit_button = $(form).find('input[name="wp-submit"], input[type="submit"], button[type="submit"]').first();
76
77 if (simba_tfasettings.hasOwnProperty('spinnerimg') && $('.simbaotp_spinner').length === 0) {
78 var styling = 'float:right; margin:6px 12px; width: 20px; height: 20px;';
79 if ($('#theme-my-login #wp-submit').length >0) {
80 styling = 'margin-left: 4px; position: relative; top: 4px; width: 20px; height: 20px; border:0px; box-shadow:none;';
81 }
82 $submit_button.after('<img class="simbaotp_spinner" src="'+simba_tfasettings.spinnerimg+'" style="'+styling+'">');
83 }
84
85 $.ajax({
86 url: simba_tfasettings.ajaxurl,
87 type: 'POST',
88 data: {
89 action: 'simbatfa-init-otp',
90 user: username
91 },
92 dataType: 'text',
93 success: function(resp) {
94 try {
95 var json_begins = resp.search('{"jsonstarter":"justhere"');
96 if (json_begins > -1) {
97 if (json_begins > 0) {
98 console.log("Expected JSON marker found at position: "+json_begins);
99 resp = resp.substring(json_begins);
100 }
101 } else {
102 console.log("Expected JSON marker not found");
103 console.log(resp);
104 }
105
106 response = JSON.parse(resp);
107
108 if (response.hasOwnProperty('php_output')) {
109 console.log("PHP output was returned (follows)");
110 console.log(response.php_output);
111 }
112
113 if (response.hasOwnProperty('extra_output')) {
114 console.log("Extra output was returned (follows)");
115 console.log(response.extra_output);
116 }
117
118 if (only_cache_the_results) {
119 // Save the result for later processing
120 username_requires_otp[username] = response;
121 $('.simbaotp_spinner').remove();
122 } else {
123 process_user_tfa_enabled_check_results($(form), response);
124 }
125
126 } catch(err) {
127 $('#login').html(resp);
128 console.log("Simba TFA: Error when processing response");
129 console.log(err);
130 console.log(resp);
131 }
132 },
133 error: function(jq_xhr, text_status, error_thrown) {
134 console.log("Simba TFA: AJAX error: "+error_thrown+": "+text_status);
135 console.log(jq_xhr);
136 if (jq_xhr.hasOwnProperty('responseText')) {
137 console.log(jq_xhr.responseText);
138 $(form).append('<p class="error" style="clear:left;">'+simba_tfasettings.error+'</p>');
139 }
140 }
141 });
142 return true;
143 }
144
145 // Parameters: see check_and_possibly_show_otp_field
146 function show_otp_field(form, user_can_trust, user_already_trusted) {
147
148 var $submit_button;
149
150 user_can_trust = ('undefined' == typeof user_can_trust) ? false : user_can_trust;
151 user_already_trusted = ('undefined' == typeof user_already_trusted) ? false : user_already_trusted;
152
153 if ('https:' != window.location.protocol && 'localhost' !== location.hostname && '127.0.0.1' !== location.hostname && /^\.localdomain$/.test(location.hostname)) {
154 user_can_trust = false;
155 }
156
157 if (!user_can_trust) { user_already_trusted = false; }
158
159 var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6));
160
161 // Gravity Forms won't submit if the elements are hidden
162 var form_retain_existing_elements = form_is_gravity_forms ? true : false;
163
164 // name="Submit" is WP-Members. 'submit' is Theme My Login starting from 7.x
165 $submit_button = $(form).find('input[name="wp-submit"], input[name="Submit"], input[name="submit"]');
166 // This hasn't been needed for anything yet (Jul 2018), but is a decent back-stop that would have prevented some breakage in the past that needed manual attention:
167 if (0 == $submit_button.length) {
168 $submit_button = $(form).find('input[type="submit"], button[type="submit"]').first();
169 }
170
171 if (!form_retain_existing_elements) {
172 // Hide all elements in a browser-safe way
173 // .user-pass-wrap is the wrapper used (instead of a paragraph) on wp-login.php from WP 5.3
174 $submit_button.parents('form').first().find('p, .impu-form-line-fr, .tml-field-wrap, .user-pass-wrap, .elementor-field-type-text, .elementor-field-type-submit, .elementor-remember-me, .bbp-username, .bbp-password, .bbp-submit-wrapper, .gform_body').each(function(i) {
175 $(this).css('visibility', 'hidden').css('position', 'absolute');
176 // On the WooCommerce form, the 'required' asterisk in the child <span> still shows without this
177 $(this).find('span').css('visibility', 'hidden').css('position', 'absolute');
178 });
179
180 // WP-Members
181 $submit_button.parents('#wpmem_login').find('fieldset').css('visibility', 'hidden').css('position', 'absolute');
182
183 }
184
185 // Add new field and controls
186 var html = '';
187
188 if (user_already_trusted) {
189
190 html += '<br><span class="simbaotp_is_trusted">'+simba_tfasettings.is_trusted+'</span>';
191
192 } else {
193
194 html += '<label ';
195
196 if (form_is_gravity_forms) {
197 html += 'class="gfield_label"';
198 }
199
200 html += 'for="simba_two_factor_auth">' + simba_tfasettings.otp + '<br><input type="text" name="two_factor_code" id="simba_two_factor_auth" autocomplete="off" data-lpignore="true"';
201
202 if ($(form).hasClass('woocommerce-form-login')) {
203 // Retain compatibility with previous full-width layout
204 html += ' style="width: 100%;"';
205 }
206
207 html += '></label>';
208
209 html += '<p class="forgetmenot';
210 if (form_is_gravity_forms) html += ' gfield';
211 html += '" style="font-size:small;';
212 if (!$(form).hasClass('woocommerce-form-login')) {
213 // Retain compatibility with previous full-width layout
214 html += ' max-width: 60%;';
215 }
216 html += '">';
217
218 // Would need further styling investigations to display this
219 if (!form_is_gravity_forms) {
220 html += '<span class="simba_tfa_otp_login_help">'+simba_tfasettings.otp_login_help+'</span>';
221 }
222
223 if (user_can_trust) {
224
225 html += '<input type="checkbox" name="simba_tfa_mark_as_trusted" id="simba_tfa_mark_as_trusted" value="1"><label for="simba_tfa_mark_as_trusted">'+ simba_tfasettings.mark_as_trusted+'</label>';
226
227 }
228 }
229
230 html += '</p>';
231
232 var submit_button_text;
233 var submit_button_name;
234
235 // Gravity forms doesn't like its button being disabled
236 if (!form_is_gravity_forms) {
237
238 if ('button' == $submit_button.prop('nodeName').toLowerCase()) {
239 submit_button_text = $submit_button.text().trim();
240 submit_button_name = $submit_button.attr('name');
241 } else {
242 submit_button_text = $submit_button.val();
243 submit_button_name = $submit_button.attr('name');
244 }
245
246 html += '<p class="submit"><input id="tfa_login_btn" class="button button-primary button-large" type="submit" ';
247 if ('undefined' !== typeof submit_button_name && '' != submit_button_name) { html += 'name="'+submit_button_name+'" '; }
248 html += 'value="' + submit_button_text + '"></p>';
249
250 $submit_button.prop('disabled', true).hide();
251
252 }
253
254 if (form_retain_existing_elements && form_is_gravity_forms) {
255 // $submit_button.parents('form').first().append(html);
256 //$('<div style="clear:both;">'+html+'</div>').insertBefore($submit_button);
257 $(form).find('#gform_fields_login').append(html);
258 } else {
259 $submit_button.parents('form').first().prepend(html);
260 }
261
262 $('#login_error').hide();
263
264 if (user_already_trusted) {
265 if (form_retain_existing_elements) {
266 $submit_button.trigger('click');
267 } else {
268 $('#tfa_login_btn').trigger('click');
269 }
270 } else {
271
272 $('#simba_two_factor_auth').trigger('focus');
273
274 // Hide extra boxes of third party plugins
275 jQuery('.hide-when-displaying-tfa-input').hide();
276 }
277
278 }
279
280 /**
281 * This function gets attached to a form submission handler and decides whether to add an OTP field or not.
282 *
283 * @param Object e - submission event
284 *
285 * @return Boolean - whether to proceed with the submission or not
286 */
287 var form_submit_handler = function(e) {
288
289 console.log('Simba TFA: form submit request');
290
291 var form = e.target;
292
293 var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6));
294
295 // Turn off everything
296 $(form).off();
297
298 if (0 == $(form).find('#simba_two_factor_auth').length && check_and_possibly_show_otp_field(form)) {
299
300 if (form_is_gravity_forms) {
301 var form_id = $(form).attr('id').substring(6);
302 // Gravity Forms won't allow the form to submit if this is already true
303 window['gf_submitting_'+form_id] = false;
304 }
305
306 e.preventDefault();
307 return false;
308
309 }
310
311 return true;
312
313 };
314
315 if (simba_tfasettings.login_form_off_selectors) {
316 $(simba_tfasettings.login_form_off_selectors).off('submit');
317 }
318
319 $(simba_tfasettings.login_form_selectors).on('submit', form_submit_handler);
320
321 $(simba_tfasettings.login_form_selectors).find(get_username_identifiers()).on('blur', function() {
322 var $form = $(this).parents('form').first();
323 check_and_possibly_show_otp_field($form, true);
324 });
325
326 });
327