Переглянути джерело

Adds frontend improvements and fixes

chaptergy 5 роки тому
батько
коміт
05f6a55a0b

+ 5 - 5
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});
             }
         }
     },

+ 15 - 3
frontend/js/app/nginx/certificates/form.ejs

@@ -1,12 +1,20 @@
 <div class="modal-content">
     <div class="modal-header">
         <h5 class="modal-title"><%- i18n('certificates', 'form-title', {provider: provider}) %></h5>
-        <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
+        <button type="button" class="close cancel non-loader-content" aria-label="Close" data-dismiss="modal">&nbsp;</button>
     </div>
     <div class="modal-body">
-        <form>
+        <div class="text-center loader-content">
+            <div class="loader mx-auto my-6"></div>
+            <p><%- i18n('ssl', 'obtaining-certificate-info') %></p>
+        </div>
+        <form class="non-loader-content">
             <div class="row">
                 <% if (provider === 'letsencrypt') { %>
+                    <div class="col-sm-12 col-md-12">
+                        <div class="alert alert-danger" id="error-info" role="alert"></div>
+                    </div>
+
                     <div class="col-sm-12 col-md-12">
                         <div class="form-group">
                             <label class="form-label"><%- i18n('all-hosts', 'domain-names') %> <span class="form-required">*</span></label>
@@ -82,6 +90,10 @@
                                             <i class="fe fe-info"></i> 
                                             <%= i18n('ssl', 'credentials-file-content-info') %>
                                         </div>
+                                        <div class="text-red small">
+                                            <i class="fe fe-alert-triangle"></i> 
+                                            <%= i18n('ssl', 'stored-as-plaintext-info') %>
+                                        </div>
                                     </div>
                                 </div>
                             </div>
@@ -158,7 +170,7 @@
             </div>
         </form>
     </div>
-    <div class="modal-footer">
+    <div class="modal-footer non-loader-content">
         <button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
         <button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
     </div>

+ 29 - 11
frontend/js/app/nginx/certificates/form.js

@@ -16,6 +16,9 @@ module.exports = Mn.View.extend({
 
     ui: {
         form:                                 'form',
+        loader_content:                       '.loader-content',
+        non_loader_content:                   '.non-loader-content',
+        error_info:                           '#error-info',
         domain_names:                         'input[name="domain_names"]',
         buttons:                              '.modal-footer button',
         cancel:                               'button.cancel',
@@ -65,6 +68,7 @@ module.exports = Mn.View.extend({
         
         'click @ui.save': function (e) {
             e.preventDefault();
+            this.ui.error_info.hide();
 
             if (!this.ui.form[0].checkValidity()) {
                 $('<input type="submit">').hide().appendTo(this.ui.form).click().remove();
@@ -93,12 +97,16 @@ module.exports = Mn.View.extend({
             }
 
             // Manipulate
-            if (typeof data.meta !== 'undefined' && typeof data.meta.letsencrypt_agree !== 'undefined') {
-                data.meta.letsencrypt_agree = !!data.meta.letsencrypt_agree;
-            }
+            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 (typeof data.meta !== 'undefined' && typeof data.meta.dns_challenge !== 'undefined') {
-                data.meta.dns_challenge = !!data.meta.dns_challenge;
+            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) {
@@ -140,8 +148,8 @@ module.exports = Mn.View.extend({
                 }
             }
 
-            this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
-            this.ui.save.addClass('btn-loading');
+            this.ui.loader_content.show();
+            this.ui.non_loader_content.hide();
 
             // compile file data
             let form_data = new FormData();
@@ -159,7 +167,8 @@ module.exports = Mn.View.extend({
                 }
             })
                 .then(() => {
-                    return App.Api.Nginx.Certificates.create(data);
+                    const timeout = 180000 + (data.meta.propagation_seconds ? Number(data.meta.propagation_seconds) : 0);
+                    return App.Api.Nginx.Certificates.create(data, timeout);
                 })
                 .then(result => {
                     view.model.set(result);
@@ -178,9 +187,16 @@ module.exports = Mn.View.extend({
                     });
                 })
                 .catch(err => {
-                    alert(err.message);
-                    this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
-                    this.ui.save.removeClass('btn-loading');
+                    try{
+                        const error_message = JSON.parse(err.debug).debug.stack.join("\n");
+                        this.ui.error_info[0].innerHTML = `<p>${err.message}</p><pre>${error_message}</pre>`;
+                    } catch(e) {
+                        this.ui.error_info[0].innerHTML = `<p>${err.message}</p>`;
+                    }
+                    this.ui.error_info.show();
+                    this.ui.le_error_info[0].scrollIntoView();
+                    this.ui.loader_content.hide();
+                    this.ui.non_loader_content.show();
                 });
         },
         'change @ui.other_certificate_key': function(e){
@@ -233,6 +249,8 @@ 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();
     },
 
     initialize: function (options) {

+ 1 - 1
frontend/js/app/nginx/certificates/list/item.ejs

@@ -28,7 +28,7 @@
     </div>
 </td>
 <td>
-    <%- 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 %><% } %>
 </td>
 <td class="<%- isExpired() ? 'text-danger' : '' %>">
     <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>

+ 5 - 0
frontend/js/app/nginx/dead/form.ejs

@@ -4,6 +4,7 @@
         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
     </div>
     <div class="modal-body has-tabs">
+        <div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
         <form>
             <ul class="nav nav-tabs" role="tablist">
                 <li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
@@ -134,6 +135,10 @@
                                                 <i class="fe fe-info"></i> 
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
+                                            <div class="text-red small">
+                                                <i class="fe fe-alert-triangle"></i> 
+                                                <%= i18n('ssl', 'stored-as-plaintext-info') %>
+                                            </div>
                                         </div>
                                     </div>
                                 </div>

+ 24 - 4
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()) {
                 $('<input type="submit">').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 !== '' ? `<pre class="mt-3">${more_info}</pre>`:''}`;
+                    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();

+ 5 - 0
frontend/js/app/nginx/proxy/form.ejs

@@ -4,6 +4,7 @@
         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
     </div>
     <div class="modal-body has-tabs">
+        <div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
         <form>
             <ul class="nav nav-tabs" role="tablist">
                 <li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
@@ -202,6 +203,10 @@
                                                 <i class="fe fe-info"></i> 
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
+                                            <div class="text-red small">
+                                                <i class="fe fe-alert-triangle"></i> 
+                                                <%= i18n('ssl', 'stored-as-plaintext-info') %>
+                                            </div>
                                         </div>
                                     </div>
                                 </div>

+ 24 - 4
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()) {
                 $('<input type="submit">').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 !== '' ? `<pre class="mt-3">${more_info}</pre>`:''}`;
+                    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();

+ 5 - 0
frontend/js/app/nginx/redirection/form.ejs

@@ -4,6 +4,7 @@
         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
     </div>
     <div class="modal-body has-tabs">
+        <div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
         <form>
             <ul class="nav nav-tabs" role="tablist">
                 <li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
@@ -158,6 +159,10 @@
                                                 <i class="fe fe-info"></i> 
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
+                                            <div class="text-red small">
+                                                <i class="fe fe-alert-triangle"></i> 
+                                                <%= i18n('ssl', 'stored-as-plaintext-info') %>
+                                            </div>
                                         </div>
                                     </div>
                                 </div>

+ 25 - 6
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()) {
                 $('<input type="submit">').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 !== '' ? `<pre class="mt-3">${more_info}</pre>`:''}`;
+                    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();

+ 3 - 1
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",

+ 6 - 2
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 <plugin-name> --<plugin-name>-credentials <FILE> --<plugin-name>-propagation-seconds <number>
  *
  * 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",