form.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. const Mn = require('backbone.marionette');
  2. const App = require('../../main');
  3. const StreamModel = require('../../../models/stream');
  4. const template = require('./form.ejs');
  5. const dns_providers = require('../../../../../global/certbot-dns-plugins');
  6. require('jquery-serializejson');
  7. require('jquery-mask-plugin');
  8. require('selectize');
  9. const Helpers = require("../../../lib/helpers");
  10. const certListItemTemplate = require("../certificates-list-item.ejs");
  11. const i18n = require("../../i18n");
  12. module.exports = Mn.View.extend({
  13. template: template,
  14. className: 'modal-dialog',
  15. ui: {
  16. form: 'form',
  17. forwarding_host: 'input[name="forwarding_host"]',
  18. type_error: '.forward-type-error',
  19. buttons: '.modal-footer button',
  20. switches: '.custom-switch-input',
  21. cancel: 'button.cancel',
  22. save: 'button.save',
  23. le_error_info: '#le-error-info',
  24. certificate_select: 'select[name="certificate_id"]',
  25. domain_names: 'input[name="domain_names"]',
  26. dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
  27. dns_challenge_content: '.dns-challenge',
  28. dns_provider: 'select[name="meta[dns_provider]"]',
  29. credentials_file_content: '.credentials-file-content',
  30. dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
  31. propagation_seconds: 'input[name="meta[propagation_seconds]"]',
  32. letsencrypt: '.letsencrypt'
  33. },
  34. events: {
  35. 'change @ui.switches': function () {
  36. this.ui.type_error.hide();
  37. },
  38. 'click @ui.save': function (e) {
  39. e.preventDefault();
  40. if (!this.ui.form[0].checkValidity()) {
  41. $('<input type="submit">').hide().appendTo(this.ui.form).click().remove();
  42. return;
  43. }
  44. let view = this;
  45. let data = this.ui.form.serializeJSON();
  46. if (!data.tcp_forwarding && !data.udp_forwarding) {
  47. this.ui.type_error.show();
  48. return;
  49. }
  50. // Manipulate
  51. data.incoming_port = parseInt(data.incoming_port, 10);
  52. data.forwarding_port = parseInt(data.forwarding_port, 10);
  53. data.tcp_forwarding = !!data.tcp_forwarding;
  54. data.udp_forwarding = !!data.udp_forwarding;
  55. if (typeof data.meta === 'undefined') data.meta = {};
  56. data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
  57. data.meta.dns_challenge = true;
  58. if (data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
  59. if (typeof data.domain_names === 'string' && data.domain_names) {
  60. data.domain_names = data.domain_names.split(',');
  61. }
  62. // Check for any domain names containing wildcards, which are not allowed with letsencrypt
  63. if (data.certificate_id === 'new') {
  64. let domain_err = false;
  65. if (!data.meta.dns_challenge) {
  66. data.domain_names.map(function (name) {
  67. if (name.match(/\*/im)) {
  68. domain_err = true;
  69. }
  70. });
  71. }
  72. if (domain_err) {
  73. alert(i18n('ssl', 'no-wildcard-without-dns'));
  74. return;
  75. }
  76. } else {
  77. data.certificate_id = parseInt(data.certificate_id, 10);
  78. }
  79. let method = App.Api.Nginx.Streams.create;
  80. let is_new = true;
  81. if (this.model.get('id')) {
  82. // edit
  83. is_new = false;
  84. method = App.Api.Nginx.Streams.update;
  85. data.id = this.model.get('id');
  86. }
  87. this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
  88. method(data)
  89. .then(result => {
  90. view.model.set(result);
  91. App.UI.closeModal(function () {
  92. if (is_new) {
  93. App.Controller.showNginxStream();
  94. }
  95. });
  96. })
  97. .catch(err => {
  98. let more_info = '';
  99. if (err.code === 500 && err.debug) {
  100. try {
  101. more_info = JSON.parse(err.debug).debug.stack.join("\n");
  102. } catch (e) {
  103. }
  104. }
  105. this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `<pre class="mt-3">${more_info}</pre>` : ''}`;
  106. this.ui.le_error_info.show();
  107. this.ui.le_error_info[0].scrollIntoView();
  108. this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
  109. this.ui.save.removeClass('btn-loading');
  110. });
  111. },
  112. 'change @ui.certificate_select': function () {
  113. let id = this.ui.certificate_select.val();
  114. if (id === 'new') {
  115. this.ui.letsencrypt.show().find('input').prop('disabled', false);
  116. this.ui.domain_names.prop('required', 'required');
  117. this.ui.dns_challenge_switch
  118. .prop('disabled', true)
  119. .parents('.form-group')
  120. .css('opacity', 0.5);
  121. this.ui.dns_provider.prop('required', 'required');
  122. const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value;
  123. if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) {
  124. this.ui.dns_provider_credentials.prop('required', 'required');
  125. }
  126. this.ui.dns_challenge_content.show();
  127. } else {
  128. this.ui.letsencrypt.hide().find('input').prop('disabled', true);
  129. }
  130. },
  131. 'change @ui.dns_provider': function () {
  132. const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value;
  133. if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) {
  134. this.ui.dns_provider_credentials.prop('required', 'required');
  135. this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials;
  136. this.ui.credentials_file_content.show();
  137. } else {
  138. this.ui.dns_provider_credentials.prop('required', false);
  139. this.ui.credentials_file_content.hide();
  140. }
  141. },
  142. },
  143. templateContext: {
  144. getLetsencryptEmail: function () {
  145. return App.Cache.User.get('email');
  146. },
  147. getDnsProvider: function () {
  148. return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null;
  149. },
  150. getDnsProviderCredentials: function () {
  151. return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : '';
  152. },
  153. getPropagationSeconds: function () {
  154. return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : '';
  155. },
  156. dns_plugins: dns_providers,
  157. },
  158. onRender: function () {
  159. let view = this;
  160. // Certificates
  161. this.ui.le_error_info.hide();
  162. this.ui.dns_challenge_content.hide();
  163. this.ui.credentials_file_content.hide();
  164. this.ui.letsencrypt.hide();
  165. this.ui.certificate_select.selectize({
  166. valueField: 'id',
  167. labelField: 'nice_name',
  168. searchField: ['nice_name', 'domain_names'],
  169. create: false,
  170. preload: true,
  171. allowEmptyOption: true,
  172. render: {
  173. option: function (item) {
  174. item.i18n = App.i18n;
  175. item.formatDbDate = Helpers.formatDbDate;
  176. return certListItemTemplate(item);
  177. }
  178. },
  179. load: function (query, callback) {
  180. App.Api.Nginx.Certificates.getAll()
  181. .then(rows => {
  182. callback(rows);
  183. })
  184. .catch(err => {
  185. console.error(err);
  186. callback();
  187. });
  188. },
  189. onLoad: function () {
  190. view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
  191. }
  192. });
  193. },
  194. initialize: function (options) {
  195. if (typeof options.model === 'undefined' || !options.model) {
  196. this.model = new StreamModel.Model();
  197. }
  198. }
  199. });