<% if (provider === 'letsencrypt') { %>
+
+
@@ -21,21 +29,96 @@
-
+
-
-
-
-
-
+
+
@@ -87,7 +170,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..c967fdb 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('../../../../../../global/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..253c4b6 100644
--- a/frontend/js/app/nginx/dead/form.ejs
+++ b/frontend/js/app/nginx/dead/form.ejs
@@ -4,6 +4,7 @@
-
+
-
-
-
-
-
+
+
diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js
index aca367a..8f6774f 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('../../../../../global/certbot-dns-plugins');
require('jquery-serializejson');
require('selectize');
@@ -13,20 +15,24 @@ 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',
+ le_error_info: '#le-error-info',
+ 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);
}
@@ -81,19 +87,37 @@ 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();
}
},
'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();
@@ -104,10 +128,22 @@ 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;
+
+ 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(',');
@@ -116,7 +152,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,12 +161,9 @@ 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);
}
@@ -159,7 +192,15 @@ module.exports = Mn.View.extend({
});
})
.catch(err => {
- alert(err.message);
+ let more_info = '';
+ if(err.code === 500 && err.debug){
+ 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');
});
@@ -169,7 +210,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 +244,9 @@ 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();
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..1a49830 100644
--- a/frontend/js/app/nginx/proxy/form.ejs
+++ b/frontend/js/app/nginx/proxy/form.ejs
@@ -4,6 +4,7 @@
-
+
-
-
-
-
-
+
+
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js
index 0f64281..8802b95 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('../../../../../global/certbot-dns-plugins');
require('jquery-serializejson');
@@ -19,25 +21,29 @@ 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',
+ 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"]',
+ 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 +55,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 +101,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();
}
},
@@ -115,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();
@@ -143,6 +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;
+
+ 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,7 +187,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,12 +196,9 @@ 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);
}
@@ -194,7 +227,15 @@ module.exports = Mn.View.extend({
});
})
.catch(err => {
- alert(err.message);
+ let more_info = '';
+ if(err.code === 500 && err.debug){
+ 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');
});
@@ -204,7 +245,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 +312,9 @@ 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();
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..3247233 100644
--- a/frontend/js/app/nginx/redirection/form.ejs
+++ b/frontend/js/app/nginx/redirection/form.ejs
@@ -4,6 +4,7 @@
-
+
-
-
-
-
-
+
+
diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js
index 4e5b168..1f81fee 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('../../../../../global/certbot-dns-plugins');
+
require('jquery-serializejson');
require('selectize');
@@ -13,20 +16,24 @@ 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',
+ le_error_info: '#le-error-info',
+ 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 +41,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,19 +87,37 @@ 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();
}
},
'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();
@@ -103,12 +128,24 @@ 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;
+
+ 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(',');
@@ -117,7 +154,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,12 +163,9 @@ 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);
}
@@ -160,7 +194,15 @@ module.exports = Mn.View.extend({
});
})
.catch(err => {
- alert(err.message);
+ let more_info = '';
+ if(err.code === 500 && err.debug){
+ 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');
});
@@ -170,7 +212,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 +246,9 @@ 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();
this.ui.certificate_select.selectize({
valueField: 'id',
diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json
index d0c9d8e..4bfb190 100644
--- a/frontend/js/i18n/messages.json
+++ b/frontend/js/i18n/messages.json
@@ -102,7 +102,17 @@
"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",
+ "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.",
+ "obtaining-certificate-info": "Obtaining certificate... This might take a few minutes."
},
"proxy-hosts": {
"title": "Proxy Hosts",
@@ -196,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",
diff --git a/global/certbot-dns-plugins.js b/global/certbot-dns-plugins.js
new file mode 100644
index 0000000..8170f73
--- /dev/null
+++ b/global/certbot-dns-plugins.js
@@ -0,0 +1,251 @@
+/**
+ * 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:
+ *
+ * {
+ * 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',
+ },
+ //####################################################//
+ 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',
+ 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
+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',
+ 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/
+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',
+ 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: `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
+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
+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
+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: `[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',
+ },
+};
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}"
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
|