From e5cb7500153756a8e30323da0245c63fe1420cd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Sep 2020 23:42:28 +0000 Subject: [PATCH 01/19] Bump node-forge from 0.9.1 to 0.10.0 in /docs Bumps [node-forge](https://github.com/digitalbazaar/forge) from 0.9.1 to 0.10.0. - [Release notes](https://github.com/digitalbazaar/forge/releases) - [Changelog](https://github.com/digitalbazaar/forge/blob/master/CHANGELOG.md) - [Commits](https://github.com/digitalbazaar/forge/compare/0.9.1...0.10.0) Signed-off-by: dependabot[bot] --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index 54a1f93..190db76 100644 --- a/docs/package.json +++ b/docs/package.json @@ -434,7 +434,7 @@ "neo-async": "^2.6.2", "nice-try": "^2.0.1", "no-case": "^3.0.3", - "node-forge": "^0.9.1", + "node-forge": "^0.10.0", "node-libs-browser": "^2.2.1", "node-releases": "^1.1.60", "nopt": "^4.0.3", diff --git a/docs/yarn.lock b/docs/yarn.lock index 4dd7fac..f87d492 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -6584,10 +6584,10 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== -node-forge@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" - integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== node-libs-browser@^2.2.1: version "2.2.1" From 3e10b7b2b197c856285679def491a61d37ec3717 Mon Sep 17 00:00:00 2001 From: Philip Mooney Date: Sat, 19 Sep 2020 22:16:16 +0100 Subject: [PATCH 02/19] Fix for access list getAll when not granted all permissions --- backend/internal/access-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index c70a53a..79daa25 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -384,7 +384,7 @@ const internalAccessList = { .orderBy('access_list.name', 'ASC'); if (access_data.permission_visibility !== 'all') { - query.andWhere('owner_user_id', access.token.getUserId(1)); + query.andWhere('access_list.owner_user_id', access.token.getUserId(1)); } // Query is used for searching 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 03/19] 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 04/19] 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 05/19] 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 06/19] 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 07/19] 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 08/19] 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 09/19] 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 10/19] 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 11/19] 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 12/19] 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 13/19] 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 14/19] 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 15/19] 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}'`; From 0df054577746d57f1991b8789c3e7ed1f5b998d5 Mon Sep 17 00:00:00 2001 From: James Morgan Date: Wed, 14 Oct 2020 20:17:25 +1100 Subject: [PATCH 16/19] Allows auth information from AccessList not to be passed to proxied hosts. Resolves issue #153. Signed-off-by: James Morgan --- backend/internal/access-list.js | 2 + .../migrations/20201014143841_pass_auth.js | 41 +++++++++++++++++++ backend/models/access_list.js | 4 ++ backend/schema/endpoints/access-lists.json | 9 ++++ backend/templates/proxy_host.conf | 2 + frontend/js/app/nginx/access/form.ejs | 10 +++++ frontend/js/app/nginx/access/form.js | 1 + frontend/js/i18n/messages.json | 3 +- 8 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 backend/migrations/20201014143841_pass_auth.js diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index 79daa25..5b817d0 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -31,6 +31,7 @@ const internalAccessList = { .insertAndFetch({ name: data.name, satisfy_any: data.satisfy_any, + pass_auth: data.pass_auth, owner_user_id: access.token.getUserId(1) }); }) @@ -128,6 +129,7 @@ const internalAccessList = { .patch({ name: data.name, satisfy_any: data.satisfy_any, + pass_auth: data.pass_auth, }); } }) diff --git a/backend/migrations/20201014143841_pass_auth.js b/backend/migrations/20201014143841_pass_auth.js new file mode 100644 index 0000000..a7767eb --- /dev/null +++ b/backend/migrations/20201014143841_pass_auth.js @@ -0,0 +1,41 @@ +const migrate_name = 'pass_auth'; +const logger = require('../logger').migrate; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.up = function (knex/*, Promise*/) { + + logger.info('[' + migrate_name + '] Migrating Up...'); + + return knex.schema.table('access_list', function (access_list) { + access_list.integer('pass_auth').notNull().defaultTo(1); + }) + .then(() => { + logger.info('[' + migrate_name + '] access_list Table altered'); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex/*, Promise*/) { + logger.info('[' + migrate_name + '] Migrating Down...'); + + return knex.schema.table('access_list', function (access_list) { + access_list.dropColumn('pass_auth'); + }) + .then(() => { + logger.info('[' + migrate_name + '] access_list pass_auth Column dropped'); + }); +}; diff --git a/backend/models/access_list.js b/backend/models/access_list.js index 8e63a2a..01974e8 100644 --- a/backend/models/access_list.js +++ b/backend/models/access_list.js @@ -93,6 +93,10 @@ class AccessList extends Model { get satisfy() { return this.satisfy_any ? 'satisfy any' : 'satisfy all'; } + + get passauth() { + return this.pass_auth ? '' : 'proxy_set_header Authorization "";'; + } } module.exports = AccessList; diff --git a/backend/schema/endpoints/access-lists.json b/backend/schema/endpoints/access-lists.json index 646306b..404e323 100644 --- a/backend/schema/endpoints/access-lists.json +++ b/backend/schema/endpoints/access-lists.json @@ -42,6 +42,9 @@ "satisfy_any": { "type": "boolean" }, + "pass_auth": { + "type": "boolean" + }, "meta": { "type": "object" } @@ -102,6 +105,9 @@ "satisfy_any": { "$ref": "#/definitions/satisfy_any" }, + "pass_auth": { + "$ref": "#/definitions/pass_auth" + }, "items": { "type": "array", "minItems": 0, @@ -167,6 +173,9 @@ "satisfy_any": { "$ref": "#/definitions/satisfy_any" }, + "pass_auth": { + "$ref": "#/definitions/pass_auth" + }, "items": { "type": "array", "minItems": 0, diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf index b553e1c..1c2c0e7 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -27,6 +27,8 @@ server { # Authorization auth_basic "Authorization required"; auth_basic_user_file /data/access/{{ access_list_id }}; + + {{ access_list.passauth }} {% endif %} # Access Rules diff --git a/frontend/js/app/nginx/access/form.ejs b/frontend/js/app/nginx/access/form.ejs index 94423db..b22b99a 100644 --- a/frontend/js/app/nginx/access/form.ejs +++ b/frontend/js/app/nginx/access/form.ejs @@ -31,6 +31,16 @@
+ +
+
+ +
+
diff --git a/frontend/js/app/nginx/access/form.js b/frontend/js/app/nginx/access/form.js index 0e4291a..92581f8 100644 --- a/frontend/js/app/nginx/access/form.js +++ b/frontend/js/app/nginx/access/form.js @@ -73,6 +73,7 @@ module.exports = Mn.View.extend({ let data = { name: form_data.name, satisfy_any: !!form_data.satisfy_any, + pass_auth: !!form_data.pass_auth, items: items_data, clients: clients_data }; diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index af3e8cb..4bfb190 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -206,7 +206,8 @@ "authorization": "Authorization", "access": "Access", "satisfy": "Satisfy", - "satisfy-any": "Satisfy Any" + "satisfy-any": "Satisfy Any", + "pass-auth": "Pass Auth to Host" }, "users": { "title": "Users", From 10f0eb17d783f50456de887ecd7a3d2ffffeda09 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 15 Oct 2020 10:33:51 +1000 Subject: [PATCH 17/19] Fix linting errors --- global/certbot-dns-plugins.js | 386 +++++++++++++++++----------------- 1 file changed, 193 insertions(+), 193 deletions(-) diff --git a/global/certbot-dns-plugins.js b/global/certbot-dns-plugins.js index 724a339..8170f73 100644 --- a/global/certbot-dns-plugins.js +++ b/global/certbot-dns-plugins.js @@ -20,205 +20,205 @@ */ module.exports = { - cloudflare: { - display_name: "Cloudflare", - package_name: "certbot-dns-cloudflare", - package_version: "1.8.0", - credentials: `# Cloudflare API token + 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 + 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", - }, - //####################################################// - corenetworks: { - display_name: "Core Networks", - package_name: "certbot-dns-corenetworks", - package_version: "0.1.4", - credentials: `certbot_dns_corenetworks:dns_corenetworks_username = asaHB12r + 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 + 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", - package_version: "1.8.0", - credentials: `dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff`, - 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 + full_plugin_name: 'certbot-dns-cpanel:cpanel', + }, + //####################################################// + digitalocean: { + display_name: 'DigitalOcean', + package_name: 'certbot-dns-digitalocean', + package_version: '1.8.0', + credentials: 'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff', + 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", - 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 + full_plugin_name: 'certbot-dns-directadmin:directadmin', + }, + //####################################################// + 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", - }, - //####################################################// - 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" + 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", - package_version: "1.8.0", - credentials: `{ - "type": "service_account", - ... + full_plugin_name: 'certbot-dns-dnspod:dns-dnspod', + }, + //####################################################// + 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", - }, - //####################################################// - 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/ + 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', + }, + //####################################################// + 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 + 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" + 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", - package_version: "1.8.0", - credentials: `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64 + full_plugin_name: 'certbot-dns-isset:dns-isset', + }, + //####################################################// + 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 + 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: `dns_netcup_customer_id = 123456 + full_plugin_name: 'dns-luadns', + }, + //####################################################// + netcup: { + display_name: 'netcup', + package_name: 'certbot-dns-netcup', + package_version: '1.0.0', + 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-njalla", - 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 + full_plugin_name: 'certbot-dns-netcup:dns-netcup', + }, + //####################################################// + njalla: { + display_name: 'Njalla', + 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', + }, + //####################################################// + 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", - }, - //####################################################// - 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 + 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", - package_version: "1.8.0", - credentials: `# Target DNS server + full_plugin_name: 'certbot-dns-powerdns:dns-powerdns', + }, + //####################################################// + 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 @@ -228,24 +228,24 @@ dns_rfc2136_name = keyname. 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: `[default] + full_plugin_name: 'dns-rfc2136', + }, + //####################################################// + route53: { + display_name: 'Route 53 (Amazon)', + package_name: 'certbot-dns-route53', + package_version: '1.8.0', + credentials: `[default] aws_access_key_id=AKIAIOSFODNN7EXAMPLE aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`, - 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", - }, + 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 dbf5dec23bbff53ae814c06cfc79a7d943fabf96 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 15 Oct 2020 10:40:01 +1000 Subject: [PATCH 18/19] Bump version --- .version | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.version b/.version index fad066f..e70b452 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.5.0 \ No newline at end of file +2.6.0 diff --git a/README.md b/README.md index b82e515..035da51 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@



- + From c413b4af3f9303d1fa614c40a83b854459500bb7 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 15 Oct 2020 14:06:21 +1000 Subject: [PATCH 19/19] Added contributors --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 035da51..b94dbcd 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,26 @@ Special thanks to the following contributors:
Jaap-Jan de Wit + + + +
James Morgan +
+ + + + + + +
chaptergy +
+ + + + +
Philip Mooney +
+