File manager - Edit - /usr/local/cpanel/base/frontend/jupiter/security/tls_wizard/views/CheckoutController.js
Back
/* * Copyright 2026 WebPros International, LLC * All rights reserved. * copyright@cpanel.net http://cpanel.net * This code is subject to the cPanel license. Unauthorized copying is prohibited. */ /* global define: false */ /* jshint -W100 */ // Then load the application dependencies define( [ "lodash", "angular", "jquery", "cjt/util/locale", "cjt/util/query", "app/views/Certificate", "cjt/modules", "app/services/CertificatesService", "app/services/LocationService", "cjt/directives/spinnerDirective", "uiBootstrap", ], function(_, angular, $, LOCALE, QUERY) { "use strict"; var app = angular.module("App"); function CheckoutController( $scope, $controller, $location, $filter, $routeParams, $window, $timeout, CertificatesService, spinnerAPI, $q, $modal, $log, Certificate, LocationService, alertService) { var steps = { "cPStore": ["login", "send_cart_items", "checkout", "payment_callback", "checkout_complete"], "default": ["login", "send_cart_items", "checkout", "payment_callback", "checkout_complete"], }; $scope.pending_certificates = CertificatesService.get_pending_certificates(); $scope.LOCALE = LOCALE; $scope.purchase_steps = []; $scope.current_step = -1; $scope.start_step = null; $scope.providers = []; $scope.certificates_count = 0; $scope.steps = []; $scope.initialized = false; $scope.html_escape = _.escape.bind(_); $scope.get_step_classes = function(provider, step) { var steps = $scope.get_steps(provider.name).length; var stepIndex = $scope.get_step_index(provider.name, step); var cols = Math.floor(12 / steps); var classes = ["col-xs-12", "col-sm-12", "col-md-" + cols, "col-lg-" + cols, "checkout-step"]; if ($scope.current_step_index === stepIndex) { classes.push("checkout-step-current"); if ("checkout_complete" === step) { classes.push("checkout-step-completed"); } } else if ($scope.current_step_index > stepIndex) { classes.push("checkout-step-completed"); } return classes; }; $scope.cert_count_title = function() { return LOCALE.maketext("Purchasing [quant,_1,certificate,certificates] …", $scope.certificates_count); }; $scope.get_purchases_title = function(provider) { return LOCALE.maketext("Completing [numerate,_2,purchase,purchases] for the “[_1]” provider …", $scope.html_escape(provider.display_name), provider.certificates.length); }; $scope.sending_items_msg = function() { return LOCALE.maketext("Sending your [numerate,_1,item,items] to the store cart …", $scope.certificates_count); }; $scope.starting_polling_msg = function() { return LOCALE.maketext("Starting background polling for the [numerate,_1,certificate,certificates]. The system will download and install the [numerate,_1,certificate,certificates] when available.", $scope.certificates_count); }; $scope.get_provider_by_name = function(name) { for (var i = 0; i < $scope.providers.length; i++) { if ($scope.providers[i].name === name) { return $scope.providers[i]; } } }; $scope.get_steps = function(providerName) { if (steps[providerName]) { return steps[providerName]; } return steps["default"]; }; $scope.get_current_step = function() { return $scope.steps[$scope.current_step_index]; }; $scope.get_step_index = function(providerName, step) { for (var i = 0; i < $scope.steps.length; i++) { if ($scope.steps[i].provider === providerName && $scope.steps[i].step === step) { return i; } } return 0; }; $scope.get_step_url = function(step) { return "/" + encodeURIComponent(step.provider) + "/" + encodeURIComponent(step.step); }; $scope.get_next_step = function() { if ($scope.current_step_index + 1 < $scope.steps.length) { return $scope.steps[$scope.current_step_index + 1]; } }; $scope.get_param = function(key) { return QUERY.parse_query_string(location.search.replace(/^\?/, ""))[key] || $routeParams[key]; }; $scope.require_params = function(keys) { var badKeys = []; var tooManyKeys = []; angular.forEach(keys, function(key) { var value = $scope.get_param(key); if (!value) { badKeys.push(key); } else if (value instanceof Array) { tooManyKeys.push(key); } }); if (badKeys.length) { alertService.add({ type: "danger", message: LOCALE.maketext("The following [numerate,_1,parameter is,parameters are] required but [numerate,_1,does,do] not appear in the [asis,URL]: [list_and_quoted,_2]", badKeys.length, badKeys), group: "tlsWizard", }); } if (tooManyKeys.length) { alertService.add({ type: "danger", message: LOCALE.maketext("The following [numerate,_1,parameter appears,parameters appear] more than once in the [asis,URL]: [list_and_quoted,_2]", tooManyKeys.length, tooManyKeys), group: "tlsWizard", }); } return badKeys.length || tooManyKeys.length ? false : true; }; $scope.in_debug_mode = false; $scope.get_route_url = function() { var routeURL = ""; routeURL += $location.absUrl().replace(/tls_wizard\/.+/, "tls_wizard/#/purchase"); return routeURL; }; function _pemToBase64(pem) { return pem .replace(/^\s*-\S+/, "") .replace(/-\S+\s*$/, "") .replace(/\s+/g, ""); } // $q.all() will reject the “aggregate” promise with the // exact same value as the one that failed. That’s not good // enough; we also need to know which promise failed in addition // to why it failed. // // This transforms all failure callback payloads into 2-member // arrays: [ <promise_index>, <payload> ] // // So, if you do: // _qAllWithErrIndex( [ prA, prB, prC ] ) // // ...and “prB” fails with the string "hahaha", the // failure callback will receive [ 1, "hahaha" ]. // function _qAllWithErrIndex(promisesArray) { if (!(promisesArray instanceof Array)) { throw "Only arrays here!"; } return $q.all(promisesArray.map(function(p, i) { return $q(function(resolve, reject) { p.then( resolve, function(payload) { reject([i, payload]); } ); }); })); } $scope.dismiss_modal = function() { this.modal.dismiss(); }; $scope.go_to_purchase_page = LocationService.go_to_last_create_route; $scope.go_to_login = function() { this.go_step(this.get_current_step().provider, "login"); }; $scope.do_current_step = function() { var step = $scope.get_current_step(); if (!step) { // something is severely wrong // maybe they hit the back button a lot for some random reason. // let's send them back somewhere safe. LocationService.go_to_last_create_route(); return; } var nextStep = $scope.get_next_step(); var orderID = $scope.get_param("order_id"); var loginCode = $scope.get_param("code"); var order = CertificatesService.get_order_by_id(orderID); var orderStatus = $scope.get_param("order_status"); var provider = $scope.get_provider_by_name(step.provider); var accessToken = $scope.get_param("access_token"); var returnURL; if (step.step === "login") { returnURL = $scope.get_route_url() + $scope.get_step_url(step); if (order) { returnURL += "?order_id=" + order.order_id; } if (loginCode) { /* Back from Login, Verify It */ CertificatesService.verify_login_token(step.provider, loginCode, returnURL).then(function(result) { if (order) { /* there's an order, so don't create another one */ $scope.go_step(step.provider, "checkout", { order_id: order.order_id, access_token: result.data.access_token, }); } else { /* no order, so create one */ $scope.go_step(step.provider, "send_cart_items", { access_token: result.data.access_token, }); } }, function(errorHTML) { $scope.return_to_wizard(); alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to verify the login token: [_1]", errorHTML) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); }); } else { /* There's no login code */ CertificatesService.get_store_login_url(step.provider, returnURL).then(function(result) { $window.location.href = result.data; }, function(errorHTML) { $scope.return_to_wizard(); alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to get the store login [output,abbr,URL,Uniform Resource Location]: [_1]", errorHTML) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); }); } } else if (step.step === "send_cart_items") { /* create order / build cart */ if (!$scope.require_params(["access_token"])) { return; } returnURL = $scope.get_route_url() + $scope.get_step_url(nextStep); return CertificatesService.request_certificates(step.provider, accessToken, provider.certificates).then(function(result) { var order = result.data; order.order_id = order.order_id.toString(); CertificatesService.add_order(order); CertificatesService.save(); $scope.go_step(step.provider, "checkout", { order_id: order.order_id, access_token: accessToken, }); }, function(errorHTML) { $scope.return_to_wizard(); alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to request the [asis,SSL] [numerate,_2,certificate,certificates]: [_1]", errorHTML, $scope.get_provider_by_name(step.provider).certificates.length) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); }); } else if (step.step === "checkout") { if (!$scope.require_params(["order_id"])) { return; } returnURL = $scope.get_route_url() + $scope.get_step_url(step); if (orderStatus) { /* are we back from checking out? */ $scope.go_step(step.provider, "payment_callback", { order_id: order.order_id, order_status: orderStatus, }); } else { if (!$scope.require_params(["access_token"])) { return; } /* no? let's update the checkout url and head to checkout */ CertificatesService.set_url_after_checkout(step.provider, accessToken, order.order_id, returnURL).then(function() { $window.location.href = order.checkout_url; }, function(response) { // NB: the argument is *not* the error! var isOtherUser = response.data && response.data.error_type === "OrderNotFound"; if (isOtherUser) { $scope.order_id = order.order_id; $scope.provider = $scope.get_provider_by_name(step.provider); $scope.modal = $modal.open({ template: document.getElementById("user-mismatch-modal").text, scope: $scope, backdrop: "static", animation: false, size: "sm", }); } else { LocationService.go_to_last_create_route(); alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to set the [asis,URL] after checkout: [_1]", _.escape(response.error)) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); } }); } } else if (step.step === "payment_callback") { /* post checkout processing */ CPANEL.PAGE.pending_certificates = null; CPANEL.PAGE.installed_hosts = null; if (orderStatus === "success") { alertService.add({ type: "success", message: LOCALE.maketext("You have successfully completed your certificate order (order ID “[_1]”). If you need help with this order, use the support [numerate,_2,link,links] below.", _.escape(orderID), order.certificates.length), closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); CertificatesService.set_confirmed_status_for_ssl_certificates(step.provider, order).then(function() { // successful $scope.go_step(step.provider, nextStep.step); }, function(response) { // This is here to accommodate cases where the certificate // becomes available, and gets installed, prior to the // browser’s being able to set the certificate to “confirmed”. // When that happens, we get back a data structure that // describes which vhosts’ pending queue entries didn’t exist; // we then do what can be done to ensure that the cert(s) // is/are installed where it/they should be. // if (response.data && response.data.error_type === "EntryDoesNotExist") { var notFound = response.data.order_item_ids; var msg = LOCALE.maketext("There are no pending certificates from “[_1]” with the following order item [numerate,_2,ID,IDs]: [join,~, ,_3]. The system will now verify that the [numerate,_2,certificate has,certificates have] been issued and installed.", _.escape(step.provider), notFound.length, notFound.map(_.escape.bind(_))); alertService.add({ type: "info", message: msg, closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); var certificates = provider.certificates; notFound.forEach(function(oiid) { // Fetch the new SSL cert. var providerPromise = CertificatesService.get_ssl_certificate_if_available(step.provider, oiid); // There will only be one vhost // per certificate for now, but with // wildcard support that could change. certificates.forEach(function(cert) { cert.get_virtual_hosts().forEach(function(vhostName) { var domain = cert.get_domains().filter(function(domain) { return domain.virtual_host === vhostName; }).pop().domain; var bigP = _qAllWithErrIndex([ CertificatesService.get_installed_ssl_for_domain(), providerPromise, ]); bigP.then(function yay(responses) { var installedPEM = responses[0].data.certificate.text; var installedB64; if (installedPEM) { installedB64 = _pemToBase64(installedPEM); } var providerPEM = responses[1].data.certificate_pem; var providerB64; if (providerPEM) { providerB64 = _pemToBase64(providerPEM); } else { var apiResponse = responses[1].data; var statusCode = apiResponse.status_code; var statusMessage = apiResponse.status_message; var alertMessage; // There is ambiguity over the spelling of “canceled”. if (/OrderCancell?ed/.test(statusCode)) { alertMessage = LOCALE.maketext("“[_1]” indicated that the order with [asis,ID] “[_2]” has been canceled.", _.escape(step.provider), _.escape(orderID)); } else if (/OrderItemCancell?ed/.test(statusCode)) { alertMessage = LOCALE.maketext("“[_1]” indicated that the certificate with order item [asis,ID] “[_2]” has been canceled.", _.escape(step.provider), _.escape(oiid)); } else { alertMessage = LOCALE.maketext("“[_1]” has not issued a certificate for order item [asis,ID] “[_2]”. Contact them for further assistance.", _.escape(step.provider), _.escape(oiid)); // This yields one of: // statusCode // statusMessage // statusCode: statusMessage // … depending on the two items’ // truthiness. var statusStr = [statusCode, statusMessage].filter( function(s) { return !!s; } ).join(": "); if (statusStr) { alertMessage += " (" + statusStr + ")"; } } alertService.add({ type: "danger", message: alertMessage, closeable: true, replace: false, group: "tlsWizard", }); // Since there’s no new certificate, // there’s nothing more we can do. LocationService.go_to_last_create_route(); return; } if (providerB64 === installedB64) { // This is the most optimal outcome: // we confirmed that the new cert is // installed, as the user wanted. alertService.add({ type: "success", message: LOCALE.maketext("The system confirmed that the certificate for the website “[_1]” is installed.", _.escape(vhostName)), closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); if (installedB64) { alertService.add({ type: "info", message: LOCALE.maketext("“[_1]” has an [asis,SSL] certificate installed, but it is not the certificate that you just ordered (order item [asis,ID] “[_2]”). The system will now install this certificate.", _.escape(vhostName), _.escape(oiid)), closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); } else { var noCertMessage; noCertMessage = LOCALE.maketext("You do not have an [asis,SSL] certificate installed for the website “[_1]”.", _.escape(vhostName)); noCertMessage += LOCALE.maketext("The system will now install the new certificate."); alertService.add({ type: "info", message: noCertMessage, closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); CertificatesService.install_certificate(providerPEM, [domain]).then( function yay() { alertService.add({ type: "success", message: LOCALE.maketext("The system installed the certificate onto the website “[_1]”.", _.escape(vhostName)), closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); }, function nay(errorHTML) { alertService.add({ type: "danger", message: LOCALE.maketext("The system failed to install the certificate onto the website “[_1]” because of the following error: [_2]", _.escape(vhostName), errorHTML), closeable: true, replace: false, group: "tlsWizard", }); } ).then(LocationService.go_to_last_create_route); } } }, function onerror(idxAndResponse) { // We’re here because we failed either // to fetch the new cert or to query // the current SSL state. var promiseI = idxAndResponse[0]; var errorHTML = idxAndResponse[1]; if (promiseI === 0) { alertService.add({ type: "danger", message: LOCALE.maketext("The system failed to locate the installed [asis,SSL] certificate for the website “[_1]” because of the following error: [_2]", _.escape(vhostName), errorHTML), closeable: true, replace: false, group: "tlsWizard", }); } else if (promiseI === 1) { alertService.add({ type: "danger", message: LOCALE.maketext("The system failed to query “[_1]” for order item [asis,ID] “[_2]” ([_3]) because of the following error: [_4]", _.escape(step.provider), _.escape(oiid), _.escape(vhostName), errorHTML), closeable: true, replace: false, group: "tlsWizard", }); } else { // should never happen alertService.add({ type: "danger", message: "Unknown index: " + promiseI, closeable: true, replace: false, group: "tlsWizard", }); } LocationService.go_to_last_create_route(); } ); }); }); }); } else { var errorHTML = response.error; alertService.add({ type: "danger", message: LOCALE.maketext("The system failed to begin polling for [quant,_2,new certificate,new certificates] because of an error: [_1]", errorHTML, $scope.certificates_count) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); } }); // get info from local storage } else { if (orderStatus === "error") { CertificatesService.reset(); CertificatesService.save(); $scope.return_to_wizard(); alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to complete your transaction.") + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); } else if (/^cancel?led$/.test(orderStatus)) { // cPStore gives two l’s var orderItemIDs = []; angular.forEach(order.certificates, function(cert) { orderItemIDs.push(cert.order_item_id); }); alertService.add({ type: "warn", message: LOCALE.maketext("You seem to have canceled your transaction.") + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); $location.url($location.path()); // clear out the params so we do not get a cancel on subsequent orders CertificatesService.cancel_pending_ssl_certificates(step.provider, orderItemIDs).then(function() { /* need to clear old unused in page data to get a fresh load */ CertificatesService.reset(); CertificatesService.save(); $scope.return_to_wizard(); }, function(errorHTML) { alertService.add({ type: "danger", message: LOCALE.maketext("The system encountered an error as it attempted to cancel your transaction: [_1]", errorHTML) + " " + LOCALE.maketext("You will now return to the beginning of the wizard."), closeable: true, replace: false, group: "tlsWizard", }); }); } return false; } } else if (step.step === "checkout_complete") { // go next step or to done page if (!nextStep) { CertificatesService.reset(); CertificatesService.save(); // done alertService.add({ type: "success", message: LOCALE.maketext("The system has completed the [numerate,_1,purchase,purchases] and will begin to poll for your [numerate,_2,certificate,certificates].", $scope.providers.length, $scope.certificates_count), closeable: true, replace: false, autoClose: 10000, group: "tlsWizard", }); $timeout($scope.go_to_pending, 1000); } } }; $scope.return_to_wizard = function() { var curURL = $location.absUrl(); // force reset for specific cases, use path redirect otherwise; // this allows us to not clear growl notifications if we don't have to. // could be replaced with replaceState if we ever get to IE11 if ($scope.get_param("code")) { var newURL = curURL.replace(/([^#?]+\/).*/, "$1#" + LocationService.last_create_route()); $window.location.href = newURL; } else { LocationService.go_to_last_create_route(); } }; $scope.check_step_success = function(stepIndex) { if (stepIndex < $scope.current_step_index) { return true; } }; $scope.go_step = function(provider, step, params) { $location.path("/purchase/" + provider + "/" + step + "/"); if (params) { $location.search(params); } }; $scope.get_providers = function() { $scope.providers = []; var steps; $scope.purchasing_certs.forEach(function(cert) { var product = cert.get_product(); var provider = $scope.get_provider_by_name(product.provider); if (!provider) { provider = { name: product.provider, display_name: product.provider_display_name || product.provider, certificates: [], }; $scope.providers.push(provider); steps = $scope.get_steps(provider.name); angular.forEach(steps, function(step) { $scope.steps.push({ provider: provider.name, step: step, }); }); } provider.certificates.push(cert); $scope.certificates_count++; }); return $scope.providers; }; $scope.go_to_pending = function(orderItemID) { if (orderItemID) { $location.path("/pending-certificates/").search("orderItemID", orderItemID); } else { $location.path("/pending-certificates"); } }; $scope.pending_certificate = function(virtualHost) { var result = false; angular.forEach($scope.pending_certificates, function(pcert) { angular.forEach(pcert.vhost_names, function(vhostName) { if (vhostName === virtualHost.display_name) { result = pcert.order_item_id; } }); }); return result; }; $scope.view_pending_certificate = function(virtualHost) { var orderItemID = $scope.pending_certificate(virtualHost); $scope.go_to_pending(orderItemID); }; $scope.begin = function() { // Only the “Simple” screen populates this. $scope.purchasing_certs = CertificatesService.get_purchasing_certs(); if ($scope.purchasing_certs.length === 0) { // The “Advanced” screen goes here, as does a resumed checkout. CertificatesService.get_virtual_hosts().filter( function(vhost) { if (!vhost.has_selected_domains()) { return false; } var product = vhost.get_product(); if (!product) { $log.warn("has selected, but no product?"); return false; } if (!CertificatesService.get_product_by_id(product.provider, product.id)) { $log.warn("Unknown product!", product); return false; } return true; }).forEach(function(virtualHost) { var product = virtualHost.get_product(); var cert = new Certificate(); cert.set_product(product); cert.set_price(virtualHost.get_price()); cert.set_domains(virtualHost.get_selected_domains()); cert.set_virtual_hosts([virtualHost.display_name]); if (product.x_identity_verification) { var idVer = virtualHost.get_identity_verification(); // It’s ok if we don’t have the idver because // that means we’re resuming a checkout, which // means that the idver is already sent in, and // the only reason we’re assembling cert/vhost/etc. // is so that the controller can quantify the // domains propertly in localization. if (idVer) { cert.set_identity_verification(idVer); } } CertificatesService.add_new_certificate(cert); }); $scope.purchasing_certs = CertificatesService.get_purchasing_certs(); } if ($scope.purchasing_certs.length === 0) { $location.path("/create"); return; } $scope.initialized = true; $scope.get_providers(); $scope.current_provider_name = $routeParams.provider; $scope.current_step_id = $routeParams.step; $scope.current_step_index = $scope.get_step_index($scope.current_provider_name, $scope.current_step_id); $scope.do_current_step(); $timeout(function() { _resizedWindow(); }, 1); }; $scope.init = function() { CertificatesService.restore(); $scope.begin(); }; function _resizedWindow() { $(".checkout-step-inner").each(function(index, block) { block = $(block); var wrapper = block.find(".content-wrapper"); var padding = (block.height() - wrapper.height()) / 2; wrapper.css("padding-top", padding); }); } var window = angular.element($window); window.bind("resize", _resizedWindow); $scope.init(); } app.controller("CheckoutController", [ "$scope", "$controller", "$location", "$filter", "$routeParams", "$window", "$timeout", "CertificatesService", "spinnerAPI", "$q", "$uibModal", "$log", "Certificate", "LocationService", "alertService", CheckoutController]); } );
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings