1 2/** 3 * Script for 2FA Twilio. 4 * 5 * @param {jQuery} $ jQuery object. 6 * @param {Object} window The window object. 7 */ 8 9 10(function ($, window) { 11 12 jQuery(document).on('click', '[data-check-twilio-2fa]', function () { 13 let role_suffix = ('' === jQuery(this).data('role')) ? '' : jQuery(this).data('role'); 14 const sid = (jQuery('#wp-2fa-twilio-sid' + role_suffix).length) ? jQuery('#wp-2fa-twilio-sid' + role_suffix).val() : jQuery('#wp-2fa-twilio-sid').val(); 15 const auth = (jQuery('#wp-2fa-twilio-auth' + role_suffix).length) ? jQuery('#wp-2fa-twilio-auth' + role_suffix).val() : jQuery('#wp-2fa-twilio-auth').val(); 16 const id = (jQuery('#wp-2fa-twilio-id' + role_suffix).length) ? jQuery('#wp-2fa-twilio-id' + role_suffix).val() : jQuery('#wp-2fa-twilio-id').val(); 17 const ajaxURL = (typeof wp2faWizardData != "undefined") ? wp2faWizardData.ajaxURL : ajaxurl; 18 const nonceValue = jQuery(this).attr('data-nonce'); 19 20 jQuery.ajax({ 21 url: ajaxURL, 22 data: { 23 action: 'check_twilio_credentials', 24 twilio_sid: sid, 25 twilio_auth: auth, 26 twilio_id: id, 27 _wpnonce: nonceValue 28 }, 29 success: function (data) { 30 if (data.success) { 31 if (jQuery('input#twilio' + role_suffix).length) { 32 storeKey(ajaxURL, sid, auth, id, nonceValue, role_suffix); 33 jQuery('#wizard-sid-key' + role_suffix).fadeIn(1000); 34 displayDialog(wp2faTwilio.keyCheckSuccessful); 35 } else { 36 displayDialog(wp2faTwilio.keyCheckSuccessful); 37 } 38 jQuery("input[id^='twilio']").each(function () { 39 jQuery(this).checked = true; 40 }); 41 /* Update sortable-list status dot and unlock checkbox */ 42 jQuery('[data-check-twilio-2fa]').each(function() { 43 var li = jQuery(this).closest('.wp2fa-sortable-item'); 44 if (li.length) { 45 li.removeAttr('data-needs-setup'); 46 li.find('.wp2fa-integration-status-dot') 47 .removeClass('wp2fa-status-not-configured') 48 .addClass('wp2fa-status-configured') 49 .attr('title', wp2faTwilio.configured || 'Configured'); 50 li.find('.wp2fa-integration-setup-notice').hide(); 51 } 52 }); 53 } else { 54 displayDialog(data.data); 55 } 56 }, 57 }); 58 }); 59 60 function displayDialog(msg) { 61 if ( typeof wp2faDialog !== 'undefined' ) { 62 wp2faDialog.alert({ 63 title: wp2faTwilio.dialogTitle || '', 64 message: msg 65 }); 66 } else { 67 alert( msg ); 68 } 69 } 70 71 var iti = jQuery("#wp-2fa-phone-twilio").intlTelInput({ 72 initialCountry: "auto", 73 geoIpLookup: function (callback) { 74 jQuery.get("//ipinfo.io", function () { }, "jsonp").always(function (resp) { 75 var countryCode = (resp && resp.country) ? resp.country : ""; 76 callback(countryCode); 77 }); 78 }, 79 placeholderNumberType: "MOBILE", 80 utilsScript: wp2faTwilio.utilsUrl, 81 }); 82 83 // Checks and validates the given telephone number 84 jQuery(document).on('click', '#twilio_tel', function (e) { 85 e.preventDefault(); 86 const errorWrapper = jQuery('#error-msg-twilio'); 87 errorWrapper.addClass('hidden'); 88 89 if ('' === jQuery('#wp-2fa-phone-twilio').val().trim()) { 90 errorWrapper.html('No number provided'); 91 errorWrapper.removeClass('hidden'); 92 } else { 93 if (!iti.intlTelInput("isValidNumber")) { 94 errorWrapper.html(wp2faTwilio.errorMap[iti.intlTelInput("getValidationError")]); 95 errorWrapper.removeClass('hidden'); 96 } else { 97 var fullNumber = iti.intlTelInput("getNumber"); 98 99 registerUserTwilio(fullNumber, jQuery(this).data('nonce')); 100 } 101 } 102 }); 103 104 jQuery( document ).on( 'click', '[data-close-2fa-modal]', function( e ) { 105 e.preventDefault(); 106 const errorWrapper = jQuery('#error-msg-twilio'); 107 errorWrapper.html(''); 108 errorWrapper.addClass('hidden'); 109 110 const currentSubStep = jQuery('.twilio-step-setting-wrapper'); 111 const nextSubStep = jQuery(currentSubStep).nextAll('.twilio-step-setting-wrapper:not(.hidden)').filter(':first'); 112 jQuery(currentSubStep).removeClass('hidden'); 113 jQuery(currentSubStep).addClass('active'); 114 jQuery(nextSubStep).addClass('hidden'); 115 jQuery(nextSubStep).removeClass('active'); 116 } ); 117 118 /** 119 * Responds with error 120 * 121 * @param {string} text 122 */ 123 function displayError(text) { 124 if (jQuery('#error-msg-twilio').length) { 125 const errorWrapper = jQuery('#error-msg-twilio'); 126 errorWrapper.html(text); 127 errorWrapper.removeClass('hidden'); 128 } 129 } 130
131 /** 132 * Registers Twilio user. 133 * 134 * @param {string} countryCode 135 * @param {string} phone 136 */ 137 function registerUserTwilio(fullNumber, nonce) { 138 const ajaxURL = (typeof wp2faWizardData != "undefined") ? wp2faWizardData.ajaxURL : ajaxurl; 139 jQuery.ajax({ 140 url: ajaxURL, 141 data: { 142 action: 'register_user_twilio', 143 phone: fullNumber, 144 _wpnonce: nonce 145 }, 146 success: function (data) { 147 if (data.success) { 148 const currentSubStep = jQuery('.twilio-step-setting-wrapper'); 149 const nextSubStep = jQuery(currentSubStep).nextAll('.twilio-step-setting-wrapper:not(.active)').filter(':first'); 150 jQuery(currentSubStep).removeClass('active'); 151 jQuery(currentSubStep).addClass('hidden'); 152 jQuery(nextSubStep).addClass('active'); 153 jQuery(nextSubStep).removeClass('hidden'); 154 } else { 155 displayError(data.data); 156 } 157 }, 158 error: function (data) { 159 displayError(data.responseJSON.data[0].message[0]); 160 console.log(data.responseJSON.data[0].message[1]); 161 } 162 }); 163 } 164 165 jQuery(document).on('click', '[data-sid-setup-wizard]', function (e) { 166 e.preventDefault(); 167 let role_suffix = ('global' === jQuery(this).data('role')) ? '' : '-' + jQuery(this).data('role'); 168 jQuery('#wizard-sid-key' + role_suffix).slideDown(600); 169 }); 170 171 /** 172 * Stores the provided Authy API key 173 * 174 * @param {string} ajaxURL 175 * @param {string} key 176 */ 177 function storeKey(ajaxURL, sid, auth, id, nonce, role_suffix) { 178 jQuery.ajax({ 179 url: ajaxURL, 180 data: { 181 action: 'store_twilio_api_key', 182 twilio_sid: sid, 183 twilio_auth: auth, 184 twilio_id: id, 185 _wpnonce: nonce 186 }, 187 success: function (data) { 188 if (data.success) { 189 jQuery('#wizard-sid-key' + role_suffix).fadeOut(1000); 190 jQuery('#twilio-links' + role_suffix).fadeIn(1000); 191 jQuery('input#twilio' + role_suffix).removeClass('disabled').removeAttr('data-sid-setup-wizard').prop('checked', true); 192 jQuery('.twilio-sub-wrapping').removeClass('disabled'); 193 194 jQuery('[for="all-users"], [for="certain-roles-only"]').removeClass('disabled'); 195 jQuery('#backup-codes' + role_suffix).removeClass('disabled'); 196 jQuery('label[for="backup-codes' + role_suffix + '"]').removeClass('disabled'); 197 198 if (jQuery('a.button[name="next_step_setting"]').length) { 199 jQuery('a.button[name="next_step_setting"]').prop('disabled', false); 200 jQuery('a.button[name="next_step_setting"]').removeClass('disabled'); 201 } 202 203 } else { 204 alert(data.data); 205 } 206 }, 207 }); 208 } 209 210 jQuery(document).on('click', '[data-api-remove-twilio]', function (e) { 211 e.preventDefault(); 212 const nonceValue = jQuery(this).attr('data-nonce'); 213 let role_suffix = ('' === jQuery(this).data('role')) ? '' : jQuery(this).data('role'); 214 removeSettings(nonceValue, role_suffix); 215 }); 216 217 /** 218 * Removes the settings 219 * 220 * @param {string} nonce 221 */ 222 function removeSettings(nonce, role_suffix) { 223 const ajaxURL = (typeof wp2faWizardData != "undefined") ? wp2faWizardData.ajaxURL : ajaxurl; 224 225 jQuery.ajax({ 226 url: ajaxURL, 227 data: { 228 action: 'remove_wp2fa_twilio_settings', 229 _wpnonce: nonce 230 }, 231 success: function (data) { 232 if (data.success) { 233 jQuery('#wizard-sid-key' + role_suffix).fadeOut(1000); 234 jQuery('#twilio-links' + role_suffix).fadeOut(1000); 235 jQuery('input#twilio' + role_suffix).addClass('disabled').attr('data-sid-setup-wizard', '').prop('checked', false); 236 jQuery('#wp-2fa-twilio-sid' + role_suffix).val(''); 237 jQuery('#wp-2fa-twilio-auth' + role_suffix).val(''); 238 jQuery('#wp-2fa-twilio-id' + role_suffix).val(''); 239 } else { 240 alert(data.data); 241 } 242 }, 243 }); 244 } 245 246 /** 247 * Shows verification messages 248 * 249 * @param {string} type 250 * @param {string} text 251 */ 252 function verificationResponse(type, text) { 253 let wrapper = jQuery('.verification-response-twilio'); 254 255 if ('error' === type) { 256 wrapper.html('<span style="color:red">' + text + '</span>'); 257 } else { 258 wrapper.html('<span style="color:green">' + text + '</span>'); 259 } 260 wrapper.removeClass('hidden'); 261 } 262 263 // Twilio validation button 264 jQuery(document).on('click', 'a[data-validate-twilio-ajax]', function (e) { 265 e.preventDefault(); 266 267 tokenField = jQuery('#twilio-token'); 268 if ('' === tokenField.val().trim()) { 269 verificationResponse('error', 'No token provided'); 270 } else { 271 let isValid = false;
272 let regex = /^[0-9\s]*$/; 273 isValid = regex.test(tokenField.val()); 274 if (!isValid) { 275 verificationResponse('error', 'Invalid token format'); 276 } else { 277 let token = tokenField.val(); 278 let nonce = jQuery(this).data('nonce'); 279 280 checkToken(token, nonce); 281 } 282 } 283 }); 284 285 /** 286 * Checks token against the Authy API 287 * 288 * @param {string} token 289 * @param {string} nonce 290 */ 291 function checkToken(token, nonce) { 292 const ajaxURL = (typeof wp2faWizardData != "undefined") ? wp2faWizardData.ajaxURL : ajaxurl; 293 let closeButton = jQuery('button[data-close-2fa-modal'); 294 let setMethod = (closeButton.length) ? true : false; 295 let fullNumber = iti.intlTelInput("getNumber"); 296 297 jQuery.ajax({ 298 url: ajaxURL, 299 data: { 300 action: 'check_twilio_token', 301 token: token, 302 phone: fullNumber, 303 method: setMethod, 304 _wpnonce: nonce 305 }, 306 success: function (data) { 307 if (data.success) { 308 if (jQuery('a[data-validate-twilio-ajax]').length) { 309 // Called from the profile setup - close the wizard 310 311 let nextSubStep = jQuery('#wp-2fa-wizard-config-backup-codes'); 312 313 if (jQuery('#wp-2fa-wizard-backup-methods').length) { 314 nextSubStep = jQuery('#wp-2fa-wizard-backup-methods'); 315 } else if (jQuery('#wp-2fa-wizard-email-backup-selected').length) { 316 nextSubStep = jQuery('#wp-2fa-wizard-email-backup-selected'); 317 } 318 319 jQuery(this).parent().parent().find('.active').not('.step-setting-wrapper').removeClass('active'); 320 jQuery('.wizard-step.active').removeClass('active'); 321 jQuery(nextSubStep).addClass('active'); 322 323 jQuery(document).on('click', '#select-backup-method', function (e) { 324 e.preventDefault(); 325 var backupRadio = jQuery("input[name=backup_method_select]:checked"); 326 327 jQuery('.wizard-step.active').removeClass('active'); 328 jQuery('#' + backupRadio.data('step')).addClass('active'); 329 }); 330 331 jQuery(document).on('click', '[name="save_step"], [data-close-2fa-modal]', function () { 332 if ('reLogin' in wp2faWizardData && 333 wp2faWizardData.reLoginEnabled == jQuery.trim(wp2faWizardData.reLogin)) { 334 jQuery.ajax({ 335 type: 'POST', 336 url: wp2faData.ajaxURL, 337 data: { 338 action: 'custom_ajax_logout', 339 _wpnonce: nonceValue, 340 }, 341 success: function (r) { 342 if ('loginUrl' in wp2faWizardData && '' != jQuery.trim(wp2faWizardData.loginUrl)) { 343 window.location.replace(wp2faWizardData.loginUrl); 344 } else { 345 window.location.replace('/wp-login.php'); 346 } 347 } 348 }); 349 } else { 350 if ('redirectToUrl' in wp2faWizardData && 351 '' != jQuery.trim(wp2faWizardData.redirectToUrl)) { 352 window.location.replace(wp2faWizardData.redirectToUrl); 353 } else { 354 removeShowParam(); 355 } 356 } 357 }); 358 } 359 } else { 360 alert(data.data); 361 } 362 }, 363 error: function (data) { 364 verificationResponse('error', data.responseJSON.data[0].message); 365 } 366 }); 367 368 } 369 370}(jQuery, window));
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.