[%
USE ExpVar;
SET CPANEL.CPVAR.dprefix = '../';
USE CPList;
USE NVData;
SET ssl_capable_domains = execute_or_die('WebVhosts', 'list_ssl_capable_domains').data;
SET installable_domains = ssl_capable_domains.ofeach('domain');
SET domain_proxies = {};
FOR ssl_d = ssl_capable_domains;
NEXT IF !ssl_d.is_proxy;
SET proxy_minus_label = ssl_d.domain.replace('^[^.]+\.','');
SET label = ssl_d.domain.replace('^([^.]+).+','$1');
IF domain_proxies.$proxy_minus_label;
domain_proxies.$proxy_minus_label.push(label);
ELSE;
domain_proxies.$proxy_minus_label = [ label ];
END;
END;
#We’ll assemble this below: it’s like domain_proxies but also contains
#“regular” aliases www/mail/etc.
SET domain_aliases = {};
#Domains
#The display_domains array contains a list of all of the user-created domains,
#exclusive of auto-created subdomains like proxies and www/mail.
#Create a mock entry for the account’s main domain.
SET display_domains = [ {
domain => ExpVar.expand('$CPDATA{DOMAIN}'),
web_subdomain_aliases => execute_or_die('DomainInfo', 'main_domain_builtin_subdomain_aliases').data,
} ];
display_domains = display_domains.import(
Api2.exec_or_die( 'SubDomain', 'listsubdomains' ),
Api2.exec_or_die( 'AddonDomain', 'listaddondomains' ),
Api2.exec_or_die( 'Park', 'listparkeddomains' ),
);
SET installed_hosts_api_call = execute_or_die('SSL', 'installed_hosts');
SET installed_hosts = installed_hosts_api_call.data();
SET safe_ip = ExpVar.expand('$ip');
IF RAW_FORM.id;
SET cert_info = execute('SSL', 'fetch_cert_info', { id => RAW_FORM.id });
END;
SET market_products = execute('Market', 'get_all_products', {
'api.filter'=>1,
'api.filter_term_0'=>'ssl_certificate',
'api.filter_type_0'=>'eq',
'api.filter_column_0'=>'product_group',
'api.filter_column_1'=>'enabled',
'api.filter_type_1'=>'eq',
'api.filter_term_1'=>'1',
}).data;
%]
[% css_code = PROCESS css_block %]
[% js_code = PROCESS js_block %]
[% WRAPPER '_assets/master.html.tt'
app_key = 'ssl_tls'
include_legacy_scripts = 1
include_cjt = 1
page_js = js_code
page_styles = css_code
embed_stylesheets = ["css/ssl.css"]
page_stylesheets = ['css2-min/ssl/install.css', 'css2-min/ssl/list-certs.css']
-%]
[% INCLUDE _assets/_ajaxapp_header.html.tt %]
<div class="body-content">
<h2 id="hdrManageHosts">
[% locale.maketext('Manage SSL Hosts') %]
</h2>
[% IF !CPANEL.feature('sslinstall') || !ExpVar.expand('$isallowedssl') -%]
<div id="notAvailableError" class="alert alert-danger">
<span id="notAvailableErrorImg" class="glyphicon glyphicon-remove-sign"></span>
<div id="notAvailableErrorMsg" class="alert-message">
[% locale.maketext('This feature is not available to your account.') -%]
</div>
</div>
[% ELSE -%]
<p id="descInterface" class="description">[% locale.maketext('This interface lets you configure SSL for your domains.') %]</p>
<p id="descAboutCert" class="description">[% locale.maketext('An SSL certificate can secure one or more domains; to create an SSL host for a domain, you must have a certificate that secures that domain. Each SSL certificate has a matching key file that must also be present to install the certificate. SSL certificates for production use usually also require a [output,acronym,CA,Certificate Authority] bundle, which this page will automatically try to obtain from the server; in the event that the server cannot find the required CA bundle, you will need to paste it here.') %]</p>
</p>
[% IF ExpVar.expand('$hasdedicatedip') -%]
<p>[% locale.maketext('[output,strong,Note:] You don’t have a dedicated IP address. Browsers that were released before 2013 may not support [output,abbr,SNI,Server Name Indication]. Because of this, users may see false security warnings when they visit your SSL-secured websites.') %]</p>
[% END -%]
<div id="cjt_pagenotice_container"></div>
<div id="installed_ssl_hosts_area" class="ssl-table-area no-hosts-installed">
<h2 id="hdrInstalledWebsites" class="page-section-header">[% locale.maketext('Manage Installed SSL Websites') %]</h2>
<div id="installed_ssl_hosts_table" class="sortable"></div>
</div>
<h2 id="hdrInstallWebsite">[% locale.maketext('Install an SSL Website') %]</h2>
<a id="linkInstaller" name="installer"></a>
<div class="section">
<div id="sni_warning_container"></div>
<div id="wildcard_subdomain_warning"></div>
<div id="autofill_message_container"></div>
</div>
<div class="section">
<form id="mainform" action="javascript:void(0)" name="mainform" method="post" enctype="multipart/form-data">
<input id="hidIp" type="hidden" name="ip" value="[% safe_ip %]">
<div class="form-group">
<input type="button" class="btn btn-primary" id="sslbrowse" value="[% locale.maketext('Browse Certificates') %]">
</div>
<div class="form-group">
<label id="lblSSLDomain" for="ssldomain">[% locale.maketext('Domain') %]</label>
<div class="row">
<div class="col-xs-4">
<select id="ssldomain" name="domain" class="form-control">
<option value="">[% locale.maketext("Select a Domain") %]</option>
[% FOREACH dom = display_domains.sort('domain'); %]
[% SET aliases = []; -%]
[% IF dom.web_subdomain_aliases.size || domain_proxies.${dom.domain} %]
[%
aliases = aliases.import(
dom.web_subdomain_aliases,
domain_proxies.${dom.domain},
);
-%]
<option value="[% dom.domain FILTER html %]">[% dom.domain FILTER html %] (+ [% locale.maketext('[numerate,_1,subdomain,subdomains]: [join,~, ,_2]', aliases.size, aliases.sort()).html() %])</option>
[% ELSE %]
<option value="[% dom.domain FILTER html %]">[% dom.domain FILTER html %]</option>
[% END %]
[% SET domain_aliases.${dom.domain} = aliases; -%]
[% END %]
</select>
</div>
<div class="col-xs-4">
<input type="button" id="fetch-domain" value="[% locale.maketext('Autofill by Domain') %]" title="[% locale.maketext('Fill this form’s other fields with values that match this domain.') %]" class="btn btn-primary" style="display:none;">
</div>
<div class="col-xs-4">
<div id="ssldomain_error"></div>
</div>
</div>
</div>
<div class="form-group">
<label id="lblIp" for="ip">[% locale.maketext('IP Address') %]</label>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<span>[% safe_ip %]</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6"></div>
</div>
</div>
<div class="form-group">
<label id="lblCrt" for="sslcrt">[% locale.maketext('Certificate: ([output,asis,CRT])') %]</label>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<textarea id="sslcrt" rows="10" name="crt" class="textarea-base64 form-control" dir="ltr">[% cert_info.data.certificate -%]</textarea>
<div id="cert_parse" class="textarea-parse"></div>
<div class="help-block">[% locale.maketext('The certificate may already be on your server. You can either paste the certificate here or try to retrieve it for your domain.') %]</div>
</div>
<div class="col-xs-4">
<div style="padding-bottom: 10px;">
<input type="button" id="fetch-cert" value="[% locale.maketext('Autofill by Certificate') %]" title="[% locale.maketext('Fill this form’s other fields with values that match this certificate.') %]" class="btn btn-primary" style="display:none;">
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<div id="sslcrt_error"></div>
</div>
</div>
</div>
<div class="form-group">
<label id="lblKey" for="sslkey">[% locale.maketext('Private Key ([output,asis,KEY])') %]</label>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<textarea id="sslkey" class="textarea-base64 form-control" rows="10" name="key" dir="ltr">[% cert_info.data.key -%]</textarea>
<div class="help-block">[% locale.maketext('The private key may already be on your server. You can either paste the private key here or try to retrieve the matching key for your certificate.') %]</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<div id="sslkey_error"></div>
</div>
</div>
</div>
<div class="form-group">
<label id="lblCab" for="sslcab">[% locale.maketext('Certificate Authority Bundle: ([output,asis,CABUNDLE])') %]</label>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<textarea id="sslcab" rows="10" class="textarea-base64 form-control" name="cabundle" dir="ltr">[% cert_info.data.cabundle -%]</textarea>
<div class="help-block">[% locale.maketext('In most cases, you do not need to supply the CA bundle because the server will fetch it from a public repository during installation.') %]</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<div id="sslcab_error"></div>
</div>
</div>
</div>
<div class="form-group">
<input id="btnInstall" type="submit" value="[% locale.maketext("Install Certificate") %]" class="btn btn-primary" title="[% locale.maketext('Click to install the certificate on your site.') %]" />
<input type="reset" class="btn btn-default" value="[% locale.maketext("Reset") %]" id="sslreset">
</div>
</form>
</div>
[% INCLUDE _assets/return_link.html.tt return_location='index.html' return_link_text=locale.maketext('Return to SSL Manager') %]
</div><!-- end body-content -->
<script id="ssl-install-require-template" type="text/html">
[% locale.maketext('You may only create SSL hosts for domains that are currently attached to your account.') %]
[% SET $domains_link = '<a href="../domains/index.html">' _ locale.maketext('Domains') _ '</a>' %]
[% locale.maketext('Before you install an SSL certificate for a domain that is not listed below, you must go to the [_1] page and attach the domain to your account.', $domains_link) %]
</script>
<script id="ssl_hosts_action_template" type="text/x-handlebars-template">
<div class="action-links">
{{#if can_be_set_primary}}
<a href="javascript:void(0)" class="make-primary-link">[% locale.maketext('Make Primary') %]</a>
<span class="link-spacer"></span>
{{/if}}
<a href="javascript:void(0)" class="uninstall-link">[% locale.maketext('Uninstall') %]</a>
<span class="link-spacer"></span>
<a href="javascript:void(0)" class="update-link">[% locale.maketext('Update Certificate') %]</a>
<span class="link-spacer"></span>
<a id="{{certificate_id}}_DetailsLink" href="javascript:void(0)" class="details-link">[% locale.maketext('Certificate Details') %]</a>
<span class="link-spacer"></span>
<a href="javascript:void(0)" class="new-host-link">[% locale.maketext('Use Certificate for New Site') %]</a>
</div>
</script>
<script id="document_root_template" type="text/x-handlebars-template">
<div class="document-root">
<span class="fas fa-home"></span>{{{documentRoot}}}
</div>
</script>
<!-- needed for javascript -->
<div id="sdiv"></div>
[% PROCESS _assets/_ajaxapp_footer.html.tt -%]
[% END #feature check -%]
[% END #wrapper %]
[% BLOCK css_block %]
<style type="text/css">
[% INSERT 'sharedcss/sslinstall_optimized.css' %]
[% INSERT 'sharedcss/ssltable_optimized.css' %]
[% INSERT 'yui/datatable/assets/datatable-core.css' %]
[% INSERT 'yui/datatable/assets/datatable.css' %]
</style>
[% END #css_block %]
[% BLOCK js_block %]
<script type="text/javascript">
[% SET lexicon = {
'SSL/TLS Manager: Manage SSL Hosts' => locale.lextext('SSL/TLS Manager: Manage SSL Hosts'),
'Manage SSL Hosts' => locale.lextext('Manage SSL Hosts'),
'This interface lets you configure SSL for your domains.' => locale.lextext('This interface lets you configure SSL for your domains.'),
'An SSL certificate can secure one or more domains; to create an SSL host for a domain, you must have a certificate that secures that domain. Each SSL certificate has a matching key file that must also be present to install the certificate. SSL certificates for production use usually also require a [output,abbr,CA,Certificate Authority] bundle, which this page will automatically try to obtain from the server; in the event that the server cannot find the required CA bundle, you will need to paste it here.' => locale.lextext('An SSL certificate can secure one or more domains; to create an SSL host for a domain, you must have a certificate that secures that domain. Each SSL certificate has a matching key file that must also be present to install the certificate. SSL certificates for production use usually also require a [output,abbr,CA,Certificate Authority] bundle, which this page will automatically try to obtain from the server; in the event that the server cannot find the required CA bundle, you will need to paste it here.'),
'Manage Installed SSL Hosts' => locale.lextext('Manage Installed SSL Hosts'),
'Browse Certificates' => locale.lextext('Browse Certificates'),
'Domain:' => locale.lextext('Domain:'),
'SSLSelectDomain' => locale.lextext('Select a Domain'),
'Autofill by Domain' => locale.lextext('Autofill by Domain'),
'Fill this form’s other fields with values that match this domain.' => locale.lextext('Fill this form’s other fields with values that match this domain.'),
'IP Address:' => locale.lextext('IP Address:'),
'Certificate: ([output,asis,CRT])' => locale.lextext('Certificate: ([output,asis,CRT])'),
'Autofill by Certificate' => locale.lextext('Autofill by Certificate'),
'Fill this form’s other fields with values that match this certificate.' => locale.lextext('Fill this form’s other fields with values that match this certificate.'),
'The certificate may already be on your server. You can either paste the certificate here or try to retrieve it for your domain.' => locale.lextext('The certificate may already be on your server. You can either paste the certificate here or try to retrieve it for your domain.'),
'Private Key: ([output,asis,KEY])' => locale.lextext('Private Key: ([output,asis,KEY])'),
'The private key may already be on your server. You can either paste the private key here or try to retrieve the matching key for your certificate.' => locale.lextext('The private key may already be on your server. You can either paste the private key here or try to retrieve the matching key for your certificate.'),
'Certificate Authority Bundle: ([output,asis,CABUNDLE])' => locale.lextext('Certificate Authority Bundle: ([output,asis,CABUNDLE])'),
'In most cases, you do not need to supply the CA bundle because the server will fetch it from a public repository during installation.' => locale.lextext('In most cases, you do not need to supply the CA bundle because the server will fetch it from a public repository during installation.'),
'SSLInstallCert' => locale.lextext('Install Certificate'),
'Click to install the certificate on your site.' => locale.lextext('Click to install the certificate on your site.'),
'SSLReturn' => locale.lextext('Return to SSL Manager'),
'Processing …' => locale.lextext('Processing …'),
'Make Primary' => locale.lextext('Make Primary'),
'Update SSL' => locale.lextext('Update SSL'),
'Uninstall' => locale.lextext('Uninstall'),
'Certificate Details' => locale.lextext('Certificate Details'),
'Use Certificate for New Site' => locale.lextext('Use Certificate for New Site'),
'Browse Certificates' => locale.lextext('Browse Certificates'),
'Optional' => locale.lextext('Optional'),
'Click to install the certificate on your site.' => locale.lextext('Click to install the certificate on your site.'),
'Clear' => locale.lextext('Clear'),
'You may only create SSL hosts for domains that are currently attached to your account.' => locale.lextext('You may only create SSL hosts for domains that are currently attached to your account.'),
'Before you install an SSL certificate for a domain that is not listed below, you must go to the [_1] page and attach the domain to your account.' => locale.lextext('Before you install an SSL certificate for a domain that is not listed below, you must go to the [_1] page and attach the domain to your account.'),
'Main Domain' => locale.lextext('Main Domain')
'Actions' => locale.lextext('Actions'),
'Are you sure that you want to delete the SSL host “[_1]”? This operation cannot be undone!' => locale.lextext('Are you sure that you want to delete the SSL host “[_1]”? This operation cannot be undone!'),
'Certificate Expiration' => locale.lextext('Certificate Expiration'),
'Certificate ID' => locale.lextext('Certificate ID'),
'Certificate Key Size' => locale.lextext('Certificate Key Size'),
'Confirm SSL Host Delete' => locale.lextext('Confirm SSL Host Delete'),
'Deleting SSL host “[_1]” …' => locale.lextext('Deleting SSL host “[_1]” …'),
'Document Root' => locale.lextext('Document Root'),
'Domains' => locale.lextext('Domains'),
'IP Address' => locale.lextext('IP Address'),
'Is Primary Website on IP Address?' => locale.lextext('Is Primary Website on IP Address?'),
'Loading …' => locale.lextext('Loading …'),
'Is Web [output,acronym,SNI,Server Name Indication] Required?' => locale.lextext('Is Web [output,acronym,SNI,Server Name Indication] Required?'),
'No' => locale.lextext('No'),
'Setting “[_1]” as the primary SSL host on “[_2]” …' => locale.lextext('Setting “[_1]” as the primary SSL host on “[_2]” …'),
'The SSL host for “[_1]” has been removed.' => locale.lextext('The SSL host for “[_1]” has been removed.'),
'This host’s certificate does not secure this domain. Security warnings will show in users’ web browsers when loading this domain.' => locale.lextext('This host’s certificate does not secure this domain. Security warnings will show in users’ web browsers when loading this domain.'),
'This host’s certificate secures this domain.' => locale.lextext('This host’s certificate secures this domain.'),
'Yes' => locale.lextext('Yes'),
'[quant,_1,bit,bits]' => locale.lextext('[quant,_1,bit,bits]'),
'“[_1]” is now the primary SSL host on “[_2]”.' => locale.lextext('“[_1]” is now the primary SSL host on “[_2]”.'),
'Certificate ID:' => locale.lextext('Certificate ID:'),
'This website’s certificate does not secure this domain.' => locale.lextext('This website’s certificate does not secure this domain.'),
'This website’s certificate secures “[_1]”.' => locale.lextext('This website’s certificate secures “[_1]”.'),
'You can only install this IP address’s active certificate onto another website with at least one domain that the certificate supports, or update the certificate for your currently installed SSL websites.' => locale.lextext('You can only install this IP address’s active certificate onto another website with at least one domain that the certificate supports, or update the certificate for your currently installed SSL websites.'),
'You cannot update the certificate unless the new certificate matches at least one domain for each SSL website on this IP address.' => locale.lextext('You cannot update the certificate unless the new certificate matches at least one domain for each SSL website on this IP address.'),
'To update the certificate on an existing SSL website will affect all of your SSL websites, and new SSL websites must use the currently installed certificate.' => locale.lextext('Updating the certificate on an existing SSL website will affect all of your SSL websites, and new SSL websites must use the currently installed certificate.'),
'[output,strong,Note:] You don’t have a dedicated IP address. Browsers that were released before 2013 may not support [output,abbr,SNI,Server Name Indication]. Because of this, users may see false security warnings when they visit your SSL-secured websites.' => locale.lextext('[output,strong,Note:] You don’t have a dedicated IP address. Browsers that were released before 2013 may not support [output,abbr,SNI,Server Name Indication]. Because of this, users may see false security warnings when they visit your SSL-secured websites.'),
'An update to the certificate on an existing SSL website will affect all of your SSL websites, and new SSL websites must use the currently installed certificate.' => locale.lextext('An update to the certificate on an existing SSL website will affect all of your SSL websites, and new SSL websites must use the currently installed certificate.'),
} -%]
YAHOO.lang.augmentObject( LOCALE.LEXICON, [% lexicon.json() %] );
[%
SET lex_path = CPANEL.get_js_lex_app_rel_path('sharedjs/form_submit_handler_optimized.js');
INSERT $lex_path IF lex_path;
INSERT 'sharedjs/form_submit_handler_optimized.js';
%]
(function() {
[% SET page_data = {
homedir => CPANEL.homedir,
installed_ssl_hosts => installed_hosts,
installable_domains => installable_domains,
dedicated_ip => ExpVar.expand('$hasdedicatedip') && safe_ip,
#domain_aliases gets added later since it’s not actually populated
#until later in the page.
} -%]
var PAGE = {
data : [% JSON.stringify(page_data) %],
nvdata : [% JSON.stringify( NVData.get_page_nvdata() || {} ) %],
cpmarket_can_sell_ssl: [% CPANEL.feature('tls_wizard') && market_products.size ? 'true' : 'false' %],
};
window.PAGE = PAGE;
/**
* Initialize the page
*
* @method initialize
* @private
*/
var initialize = function() {
//In case there are validation messages on page load.
CPANEL.align_panels_event.fire();
setTimeout(function(){
// Check for certificate "id" in url, auto-expand details if it exists.
var query = CPANEL.util.parse_query_string();
var detailsLink = document.getElementById(query.id + "_DetailsLink");
if(detailsLink){
detailsLink.click();
// Then we scroll to the detail block.
setTimeout(function(){
var detailBlock = document.getElementsByClassName("yui-dt-expansion");
if(detailBlock.length){
var firstBlock = detailBlock[0];
var bodyRect = document.body.getBoundingClientRect(),
elemRect = firstBlock.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
var rect = firstBlock.getBoundingClientRect();
window.scrollTo(0, offset - 50);
}
},500);
}
},500);
}
// Register startup events.
YAHOO.util.Event.onDOMReady(initialize);
}());
[%# Load these last; in particular, load them after window.PAGE is set. -%]
[% INSERT 'sharedjs/asn1_optimized.js' %]
[% INSERT 'cjt/ssl-min.js' %]
</script>
[% PROCESS 'ssl/ssl_certificate_parse.html.tt' -%]
[% PROCESS 'ssl/ssltable_include.html.tt' -%]
[% PROCESS 'ssl/sslinstall_include.html.tt' -%]
<script type="text/javascript">
[%
SET lex_path = CPANEL.get_js_lex_app_rel_path('sharedjs/sslwidgets_optimized.js');
INSERT $lex_path IF lex_path;
INSERT 'sharedjs/sslwidgets_optimized.js';
%]
[%
SET lex_path = CPANEL.get_js_lex_app_rel_path('sharedjs/ssltable_optimized.js');
INSERT $lex_path IF lex_path;
INSERT 'sharedjs/ssltable_optimized.js';
%]
[%
SET lex_path = CPANEL.get_js_lex_app_rel_path('sharedjs/sslinstall_optimized.js');
INSERT $lex_path IF lex_path;
INSERT 'sharedjs/sslinstall_optimized.js';
%]
[% INSERT 'yui/datasource/datasource-min.js' %]
[% INSERT 'cjt/yui-patch/datatable/datatable-min.js' %]
[% INSERT 'sharedjs/yui2_datatable_row_expansion_optimized.js' -%]
[%
SET lex_path = CPANEL.get_js_lex_app_rel_path('js2/ssl/install.js');
INSERT $lex_path IF lex_path;
INSERT 'js2/ssl/install.js';
%]
</script>
[% END #js_block %]
[%# See above for why this is here. %]
<script>
PAGE.data.domain_aliases = [% JSON.stringify(domain_aliases) %];
</script>