1jQuery(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 and RegistrationMagic 12 return '[name="log"], [name="username"], #user_login, #affwp-login-user-login, #affwp-user-login, #gform_fields_login input[type="text"], .um-field-username input[type="text"], [name="edd_user_login"]'; 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 // The un-disabling is for Ultimate Member, which for unknown reasons outputs the login button in a disabled state 41 $(form).find('input[type="submit"], button[type="submit"]').first().prop('disabled', false).trigger('click'); 42 // $('#wp-submit').parents('form').first().trigger('submit'); 43 } 44 return false; 45 } 46 47 /** 48 * Check if the user requires an OTP field and if so, display it 49 * 50 * @param String form - DOM selector string 51 * @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) 52 * 53 * @uses show_otp_field() 54 * 55 * @return Boolean - true if we got involved 56 */ 57 function check_and_possibly_show_otp_field(form, only_cache_the_results) { 58 59 // If this is a "lost password" form, then exit 60 if ($(form).attr('id') === 'lostpasswordform' || $(form).attr('id') === 'resetpasswordform') return false; 61 62 var username = $(form).find(get_username_identifiers()).first().val(); 63 64 if (!username.length) return false; 65 66 // Is the result already known? 67 if ('object' === typeof username_requires_otp[username]) { 68 if (!only_cache_the_results) { 69 // Process the already-known result 70 return process_user_tfa_enabled_check_results($(form), username_requires_otp[username]); 71 } 72 // No further processing 73 return true; 74 } 75 76 var $submit_button = $(form).find('input[name="wp-submit"], input[type="submit"], button[type="submit"]').first(); 77 78 if (simba_tfasettings.hasOwnProperty('spinnerimg') && $('.simbaotp_spinner').length === 0) { 79 var styling = 'float:right; margin:6px 12px; width: 20px; height: 20px;'; 80 if ($('#theme-my-login #wp-submit').length >0) { 81 styling = 'margin-left: 4px; position: relative; top: 4px; width: 20px; height: 20px; border:0px; box-shadow:none;'; 82 } 83 $submit_button.after('<img class="simbaotp_spinner" src="'+simba_tfasettings.spinnerimg+'" style="'+styling+'">'); 84 } 85 86 $.ajax({ 87 url: simba_tfasettings.ajaxurl, 88 type: 'POST', 89 data: { 90 action: 'simbatfa-init-otp', 91 user: username 92 }, 93 dataType: 'text', 94 success: function(resp) { 95 try { 96 var json_begins = resp.search('{"jsonstarter":"justhere"'); 97 if (json_begins > -1) { 98 if (json_begins > 0) { 99 console.log("Expected JSON marker found at position: "+json_begins); 100 resp = resp.substring(json_begins); 101 } 102 } else { 103 console.log("Expected JSON marker not found"); 104 console.log(resp); 105 } 106 107 response = JSON.parse(resp); 108 109 if (response.hasOwnProperty('php_output')) { 110 console.log("PHP output was returned (follows)"); 111 console.log(response.php_output); 112 } 113 114 if (response.hasOwnProperty('extra_output')) { 115 console.log("Extra output was returned (follows)"); 116 console.log(response.extra_output); 117 } 118 119 if (only_cache_the_results) { 120 // Save the result for later processing 121 username_requires_otp[username] = response; 122 $('.simbaotp_spinner').remove(); 123 } else { 124 process_user_tfa_enabled_check_results($(form), response); 125 } 126 127 } catch(err) { 128 $('#login').html(resp); 129 console.log("Simba TFA: Error when processing response"); 130 console.log(err); 131 console.log(resp); 132 } 133 }, 134 error: function(jq_xhr, text_status, error_thrown) { 135 console.log("Simba TFA: AJAX error: "+error_thrown+": "+text_status); 136 console.log(jq_xhr); 137 if (jq_xhr.hasOwnProperty('responseText')) { 138 console.log(jq_xhr.responseText); 139 $(form).append('<p class="error" style="clear:left;">
139'+simba_tfasettings.error+'</p>'); 140 } 141 } 142 }); 143 return true; 144 } 145 146 // Parameters: see check_and_possibly_show_otp_field 147 function show_otp_field(form, user_can_trust, user_already_trusted) { 148 149 var $submit_button; 150 151 user_can_trust = ('undefined' == typeof user_can_trust) ? false : user_can_trust; 152 user_already_trusted = ('undefined' == typeof user_already_trusted) ? false : user_already_trusted; 153 154 if ('https:' != window.location.protocol && 'localhost' !== location.hostname && '127.0.0.1' !== location.hostname && /^\.localdomain$/.test(location.hostname)) { 155 user_can_trust = false; 156 } 157 158 if (!user_can_trust) { user_already_trusted = false; } 159 160 var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6)); 161 162 // This is used just for applying similar styling (via adding structure/CSS classes) 163 var form_is_ultimate_member = ($(form).find('.um-row').length > 0) ? true : false; 164 165 // This is used just for applying styling if .js-login-form class exists inside form 166 var form_is_login_form = ($(form).find('.js-login-form').length > 0) ? true : false; 167 168 // Gravity Forms won't submit if the elements are hidden 169 var form_retain_existing_elements = form_is_gravity_forms ? true : false; 170 171 // name="Submit" is WP-Members. 'submit' is Theme My Login starting from 7.x 172 $submit_button = $(form).find('input[name="wp-submit"], input[name="Submit"], input[name="submit"]'); 173 // 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: 174 if (0 == $submit_button.length) { 175 $submit_button = $(form).find('input[type="submit"], button[type="submit"]').first(); 176 } 177 178 if (!form_retain_existing_elements) { 179 // Hide all elements in a browser-safe way 180 // .user-pass-wrap is the wrapper used (instead of a paragraph) on wp-login.php from WP 5.3 181 // .um-row : Ultimate Member 182 // .rmrow : RegistrationMagic 183 $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, .um-row, .um-button, .js-login-form, .rmrow').each(function(i) { 184 $(this).css('visibility', 'hidden').css('position', 'absolute'); 185 // On the WooCommerce form, the 'required' asterisk in the child <span> still shows without this 186 $(this).find('span').css('visibility', 'hidden').css('position', 'absolute'); 187 }); 188 189 // WP-Members 190 $submit_button.parents('#wpmem_login').find('fieldset').css('visibility', 'hidden').css('position', 'absolute'); 191 192 } 193 194 // Add new field and controls 195 var html = ''; 196 197 if (form_is_ultimate_member) { 198 html += '<div class="um-row">'; 199 } 200 201 if (user_already_trusted) { 202 203 html += '<br><span class="simbaotp_is_trusted">'+simba_tfasettings.is_trusted+'</span>'; 204 205 } else { 206 207 if (form_is_ultimate_member) { html += '<div class="um-field um-field-text um-field-type_text"><div class="um-field-label">'; } 208 209 html += '<label '; 210 211 if (form_is_gravity_forms) { 212 html += 'class="gfield_label"'; 213 } 214 215 html += 'for="simba_two_factor_auth">'; 216 217 html += simba_tfasettings.otp + '</label><input type="text" name="two_factor_code" id="simba_two_factor_auth" autocomplete="off" data-lpignore="true"'; 218 219 if ($(form).hasClass('woocommerce-form-login')) { 220 // Retain compatibility with previous full-width layout 221 html += ' style="width: 100%;"'; 222 } 223 224 html += '>'; 225 226 if (form_is_ultimate_member) { html += '</div>'; } 227 228 html += '<p class="forgetmenot'; 229 if (form_is_gravity_forms) html += ' gfield'; 230 html += '" style="font-size:small;'; 231 if (!$(form).hasClass('woocommerce-form-login')) { 232 // Retain compatibility with previous full-width layout 233 html += ' max-width: 60%;'; 234 } 235 html += '">'; 236 237 if (form_is_ultimate_member) { html += '</div>'; } 238 239 // Would need further styling investigations to display this 240 if (!form_is_gravity_forms) { 241 html += '<span class="simba_tfa_otp_login_help">'+simba_tfasettings.otp_login_help+'</span>'; 242 } 243 244 if (form_is_ultimate_member) { 245 html += '</div>'; 246 } 247 248 if (user_can_trust) { 249 250 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>'; 251 252 } 253 } 254 255 html += '</p>'; 256 257 var submit_button_text; 258 var submit_button_name; 259 260 // Gravity forms doesn't like its button being disabled 261 if (!form_is_gravity_forms) { 262 263 if ('button' == $submit_button.prop('nodeName').toLowerCase()) { 264 submit_button_text = $submit_button.text().trim(); 265 submit_button_name = $submit_button.attr('name'); 266 } else { 267 submit_button_text = $submit_button.val(); 268 submit_button_name = $submit_button.attr('name'); 269 } 270 271 html += '<p class="submit'; 272 273 if (form_is_ultimate_member) { html += ' um-center'; } 274 275 html += '"><input id="tfa_login_btn" class="button button-primary button-large'; 276 277 if (form_is_ultimate_member) { html += ' um-button'; } 278 279 if (form_is_login_form) { html += ' c-btn-rg hover:bg-main focus:bg-main'; } 280 281 html += '" type="submit" '; 282 if ('undefined' !== typeof submit_button_name && '' != submit_button_name) { html += 'name="'+submit_button_name+'" '; } 283 html += 'value="' + submit_button_text + '"></p>'; 284 285 $submit_button.prop('disabled', true).hide(); 286 287 } 288 289 if (form_retain_existing_elements && form_is_gravity_forms) { 290 // $submit_button.parents('form').first().append(html); 291 //$('<div style="clear:both;">
291'+html+'</div>').insertBefore($submit_button); 292 $(form).find('#gform_fields_login').append(html); 293 } else { 294 $submit_button.parents('form').first().prepend(html); 295 } 296 297 $('#login_error').hide(); 298 299 if (user_already_trusted) { 300 if (form_retain_existing_elements) { 301 $submit_button.trigger('click'); 302 } else { 303 $('#tfa_login_btn').trigger('click'); 304 } 305 } else { 306 307 $('#simba_two_factor_auth').trigger('focus'); 308 309 // Hide extra boxes of third party plugins 310 jQuery('.hide-when-displaying-tfa-input').hide(); 311 } 312 313 } 314 315 /** 316 * This function gets attached to a form submission handler and decides whether to add an OTP field or not. 317 * 318 * @param Object e - submission event 319 * 320 * @return Boolean - whether to proceed with the submission or not 321 */ 322 var form_submit_handler = function(e) { 323 324 console.log('Simba TFA: form submit request'); 325 326 var form = e.target; 327 328 var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6)); 329 330 // Turn off everything 331 $(form).off(); 332 333 if (0 == $(form).find('#simba_two_factor_auth').length && check_and_possibly_show_otp_field(form)) { 334 335 if (form_is_gravity_forms) { 336 var form_id = $(form).attr('id').substring(6); 337 // Gravity Forms won't allow the form to submit if this is already true 338 window['gf_submitting_'+form_id] = false; 339 } 340 341 e.preventDefault(); 342 return false; 343 344 } 345 346 return true; 347 348 }; 349 350 if (simba_tfasettings.login_form_off_selectors) { 351 $(simba_tfasettings.login_form_off_selectors).off('submit'); 352 } 353 354 $(simba_tfasettings.login_form_selectors).on('submit', form_submit_handler); 355 356 $(simba_tfasettings.login_form_selectors).find(get_username_identifiers()).on('blur', function() { 357 var $form = $(this).parents('form').first(); 358 check_and_possibly_show_otp_field($form, true); 359 }); 360 361});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.