mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	Implements dns challenge provider selection in frontend
This commit is contained in:
		| @@ -21,21 +21,92 @@ | ||||
|                         </div> | ||||
|                     </div> | ||||
|  | ||||
|                     <!-- CloudFlare --> | ||||
|                     <!-- DNS challenge --> | ||||
|                     <div class="col-sm-12 col-md-12"> | ||||
|                         <div class="form-group"> | ||||
|                             <label class="custom-switch"> | ||||
|                                 <input type="checkbox" class="custom-switch-input" name="meta[cloudflare_use]" value="1"> | ||||
|                                 <input  | ||||
|                                     type="checkbox"  | ||||
|                                     class="custom-switch-input"  | ||||
|                                     name="meta[dns_challenge]"  | ||||
|                                     value="1"  | ||||
|                                     <%- getUseDnsChallenge() ? 'checked' : '' %> | ||||
|                                 > | ||||
|                                 <span class="custom-switch-indicator"></span> | ||||
|                                 <span class="custom-switch-description"><%= i18n('ssl', 'use-cloudflare') %></span> | ||||
|                                 <span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span> | ||||
|                             </label> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div class="col-sm-12 col-md-12 cloudflare"> | ||||
|                         <div class="form-group"> | ||||
|                             <label class="form-label">CloudFlare DNS API Token  <span class="form-required">*</span></label> | ||||
|                             <input type="text" name="meta[cloudflare_token]" class="form-control" id="cloudflare_token"> | ||||
|                         </div> | ||||
|                     <div class="col-sm-12 col-md-12"> | ||||
|                         <fieldset class="form-fieldset dns-challenge"> | ||||
|                             <div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div> | ||||
|  | ||||
|                             <!-- Certbot DNS plugin selection --> | ||||
|                             <div class="row"> | ||||
|                                 <div class="col-sm-12 col-md-12"> | ||||
|                                     <div class="form-group"> | ||||
|                                         <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label> | ||||
|                                         <select  | ||||
|                                             name="meta[dns_provider]"  | ||||
|                                             id="dns_provider" | ||||
|                                             class="form-control custom-select" | ||||
|                                         > | ||||
|                                             <option  | ||||
|                                                 value=""  | ||||
|                                                 disabled  | ||||
|                                                 hidden | ||||
|                                                 <%- getDnsProvider() === null ? 'selected' : '' %> | ||||
|                                             >Please Choose...</option> | ||||
|                                             <% _.each(dns_plugins, function(plugin_info, plugin_name){ %> | ||||
|                                             <option  | ||||
|                                                 value="<%- plugin_name %>" | ||||
|                                                 <%- getDnsProvider() === plugin_name ? 'selected' : '' %> | ||||
|                                             ><%- plugin_info.display_name %></option> | ||||
|                                             <% }); %> | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|  | ||||
|                             <!-- Certbot credentials file content --> | ||||
|                             <div class="row credentials-file-content"> | ||||
|                                 <div class="col-sm-12 col-md-12"> | ||||
|                                     <div class="form-group"> | ||||
|                                         <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label> | ||||
|                                         <textarea  | ||||
|                                             name="meta[dns_provider_credentials]"  | ||||
|                                             class="form-control text-monospace"  | ||||
|                                             id="dns_provider_credentials"  | ||||
|                                         ><%- getDnsProviderCredentials() %></textarea> | ||||
|                                         <div class="text-secondary small"> | ||||
|                                             <i class="fe fe-info"></i>  | ||||
|                                             <%= i18n('ssl', 'credentials-file-content-info') %> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|  | ||||
|                             <!-- DNS propagation delay --> | ||||
|                             <div class="row"> | ||||
|                                 <div class="col-sm-12 col-md-12"> | ||||
|                                     <div class="form-group mb-0"> | ||||
|                                         <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label> | ||||
|                                         <input  | ||||
|                                             type="number" | ||||
|                                             min="0" | ||||
|                                             name="meta[propagation_seconds]"  | ||||
|                                             class="form-control"  | ||||
|                                             id="propagation_seconds"  | ||||
|                                             value="<%- getPropagationSeconds() %>" | ||||
|                                         > | ||||
|                                         <div class="text-secondary small"> | ||||
|                                             <i class="fe fe-info"></i>  | ||||
|                                             <%= i18n('ssl', 'propagation-seconds-info') %> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </fieldset> | ||||
|                     </div> | ||||
|  | ||||
|                     <div class="col-sm-12 col-md-12"> | ||||
|   | ||||
| @@ -3,6 +3,8 @@ const Mn               = require('backbone.marionette'); | ||||
| const App              = require('../../main'); | ||||
| const CertificateModel = require('../../../models/certificate'); | ||||
| const template         = require('./form.ejs'); | ||||
| const i18n             = require('../../i18n'); | ||||
| const dns_providers    = require('../../../../../utils/certbot-dns-plugins'); | ||||
|  | ||||
| require('jquery-serializejson'); | ||||
| require('selectize'); | ||||
| @@ -21,25 +23,46 @@ module.exports = Mn.View.extend({ | ||||
|         other_certificate:                    '#other_certificate', | ||||
|         other_certificate_label:              '#other_certificate_label', | ||||
|         other_certificate_key:                '#other_certificate_key', | ||||
|         cloudflare_switch:                    'input[name="meta[cloudflare_use]"]', | ||||
|         cloudflare_token:                     'input[name="meta[cloudflare_token]"', | ||||
|         cloudflare:                           '.cloudflare', | ||||
|         dns_challenge_switch:                 'input[name="meta[dns_challenge]"]', | ||||
|         dns_challenge_content:                '.dns-challenge', | ||||
|         dns_provider:                         'select[name="meta[dns_provider]"]', | ||||
|         credentials_file_content:             '.credentials-file-content', | ||||
|         dns_provider_credentials:             'textarea[name="meta[dns_provider_credentials]"]', | ||||
|         propagation_seconds:                  'input[name="meta[propagation_seconds]"]', | ||||
|         other_certificate_key_label:          '#other_certificate_key_label', | ||||
|         other_intermediate_certificate:       '#other_intermediate_certificate', | ||||
|         other_intermediate_certificate_label: '#other_intermediate_certificate_label' | ||||
|     }, | ||||
|      | ||||
|     events: { | ||||
|         'change @ui.cloudflare_switch': function() { | ||||
|             let checked = this.ui.cloudflare_switch.prop('checked'); | ||||
|             if (checked) {                 | ||||
|                 this.ui.cloudflare_token.prop('required', 'required'); | ||||
|                 this.ui.cloudflare.show(); | ||||
|             } else {                 | ||||
|                 this.ui.cloudflare_token.prop('required', false); | ||||
|                 this.ui.cloudflare.hide();                 | ||||
|         'change @ui.dns_challenge_switch': function () { | ||||
|             const checked = this.ui.dns_challenge_switch.prop('checked'); | ||||
|             if (checked) { | ||||
|                 this.ui.dns_provider.prop('required', 'required'); | ||||
|                 const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|                 if(selected_provider != '' && dns_providers[selected_provider].credentials !== false){ | ||||
|                     this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 } | ||||
|                 this.ui.dns_challenge_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider.prop('required', false); | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.dns_challenge_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.dns_provider': function () { | ||||
|             const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|             if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) { | ||||
|                 this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials; | ||||
|                 this.ui.credentials_file_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.credentials_file_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|          | ||||
|         'click @ui.save': function (e) { | ||||
|             e.preventDefault(); | ||||
|  | ||||
| @@ -56,7 +79,7 @@ module.exports = Mn.View.extend({ | ||||
|  | ||||
|  | ||||
|             let domain_err = false; | ||||
|             if (!data.meta.cloudflare_use) {                 | ||||
|             if (!data.meta.dns_challenge) {                 | ||||
|                 data.domain_names.split(',').map(function (name) { | ||||
|                     if (name.match(/\*/im)) { | ||||
|                         domain_err = true; | ||||
| @@ -65,7 +88,7 @@ module.exports = Mn.View.extend({ | ||||
|             } | ||||
|  | ||||
|             if (domain_err) { | ||||
|                 alert('Cannot request Let\'s Encrypt Certificate for wildcard domains when not using CloudFlare DNS'); | ||||
|                 alert(i18n('ssl', 'no-wildcard-without-dns')); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| @@ -73,8 +96,9 @@ module.exports = Mn.View.extend({ | ||||
|             if (typeof data.meta !== 'undefined' && typeof data.meta.letsencrypt_agree !== 'undefined') { | ||||
|                 data.meta.letsencrypt_agree = !!data.meta.letsencrypt_agree; | ||||
|             } | ||||
|             if (typeof data.meta !== 'undefined' && typeof data.meta.cloudflare_use !== 'undefined') { | ||||
|                 data.meta.cloudflare_use = !!data.meta.cloudflare_use; | ||||
|  | ||||
|             if (typeof data.meta !== 'undefined' && typeof data.meta.dns_challenge !== 'undefined') { | ||||
|                 data.meta.dns_challenge = !!data.meta.dns_challenge; | ||||
|             } | ||||
|  | ||||
|             if (typeof data.domain_names === 'string' && data.domain_names) { | ||||
| @@ -176,14 +200,22 @@ module.exports = Mn.View.extend({ | ||||
|         getLetsencryptEmail: function () { | ||||
|             return typeof this.meta.letsencrypt_email !== 'undefined' ? this.meta.letsencrypt_email : App.Cache.User.get('email'); | ||||
|         }, | ||||
|  | ||||
|         getLetsencryptAgree: function () { | ||||
|             return typeof this.meta.letsencrypt_agree !== 'undefined' ? this.meta.letsencrypt_agree : false; | ||||
|         }, | ||||
|  | ||||
|         getCloudflareUse: function () { | ||||
|             return typeof this.meta.cloudflare_use !== 'undefined' ? this.meta.cloudflare_use : false; | ||||
|         } | ||||
|         getUseDnsChallenge: function () { | ||||
|             return typeof this.meta.dns_challenge !== 'undefined' ? this.meta.dns_challenge : false; | ||||
|         }, | ||||
|         getDnsProvider: function () { | ||||
|             return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null; | ||||
|         }, | ||||
|         getDnsProviderCredentials: function () { | ||||
|             return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : ''; | ||||
|         }, | ||||
|         getPropagationSeconds: function () { | ||||
|             return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : ''; | ||||
|         }, | ||||
|         dns_plugins: dns_providers, | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
| @@ -199,7 +231,8 @@ module.exports = Mn.View.extend({ | ||||
|             }, | ||||
|             createFilter: /^(?:[^.]+\.?)+[^.]$/ | ||||
|         }); | ||||
|         this.ui.cloudflare.hide(); | ||||
|         this.ui.dns_challenge_content.hide(); | ||||
|         this.ui.credentials_file_content.hide();  | ||||
|     }, | ||||
|  | ||||
|     initialize: function (options) { | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
|     </div> | ||||
| </td> | ||||
| <td> | ||||
|     <%- i18n('ssl', provider) %><% if (meta.cloudflare_use) { %> - CloudFlare DNS<% } %> | ||||
|     <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <% dns_providers[meta.dns_provider].display_name } %> | ||||
| </td> | ||||
| <td class="<%- isExpired() ? 'text-danger' : '' %>"> | ||||
|     <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %> | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| const Mn       = require('backbone.marionette'); | ||||
| const moment   = require('moment'); | ||||
| const App      = require('../../../main'); | ||||
| const template = require('./item.ejs'); | ||||
| const Mn            = require('backbone.marionette'); | ||||
| const moment        = require('moment'); | ||||
| const App           = require('../../../main'); | ||||
| const template      = require('./item.ejs'); | ||||
| const dns_providers = require('../../../../../../utils/certbot-dns-plugins') | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     template: template, | ||||
| @@ -35,7 +36,8 @@ module.exports = Mn.View.extend({ | ||||
|         canManage: App.Cache.User.canManage('certificates'), | ||||
|         isExpired: function () { | ||||
|             return moment(this.expires_on).isBefore(moment()); | ||||
|         } | ||||
|         }, | ||||
|         dns_providers: dns_providers | ||||
|     }, | ||||
|  | ||||
|     initialize: function () { | ||||
|   | ||||
| @@ -73,21 +73,92 @@ | ||||
|                             </div> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- CloudFlare --> | ||||
|                         <!-- DNS challenge --> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="custom-switch"> | ||||
|                                     <input type="checkbox" class="custom-switch-input" name="meta[cloudflare_use]" value="1"> | ||||
|                                     <input  | ||||
|                                         type="checkbox"  | ||||
|                                         class="custom-switch-input"  | ||||
|                                         name="meta[dns_challenge]"  | ||||
|                                         value="1"  | ||||
|                                         <%- getUseDnsChallenge() ? 'checked' : '' %> | ||||
|                                     > | ||||
|                                     <span class="custom-switch-indicator"></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'use-cloudflare') %></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span> | ||||
|                                 </label> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="col-sm-12 col-md-12 cloudflare letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="form-label">CloudFlare DNS API Token  <span class="form-required">*</span></label> | ||||
|                                 <input type="text" name="meta[cloudflare_token]" class="form-control" id="cloudflare_token"> | ||||
|                             </div> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <fieldset class="form-fieldset dns-challenge"> | ||||
|                                 <div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div> | ||||
|  | ||||
|                                 <!-- Certbot DNS plugin selection --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label> | ||||
|                                             <select  | ||||
|                                                 name="meta[dns_provider]"  | ||||
|                                                 id="dns_provider" | ||||
|                                                 class="form-control custom-select" | ||||
|                                             > | ||||
|                                                 <option  | ||||
|                                                     value=""  | ||||
|                                                     disabled  | ||||
|                                                     hidden | ||||
|                                                     <%- getDnsProvider() === null ? 'selected' : '' %> | ||||
|                                                 >Please Choose...</option> | ||||
|                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %> | ||||
|                                                 <option  | ||||
|                                                     value="<%- plugin_name %>" | ||||
|                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %> | ||||
|                                                 ><%- plugin_info.display_name %></option> | ||||
|                                                 <% }); %> | ||||
|                                             </select> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- Certbot credentials file content --> | ||||
|                                 <div class="row credentials-file-content"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label> | ||||
|                                             <textarea  | ||||
|                                                 name="meta[dns_provider_credentials]"  | ||||
|                                                 class="form-control text-monospace"  | ||||
|                                                 id="dns_provider_credentials"  | ||||
|                                             ><%- getDnsProviderCredentials() %></textarea> | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'credentials-file-content-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- DNS propagation delay --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group mb-0"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label> | ||||
|                                             <input  | ||||
|                                                 type="number" | ||||
|                                                 min="0" | ||||
|                                                 name="meta[propagation_seconds]"  | ||||
|                                                 class="form-control"  | ||||
|                                                 id="propagation_seconds"  | ||||
|                                                 value="<%- getPropagationSeconds() %>" | ||||
|                                             > | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'propagation-seconds-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </fieldset> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- Lets encrypt --> | ||||
|   | ||||
| @@ -4,6 +4,8 @@ const DeadHostModel        = require('../../../models/dead-host'); | ||||
| const template             = require('./form.ejs'); | ||||
| const certListItemTemplate = require('../certificates-list-item.ejs'); | ||||
| const Helpers              = require('../../../lib/helpers'); | ||||
| const i18n                 = require('../../i18n'); | ||||
| const dns_providers        = require('../../../../../utils/certbot-dns-plugins'); | ||||
|  | ||||
| require('jquery-serializejson'); | ||||
| require('selectize'); | ||||
| @@ -13,20 +15,23 @@ module.exports = Mn.View.extend({ | ||||
|     className: 'modal-dialog', | ||||
|  | ||||
|     ui: { | ||||
|         form:               'form', | ||||
|         domain_names:       'input[name="domain_names"]', | ||||
|         buttons:            '.modal-footer button', | ||||
|         cancel:             'button.cancel', | ||||
|         save:               'button.save', | ||||
|         certificate_select: 'select[name="certificate_id"]', | ||||
|         ssl_forced:         'input[name="ssl_forced"]', | ||||
|         hsts_enabled:       'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:    'input[name="hsts_subdomains"]', | ||||
|         http2_support:      'input[name="http2_support"]', | ||||
|         cloudflare_switch:  'input[name="meta[cloudflare_use]"]', | ||||
|         cloudflare_token:   'input[name="meta[cloudflare_token]"', | ||||
|         cloudflare:         '.cloudflare', | ||||
|         letsencrypt:        '.letsencrypt' | ||||
|         form:                     'form', | ||||
|         domain_names:             'input[name="domain_names"]', | ||||
|         buttons:                  '.modal-footer button', | ||||
|         cancel:                   'button.cancel', | ||||
|         save:                     'button.save', | ||||
|         certificate_select:       'select[name="certificate_id"]', | ||||
|         ssl_forced:               'input[name="ssl_forced"]', | ||||
|         hsts_enabled:             'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:          'input[name="hsts_subdomains"]', | ||||
|         http2_support:            'input[name="http2_support"]', | ||||
|         dns_challenge_switch:     'input[name="meta[dns_challenge]"]', | ||||
|         dns_challenge_content:    '.dns-challenge', | ||||
|         dns_provider:             'select[name="meta[dns_provider]"]', | ||||
|         credentials_file_content: '.credentials-file-content', | ||||
|         dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]', | ||||
|         propagation_seconds:      'input[name="meta[propagation_seconds]"]', | ||||
|         letsencrypt:              '.letsencrypt' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
| @@ -34,7 +39,7 @@ module.exports = Mn.View.extend({ | ||||
|             let id = this.ui.certificate_select.val(); | ||||
|             if (id === 'new') { | ||||
|                 this.ui.letsencrypt.show().find('input').prop('disabled', false); | ||||
|                 this.ui.cloudflare.hide(); | ||||
|                 this.ui.dns_challenge_content.hide(); | ||||
|             } else { | ||||
|                 this.ui.letsencrypt.hide().find('input').prop('disabled', true); | ||||
|             } | ||||
| @@ -81,14 +86,31 @@ module.exports = Mn.View.extend({ | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.cloudflare_switch': function() { | ||||
|             let checked = this.ui.cloudflare_switch.prop('checked'); | ||||
|             if (checked) {                 | ||||
|                 this.ui.cloudflare_token.prop('required', 'required'); | ||||
|                 this.ui.cloudflare.show(); | ||||
|             } else {                 | ||||
|                 this.ui.cloudflare_token.prop('required', false); | ||||
|                 this.ui.cloudflare.hide();                 | ||||
|         'change @ui.dns_challenge_switch': function () { | ||||
|             const checked = this.ui.dns_challenge_switch.prop('checked'); | ||||
|             if (checked) { | ||||
|                 this.ui.dns_provider.prop('required', 'required'); | ||||
|                 const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|                 if(selected_provider != '' && dns_providers[selected_provider].credentials !== false){ | ||||
|                     this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 } | ||||
|                 this.ui.dns_challenge_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider.prop('required', false); | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.dns_challenge_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.dns_provider': function () { | ||||
|             const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|             if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) { | ||||
|                 this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials; | ||||
|                 this.ui.credentials_file_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.credentials_file_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
| @@ -104,10 +126,11 @@ module.exports = Mn.View.extend({ | ||||
|             let data = this.ui.form.serializeJSON(); | ||||
|  | ||||
|             // Manipulate | ||||
|             data.hsts_enabled    = !!data.hsts_enabled; | ||||
|             data.hsts_subdomains = !!data.hsts_subdomains; | ||||
|             data.http2_support   = !!data.http2_support; | ||||
|             data.ssl_forced      = !!data.ssl_forced; | ||||
|             data.hsts_enabled       = !!data.hsts_enabled; | ||||
|             data.hsts_subdomains    = !!data.hsts_subdomains; | ||||
|             data.http2_support      = !!data.http2_support; | ||||
|             data.ssl_forced         = !!data.ssl_forced; | ||||
|             data.meta.dns_challenge = !!data.meta.dns_challenge; | ||||
|  | ||||
|             if (typeof data.domain_names === 'string' && data.domain_names) { | ||||
|                 data.domain_names = data.domain_names.split(','); | ||||
| @@ -116,7 +139,7 @@ module.exports = Mn.View.extend({ | ||||
|             // Check for any domain names containing wildcards, which are not allowed with letsencrypt | ||||
|             if (data.certificate_id === 'new') {                 | ||||
|                 let domain_err = false; | ||||
|                 if (!data.meta.cloudflare_use) { | ||||
|                 if (!data.meta.dns_challenge) { | ||||
|                     data.domain_names.map(function (name) { | ||||
|                         if (name.match(/\*/im)) { | ||||
|                             domain_err = true; | ||||
| @@ -125,11 +148,10 @@ module.exports = Mn.View.extend({ | ||||
|                 } | ||||
|  | ||||
|                 if (domain_err) { | ||||
|                     alert('Cannot request Let\'s Encrypt Certificate for wildcard domains without CloudFlare DNS.'); | ||||
|                     alert(i18n('ssl', 'no-wildcard-without-dns')); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 data.meta.cloudflare_use = data.meta.cloudflare_use === '1'; | ||||
|                 data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1';                 | ||||
|             } else { | ||||
|                 data.certificate_id = parseInt(data.certificate_id, 10); | ||||
| @@ -169,7 +191,20 @@ module.exports = Mn.View.extend({ | ||||
|     templateContext: { | ||||
|         getLetsencryptEmail: function () { | ||||
|             return App.Cache.User.get('email'); | ||||
|         } | ||||
|         }, | ||||
|         getUseDnsChallenge: function () { | ||||
|             return typeof this.meta.dns_challenge !== 'undefined' ? this.meta.dns_challenge : false; | ||||
|         }, | ||||
|         getDnsProvider: function () { | ||||
|             return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null; | ||||
|         }, | ||||
|         getDnsProviderCredentials: function () { | ||||
|             return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : ''; | ||||
|         }, | ||||
|         getPropagationSeconds: function () { | ||||
|             return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : ''; | ||||
|         }, | ||||
|         dns_plugins: dns_providers, | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
| @@ -190,6 +225,8 @@ module.exports = Mn.View.extend({ | ||||
|         }); | ||||
|  | ||||
|         // Certificates | ||||
|         this.ui.dns_challenge_content.hide(); | ||||
|         this.ui.credentials_file_content.hide(); | ||||
|         this.ui.letsencrypt.hide(); | ||||
|         this.ui.certificate_select.selectize({ | ||||
|             valueField:       'id', | ||||
|   | ||||
| @@ -141,21 +141,92 @@ | ||||
|                             </div> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- CloudFlare --> | ||||
|                         <!-- DNS challenge --> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="custom-switch"> | ||||
|                                     <input type="checkbox" class="custom-switch-input" name="meta[cloudflare_use]" value="1"> | ||||
|                                     <input  | ||||
|                                         type="checkbox"  | ||||
|                                         class="custom-switch-input"  | ||||
|                                         name="meta[dns_challenge]"  | ||||
|                                         value="1"  | ||||
|                                         <%- getUseDnsChallenge() ? 'checked' : '' %> | ||||
|                                     > | ||||
|                                     <span class="custom-switch-indicator"></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'use-cloudflare') %></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span> | ||||
|                                 </label> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="col-sm-12 col-md-12 cloudflare letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="form-label">CloudFlare DNS API Token  <span class="form-required">*</span></label> | ||||
|                                 <input type="text" name="meta[cloudflare_token]" class="form-control" id="cloudflare_token"> | ||||
|                             </div> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <fieldset class="form-fieldset dns-challenge"> | ||||
|                                 <div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div> | ||||
|  | ||||
|                                 <!-- Certbot DNS plugin selection --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label> | ||||
|                                             <select  | ||||
|                                                 name="meta[dns_provider]"  | ||||
|                                                 id="dns_provider" | ||||
|                                                 class="form-control custom-select" | ||||
|                                             > | ||||
|                                                 <option  | ||||
|                                                     value=""  | ||||
|                                                     disabled  | ||||
|                                                     hidden | ||||
|                                                     <%- getDnsProvider() === null ? 'selected' : '' %> | ||||
|                                                 >Please Choose...</option> | ||||
|                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %> | ||||
|                                                 <option  | ||||
|                                                     value="<%- plugin_name %>" | ||||
|                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %> | ||||
|                                                 ><%- plugin_info.display_name %></option> | ||||
|                                                 <% }); %> | ||||
|                                             </select> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- Certbot credentials file content --> | ||||
|                                 <div class="row credentials-file-content"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label> | ||||
|                                             <textarea  | ||||
|                                                 name="meta[dns_provider_credentials]"  | ||||
|                                                 class="form-control text-monospace"  | ||||
|                                                 id="dns_provider_credentials"  | ||||
|                                             ><%- getDnsProviderCredentials() %></textarea> | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'credentials-file-content-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- DNS propagation delay --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group mb-0"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label> | ||||
|                                             <input  | ||||
|                                                 type="number" | ||||
|                                                 min="0" | ||||
|                                                 name="meta[propagation_seconds]"  | ||||
|                                                 class="form-control"  | ||||
|                                                 id="propagation_seconds"  | ||||
|                                                 value="<%- getPropagationSeconds() %>" | ||||
|                                             > | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'propagation-seconds-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </fieldset> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- Lets encrypt --> | ||||
|   | ||||
| @@ -7,6 +7,8 @@ const certListItemTemplate   = require('../certificates-list-item.ejs'); | ||||
| const accessListItemTemplate = require('./access-list-item.ejs'); | ||||
| const CustomLocation         = require('./location'); | ||||
| const Helpers                = require('../../../lib/helpers'); | ||||
| const i18n                   = require('../../i18n'); | ||||
| const dns_providers          = require('../../../../../utils/certbot-dns-plugins'); | ||||
|  | ||||
|  | ||||
| require('jquery-serializejson'); | ||||
| @@ -19,25 +21,28 @@ module.exports = Mn.View.extend({ | ||||
|     locationsCollection: new ProxyLocationModel.Collection(), | ||||
|  | ||||
|     ui: { | ||||
|         form:               'form', | ||||
|         domain_names:       'input[name="domain_names"]', | ||||
|         forward_host:       'input[name="forward_host"]', | ||||
|         buttons:            '.modal-footer button', | ||||
|         cancel:             'button.cancel', | ||||
|         save:               'button.save', | ||||
|         add_location_btn:   'button.add_location', | ||||
|         locations_container:'.locations_container', | ||||
|         certificate_select: 'select[name="certificate_id"]', | ||||
|         access_list_select: 'select[name="access_list_id"]', | ||||
|         ssl_forced:         'input[name="ssl_forced"]', | ||||
|         hsts_enabled:       'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:    'input[name="hsts_subdomains"]', | ||||
|         http2_support:      'input[name="http2_support"]', | ||||
|         cloudflare_switch:  'input[name="meta[cloudflare_use]"]', | ||||
|         cloudflare_token:   'input[name="meta[cloudflare_token]"', | ||||
|         cloudflare:         '.cloudflare', | ||||
|         forward_scheme:     'select[name="forward_scheme"]', | ||||
|         letsencrypt:        '.letsencrypt' | ||||
|         form:                     'form', | ||||
|         domain_names:             'input[name="domain_names"]', | ||||
|         forward_host:             'input[name="forward_host"]', | ||||
|         buttons:                  '.modal-footer button', | ||||
|         cancel:                   'button.cancel', | ||||
|         save:                     'button.save', | ||||
|         add_location_btn:         'button.add_location', | ||||
|         locations_container:      '.locations_container', | ||||
|         certificate_select:       'select[name="certificate_id"]', | ||||
|         access_list_select:       'select[name="access_list_id"]', | ||||
|         ssl_forced:               'input[name="ssl_forced"]', | ||||
|         hsts_enabled:             'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:          'input[name="hsts_subdomains"]', | ||||
|         http2_support:            'input[name="http2_support"]', | ||||
|         dns_challenge_switch:     'input[name="meta[dns_challenge]"]', | ||||
|         dns_challenge_content:    '.dns-challenge', | ||||
|         dns_provider:             'select[name="meta[dns_provider]"]', | ||||
|         credentials_file_content: '.credentials-file-content', | ||||
|         dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]', | ||||
|         propagation_seconds:      'input[name="meta[propagation_seconds]"]', | ||||
|         forward_scheme:           'select[name="forward_scheme"]', | ||||
|         letsencrypt:              '.letsencrypt' | ||||
|     }, | ||||
|  | ||||
|     regions: { | ||||
| @@ -49,7 +54,7 @@ module.exports = Mn.View.extend({ | ||||
|             let id = this.ui.certificate_select.val(); | ||||
|             if (id === 'new') { | ||||
|                 this.ui.letsencrypt.show().find('input').prop('disabled', false); | ||||
|                 this.ui.cloudflare.hide(); | ||||
|                 this.ui.dns_challenge_content.hide(); | ||||
|             } else { | ||||
|                 this.ui.letsencrypt.hide().find('input').prop('disabled', true); | ||||
|             } | ||||
| @@ -95,14 +100,31 @@ module.exports = Mn.View.extend({ | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.cloudflare_switch': function() { | ||||
|             let checked = this.ui.cloudflare_switch.prop('checked'); | ||||
|             if (checked) {                 | ||||
|                 this.ui.cloudflare_token.prop('required', 'required'); | ||||
|                 this.ui.cloudflare.show(); | ||||
|             } else {                 | ||||
|                 this.ui.cloudflare_token.prop('required', false); | ||||
|                 this.ui.cloudflare.hide();                 | ||||
|         'change @ui.dns_challenge_switch': function () { | ||||
|             const checked = this.ui.dns_challenge_switch.prop('checked'); | ||||
|             if (checked) { | ||||
|                 this.ui.dns_provider.prop('required', 'required'); | ||||
|                 const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|                 if(selected_provider != '' && dns_providers[selected_provider].credentials !== false){ | ||||
|                     this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 } | ||||
|                 this.ui.dns_challenge_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider.prop('required', false); | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.dns_challenge_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.dns_provider': function () { | ||||
|             const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|             if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) { | ||||
|                 this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials; | ||||
|                 this.ui.credentials_file_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.credentials_file_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
| @@ -143,6 +165,7 @@ module.exports = Mn.View.extend({ | ||||
|             data.hsts_enabled            = !!data.hsts_enabled; | ||||
|             data.hsts_subdomains         = !!data.hsts_subdomains; | ||||
|             data.ssl_forced              = !!data.ssl_forced; | ||||
|             data.meta.dns_challenge      = !!data.meta.dns_challenge; | ||||
|  | ||||
|             if (typeof data.domain_names === 'string' && data.domain_names) { | ||||
|                 data.domain_names = data.domain_names.split(','); | ||||
| @@ -151,7 +174,7 @@ module.exports = Mn.View.extend({ | ||||
|             // Check for any domain names containing wildcards, which are not allowed with letsencrypt | ||||
|             if (data.certificate_id === 'new') {                 | ||||
|                 let domain_err = false; | ||||
|                 if (!data.meta.cloudflare_use) { | ||||
|                 if (!data.meta.dns_challenge) { | ||||
|                     data.domain_names.map(function (name) { | ||||
|                         if (name.match(/\*/im)) { | ||||
|                             domain_err = true; | ||||
| @@ -160,11 +183,10 @@ module.exports = Mn.View.extend({ | ||||
|                 } | ||||
|  | ||||
|                 if (domain_err) { | ||||
|                     alert('Cannot request Let\'s Encrypt Certificate for wildcard domains without CloudFlare DNS.'); | ||||
|                     alert(i18n('ssl', 'no-wildcard-without-dns')); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 data.meta.cloudflare_use = data.meta.cloudflare_use === '1'; | ||||
|                 data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1';                 | ||||
|             } else { | ||||
|                 data.certificate_id = parseInt(data.certificate_id, 10); | ||||
| @@ -204,7 +226,20 @@ module.exports = Mn.View.extend({ | ||||
|     templateContext: { | ||||
|         getLetsencryptEmail: function () { | ||||
|             return App.Cache.User.get('email'); | ||||
|         } | ||||
|         }, | ||||
|         getUseDnsChallenge: function () { | ||||
|             return typeof this.meta.dns_challenge !== 'undefined' ? this.meta.dns_challenge : false; | ||||
|         }, | ||||
|         getDnsProvider: function () { | ||||
|             return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null; | ||||
|         }, | ||||
|         getDnsProviderCredentials: function () { | ||||
|             return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : ''; | ||||
|         }, | ||||
|         getPropagationSeconds: function () { | ||||
|             return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : ''; | ||||
|         }, | ||||
|         dns_plugins: dns_providers, | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
| @@ -258,6 +293,8 @@ module.exports = Mn.View.extend({ | ||||
|         }); | ||||
|  | ||||
|         // Certificates | ||||
|         this.ui.dns_challenge_content.hide(); | ||||
|         this.ui.credentials_file_content.hide(); | ||||
|         this.ui.letsencrypt.hide(); | ||||
|         this.ui.certificate_select.selectize({ | ||||
|             valueField:       'id', | ||||
|   | ||||
| @@ -97,21 +97,92 @@ | ||||
|                             </div> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- CloudFlare --> | ||||
|                         <!-- DNS challenge --> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="custom-switch"> | ||||
|                                     <input type="checkbox" class="custom-switch-input" name="meta[cloudflare_use]" value="1"> | ||||
|                                     <input  | ||||
|                                         type="checkbox"  | ||||
|                                         class="custom-switch-input"  | ||||
|                                         name="meta[dns_challenge]"  | ||||
|                                         value="1"  | ||||
|                                         <%- getUseDnsChallenge() ? 'checked' : '' %> | ||||
|                                     > | ||||
|                                     <span class="custom-switch-indicator"></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'use-cloudflare') %></span> | ||||
|                                     <span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span> | ||||
|                                 </label> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="col-sm-12 col-md-12 cloudflare letsencrypt"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label class="form-label">CloudFlare DNS API Token  <span class="form-required">*</span></label> | ||||
|                                 <input type="text" name="meta[cloudflare_token]" class="form-control" id="cloudflare_token"> | ||||
|                             </div> | ||||
|                         <div class="col-sm-12 col-md-12 letsencrypt"> | ||||
|                             <fieldset class="form-fieldset dns-challenge"> | ||||
|                                 <div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div> | ||||
|  | ||||
|                                 <!-- Certbot DNS plugin selection --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label> | ||||
|                                             <select  | ||||
|                                                 name="meta[dns_provider]"  | ||||
|                                                 id="dns_provider" | ||||
|                                                 class="form-control custom-select" | ||||
|                                             > | ||||
|                                                 <option  | ||||
|                                                     value=""  | ||||
|                                                     disabled  | ||||
|                                                     hidden | ||||
|                                                     <%- getDnsProvider() === null ? 'selected' : '' %> | ||||
|                                                 >Please Choose...</option> | ||||
|                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %> | ||||
|                                                 <option  | ||||
|                                                     value="<%- plugin_name %>" | ||||
|                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %> | ||||
|                                                 ><%- plugin_info.display_name %></option> | ||||
|                                                 <% }); %> | ||||
|                                             </select> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- Certbot credentials file content --> | ||||
|                                 <div class="row credentials-file-content"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label> | ||||
|                                             <textarea  | ||||
|                                                 name="meta[dns_provider_credentials]"  | ||||
|                                                 class="form-control text-monospace"  | ||||
|                                                 id="dns_provider_credentials"  | ||||
|                                             ><%- getDnsProviderCredentials() %></textarea> | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'credentials-file-content-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|  | ||||
|                                 <!-- DNS propagation delay --> | ||||
|                                 <div class="row"> | ||||
|                                     <div class="col-sm-12 col-md-12"> | ||||
|                                         <div class="form-group mb-0"> | ||||
|                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label> | ||||
|                                             <input  | ||||
|                                                 type="number" | ||||
|                                                 min="0" | ||||
|                                                 name="meta[propagation_seconds]"  | ||||
|                                                 class="form-control"  | ||||
|                                                 id="propagation_seconds"  | ||||
|                                                 value="<%- getPropagationSeconds() %>" | ||||
|                                             > | ||||
|                                             <div class="text-secondary small"> | ||||
|                                                 <i class="fe fe-info"></i>  | ||||
|                                                 <%= i18n('ssl', 'propagation-seconds-info') %> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </fieldset> | ||||
|                         </div> | ||||
|  | ||||
|                         <!-- Lets encrypt --> | ||||
|   | ||||
| @@ -4,6 +4,9 @@ const RedirectionHostModel = require('../../../models/redirection-host'); | ||||
| const template             = require('./form.ejs'); | ||||
| const certListItemTemplate = require('../certificates-list-item.ejs'); | ||||
| const Helpers              = require('../../../lib/helpers'); | ||||
| const i18n                 = require('../../i18n'); | ||||
| const dns_providers        = require('../../../../../utils/certbot-dns-plugins'); | ||||
|  | ||||
|  | ||||
| require('jquery-serializejson'); | ||||
| require('selectize'); | ||||
| @@ -13,20 +16,23 @@ module.exports = Mn.View.extend({ | ||||
|     className: 'modal-dialog', | ||||
|  | ||||
|     ui: { | ||||
|         form:               'form', | ||||
|         domain_names:       'input[name="domain_names"]', | ||||
|         buttons:            '.modal-footer button', | ||||
|         cancel:             'button.cancel', | ||||
|         save:               'button.save', | ||||
|         certificate_select: 'select[name="certificate_id"]', | ||||
|         ssl_forced:         'input[name="ssl_forced"]', | ||||
|         hsts_enabled:       'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:    'input[name="hsts_subdomains"]', | ||||
|         http2_support:      'input[name="http2_support"]', | ||||
|         cloudflare_switch:  'input[name="meta[cloudflare_use]"]', | ||||
|         cloudflare_token:   'input[name="meta[cloudflare_token]"', | ||||
|         cloudflare:         '.cloudflare', | ||||
|         letsencrypt:        '.letsencrypt' | ||||
|         form:                     'form', | ||||
|         domain_names:             'input[name="domain_names"]', | ||||
|         buttons:                  '.modal-footer button', | ||||
|         cancel:                   'button.cancel', | ||||
|         save:                     'button.save', | ||||
|         certificate_select:       'select[name="certificate_id"]', | ||||
|         ssl_forced:               'input[name="ssl_forced"]', | ||||
|         hsts_enabled:             'input[name="hsts_enabled"]', | ||||
|         hsts_subdomains:          'input[name="hsts_subdomains"]', | ||||
|         http2_support:            'input[name="http2_support"]', | ||||
|         dns_challenge_switch:     'input[name="meta[dns_challenge]"]', | ||||
|         dns_challenge_content:    '.dns-challenge', | ||||
|         dns_provider:             'select[name="meta[dns_provider]"]', | ||||
|         credentials_file_content: '.credentials-file-content', | ||||
|         dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]', | ||||
|         propagation_seconds:      'input[name="meta[propagation_seconds]"]', | ||||
|         letsencrypt:              '.letsencrypt' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
| @@ -34,7 +40,7 @@ module.exports = Mn.View.extend({ | ||||
|             let id = this.ui.certificate_select.val(); | ||||
|             if (id === 'new') { | ||||
|                 this.ui.letsencrypt.show().find('input').prop('disabled', false); | ||||
|                 this.ui.cloudflare.hide(); | ||||
|                 this.ui.dns_challenge_content.hide(); | ||||
|             } else { | ||||
|                 this.ui.letsencrypt.hide().find('input').prop('disabled', true); | ||||
|             } | ||||
| @@ -80,14 +86,31 @@ module.exports = Mn.View.extend({ | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.cloudflare_switch': function() { | ||||
|             let checked = this.ui.cloudflare_switch.prop('checked'); | ||||
|             if (checked) {                 | ||||
|                 this.ui.cloudflare_token.prop('required', 'required'); | ||||
|                 this.ui.cloudflare.show(); | ||||
|             } else {                 | ||||
|                 this.ui.cloudflare_token.prop('required', false); | ||||
|                 this.ui.cloudflare.hide();                 | ||||
|         'change @ui.dns_challenge_switch': function () { | ||||
|             const checked = this.ui.dns_challenge_switch.prop('checked'); | ||||
|             if (checked) { | ||||
|                 this.ui.dns_provider.prop('required', 'required'); | ||||
|                 const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|                 if(selected_provider != '' && dns_providers[selected_provider].credentials !== false){ | ||||
|                     this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 } | ||||
|                 this.ui.dns_challenge_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider.prop('required', false); | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.dns_challenge_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         'change @ui.dns_provider': function () { | ||||
|             const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value; | ||||
|             if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) { | ||||
|                 this.ui.dns_provider_credentials.prop('required', 'required'); | ||||
|                 this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials; | ||||
|                 this.ui.credentials_file_content.show(); | ||||
|             } else { | ||||
|                 this.ui.dns_provider_credentials.prop('required', false); | ||||
|                 this.ui.credentials_file_content.hide();                 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
| @@ -103,12 +126,13 @@ module.exports = Mn.View.extend({ | ||||
|             let data = this.ui.form.serializeJSON(); | ||||
|  | ||||
|             // Manipulate | ||||
|             data.block_exploits  = !!data.block_exploits; | ||||
|             data.preserve_path   = !!data.preserve_path; | ||||
|             data.http2_support   = !!data.http2_support; | ||||
|             data.hsts_enabled    = !!data.hsts_enabled; | ||||
|             data.hsts_subdomains = !!data.hsts_subdomains; | ||||
|             data.ssl_forced      = !!data.ssl_forced; | ||||
|             data.block_exploits     = !!data.block_exploits; | ||||
|             data.preserve_path      = !!data.preserve_path; | ||||
|             data.http2_support      = !!data.http2_support; | ||||
|             data.hsts_enabled       = !!data.hsts_enabled; | ||||
|             data.hsts_subdomains    = !!data.hsts_subdomains; | ||||
|             data.ssl_forced         = !!data.ssl_forced; | ||||
|             data.meta.dns_challenge = !!data.meta.dns_challenge; | ||||
|  | ||||
|             if (typeof data.domain_names === 'string' && data.domain_names) { | ||||
|                 data.domain_names = data.domain_names.split(','); | ||||
| @@ -117,7 +141,7 @@ module.exports = Mn.View.extend({ | ||||
|             // Check for any domain names containing wildcards, which are not allowed with letsencrypt | ||||
|             if (data.certificate_id === 'new') {                 | ||||
|                 let domain_err = false; | ||||
|                 if (!data.meta.cloudflare_use) { | ||||
|                 if (!data.meta.dns_challenge) { | ||||
|                     data.domain_names.map(function (name) { | ||||
|                         if (name.match(/\*/im)) { | ||||
|                             domain_err = true; | ||||
| @@ -126,7 +150,7 @@ module.exports = Mn.View.extend({ | ||||
|                 } | ||||
|  | ||||
|                 if (domain_err) { | ||||
|                     alert('Cannot request Let\'s Encrypt Certificate for wildcard domains without CloudFlare DNS.'); | ||||
|                     alert(i18n('ssl', 'no-wildcard-without-dns')); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
| @@ -170,7 +194,20 @@ module.exports = Mn.View.extend({ | ||||
|     templateContext: { | ||||
|         getLetsencryptEmail: function () { | ||||
|             return App.Cache.User.get('email'); | ||||
|         } | ||||
|         }, | ||||
|         getUseDnsChallenge: function () { | ||||
|             return typeof this.meta.dns_challenge !== 'undefined' ? this.meta.dns_challenge : false; | ||||
|         }, | ||||
|         getDnsProvider: function () { | ||||
|             return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null; | ||||
|         }, | ||||
|         getDnsProviderCredentials: function () { | ||||
|             return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : ''; | ||||
|         }, | ||||
|         getPropagationSeconds: function () { | ||||
|             return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : ''; | ||||
|         }, | ||||
|         dns_plugins: dns_providers, | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
| @@ -191,6 +228,8 @@ module.exports = Mn.View.extend({ | ||||
|         }); | ||||
|  | ||||
|         // Certificates | ||||
|         this.ui.dns_challenge_content.hide(); | ||||
|         this.ui.credentials_file_content.hide(); | ||||
|         this.ui.letsencrypt.hide(); | ||||
|         this.ui.certificate_select.selectize({ | ||||
|             valueField:       'id', | ||||
|   | ||||
| @@ -102,7 +102,15 @@ | ||||
|       "letsencrypt-agree": "I Agree to the <a href=\"{url}\" target=\"_blank\">Let's Encrypt Terms of Service</a>", | ||||
|       "delete-ssl": "The SSL certificates attached will NOT be removed, they will need to be removed manually.", | ||||
|       "hosts-warning": "These domains must be already configured to point to this installation", | ||||
|       "use-cloudflare": "Use CloudFlare DNS verification"       | ||||
|       "no-wildcard-without-dns": "Cannot request Let's Encrypt Certificate for wildcard domains when not using DNS challenge", | ||||
|       "dns-challenge": "Use a DNS Challenge", | ||||
|       "certbot-warning": "This section requires some knowledge about Certbot and its DNS plugins. Please consult the respective plugins documentation.", | ||||
|       "dns-provider": "DNS Provider", | ||||
|       "please-choose": "Please Choose...", | ||||
|       "credentials-file-content": "Credentials File Content", | ||||
|       "credentials-file-content-info": "This plugin requires a configuration file containing an API token or other credentials to your provider", | ||||
|       "propagation-seconds": "Propagation Seconds", | ||||
|       "propagation-seconds-info": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation." | ||||
|     }, | ||||
|     "proxy-hosts": { | ||||
|       "title": "Proxy Hosts", | ||||
|   | ||||
							
								
								
									
										160
									
								
								utils/certbot-dns-plugins.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								utils/certbot-dns-plugins.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| /** | ||||
|  * This file contains info about available Certbot DNS plugins. | ||||
|  * | ||||
|  * File Structure: | ||||
|  * | ||||
|  *  { | ||||
|  *    cloudflare: { | ||||
|  *      display_name: "Name displayed to the user", | ||||
|  *      package_name: "Package name in PyPi repo", | ||||
|  *      package_version: "Package version in PyPi repo", | ||||
|  *      credentials: `Template of the credentials file`, | ||||
|  *      full_plugin_name: "The full plugin name as used in the commandline with certbot, including prefixes, e.g. 'certbot-dns-njalla:dns-njalla'", | ||||
|  *      credentials_file: Whether the plugin has a credentials file | ||||
|  *    }, | ||||
|  *    ... | ||||
|  *  } | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| module.exports = { | ||||
|   cloudflare: { | ||||
|     display_name: "Cloudflare", | ||||
|     package_name: "certbot-dns-cloudflare", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `# Cloudflare API token | ||||
| dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`, | ||||
|     full_plugin_name: "dns-cloudflare", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   cloudxns: { | ||||
|     display_name: "CloudXNS", | ||||
|     package_name: "certbot-dns-cloudxns", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef | ||||
| dns_cloudxns_secret_key = 1122334455667788`, | ||||
|     full_plugin_name: "dns-cloudxns", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   digitalocean: { | ||||
|     display_name: "DigitalOcean", | ||||
|     package_name: "certbot-dns-digitalocean", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff`, | ||||
|     full_plugin_name: "dns-digitalocean", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   dnsimple: { | ||||
|     display_name: "DNSimple", | ||||
|     package_name: "certbot-dns-dnsimple", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`, | ||||
|     full_plugin_name: "dns-dnsimple", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   dnsmadeeasy: { | ||||
|     display_name: "DNS Made Easy", | ||||
|     package_name: "certbot-dns-dnsmadeeasy", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a | ||||
| dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`, | ||||
|     full_plugin_name: "dns-dnsmadeeasy", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   google: { | ||||
|     display_name: "Google", | ||||
|     package_name: "certbot-dns-google", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `{ | ||||
|   "type": "service_account", | ||||
|   ... | ||||
| }`, | ||||
|     full_plugin_name: "dns-google", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   hetzner: { | ||||
|     display_name: "Hetzner", | ||||
|     package_name: "certbot-dns-hetzner", | ||||
|     package_version: "1.0.4", | ||||
|     credentials: `certbot_dns_hetzner:dns_hetzner_api_token = 0123456789abcdef0123456789abcdef`, | ||||
|     full_plugin_name: "certbot-dns-hetzner:dns-hetzner", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   linode: { | ||||
|     display_name: "Linode", | ||||
|     package_name: "certbot-dns-linode", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64 | ||||
| dns_linode_version = [<blank>|3|4]`, | ||||
|     full_plugin_name: "dns-linode", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   luadns: { | ||||
|     display_name: "LuaDNS", | ||||
|     package_name: "certbot-dns-luadns", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_luadns_email = user@example.com | ||||
| dns_luadns_token = 0123456789abcdef0123456789abcdef`, | ||||
|     full_plugin_name: "dns-luadns", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   netcup: { | ||||
|     display_name: "netcup", | ||||
|     package_name: "certbot-dns-netcup", | ||||
|     package_version: "1.0.0", | ||||
|     credentials: `certbot_dns_njalla:dns_njalla_token = 0123456789abcdef0123456789abcdef01234567`, | ||||
|     full_plugin_name: "certbot-dns-netcup:dns-netcup", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   njalla: { | ||||
|     display_name: "Njalla", | ||||
|     package_name: "certbot-dns-nsone", | ||||
|     package_version: "0.0.4", | ||||
|     credentials: `certbot_dns_njalla:dns_njalla_token = 0123456789abcdef0123456789abcdef01234567`, | ||||
|     full_plugin_name: "certbot-dns-njalla:dns-njalla", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   nsone: { | ||||
|     display_name: "NS1", | ||||
|     package_name: "certbot-dns-nsone", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw`, | ||||
|     full_plugin_name: "dns-nsone", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   ovh: { | ||||
|     display_name: "OVH", | ||||
|     package_name: "certbot-dns-ovh", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `dns_ovh_endpoint = ovh-eu | ||||
| dns_ovh_application_key = MDAwMDAwMDAwMDAw | ||||
| dns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw | ||||
| dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`, | ||||
|     full_plugin_name: "dns-ovh", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   rfc2136: { | ||||
|     display_name: "RFC 2136", | ||||
|     package_name: "certbot-dns-rfc2136", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: `# Target DNS server | ||||
| dns_rfc2136_server = 192.0.2.1 | ||||
| # Target DNS port | ||||
| dns_rfc2136_port = 53 | ||||
| # TSIG key name | ||||
| dns_rfc2136_name = keyname. | ||||
| # TSIG key secret | ||||
| dns_rfc2136_secret = 4q4wM/2I180UXoMyN4INVhJNi8V9BCV+jMw2mXgZw/CSuxUT8C7NKKFs AmKd7ak51vWKgSl12ib86oQRPkpDjg== | ||||
| # TSIG key algorithm | ||||
| dns_rfc2136_algorithm = HMAC-SHA512`, | ||||
|     full_plugin_name: "dns-rfc2136", | ||||
|   }, | ||||
|   //####################################################// | ||||
|   route53: { | ||||
|     display_name: "Route 53 (Amazon)", | ||||
|     package_name: "certbot-dns-route53", | ||||
|     package_version: "1.8.0", | ||||
|     credentials: false, | ||||
|     full_plugin_name: "dns-route53", | ||||
|   }, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user