1(function () { 2 "use strict"; 3 4 if (typeof window.jQuery === "undefined") { 5 const message = "scripts.preapp.js: jQuery is required but not loaded before this script."; 6 7 console.error(message); 8 9 if (window.Sentry && typeof window.Sentry.captureMessage === "function") { 10 window.Sentry.captureMessage(message, { level: "error" }); 11 } 12 13 return; 14 } 15 16 const $ = window.jQuery; 17 18 /* LOGIN */ 19 $('body').on('submit', 'form[name="login"]', async function(e) { 20 "use strict"; 21 e.preventDefault(); 22 23 var button = $(this).find('button[type="submit"]'); 24 25 var emailInput = $('body').find('[name="login[email]"]'); 26 var passwordInput = $('body').find('[name="login[password]"]'); 27 var passwordValue = passwordInput.val(); 28 29 var error = false; 30 31 if (!emailInput.val() || !isValidEmailAddress(emailInput.val())) { 32 error = true; 33 emailInput.addClass('error'); 34 } else { 35 emailInput.removeClass('error'); 36 } 37 38 if (!passwordInput.val()) { 39 error = true; 40 passwordInput.addClass('error'); 41 } else { 42 passwordInput.removeClass('error'); 43 } 44 45 if (error === true) { 46 generalInfo('show', 'error', 'There were errors. Please try again.'); 47 return false; 48 } else { 49 generalInfo('hide'); 50 } 51 52 button.addClass('loading'); 53 54 var postData = { 55 email_address: emailInput.val(), 56 password: await generateSHA256(passwordInput.val()), 57 }; 58 59 var postDataJSON = JSON.stringify(postData); 60 //console.log(postDataJSON); 61 62 $.ajax({ 63 type: "POST", 64 url: '/ajax/public_ajax_handler.php?type=sign_in', 65 data: ({ postArray: postDataJSON }), 66 dataType: "json", 67 error: function(XMLHttpRequest, textStatus, errorThrown) { 68 //alert(textStatus + ', ' + errorThrown); 69 }, 70 success: async function(data){ 71 if (data.success === 1) { 72 // store encryption key 73 await storeEncryptionKey(passwordValue); 74 75 const params = new URLSearchParams(window.location.search); 76 const redirectParam = params.get('u'); 77 let redirectUrl = '/dashboard'; 78 79 if (redirectParam) { 80 try { 81 const decodedUrl = decodeURIComponent(redirectParam); 82 const targetUrl = new URL(decodedUrl, window.location.origin); 83 84 if (targetUrl.origin === window.location.origin) { 85 redirectUrl = targetUrl.pathname + targetUrl.search + targetUrl.hash; 86 } 87 } catch (e) { 88 // ignore malformed URLs 89 } 90 } 91 92 const winbackPlanId = parseInt(getCookie('winback_plan'), 10); 93 if (winbackPlanId && !isNaN(winbackPlanId)) { 94 eraseCookie('winback_plan'); 95 const winbackPostData = JSON.stringify({ 96 plan_id: winbackPlanId, 97 payment_frequency: 'yearly', 98 source: 'winback', 99 }); 100 $.ajax({ 101 type: 'POST', 102 url: '/ajax/advanced_ajax_handler.php?type=change_subscription_plan&_cpt=' + getCookie('_cpt'), 103 data: { postArray: winbackPostData }, 104 dataType: 'json', 105 success: function (winbackData) { 106 if (winbackData.success === 1 && winbackData.message && winbackData.message.payment_required === 1 && winbackData.message.invoice_id) { 107 window.location.href = '/checkout/' + winbackData.message.invoice_id; 108 } else if (winbackData.message === 'winback_free_plan_required') { 109 window.location.href = '/dashboard?winback=not_free'; 110 } else { 111 window.location.href = '/dashboard?winback=failed'; 112 } 113 }, 114 error: function () { 115 window.location.href = '/dashboard?winback=failed'; 116 } 117 }); 118 return false; 119 } 120 121 window.location.href = redirectUrl; 122 return false; 123 } else { 124 button.removeClass('loading'); 125 126 if ($('body').attr('data-sslforfree') === 'true') { 127 generalInfo('show', 'error', (data.message ? data.message : 'Login failed: Incorrect email or password') + '<br><br>Please note that log-ins from before May 18th no longer work. To keep using our product, please <a title="Sign Up" href="/signup">create a new account for free.</a>'); 128 } else { 129 generalInfo('show', 'error', data.message ? data.message : 'Login failed: Incorrect email or password'); 130 } 131 return false;
132 } 133 134 } 135 136 }); 137 138 }); 139 140 /* FORGOT PASSWORD */ 141 $('body').on('submit', 'form[name="forgot"]', function(e) { 142 "use strict"; 143 e.preventDefault(); 144 145 var button = $(this).find('button[type="submit"]'); 146 147 var emailInput = $('body').find('[name="forgot[email]"]'); 148 149 var error = false; 150 151 if (!emailInput.val() || !isValidEmailAddress(emailInput.val())) { 152 error = true; 153 emailInput.addClass('error'); 154 } else { 155 emailInput.removeClass('error'); 156 } 157 158 if (error === true) { 159 generalInfo('show', 'error', 'Invalid account email. Please try again.'); 160 return false; 161 } else { 162 generalInfo('hide'); 163 } 164 165 button.addClass('loading'); 166 167 var postData = { 168 email_address: emailInput.val(), 169 }; 170 171 var postDataJSON = JSON.stringify(postData); 172 //console.log(postDataJSON); 173 174 $.ajax({ 175 type: "POST", 176 url: '/ajax/public_ajax_handler.php?type=reset_password', 177 data: ({ postArray: postDataJSON }), 178 dataType: "json", 179 error: function(XMLHttpRequest, textStatus, errorThrown) { 180 //alert(textStatus + ', ' + errorThrown); 181 }, 182 success: function(data){ 183 184 if (data.success === 1) { 185 186 button.removeClass('loading'); 187 188 generalInfo('show', 'success', 'An email with account recovery instructions has been sent to your email address.'); 189 return false; 190 191 } else { 192 193 button.removeClass('loading'); 194 195 generalInfo('show', 'error', 'An error occurred. Please try again.'); 196 return false; 197 198 } 199 200 } 201 202 }); 203 204 205 }); 206 207 208 /* FINALIZE RESET PASSWORD */ 209 $('body').on('submit', 'form[name="reset"]', async function(e) { 210 "use strict"; 211 e.preventDefault(); 212 213 var button = $(this).find('button[type="submit"]'); 214 215 var newPasswordInput = $('body').find('[name="reset[new_password]"]'); 216 var newPasswordAgainInput = $('body').find('[name="reset[new_password_again]"]'); 217 218 /* product-based password error messages */ 219 var passwordErrorMessage = 'New password must contain: 8 characters or more, including lowercase, uppercase characters and a number.'; 220 221 if (isProduct === 'sslforfree') { 222 passwordErrorMessage = 'Password must contain at least 6 characters'; 223 } 224 225 // check password strength, custom error 226 if (!newPasswordInput.val() || !passwordStrength(newPasswordInput.val())) { 227 generalInfo('show', 'error', passwordErrorMessage); 228 return false; 229 } else { 230 generalInfo('hide'); 231 newPasswordInput.removeClass('error'); 232 } 233 234 if (!newPasswordAgainInput.val() || newPasswordInput.val() !== newPasswordAgainInput.val()) { 235 newPasswordAgainInput.addClass('error'); 236 generalInfo('show', 'error', 'Your new passwords must match.'); 237 return false; 238 } else { 239 generalInfo('hide'); 240 newPasswordAgainInput.removeClass('error'); 241 } 242 243 button.addClass('loading'); 244 245 var postData = { 246 new_password: await generateSHA256(newPasswordInput.val()), 247 new_password_again: await generateSHA256(newPasswordAgainInput.val()), 248 key: $('body').find('[name="key"]').val() 249 }; 250 251 var postDataJSON = JSON.stringify(postData); 252 //console.log(postDataJSON); 253 254 $.ajax({ 255 type: "POST", 256 url: '/ajax/public_ajax_handler.php?type=finalize_reset_password', 257 data: ({ postArray: postDataJSON }), 258 dataType: "json", 259 error: function(XMLHttpRequest, textStatus, errorThrown) { 260 //alert(textStatus + ', ' + errorThrown); 261 }, 262 success: function(data){ 263 264 if (data.success === 1) { 265 266 // set cookie in client that invalidates all private keys on next login 267 localStorage.setItem('inv_pk', 'true'); 268 269 window.location.href = '/login/recovered'; 270 return false; 271 272 } else { 273 274 button.removeClass('loading'); 275 276 generalInfo('show', 'error', 'Error: Please try again or contact support.'); 277 return false; 278 279 } 280 281 } 282 283 }); 284 285 286 }); 287 288 289 /* SIGNUP */ 290 $('body').on('submit', 'form[name="signup"]', async function(e) { 291 "use strict"; 292 e.preventDefault(); 293 294 generateRecaptchaToken(); 295 296 var button = $(this).find('button[type="submit"]'); 297 298 var emailInput = $('body').find('[name="signup[email]"]'); 299 var passwordInput = $('body').find('[name="signup[password]"]'); 300 var countryInput = $('body').find('[name="signup[country_code]"]'); 301 302 var passwordValue = passwordInput.val(); 303 304 var error = false;
305 306 if (!emailInput.val() || !isValidEmailAddress(emailInput.val())) { 307 error = true; 308 emailInput.addClass('error'); 309 } else { 310 emailInput.removeClass('error'); 311 } 312 313 if (!passwordInput.val()) { 314 error = true; 315 passwordInput.addClass('error'); 316 } else { 317 passwordInput.removeClass('error'); 318 } 319 320 if (!countryInput.val()) { 321 error = true; 322 countryInput.addClass('error'); 323 } else { 324 countryInput.removeClass('error'); 325 } 326 327 if (error === true) { 328 generalInfo('show', 'error', 'There were errors. Please try again.'); 329 return false; 330 } else { 331 generalInfo('hide'); 332 } 333 334 /* product-based password error messages */ 335 var passwordErrorMessage = 'Your password must contain 8 characters or more, including lowercase, uppercase characters and a number.'; 336 337 if (isProduct === 'sslforfree') { 338 passwordErrorMessage = 'Password must contain at least 6 characters'; 339 } 340 341 if (!passwordStrength(passwordInput.val())) { 342 343 passwordInput.addClass('error'); 344 generalInfo('show', 'error', passwordErrorMessage); 345 346 return false; 347 348 } else { 349 generalInfo('hide'); 350 passwordInput.removeClass('error'); 351 } 352 353 button.addClass('loading'); 354 355 var domainToSecure = $('body').find('[name="signup[domain]"]').val(); 356 357 let v2Response = null; 358 try { 359 v2Response = grecaptcha.getResponse(); 360 } catch { 361 // usually the case, v2Response is only for the fallback 362 } 363 364 var postData = { 365 email_address: emailInput.val(), 366 password: await generateSHA256(passwordInput.val()), 367 payment_frequency: 'yearly', 368 country_code: $('body').find('[name="signup[country_code]"]').val(), 369 domain: $('body').find('[name="signup[domain]"]').val(), 370 plan_id: $('body').find('[name="signup[plan_id]"]').val(), 371 token: $('body').find('[name="recaptcha_token"]').val(), 372 v2response: v2Response, 373 origin: $('body').find('[name="signup[origin]"]').val(), 374 origin_full: $('body').find('[name="signup[origin_full]"]').val(), 375 }; 376 377 var postDataJSON = JSON.stringify(postData); 378 //console.log(postDataJSON); 379 380 $.ajax({ 381 type: "POST", 382 url: '/ajax/public_ajax_handler.php?type=create_account', 383 data: ({ postArray: postDataJSON }), 384 dataType: "json", 385 error: function(XMLHttpRequest, textStatus, errorThrown) { 386 //alert(textStatus + ', ' + errorThrown); 387 }, 388 success: async function(data){ 389 if (data.success === 1) { 390 // store encryption key 391 await storeEncryptionKey(passwordValue); 392 393 if (data?.message?.payment_required === 1) { 394 window.location.href = '/checkout/'+data.message.invoice_id; 395 } else { 396 setCookie('free_client_onboarding', domainToSecure) 397 window.location.href = '/select-plan'; 398 } 399 return false; 400 } else { 401 button.removeClass('loading'); 402 if(parseInt(data.success) === -10) { 403 let url = window.location.href; 404 if (url.indexOf('?') > -1){ 405 url += '&sverify=1&email=' + emailInput.val() 406 } else { 407 url += '?sverify=1&email=' + emailInput.val() 408 } 409 window.location.href = url; 410 } else { 411 generalInfo('show', 'error', translateError(data.message)); 412 return false; 413 } 414 } 415 416 } 417 418 }); 419 420 }); 421 422 423 424 /* CTA FOOTER SUBMISSION */ 425 $('body').on('click', '[data-action="submit_footer_cta"]', function(event) { 426 427 event.preventDefault(); 428 429 var email = $('body').find('[name="cta_email"]').val(); 430 431 if (!isValidEmailAddress(email)) { 432 email = ''; 433 } 434 435 // redirect to signup 436 window.location.href = 'https://app.zerossl.com/signup/email/' + email; 437 438 }); 439 440 441 $('body').on('submit', 'form[name="otp"]', function(e) { 442 "use strict"; 443 e.preventDefault(); 444 445 var button = $(this).find('button[type="submit"]'); 446 447 var otpInput = $('body').find('[name="otp[otp]"]'); 448 449 var otpError = $('body').find('.otp-error'); 450 451 button.addClass('loading'); 452 otpError.hide(); 453 454 var postData = { 455 otp: otpInput.val(), 456 }; 457 458 var postDataJSON = JSON.stringify(postData); 459 460 $.ajax({ 461 type: "POST", 462 url: '/ajax/public_ajax_handler.php?type=verify_otp', 463 data: ({ postArray: postDataJSON }), 464 dataType: "json", 465 success: function(data){ 466 if(data.success === 1) { 467 location.reload(); 468 } else { 469 470 button.removeClass('loading'); 471 472 otpError.html(data.message) 473 otpError.show(); 474 } 475 } 476 477 }); 478 479 }); 480})(); 481 482function handleSubscriptionChangeSuccess(responseObject) { 483 setCookie('free_client_onboarding', '', -1); 484 location.href = '/checkout/'+responseObject.invoice_id; 485} 486 487function proceedWithFreeAccount(e) { 488 e.preventDefault(); 489 setCookie('free_client_onboarding', '', -1); 490 location.href = e.target.href; 491} 492 493/* WINBACK PRE-LOGIN SURVEY 494 * Runs on /login?winback=1. Opens the winback popup and delegates survey 495 * initialisation to window.WinbackSurvey. On a valid plan selection the plan 496 * ID is saved to the winback_plan cookie; after login the user is redirected 497 * to checkout. 498 */ 499$(document).ready(function () { 500 if (!$('#login[data-winback]').length) { 501 return; 502 } 503 504 openPopup('confirm_winback_survey_prelogin', undefined, function () { 505 var surveyElem = $('#winbackSurvey'); 506 var confirmButton = $('#confirmWinBackButton'); 507 508 window.WinbackSurvey.init(surveyElem, confirmButton, { 509 origin: surveyElem.data('origin'), 510 env: surveyElem.data('env') || '' 511 }, function (planId) {
512 if (planId) { 513 setCookie('winback_plan', planId, 1); 514 confirmButton.addClass('primary'); 515 516 const planNames = { 1128: 'Basic', 1129: 'Premium', 1130: 'Business' }; 517 const planName = planNames[planId] || 'selected'; 518 $('.alerts').find('.winback-plan-alert').remove(); 519 $('.alerts').append('<p class="alert success winback-plan-alert">You\'ve selected the <strong>' + planName + '</strong> plan. Log in below and you\'ll be redirected to checkout automatically.</p>'); 520 } 521 }); 522 }, undefined, 'full-screen'); 523});
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.