From b81325d7bf4606a37b3c19a9ab2676c4b209e6ef Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Sun, 4 Oct 2020 23:56:02 +0200 Subject: [PATCH 01/13] Implements dns challenge provider selection in frontend --- frontend/js/app/nginx/certificates/form.ejs | 87 +++++++++- frontend/js/app/nginx/certificates/form.js | 75 +++++--- .../js/app/nginx/certificates/list/item.ejs | 2 +- .../js/app/nginx/certificates/list/item.js | 12 +- frontend/js/app/nginx/dead/form.ejs | 87 +++++++++- frontend/js/app/nginx/dead/form.js | 99 +++++++---- frontend/js/app/nginx/proxy/form.ejs | 87 +++++++++- frontend/js/app/nginx/proxy/form.js | 101 +++++++---- frontend/js/app/nginx/redirection/form.ejs | 87 +++++++++- frontend/js/app/nginx/redirection/form.js | 103 +++++++---- frontend/js/i18n/messages.json | 10 +- utils/certbot-dns-plugins.js | 160 ++++++++++++++++++ 12 files changed, 755 insertions(+), 155 deletions(-) create mode 100644 utils/certbot-dns-plugins.js diff --git a/frontend/js/app/nginx/certificates/form.ejs b/frontend/js/app/nginx/certificates/form.ejs index 207e59e..a3d6c07 100644 --- a/frontend/js/app/nginx/certificates/form.ejs +++ b/frontend/js/app/nginx/certificates/form.ejs @@ -21,21 +21,92 @@ - +
-
-
- - -
+
+
+
<%= i18n('ssl', 'certbot-warning') %>
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'credentials-file-content-info') %> +
+
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'propagation-seconds-info') %> +
+
+
+
+
diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index 53a6e14..bc239df 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -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) { diff --git a/frontend/js/app/nginx/certificates/list/item.ejs b/frontend/js/app/nginx/certificates/list/item.ejs index 857a08b..67764b0 100644 --- a/frontend/js/app/nginx/certificates/list/item.ejs +++ b/frontend/js/app/nginx/certificates/list/item.ejs @@ -28,7 +28,7 @@
- <%- i18n('ssl', provider) %><% if (meta.cloudflare_use) { %> - CloudFlare DNS<% } %> + <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <% dns_providers[meta.dns_provider].display_name } %> <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %> diff --git a/frontend/js/app/nginx/certificates/list/item.js b/frontend/js/app/nginx/certificates/list/item.js index 6915227..b5b2d85 100644 --- a/frontend/js/app/nginx/certificates/list/item.js +++ b/frontend/js/app/nginx/certificates/list/item.js @@ -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 () { diff --git a/frontend/js/app/nginx/dead/form.ejs b/frontend/js/app/nginx/dead/form.ejs index d48820f..1d01e09 100644 --- a/frontend/js/app/nginx/dead/form.ejs +++ b/frontend/js/app/nginx/dead/form.ejs @@ -73,21 +73,92 @@
- +
-
-
- - -
+
+
+
<%= i18n('ssl', 'certbot-warning') %>
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'credentials-file-content-info') %> +
+
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'propagation-seconds-info') %> +
+
+
+
+
diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js index aca367a..393788d 100644 --- a/frontend/js/app/nginx/dead/form.js +++ b/frontend/js/app/nginx/dead/form.js @@ -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', diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index e003597..34f319c 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -141,21 +141,92 @@
- +
-
-
- - -
+
+
+
<%= i18n('ssl', 'certbot-warning') %>
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'credentials-file-content-info') %> +
+
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'propagation-seconds-info') %> +
+
+
+
+
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 0f64281..4211050 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -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', diff --git a/frontend/js/app/nginx/redirection/form.ejs b/frontend/js/app/nginx/redirection/form.ejs index 7d49769..f4e4375 100644 --- a/frontend/js/app/nginx/redirection/form.ejs +++ b/frontend/js/app/nginx/redirection/form.ejs @@ -97,21 +97,92 @@
- +
-
-
- - -
+
+
+
<%= i18n('ssl', 'certbot-warning') %>
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'credentials-file-content-info') %> +
+
+
+
+ + +
+
+
+ + +
+ + <%= i18n('ssl', 'propagation-seconds-info') %> +
+
+
+
+
diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js index 4e5b168..c1c6d9d 100644 --- a/frontend/js/app/nginx/redirection/form.js +++ b/frontend/js/app/nginx/redirection/form.js @@ -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', diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index d0c9d8e..8826afa 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -102,7 +102,15 @@ "letsencrypt-agree": "I Agree to the Let's Encrypt Terms of Service", "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", diff --git a/utils/certbot-dns-plugins.js b/utils/certbot-dns-plugins.js new file mode 100644 index 0000000..4af678e --- /dev/null +++ b/utils/certbot-dns-plugins.js @@ -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 = [|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", + }, +}; From 2523424f682d5f1da5a28324277acd4c3f1abdb8 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Mon, 5 Oct 2020 01:04:18 +0200 Subject: [PATCH 02/13] Updates dockerfiles --- docker/Dockerfile | 4 ++-- docker/dev/Dockerfile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 5224416..3c99751 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -17,8 +17,8 @@ ENV NODE_ENV=production RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ && apk update \ - && apk add python2 py-pip certbot jq \ - && pip install certbot-dns-cloudflare \ + && apk add python3 certbot jq \ + && python3 -m ensurepip \ && rm -rf /var/cache/apk/* ENV NPM_BUILD_VERSION="${BUILD_VERSION}" NPM_BUILD_COMMIT="${BUILD_COMMIT}" NPM_BUILD_DATE="${BUILD_DATE}" diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 5b67981..45ee534 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -7,8 +7,8 @@ ENV S6_FIX_ATTRS_HIDDEN=1 RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ && apk update \ - && apk add python2 py-pip certbot jq \ - && pip install certbot-dns-cloudflare \ + && apk add python3 certbot jq \ + && python3 -m ensurepip \ && rm -rf /var/cache/apk/* # Task From 05f6a55a0b4e16e678e20c3b66588122d4c5669e Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Tue, 6 Oct 2020 14:49:02 +0200 Subject: [PATCH 03/13] Adds frontend improvements and fixes --- frontend/js/app/api.js | 10 ++--- frontend/js/app/nginx/certificates/form.ejs | 18 +++++++-- frontend/js/app/nginx/certificates/form.js | 40 ++++++++++++++----- .../js/app/nginx/certificates/list/item.ejs | 2 +- frontend/js/app/nginx/dead/form.ejs | 5 +++ frontend/js/app/nginx/dead/form.js | 28 +++++++++++-- frontend/js/app/nginx/proxy/form.ejs | 5 +++ frontend/js/app/nginx/proxy/form.js | 28 +++++++++++-- frontend/js/app/nginx/redirection/form.ejs | 5 +++ frontend/js/app/nginx/redirection/form.js | 31 +++++++++++--- frontend/js/i18n/messages.json | 4 +- utils/certbot-dns-plugins.js | 8 +++- 12 files changed, 147 insertions(+), 37 deletions(-) diff --git a/frontend/js/app/api.js b/frontend/js/app/api.js index 74356f0..1d7b358 100644 --- a/frontend/js/app/api.js +++ b/frontend/js/app/api.js @@ -53,7 +53,7 @@ function fetch(verb, path, data, options) { contentType: options.contentType || 'application/json; charset=UTF-8', processData: options.processData || true, crossDomain: true, - timeout: options.timeout ? options.timeout : 30000, + timeout: options.timeout ? options.timeout : 180000, xhrFields: { withCredentials: true }, @@ -586,8 +586,8 @@ module.exports = { /** * @param {Object} data */ - create: function (data) { - return fetch('post', 'nginx/certificates', data); + create: function (data, timeout = 180000) { + return fetch('post', 'nginx/certificates', data, {timeout}); }, /** @@ -630,8 +630,8 @@ module.exports = { * @param {Number} id * @returns {Promise} */ - renew: function (id) { - return fetch('post', 'nginx/certificates/' + id + '/renew'); + renew: function (id, timeout = 180000) { + return fetch('post', 'nginx/certificates/' + id + '/renew', undefined, {timeout}); } } }, diff --git a/frontend/js/app/nginx/certificates/form.ejs b/frontend/js/app/nginx/certificates/form.ejs index a3d6c07..4c7a596 100644 --- a/frontend/js/app/nginx/certificates/form.ejs +++ b/frontend/js/app/nginx/certificates/form.ejs @@ -1,12 +1,20 @@
- - <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <% dns_providers[meta.dns_provider].display_name } %> + <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <%- dns_providers[meta.dns_provider].display_name %><% } %> <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %> diff --git a/frontend/js/app/nginx/dead/form.ejs b/frontend/js/app/nginx/dead/form.ejs index 1d01e09..253c4b6 100644 --- a/frontend/js/app/nginx/dead/form.ejs +++ b/frontend/js/app/nginx/dead/form.ejs @@ -4,6 +4,7 @@ +
+ + <%= i18n('ssl', 'stored-as-plaintext-info') %> +
diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js index 393788d..0df24f7 100644 --- a/frontend/js/app/nginx/dead/form.js +++ b/frontend/js/app/nginx/dead/form.js @@ -20,6 +20,7 @@ module.exports = Mn.View.extend({ buttons: '.modal-footer button', cancel: 'button.cancel', save: 'button.save', + le_error_info: '#le-error-info', certificate_select: 'select[name="certificate_id"]', ssl_forced: 'input[name="ssl_forced"]', hsts_enabled: 'input[name="hsts_enabled"]', @@ -116,6 +117,7 @@ module.exports = Mn.View.extend({ 'click @ui.save': function (e) { e.preventDefault(); + this.ui.le_error_info.hide(); if (!this.ui.form[0].checkValidity()) { $('').hide().appendTo(this.ui.form).click().remove(); @@ -130,7 +132,18 @@ module.exports = Mn.View.extend({ 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.meta === 'undefined') data.meta = {}; + data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1; + data.meta.dns_challenge = data.meta.dns_challenge == 1; + + if(!data.meta.dns_challenge){ + data.meta.dns_provider = undefined; + data.meta.dns_provider_credentials = undefined; + data.meta.propagation_seconds = undefined; + } else { + if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined; + } if (typeof data.domain_names === 'string' && data.domain_names) { data.domain_names = data.domain_names.split(','); @@ -151,8 +164,6 @@ module.exports = Mn.View.extend({ alert(i18n('ssl', 'no-wildcard-without-dns')); return; } - - data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1'; } else { data.certificate_id = parseInt(data.certificate_id, 10); } @@ -181,7 +192,15 @@ module.exports = Mn.View.extend({ }); }) .catch(err => { - alert(err.message); + let more_info = ''; + if(err.code === 500){ + try{ + more_info = JSON.parse(err.debug).debug.stack.join("\n"); + } catch(e) {} + } + this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `
${more_info}
`:''}`; + this.ui.le_error_info.show(); + this.ui.le_error_info[0].scrollIntoView(); this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); this.ui.save.removeClass('btn-loading'); }); @@ -225,6 +244,7 @@ module.exports = Mn.View.extend({ }); // Certificates + this.ui.le_error_info.hide(); this.ui.dns_challenge_content.hide(); this.ui.credentials_file_content.hide(); this.ui.letsencrypt.hide(); diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 34f319c..1a49830 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -4,6 +4,7 @@ +
+ + <%= i18n('ssl', 'stored-as-plaintext-info') %> +
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 4211050..3c17225 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -29,6 +29,7 @@ module.exports = Mn.View.extend({ save: 'button.save', add_location_btn: 'button.add_location', locations_container: '.locations_container', + le_error_info: '#le-error-info', certificate_select: 'select[name="certificate_id"]', access_list_select: 'select[name="access_list_id"]', ssl_forced: 'input[name="ssl_forced"]', @@ -137,6 +138,7 @@ module.exports = Mn.View.extend({ 'click @ui.save': function (e) { e.preventDefault(); + this.ui.le_error_info.hide(); if (!this.ui.form[0].checkValidity()) { $('').hide().appendTo(this.ui.form).click().remove(); @@ -165,7 +167,18 @@ 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.meta === 'undefined') data.meta = {}; + data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1; + data.meta.dns_challenge = data.meta.dns_challenge == 1; + + if(!data.meta.dns_challenge){ + data.meta.dns_provider = undefined; + data.meta.dns_provider_credentials = undefined; + data.meta.propagation_seconds = undefined; + } else { + if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined; + } if (typeof data.domain_names === 'string' && data.domain_names) { data.domain_names = data.domain_names.split(','); @@ -186,8 +199,6 @@ module.exports = Mn.View.extend({ alert(i18n('ssl', 'no-wildcard-without-dns')); return; } - - data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1'; } else { data.certificate_id = parseInt(data.certificate_id, 10); } @@ -216,7 +227,15 @@ module.exports = Mn.View.extend({ }); }) .catch(err => { - alert(err.message); + let more_info = ''; + if(err.code === 500){ + try{ + more_info = JSON.parse(err.debug).debug.stack.join("\n"); + } catch(e) {} + } + this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `
${more_info}
`:''}`; + this.ui.le_error_info.show(); + this.ui.le_error_info[0].scrollIntoView(); this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); this.ui.save.removeClass('btn-loading'); }); @@ -293,6 +312,7 @@ module.exports = Mn.View.extend({ }); // Certificates + this.ui.le_error_info.hide(); this.ui.dns_challenge_content.hide(); this.ui.credentials_file_content.hide(); this.ui.letsencrypt.hide(); diff --git a/frontend/js/app/nginx/redirection/form.ejs b/frontend/js/app/nginx/redirection/form.ejs index f4e4375..3247233 100644 --- a/frontend/js/app/nginx/redirection/form.ejs +++ b/frontend/js/app/nginx/redirection/form.ejs @@ -4,6 +4,7 @@ +
+ + <%= i18n('ssl', 'stored-as-plaintext-info') %> +
diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js index c1c6d9d..5ca3b8d 100644 --- a/frontend/js/app/nginx/redirection/form.js +++ b/frontend/js/app/nginx/redirection/form.js @@ -21,6 +21,7 @@ module.exports = Mn.View.extend({ buttons: '.modal-footer button', cancel: 'button.cancel', save: 'button.save', + le_error_info: '#le-error-info', certificate_select: 'select[name="certificate_id"]', ssl_forced: 'input[name="ssl_forced"]', hsts_enabled: 'input[name="hsts_enabled"]', @@ -116,6 +117,7 @@ module.exports = Mn.View.extend({ 'click @ui.save': function (e) { e.preventDefault(); + this.ui.le_error_info.hide(); if (!this.ui.form[0].checkValidity()) { $('').hide().appendTo(this.ui.form).click().remove(); @@ -132,7 +134,18 @@ 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.meta === 'undefined') data.meta = {}; + data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1; + data.meta.dns_challenge = data.meta.dns_challenge == 1; + + if(!data.meta.dns_challenge){ + data.meta.dns_provider = undefined; + data.meta.dns_provider_credentials = undefined; + data.meta.propagation_seconds = undefined; + } else { + if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined; + } if (typeof data.domain_names === 'string' && data.domain_names) { data.domain_names = data.domain_names.split(','); @@ -152,10 +165,7 @@ module.exports = Mn.View.extend({ if (domain_err) { 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); } @@ -184,7 +194,15 @@ module.exports = Mn.View.extend({ }); }) .catch(err => { - alert(err.message); + let more_info = ''; + if(err.code === 500){ + try{ + more_info = JSON.parse(err.debug).debug.stack.join("\n"); + } catch(e) {} + } + this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `
${more_info}
`:''}`; + this.ui.le_error_info.show(); + this.ui.le_error_info[0].scrollIntoView(); this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); this.ui.save.removeClass('btn-loading'); }); @@ -228,6 +246,7 @@ module.exports = Mn.View.extend({ }); // Certificates + this.ui.le_error_info.hide(); this.ui.dns_challenge_content.hide(); this.ui.credentials_file_content.hide(); this.ui.letsencrypt.hide(); diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 8826afa..af3e8cb 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -109,8 +109,10 @@ "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", + "stored-as-plaintext-info": "This data will be stored as plaintext in the database!", "propagation-seconds": "Propagation Seconds", - "propagation-seconds-info": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation." + "propagation-seconds-info": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation.", + "obtaining-certificate-info": "Obtaining certificate... This might take a few minutes." }, "proxy-hosts": { "title": "Proxy Hosts", diff --git a/utils/certbot-dns-plugins.js b/utils/certbot-dns-plugins.js index 4af678e..ef533c1 100644 --- a/utils/certbot-dns-plugins.js +++ b/utils/certbot-dns-plugins.js @@ -1,5 +1,7 @@ /** * This file contains info about available Certbot DNS plugins. + * This only works for plugins which use the standard argument structure, so: + * --authenticator ---credentials ---propagation-seconds * * File Structure: * @@ -102,13 +104,15 @@ dns_luadns_token = 0123456789abcdef0123456789abcdef`, display_name: "netcup", package_name: "certbot-dns-netcup", package_version: "1.0.0", - credentials: `certbot_dns_njalla:dns_njalla_token = 0123456789abcdef0123456789abcdef01234567`, + credentials: `dns_netcup_customer_id = 123456 +dns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567 +dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`, full_plugin_name: "certbot-dns-netcup:dns-netcup", }, //####################################################// njalla: { display_name: "Njalla", - package_name: "certbot-dns-nsone", + package_name: "certbot-dns-njalla", package_version: "0.0.4", credentials: `certbot_dns_njalla:dns_njalla_token = 0123456789abcdef0123456789abcdef01234567`, full_plugin_name: "certbot-dns-njalla:dns-njalla", From 093b48ad7b5417968d33ee3636e000bcc37f8795 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Tue, 6 Oct 2020 14:52:06 +0200 Subject: [PATCH 04/13] Implements backend changes to allow more dns challenges --- backend/internal/certificate.js | 110 ++++++++++++++------- backend/schema/endpoints/certificates.json | 16 ++- 2 files changed, 91 insertions(+), 35 deletions(-) diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 2acd895..1b6689b 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -13,6 +13,7 @@ const internalNginx = require('./nginx'); const internalHost = require('./host'); const certbot_command = '/usr/bin/certbot'; const le_config = '/etc/letsencrypt.ini'; +const dns_plugins = require('../../utils/certbot-dns-plugins') function omissions() { return ['is_deleted']; @@ -141,11 +142,11 @@ const internalCertificate = { }); }) .then((in_use_result) => { - // Is CloudFlare, no config needed, so skip 3 and 5. - if (data.meta.cloudflare_use) { + // With DNS challenge no config is needed, so skip 3 and 5. + if (certificate.meta.dns_challenge) { return internalNginx.reload().then(() => { // 4. Request cert - return internalCertificate.requestLetsEncryptCloudFlareDnsSsl(certificate, data.meta.cloudflare_token); + return internalCertificate.requestLetsEncryptSslWithDnsChallenge(certificate); }) .then(internalNginx.reload) .then(() => { @@ -772,35 +773,58 @@ const internalCertificate = { }, /** - * @param {Object} certificate the certificate row - * @param {String} apiToken the cloudflare api token + * @param {Object} certificate the certificate row + * @param {String} dns_provider the dns provider name (key used in `certbot-dns-plugins.js`) + * @param {String | null} credentials the content of this providers credentials file + * @param {String} propagation_seconds the cloudflare api token * @returns {Promise} */ - requestLetsEncryptCloudFlareDnsSsl: (certificate, apiToken) => { - logger.info('Requesting Let\'sEncrypt certificates via Cloudflare DNS for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', ')); + requestLetsEncryptSslWithDnsChallenge: (certificate) => { + const dns_plugin = dns_plugins[certificate.meta.dns_provider]; - let tokenLoc = '~/cloudflare-token'; - let storeKey = 'echo "dns_cloudflare_api_token = ' + apiToken + '" > ' + tokenLoc; + if(!dns_plugin){ + throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`) + } - let cmd = - storeKey + ' && ' + + logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); + + const credentials_loc = `/etc/letsencrypt/credentials-${certificate.id}`; + const credentials_cmd = `echo '${certificate.meta.dns_provider_credentials.replace("'", "\'")}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'`; + const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; + + const main_cmd = certbot_command + ' certonly --non-interactive ' + '--cert-name "npm-' + certificate.id + '" ' + '--agree-tos ' + '--email "' + certificate.meta.letsencrypt_email + '" ' + '--domains "' + certificate.domain_names.join(',') + '" ' + - '--dns-cloudflare --dns-cloudflare-credentials ' + tokenLoc + - (le_staging ? ' --staging' : '') - + ' && rm ' + tokenLoc; + '--authenticator ' + dns_plugin.full_plugin_name + ' ' + + '--' + dns_plugin.full_plugin_name + '-credentials "' + credentials_loc + '"' + + ( + certificate.meta.propagation_seconds !== undefined + ? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds + : '' + ) + + (le_staging ? ' --staging' : ''); + + const teardown_cmd = `rm '${credentials_loc}'`; if (debug_mode) { - logger.info('Command:', cmd); + logger.info('Command:', `${credentials_cmd} && ${prepare_cmd} && ${main_cmd} && ${teardown_cmd}`); } - return utils.exec(cmd).then((result) => { - logger.info(result); - return result; - }); + return utils.exec(credentials_cmd) + .then(() => { + return utils.exec(prepare_cmd) + .then(() => { + return utils.exec(main_cmd) + .then(async (result) => { + await utils.exec(teardown_cmd); + logger.info(result); + return result; + }); + }); + }); }, @@ -817,7 +841,7 @@ const internalCertificate = { }) .then((certificate) => { if (certificate.provider === 'letsencrypt') { - let renewMethod = certificate.meta.cloudflare_use ? internalCertificate.renewLetsEncryptCloudFlareSsl : internalCertificate.renewLetsEncryptSsl; + let renewMethod = certificate.meta.dns_challenge ? internalCertificate.renewLetsEncryptSslWithDnsChallenge : internalCertificate.renewLetsEncryptSsl; return renewMethod(certificate) .then(() => { @@ -877,22 +901,42 @@ const internalCertificate = { * @param {Object} certificate the certificate row * @returns {Promise} */ - renewLetsEncryptCloudFlareSsl: (certificate) => { - logger.info('Renewing Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', ')); + renewLetsEncryptSslWithDnsChallenge: (certificate) => { + const dns_plugin = dns_plugins[certificate.meta.dns_provider]; - let cmd = certbot_command + ' renew --non-interactive ' + - '--cert-name "npm-' + certificate.id + '" ' + - '--disable-hook-validation ' + - (le_staging ? '--staging' : ''); - - if (debug_mode) { - logger.info('Command:', cmd); + if(!dns_plugin){ + throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`) } - return utils.exec(cmd) - .then((result) => { - logger.info(result); - return result; + logger.info(`Renewing Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); + + const credentials_loc = `/etc/letsencrypt/credentials-${certificate.id}`; + const credentials_cmd = `echo '${certificate.meta.dns_provider_credentials.replace("'", "\'")}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'`; + const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; + + const main_cmd = + certbot_command + ' renew --non-interactive ' + + '--cert-name "npm-' + certificate.id + '" ' + + '--disable-hook-validation' + + (le_staging ? ' --staging' : ''); + + const teardown_cmd = `rm '${credentials_loc}'`; + + if (debug_mode) { + logger.info('Command:', `${credentials_cmd} && ${prepare_cmd} && ${main_cmd} && ${teardown_cmd}`); + } + + return utils.exec(credentials_cmd) + .then(() => { + return utils.exec(prepare_cmd) + .then(() => { + return utils.exec(main_cmd) + .then(async (result) => { + await utils.exec(teardown_cmd); + logger.info(result); + return result; + }); + }); }); }, diff --git a/backend/schema/endpoints/certificates.json b/backend/schema/endpoints/certificates.json index 27ea2d2..49fd6a7 100644 --- a/backend/schema/endpoints/certificates.json +++ b/backend/schema/endpoints/certificates.json @@ -42,11 +42,23 @@ "letsencrypt_agree": { "type": "boolean" }, - "cloudflare_use": { + "dns_challenge": { "type": "boolean" }, - "cloudflare_token": { + "dns_provider": { "type": "string" + }, + "dns_provider_credentials": { + "type": "string" + }, + "propagation_seconds": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + } + ] + } } } From 64de36cdf27865eb342847e013d0c372405c939c Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Tue, 6 Oct 2020 15:16:45 +0200 Subject: [PATCH 05/13] Adds more DNS plugins --- docker/docker-compose.dev.yml | 9 ++++ utils/certbot-dns-plugins.js | 85 +++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 4321d86..24f2ee1 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -11,6 +11,8 @@ services: - 3080:80 - 3081:81 - 3443:443 + networks: + - nginx_proxy_manager environment: - NODE_ENV=development - FORCE_COLOR=1 @@ -26,6 +28,8 @@ services: db: image: jc21/mariadb-aria + networks: + - nginx_proxy_manager environment: MYSQL_ROOT_PASSWORD: "npm" MYSQL_DATABASE: "npm" @@ -38,6 +42,8 @@ services: image: 'swaggerapi/swagger-ui:latest' ports: - 3001:80 + networks: + - nginx_proxy_manager environment: URL: "http://127.0.0.1:3081/api/schema" PORT: '80' @@ -48,3 +54,6 @@ volumes: npm_data: le_data: db_data: + +networks: + nginx_proxy_manager: diff --git a/utils/certbot-dns-plugins.js b/utils/certbot-dns-plugins.js index ef533c1..a0a5c9a 100644 --- a/utils/certbot-dns-plugins.js +++ b/utils/certbot-dns-plugins.js @@ -38,6 +38,25 @@ dns_cloudxns_secret_key = 1122334455667788`, full_plugin_name: "dns-cloudxns", }, //####################################################// + corenetworks: { + display_name: "Core Networks", + package_name: "certbot-dns-corenetworks", + package_version: "0.1.4", + credentials: `certbot_dns_corenetworks:dns_corenetworks_username = asaHB12r +certbot_dns_corenetworks:dns_corenetworks_password = secure_password`, + full_plugin_name: "certbot-dns-corenetworks:dns-corenetworks", + }, + //####################################################// + cpanel: { + display_name: "cPanel", + package_name: "certbot-dns-cpanel", + package_version: "0.2.2", + credentials: `certbot_dns_cpanel:cpanel_url = https://cpanel.example.com:2083 +certbot_dns_cpanel:cpanel_username = user +certbot_dns_cpanel:cpanel_password = hunter2`, + full_plugin_name: "certbot-dns-cpanel:cpanel", + }, + //####################################################// digitalocean: { display_name: "DigitalOcean", package_name: "certbot-dns-digitalocean", @@ -46,6 +65,16 @@ dns_cloudxns_secret_key = 1122334455667788`, full_plugin_name: "dns-digitalocean", }, //####################################################// + directadmin: { + display_name: "DirectAdmin", + package_name: "certbot-dns-directadmin", + package_version: "0.0.20", + credentials: `directadmin_url = https://my.directadminserver.com:2222 +directadmin_username = username +directadmin_password = aSuperStrongPassword`, + full_plugin_name: "certbot-dns-directadmin:directadmin", + }, + //####################################################// dnsimple: { display_name: "DNSimple", package_name: "certbot-dns-dnsimple", @@ -63,6 +92,15 @@ dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`, full_plugin_name: "dns-dnsmadeeasy", }, //####################################################// + dnspod: { + display_name: "DNSPod", + package_name: "certbot-dns-dnspod", + package_version: "0.1.0", + credentials: `certbot_dns_dnspod:dns_dnspod_email = "DNSPOD-API-REQUIRES-A-VALID-EMAIL" +certbot_dns_dnspod:dns_dnspod_api_token = "DNSPOD-API-TOKEN"`, + full_plugin_name: "certbot-dns-dnspod:dns-dnspod", + }, + //####################################################// google: { display_name: "Google", package_name: "certbot-dns-google", @@ -82,6 +120,36 @@ dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`, full_plugin_name: "certbot-dns-hetzner:dns-hetzner", }, //####################################################// + inwx: { + display_name: "INWX", + package_name: "certbot-dns-inwx", + package_version: "2.1.2", + credentials: `certbot_dns_inwx:dns_inwx_url = https://api.domrobot.com/xmlrpc/ +certbot_dns_inwx:dns_inwx_username = your_username +certbot_dns_inwx:dns_inwx_password = your_password +certbot_dns_inwx:dns_inwx_shared_secret = your_shared_secret optional`, + full_plugin_name: "certbot-dns-inwx:dns-inwx", + }, + //####################################################// + ispconfig: { + display_name: "ISPConfig", + package_name: "certbot-dns-ispconfig", + package_version: "0.2.0", + credentials: `certbot_dns_ispconfig:dns_ispconfig_username = myremoteuser +certbot_dns_ispconfig:dns_ispconfig_password = verysecureremoteuserpassword +certbot_dns_ispconfig:dns_ispconfig_endpoint = https://localhost:8080`, + full_plugin_name: "certbot-dns-ispconfig:dns-ispconfig", + }, + //####################################################// + isset: { + display_name: "Isset", + package_name: "certbot-dns-isset", + package_version: "0.0.3", + credentials: `certbot_dns_isset:dns_isset_endpoint="https://customer.isset.net/api" +certbot_dns_isset:dns_isset_token=""`, + full_plugin_name: "certbot-dns-isset:dns-isset", + }, + //####################################################// linode: { display_name: "Linode", package_name: "certbot-dns-linode", @@ -137,6 +205,15 @@ dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`, full_plugin_name: "dns-ovh", }, //####################################################// + powerdns: { + display_name: "PowerDNS", + package_name: "certbot-dns-powerdns", + package_version: "0.2.0", + credentials: `certbot_dns_powerdns:dns_powerdns_api_url = https://api.mypowerdns.example.org +certbot_dns_powerdns:dns_powerdns_api_key = AbCbASsd!@34`, + full_plugin_name: "certbot-dns-powerdns:dns-powerdns", + }, + //####################################################// rfc2136: { display_name: "RFC 2136", package_name: "certbot-dns-rfc2136", @@ -161,4 +238,12 @@ dns_rfc2136_algorithm = HMAC-SHA512`, credentials: false, full_plugin_name: "dns-route53", }, + //####################################################// + vultr: { + display_name: "Vultr", + package_name: "certbot-dns-vultr", + package_version: "1.0.3", + credentials: `certbot_dns_vultr:dns_vultr_key = YOUR_VULTR_API_KEY`, + full_plugin_name: "certbot-dns-vultr:dns-vultr", + }, }; From 4cbc1f5bbea2ac5dc1ad4b31639e2e2755c42e9d Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Tue, 6 Oct 2020 15:37:51 +0200 Subject: [PATCH 06/13] Minor refactoring --- frontend/js/app/nginx/certificates/form.ejs | 2 +- frontend/js/app/nginx/certificates/form.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/js/app/nginx/certificates/form.ejs b/frontend/js/app/nginx/certificates/form.ejs index 4c7a596..270ab71 100644 --- a/frontend/js/app/nginx/certificates/form.ejs +++ b/frontend/js/app/nginx/certificates/form.ejs @@ -12,7 +12,7 @@
<% if (provider === 'letsencrypt') { %>
- +
diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index 7db7a01..25ebeaf 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -18,7 +18,7 @@ module.exports = Mn.View.extend({ form: 'form', loader_content: '.loader-content', non_loader_content: '.non-loader-content', - error_info: '#error-info', + le_error_info: '#le-error-info', domain_names: 'input[name="domain_names"]', buttons: '.modal-footer button', cancel: 'button.cancel', @@ -68,7 +68,7 @@ module.exports = Mn.View.extend({ 'click @ui.save': function (e) { e.preventDefault(); - this.ui.error_info.hide(); + this.ui.le_error_info.hide(); if (!this.ui.form[0].checkValidity()) { $('').hide().appendTo(this.ui.form).click().remove(); @@ -189,11 +189,11 @@ module.exports = Mn.View.extend({ .catch(err => { try{ const error_message = JSON.parse(err.debug).debug.stack.join("\n"); - this.ui.error_info[0].innerHTML = `

${err.message}

${error_message}
`; + this.ui.le_error_info[0].innerHTML = `

${err.message}

${error_message}
`; } catch(e) { - this.ui.error_info[0].innerHTML = `

${err.message}

`; + this.ui.le_error_info[0].innerHTML = `

${err.message}

`; } - this.ui.error_info.show(); + this.ui.le_error_info.show(); this.ui.le_error_info[0].scrollIntoView(); this.ui.loader_content.hide(); this.ui.non_loader_content.show(); @@ -250,7 +250,7 @@ module.exports = Mn.View.extend({ this.ui.dns_challenge_content.hide(); this.ui.credentials_file_content.hide(); this.ui.loader_content.hide(); - this.ui.error_info.hide(); + this.ui.le_error_info.hide(); }, initialize: function (options) { From 514b13fcc24fd07bcef6885bec40b9c169626597 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Tue, 6 Oct 2020 16:12:12 +0200 Subject: [PATCH 07/13] Fixes build issues due to globally used file --- backend/internal/certificate.js | 2 +- docker/Dockerfile | 1 + frontend/js/app/nginx/certificates/form.js | 2 +- frontend/js/app/nginx/certificates/list/item.js | 2 +- frontend/js/app/nginx/dead/form.js | 2 +- frontend/js/app/nginx/proxy/form.js | 2 +- frontend/js/app/nginx/redirection/form.js | 2 +- {utils => global}/certbot-dns-plugins.js | 0 8 files changed, 7 insertions(+), 6 deletions(-) rename {utils => global}/certbot-dns-plugins.js (100%) diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 1b6689b..fc11a31 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -13,7 +13,7 @@ const internalNginx = require('./nginx'); const internalHost = require('./host'); const certbot_command = '/usr/bin/certbot'; const le_config = '/etc/letsencrypt.ini'; -const dns_plugins = require('../../utils/certbot-dns-plugins') +const dns_plugins = require('../../global/certbot-dns-plugins') function omissions() { return ['is_deleted']; diff --git a/docker/Dockerfile b/docker/Dockerfile index 3c99751..acac5fa 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,6 +34,7 @@ EXPOSE 443 COPY docker/rootfs / ADD backend /app ADD frontend/dist /app/frontend +COPY global /app/global WORKDIR /app RUN yarn install diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index 25ebeaf..df38159 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -4,7 +4,7 @@ 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'); +const dns_providers = require('../../../../../global/certbot-dns-plugins'); require('jquery-serializejson'); require('selectize'); diff --git a/frontend/js/app/nginx/certificates/list/item.js b/frontend/js/app/nginx/certificates/list/item.js index b5b2d85..c967fdb 100644 --- a/frontend/js/app/nginx/certificates/list/item.js +++ b/frontend/js/app/nginx/certificates/list/item.js @@ -2,7 +2,7 @@ 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') +const dns_providers = require('../../../../../../global/certbot-dns-plugins') module.exports = Mn.View.extend({ template: template, diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js index 0df24f7..a39038b 100644 --- a/frontend/js/app/nginx/dead/form.js +++ b/frontend/js/app/nginx/dead/form.js @@ -5,7 +5,7 @@ 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'); +const dns_providers = require('../../../../../global/certbot-dns-plugins'); require('jquery-serializejson'); require('selectize'); diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 3c17225..ec76987 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -8,7 +8,7 @@ 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'); +const dns_providers = require('../../../../../global/certbot-dns-plugins'); require('jquery-serializejson'); diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js index 5ca3b8d..6fa3693 100644 --- a/frontend/js/app/nginx/redirection/form.js +++ b/frontend/js/app/nginx/redirection/form.js @@ -5,7 +5,7 @@ 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'); +const dns_providers = require('../../../../../global/certbot-dns-plugins'); require('jquery-serializejson'); diff --git a/utils/certbot-dns-plugins.js b/global/certbot-dns-plugins.js similarity index 100% rename from utils/certbot-dns-plugins.js rename to global/certbot-dns-plugins.js From 95208a50a742a40f4aba51b8d73433f7afd35327 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Thu, 8 Oct 2020 13:21:17 +0200 Subject: [PATCH 08/13] Increases timeouts in front- and backend --- Jenkinsfile | 1 + backend/internal/certificate.js | 2 +- backend/routes/api/nginx/certificates.js | 2 ++ docker/rootfs/etc/nginx/conf.d/dev.conf | 3 +++ docker/rootfs/etc/nginx/conf.d/production.conf | 3 +++ frontend/js/app/api.js | 3 ++- frontend/js/app/nginx/certificates/form.js | 14 +++++++------- scripts/frontend-build | 2 +- 8 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f5ec652..74dc0a1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -65,6 +65,7 @@ pipeline { // See: https://github.com/yarnpkg/yarn/issues/3254 sh '''docker run --rm \\ -v "$(pwd)/backend:/app" \\ + -v "$(pwd)/global:/app/global" \\ -w /app \\ node:latest \\ sh -c "yarn install && yarn eslint . && rm -rf node_modules" diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index fc11a31..641b494 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -13,7 +13,7 @@ const internalNginx = require('./nginx'); const internalHost = require('./host'); const certbot_command = '/usr/bin/certbot'; const le_config = '/etc/letsencrypt.ini'; -const dns_plugins = require('../../global/certbot-dns-plugins') +const dns_plugins = require('../global/certbot-dns-plugins'); function omissions() { return ['is_deleted']; diff --git a/backend/routes/api/nginx/certificates.js b/backend/routes/api/nginx/certificates.js index 50d3913..553a0bb 100644 --- a/backend/routes/api/nginx/certificates.js +++ b/backend/routes/api/nginx/certificates.js @@ -58,6 +58,7 @@ router .post((req, res, next) => { apiValidator({$ref: 'endpoints/certificates#/links/1/schema'}, req.body) .then((payload) => { + req.setTimeout(900000); // 15 minutes timeout return internalCertificate.create(res.locals.access, payload); }) .then((result) => { @@ -197,6 +198,7 @@ router * Renew certificate */ .post((req, res, next) => { + req.setTimeout(900000); // 15 minutes timeout internalCertificate.renew(res.locals.access, { id: parseInt(req.params.certificate_id, 10) }) diff --git a/docker/rootfs/etc/nginx/conf.d/dev.conf b/docker/rootfs/etc/nginx/conf.d/dev.conf index b70db17..edbdec8 100644 --- a/docker/rootfs/etc/nginx/conf.d/dev.conf +++ b/docker/rootfs/etc/nginx/conf.d/dev.conf @@ -17,6 +17,9 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://127.0.0.1:3000/; + + proxy_read_timeout 15m; + proxy_send_timeout 15m; } location / { diff --git a/docker/rootfs/etc/nginx/conf.d/production.conf b/docker/rootfs/etc/nginx/conf.d/production.conf index b632bce..877e51d 100644 --- a/docker/rootfs/etc/nginx/conf.d/production.conf +++ b/docker/rootfs/etc/nginx/conf.d/production.conf @@ -18,6 +18,9 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://127.0.0.1:3000/; + + proxy_read_timeout 15m; + proxy_send_timeout 15m; } location / { diff --git a/frontend/js/app/api.js b/frontend/js/app/api.js index 1d7b358..baa5cb1 100644 --- a/frontend/js/app/api.js +++ b/frontend/js/app/api.js @@ -586,7 +586,8 @@ module.exports = { /** * @param {Object} data */ - create: function (data, timeout = 180000) { + create: function (data) { + const timeout = 180000 + (data.meta.propagation_seconds ? Number(data.meta.propagation_seconds) * 1000 : 0); return fetch('post', 'nginx/certificates', data, {timeout}); }, diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index df38159..94b18a8 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -167,8 +167,7 @@ module.exports = Mn.View.extend({ } }) .then(() => { - const timeout = 180000 + (data.meta.propagation_seconds ? Number(data.meta.propagation_seconds) : 0); - return App.Api.Nginx.Certificates.create(data, timeout); + return App.Api.Nginx.Certificates.create(data); }) .then(result => { view.model.set(result); @@ -187,12 +186,13 @@ module.exports = Mn.View.extend({ }); }) .catch(err => { - try{ - const error_message = JSON.parse(err.debug).debug.stack.join("\n"); - this.ui.le_error_info[0].innerHTML = `

${err.message}

${error_message}
`; - } catch(e) { - this.ui.le_error_info[0].innerHTML = `

${err.message}

`; + let more_info = ''; + if(err.code === 500){ + try{ + more_info = JSON.parse(err.debug).debug.stack.join("\n"); + } catch(e) {} } + this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `
${more_info}
`:''}`; this.ui.le_error_info.show(); this.ui.le_error_info[0].scrollIntoView(); this.ui.loader_content.hide(); diff --git a/scripts/frontend-build b/scripts/frontend-build index 506a334..45c6d59 100755 --- a/scripts/frontend-build +++ b/scripts/frontend-build @@ -10,7 +10,7 @@ if hash docker 2>/dev/null; then docker pull "${DOCKER_IMAGE}" cd "${DIR}/.." echo -e "${BLUE}❯ ${CYAN}Building Frontend ...${RESET}" - docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend" + docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -v "$(pwd)/global:/app/global" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend" echo -e "${BLUE}❯ ${GREEN}Building Frontend Complete${RESET}" else echo -e "${RED}❯ docker command is not available${RESET}" From 867fe1322bdca87929f6e74196d24605f2b170e8 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Thu, 8 Oct 2020 13:38:20 +0200 Subject: [PATCH 09/13] Unifies directory structure in dev and prod containers --- backend/config/sqlite-test-db.json | 2 +- docker/docker-compose.dev.yml | 4 +++- docker/rootfs/etc/services.d/manager/run | 2 +- scripts/test-dev | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/config/sqlite-test-db.json b/backend/config/sqlite-test-db.json index 2806121..ad54886 100644 --- a/backend/config/sqlite-test-db.json +++ b/backend/config/sqlite-test-db.json @@ -4,7 +4,7 @@ "knex": { "client": "sqlite3", "connection": { - "filename": "/app/backend/config/mydb.sqlite" + "filename": "/app/config/mydb.sqlite" }, "pool": { "min": 0, diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 24f2ee1..5668dbd 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -21,7 +21,9 @@ services: volumes: - npm_data:/data - le_data:/etc/letsencrypt - - ..:/app + - ../backend:/app + - ../frontend:/app/frontend + - ../global:/app/global depends_on: - db working_dir: /app diff --git a/docker/rootfs/etc/services.d/manager/run b/docker/rootfs/etc/services.d/manager/run index 3ea1a17..ba0fb05 100755 --- a/docker/rootfs/etc/services.d/manager/run +++ b/docker/rootfs/etc/services.d/manager/run @@ -5,7 +5,7 @@ mkdir -p /data/letsencrypt-acme-challenge cd /app || echo if [ "$DEVELOPMENT" == "true" ]; then - cd /app/backend || exit 1 + cd /app || exit 1 yarn install node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js else diff --git a/scripts/test-dev b/scripts/test-dev index eb5c5bd..f75527b 100755 --- a/scripts/test-dev +++ b/scripts/test-dev @@ -7,7 +7,7 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if hash docker-compose 2>/dev/null; then cd "${DIR}/.." echo -e "${BLUE}❯ ${CYAN}Testing Dev Stack ...${RESET}" - docker-compose exec -T npm bash -c "cd /app/backend && task test" + docker-compose exec -T npm bash -c "cd /app && task test" else echo -e "${RED}❯ docker-compose command is not available${RESET}" fi From 3fec135fe5ef3cdfeb0090533ba737aa78fc329b Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:23:21 +0200 Subject: [PATCH 10/13] Fixes ESlint formatting errors --- backend/internal/certificate.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 641b494..98e5274 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -782,15 +782,15 @@ const internalCertificate = { requestLetsEncryptSslWithDnsChallenge: (certificate) => { const dns_plugin = dns_plugins[certificate.meta.dns_provider]; - if(!dns_plugin){ - throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`) + if (!dns_plugin) { + throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`); } logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); - const credentials_loc = `/etc/letsencrypt/credentials-${certificate.id}`; - const credentials_cmd = `echo '${certificate.meta.dns_provider_credentials.replace("'", "\'")}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'`; - const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; + const credentials_loc = '/etc/letsencrypt/credentials-' + certificate.id; + const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\''; + const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; const main_cmd = certbot_command + ' certonly --non-interactive ' + @@ -802,8 +802,8 @@ const internalCertificate = { '--' + dns_plugin.full_plugin_name + '-credentials "' + credentials_loc + '"' + ( certificate.meta.propagation_seconds !== undefined - ? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds - : '' + ? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds + : '' ) + (le_staging ? ' --staging' : ''); @@ -904,15 +904,15 @@ const internalCertificate = { renewLetsEncryptSslWithDnsChallenge: (certificate) => { const dns_plugin = dns_plugins[certificate.meta.dns_provider]; - if(!dns_plugin){ - throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`) + if (!dns_plugin) { + throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`); } logger.info(`Renewing Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); - const credentials_loc = `/etc/letsencrypt/credentials-${certificate.id}`; - const credentials_cmd = `echo '${certificate.meta.dns_provider_credentials.replace("'", "\'")}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'`; - const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; + const credentials_loc = '/etc/letsencrypt/credentials-' + certificate.id; + const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\''; + const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; const main_cmd = certbot_command + ' renew --non-interactive ' + From 07e78aec482125482da9f668669d2614872cf3b5 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Thu, 8 Oct 2020 15:30:13 +0200 Subject: [PATCH 11/13] Adds error stack information in prod environment for certificates --- backend/app.js | 2 +- frontend/js/app/nginx/certificates/form.js | 2 +- frontend/js/app/nginx/dead/form.js | 2 +- frontend/js/app/nginx/proxy/form.js | 2 +- frontend/js/app/nginx/redirection/form.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/app.js b/backend/app.js index fc39e10..33ffacc 100644 --- a/backend/app.js +++ b/backend/app.js @@ -66,7 +66,7 @@ app.use(function (err, req, res, next) { } }; - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === 'development' || (req.baseUrl + req.path).includes('nginx/certificates')) { payload.debug = { stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null, previous: err.previous diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index 94b18a8..677ba9a 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -187,7 +187,7 @@ module.exports = Mn.View.extend({ }) .catch(err => { let more_info = ''; - if(err.code === 500){ + if(err.code === 500 && err.debug){ try{ more_info = JSON.parse(err.debug).debug.stack.join("\n"); } catch(e) {} diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js index a39038b..8f6774f 100644 --- a/frontend/js/app/nginx/dead/form.js +++ b/frontend/js/app/nginx/dead/form.js @@ -193,7 +193,7 @@ module.exports = Mn.View.extend({ }) .catch(err => { let more_info = ''; - if(err.code === 500){ + if(err.code === 500 && err.debug){ try{ more_info = JSON.parse(err.debug).debug.stack.join("\n"); } catch(e) {} diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index ec76987..8802b95 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -228,7 +228,7 @@ module.exports = Mn.View.extend({ }) .catch(err => { let more_info = ''; - if(err.code === 500){ + if(err.code === 500 && err.debug){ try{ more_info = JSON.parse(err.debug).debug.stack.join("\n"); } catch(e) {} diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js index 6fa3693..1f81fee 100644 --- a/frontend/js/app/nginx/redirection/form.js +++ b/frontend/js/app/nginx/redirection/form.js @@ -195,7 +195,7 @@ module.exports = Mn.View.extend({ }) .catch(err => { let more_info = ''; - if(err.code === 500){ + if(err.code === 500 && err.debug){ try{ more_info = JSON.parse(err.debug).debug.stack.join("\n"); } catch(e) {} From 049e4249570fe629b0ddf46ca2bccde82e48a392 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Wed, 14 Oct 2020 09:20:52 +0200 Subject: [PATCH 12/13] Adds special case for Route53 --- backend/internal/certificate.js | 23 ++++++++++++++++++++--- global/certbot-dns-plugins.js | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 98e5274..06b0990 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -792,20 +792,32 @@ const internalCertificate = { const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\''; const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; - const main_cmd = + // Whether the plugin has a ---credentials argument + const has_config_arg = certificate.meta.dns_provider !== 'route53'; + + let main_cmd = certbot_command + ' certonly --non-interactive ' + '--cert-name "npm-' + certificate.id + '" ' + '--agree-tos ' + '--email "' + certificate.meta.letsencrypt_email + '" ' + '--domains "' + certificate.domain_names.join(',') + '" ' + '--authenticator ' + dns_plugin.full_plugin_name + ' ' + - '--' + dns_plugin.full_plugin_name + '-credentials "' + credentials_loc + '"' + + ( + has_config_arg + ? '--' + dns_plugin.full_plugin_name + '-credentials "' + credentials_loc + '"' + : '' + ) + ( certificate.meta.propagation_seconds !== undefined ? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds : '' ) + (le_staging ? ' --staging' : ''); + + // Prepend the path to the credentials file as an environment variable + if (certificate.meta.dns_provider === 'route53') { + main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd + } const teardown_cmd = `rm '${credentials_loc}'`; @@ -914,12 +926,17 @@ const internalCertificate = { const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\''; const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version; - const main_cmd = + let main_cmd = certbot_command + ' renew --non-interactive ' + '--cert-name "npm-' + certificate.id + '" ' + '--disable-hook-validation' + (le_staging ? ' --staging' : ''); + // Prepend the path to the credentials file as an environment variable + if (certificate.meta.dns_provider === 'route53') { + main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd + } + const teardown_cmd = `rm '${credentials_loc}'`; if (debug_mode) { diff --git a/global/certbot-dns-plugins.js b/global/certbot-dns-plugins.js index a0a5c9a..724a339 100644 --- a/global/certbot-dns-plugins.js +++ b/global/certbot-dns-plugins.js @@ -235,7 +235,9 @@ dns_rfc2136_algorithm = HMAC-SHA512`, display_name: "Route 53 (Amazon)", package_name: "certbot-dns-route53", package_version: "1.8.0", - credentials: false, + credentials: `[default] +aws_access_key_id=AKIAIOSFODNN7EXAMPLE +aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`, full_plugin_name: "dns-route53", }, //####################################################// From ac9f05230981f13beb688e6ea19c61c45c91fea0 Mon Sep 17 00:00:00 2001 From: chaptergy <26956711+chaptergy@users.noreply.github.com> Date: Wed, 14 Oct 2020 09:55:45 +0200 Subject: [PATCH 13/13] Fixes linting errors --- backend/internal/certificate.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 06b0990..613c837 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -814,10 +814,10 @@ const internalCertificate = { ) + (le_staging ? ' --staging' : ''); - // Prepend the path to the credentials file as an environment variable - if (certificate.meta.dns_provider === 'route53') { - main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd - } + // Prepend the path to the credentials file as an environment variable + if (certificate.meta.dns_provider === 'route53') { + main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd; + } const teardown_cmd = `rm '${credentials_loc}'`; @@ -934,7 +934,7 @@ const internalCertificate = { // Prepend the path to the credentials file as an environment variable if (certificate.meta.dns_provider === 'route53') { - main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd + main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd; } const teardown_cmd = `rm '${credentials_loc}'`;