mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-11-04 09:25:15 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
		@@ -33,6 +33,13 @@
 | 
			
		||||
<td class="<%- isExpired() ? 'text-danger' : '' %>">
 | 
			
		||||
    <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
 | 
			
		||||
</td>
 | 
			
		||||
<td>
 | 
			
		||||
    <% if (active_domain_names().length > 0) { %>
 | 
			
		||||
        <span class="status-icon bg-success"></span> <%- i18n('certificates', 'in-use') %>
 | 
			
		||||
    <% } else { %>
 | 
			
		||||
        <span class="status-icon bg-danger"></span> <%- i18n('certificates', 'inactive') %>
 | 
			
		||||
    <% } %>
 | 
			
		||||
</td>
 | 
			
		||||
<% if (canManage) { %>
 | 
			
		||||
<td class="text-right">
 | 
			
		||||
    <div class="item-action dropdown">
 | 
			
		||||
@@ -48,7 +55,14 @@
 | 
			
		||||
                <div class="dropdown-divider"></div>
 | 
			
		||||
            <% } %>
 | 
			
		||||
            <a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
 | 
			
		||||
            <% if (active_domain_names().length > 0) { %>
 | 
			
		||||
                <div class="dropdown-divider"></div>
 | 
			
		||||
                <span class="dropdown-header"><%- i18n('certificates', 'active-domain_names') %></span>
 | 
			
		||||
                <% active_domain_names().forEach(function(host) { %>
 | 
			
		||||
                    <a href="https://<%- host %>" class="dropdown-item" target="_blank"><%- host %></a>
 | 
			
		||||
                <% }); %>
 | 
			
		||||
            <% } %>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</td>
 | 
			
		||||
<% } %>
 | 
			
		||||
<% } %>
 | 
			
		||||
@@ -44,14 +44,24 @@ module.exports = Mn.View.extend({
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    templateContext: {
 | 
			
		||||
        canManage: App.Cache.User.canManage('certificates'),
 | 
			
		||||
        isExpired: function () {
 | 
			
		||||
            return moment(this.expires_on).isBefore(moment());
 | 
			
		||||
        },
 | 
			
		||||
        dns_providers: dns_providers
 | 
			
		||||
    templateContext: function () {
 | 
			
		||||
        return {
 | 
			
		||||
            canManage: App.Cache.User.canManage('certificates'),
 | 
			
		||||
            isExpired: function () {
 | 
			
		||||
                return moment(this.expires_on).isBefore(moment());
 | 
			
		||||
            },
 | 
			
		||||
            dns_providers: dns_providers,
 | 
			
		||||
            active_domain_names: function () {
 | 
			
		||||
                const { proxy_hosts = [], redirect_hosts = [], dead_hosts = [] } = this;
 | 
			
		||||
                return [...proxy_hosts, ...redirect_hosts, ...dead_hosts].reduce((acc, host) => {
 | 
			
		||||
                    acc.push(...(host.domain_names || []));
 | 
			
		||||
                    return acc;
 | 
			
		||||
                }, []);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    initialize: function () {
 | 
			
		||||
        this.listenTo(this.model, 'change', this.render);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
    <th><%- i18n('str', 'name') %></th>
 | 
			
		||||
    <th><%- i18n('all-hosts', 'cert-provider') %></th>
 | 
			
		||||
    <th><%- i18n('str', 'expires') %></th>
 | 
			
		||||
    <th><%- i18n('str', 'status') %></th>
 | 
			
		||||
    <% if (canManage) { %>
 | 
			
		||||
    <th> </th>
 | 
			
		||||
    <% } %>
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ module.exports = Mn.View.extend({
 | 
			
		||||
            e.preventDefault();
 | 
			
		||||
            let query = this.ui.query.val();
 | 
			
		||||
 | 
			
		||||
            this.fetch(['owner'], query)
 | 
			
		||||
            this.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'], query)
 | 
			
		||||
                .then(response => this.showData(response))
 | 
			
		||||
                .catch(err => {
 | 
			
		||||
                    this.showError(err);
 | 
			
		||||
@@ -89,7 +89,7 @@ module.exports = Mn.View.extend({
 | 
			
		||||
    onRender: function () {
 | 
			
		||||
        let view = this;
 | 
			
		||||
 | 
			
		||||
        view.fetch(['owner'])
 | 
			
		||||
        view.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'])
 | 
			
		||||
            .then(response => {
 | 
			
		||||
                if (!view.isDestroyed()) {
 | 
			
		||||
                    if (response && response.length) {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,48 +3,187 @@
 | 
			
		||||
        <h5 class="modal-title"><%- i18n('streams', 'form-title', {id: id}) %></h5>
 | 
			
		||||
        <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="modal-body">
 | 
			
		||||
    <div class="modal-body has-tabs">
 | 
			
		||||
        <div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
 | 
			
		||||
        <form>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-sm-12 col-md-12">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
 | 
			
		||||
                        <input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" min="1" max="65535" value="<%- incoming_port %>" required>
 | 
			
		||||
            <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>
 | 
			
		||||
                <li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
 | 
			
		||||
            </ul>
 | 
			
		||||
            <div class="tab-content">
 | 
			
		||||
                <!-- Details -->
 | 
			
		||||
                <div role="tabpanel" class="tab-pane active" id="details">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-12 col-md-12">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                <input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" min="1" max="65535" value="<%- incoming_port %>" required>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-8 col-md-8">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('streams', 'forwarding-host') %><span class="form-required">*</span></label>
 | 
			
		||||
                                <input type="text" name="forwarding_host" class="form-control text-monospace" placeholder="example.com or 10.0.0.1 or 2001:db8:3333:4444:5555:6666:7777:8888" value="<%- forwarding_host %>" autocomplete="off" maxlength="255" required>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-4 col-md-4">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                <input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" min="1" max="65535" value="<%- forwarding_port %>" required>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-6 col-md-6">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="custom-switch">
 | 
			
		||||
                                    <input type="checkbox" class="custom-switch-input" name="tcp_forwarding" value="1"<%- tcp_forwarding ? ' checked' : '' %>>
 | 
			
		||||
                                    <span class="custom-switch-indicator"></span>
 | 
			
		||||
                                    <span class="custom-switch-description"><%- i18n('streams', 'tcp-forwarding') %></span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-6 col-md-6">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="custom-switch">
 | 
			
		||||
                                    <input type="checkbox" class="custom-switch-input" name="udp_forwarding" value="1"<%- udp_forwarding ? ' checked' : '' %>>
 | 
			
		||||
                                    <span class="custom-switch-indicator"></span>
 | 
			
		||||
                                    <span class="custom-switch-description"><%- i18n('streams', 'udp-forwarding') %></span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-12 col-md-12">
 | 
			
		||||
                            <div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-8 col-md-8">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label class="form-label"><%- i18n('streams', 'forwarding-host') %><span class="form-required">*</span></label>
 | 
			
		||||
                        <input type="text" name="forwarding_host" class="form-control text-monospace" placeholder="example.com or 10.0.0.1 or 2001:db8:3333:4444:5555:6666:7777:8888" value="<%- forwarding_host %>" autocomplete="off" maxlength="255" required>
 | 
			
		||||
 | 
			
		||||
                <!-- SSL -->
 | 
			
		||||
                <div role="tabpanel" class="tab-pane" id="ssl-options">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-12 col-md-12">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('streams', 'ssl-certificate') %></label>
 | 
			
		||||
                                <select name="certificate_id" class="form-control custom-select" placeholder="<%- i18n('all-hosts', 'none') %>">
 | 
			
		||||
                                    <option selected value="0" data-data="{"id":0}" <%- certificate_id ? '' : 'selected' %>><%- i18n('all-hosts', 'none') %></option>
 | 
			
		||||
                                    <option selected value="new" data-data="{"id":"new"}"><%- i18n('all-hosts', 'new-cert') %></option>
 | 
			
		||||
                                </select>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <!-- DNS challenge -->
 | 
			
		||||
                        <div class="col-sm-12 col-md-12 letsencrypt">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('all-hosts', 'domain-names') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                <input type="text" name="domain_names" class="form-control" id="input-domains" value="<%- domain_names.join(',') %>">
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="custom-switch">
 | 
			
		||||
                                    <input
 | 
			
		||||
                                            type="checkbox"
 | 
			
		||||
                                            class="custom-switch-input"
 | 
			
		||||
                                            name="meta[dns_challenge]"
 | 
			
		||||
                                            value="1"
 | 
			
		||||
                                            checked
 | 
			
		||||
                                            disabled
 | 
			
		||||
                                    >
 | 
			
		||||
                                    <span class="custom-switch-indicator"></span>
 | 
			
		||||
                                    <span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-12 col-md-12 letsencrypt">
 | 
			
		||||
                            <fieldset class="form-fieldset dns-challenge">
 | 
			
		||||
                                <div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div>
 | 
			
		||||
 | 
			
		||||
                                <!-- Certbot DNS plugin selection -->
 | 
			
		||||
                                <div class="row">
 | 
			
		||||
                                    <div class="col-sm-12 col-md-12">
 | 
			
		||||
                                        <div class="form-group">
 | 
			
		||||
                                            <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                            <select
 | 
			
		||||
                                                    name="meta[dns_provider]"
 | 
			
		||||
                                                    id="dns_provider"
 | 
			
		||||
                                                    class="form-control custom-select"
 | 
			
		||||
                                            >
 | 
			
		||||
                                                <option
 | 
			
		||||
                                                        value=""
 | 
			
		||||
                                                        disabled
 | 
			
		||||
                                                        hidden
 | 
			
		||||
                                                        <%- getDnsProvider() === null ? 'selected' : '' %>
 | 
			
		||||
                                                >Please Choose...</option>
 | 
			
		||||
                                                <% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
 | 
			
		||||
                                                    <option
 | 
			
		||||
                                                            value="<%- plugin_name %>"
 | 
			
		||||
                                                            <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
 | 
			
		||||
                                                    ><%- plugin_info.name %></option>
 | 
			
		||||
                                                <% }); %>
 | 
			
		||||
                                            </select>
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
 | 
			
		||||
                                <!-- Certbot credentials file content -->
 | 
			
		||||
                                <div class="row credentials-file-content">
 | 
			
		||||
                                    <div class="col-sm-12 col-md-12">
 | 
			
		||||
                                        <div class="form-group">
 | 
			
		||||
                                            <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                            <textarea
 | 
			
		||||
                                                    name="meta[dns_provider_credentials]"
 | 
			
		||||
                                                    class="form-control text-monospace"
 | 
			
		||||
                                                    id="dns_provider_credentials"
 | 
			
		||||
                                            ><%- getDnsProviderCredentials() %></textarea>
 | 
			
		||||
                                            <div class="text-secondary small">
 | 
			
		||||
                                                <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>
 | 
			
		||||
 | 
			
		||||
                                <!-- DNS propagation delay -->
 | 
			
		||||
                                <div class="row">
 | 
			
		||||
                                    <div class="col-sm-12 col-md-12">
 | 
			
		||||
                                        <div class="form-group mb-0">
 | 
			
		||||
                                            <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
 | 
			
		||||
                                            <input
 | 
			
		||||
                                                    type="number"
 | 
			
		||||
                                                    min="0"
 | 
			
		||||
                                                    name="meta[propagation_seconds]"
 | 
			
		||||
                                                    class="form-control"
 | 
			
		||||
                                                    id="propagation_seconds"
 | 
			
		||||
                                                    value="<%- getPropagationSeconds() %>"
 | 
			
		||||
                                            >
 | 
			
		||||
                                            <div class="text-secondary small">
 | 
			
		||||
                                                <i class="fe fe-info"></i>
 | 
			
		||||
                                                <%= i18n('ssl', 'propagation-seconds-info') %>
 | 
			
		||||
                                            </div>
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </fieldset>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <!-- Lets encrypt -->
 | 
			
		||||
                        <div class="col-sm-12 col-md-12 letsencrypt">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="form-label"><%- i18n('ssl', 'letsencrypt-email') %> <span class="form-required">*</span></label>
 | 
			
		||||
                                <input name="meta[letsencrypt_email]" type="email" class="form-control" placeholder="" value="<%- getLetsencryptEmail() %>" required disabled>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-12 col-md-12 letsencrypt">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <label class="custom-switch">
 | 
			
		||||
                                    <input type="checkbox" class="custom-switch-input" name="meta[letsencrypt_agree]" value="1" required disabled>
 | 
			
		||||
                                    <span class="custom-switch-indicator"></span>
 | 
			
		||||
                                    <span class="custom-switch-description"><%= i18n('ssl', 'letsencrypt-agree', {url: 'https://letsencrypt.org/repository/'}) %> <span class="form-required">*</span></span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-4 col-md-4">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
 | 
			
		||||
                        <input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" min="1" max="65535" value="<%- forwarding_port %>" required>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-6 col-md-6">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label class="custom-switch">
 | 
			
		||||
                            <input type="checkbox" class="custom-switch-input" name="tcp_forwarding" value="1"<%- tcp_forwarding ? ' checked' : '' %>>
 | 
			
		||||
                            <span class="custom-switch-indicator"></span>
 | 
			
		||||
                            <span class="custom-switch-description"><%- i18n('streams', 'tcp-forwarding') %></span>
 | 
			
		||||
                        </label>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-6 col-md-6">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label class="custom-switch">
 | 
			
		||||
                            <input type="checkbox" class="custom-switch-input" name="udp_forwarding" value="1"<%- udp_forwarding ? ' checked' : '' %>>
 | 
			
		||||
                            <span class="custom-switch-indicator"></span>
 | 
			
		||||
                            <span class="custom-switch-description"><%- i18n('streams', 'udp-forwarding') %></span>
 | 
			
		||||
                        </label>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-12 col-md-12">
 | 
			
		||||
                    <div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </form>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,38 @@
 | 
			
		||||
const Mn          = require('backbone.marionette');
 | 
			
		||||
const App         = require('../../main');
 | 
			
		||||
const StreamModel = require('../../../models/stream');
 | 
			
		||||
const template    = require('./form.ejs');
 | 
			
		||||
const Mn            = require('backbone.marionette');
 | 
			
		||||
const App           = require('../../main');
 | 
			
		||||
const StreamModel   = require('../../../models/stream');
 | 
			
		||||
const template      = require('./form.ejs');
 | 
			
		||||
const dns_providers = require('../../../../../global/certbot-dns-plugins');
 | 
			
		||||
 | 
			
		||||
require('jquery-serializejson');
 | 
			
		||||
require('jquery-mask-plugin');
 | 
			
		||||
require('selectize');
 | 
			
		||||
const Helpers = require("../../../lib/helpers");
 | 
			
		||||
const certListItemTemplate = require("../certificates-list-item.ejs");
 | 
			
		||||
const i18n = require("../../i18n");
 | 
			
		||||
 | 
			
		||||
module.exports = Mn.View.extend({
 | 
			
		||||
    template:  template,
 | 
			
		||||
    className: 'modal-dialog',
 | 
			
		||||
 | 
			
		||||
    ui: {
 | 
			
		||||
        form:       'form',
 | 
			
		||||
        forwarding_host: 'input[name="forwarding_host"]',
 | 
			
		||||
        type_error: '.forward-type-error',
 | 
			
		||||
        buttons:    '.modal-footer button',
 | 
			
		||||
        switches:   '.custom-switch-input',
 | 
			
		||||
        cancel:     'button.cancel',
 | 
			
		||||
        save:       'button.save'
 | 
			
		||||
        form:                     'form',
 | 
			
		||||
        forwarding_host:          'input[name="forwarding_host"]',
 | 
			
		||||
        type_error:               '.forward-type-error',
 | 
			
		||||
        buttons:                  '.modal-footer button',
 | 
			
		||||
        switches:                 '.custom-switch-input',
 | 
			
		||||
        cancel:                   'button.cancel',
 | 
			
		||||
        save:                     'button.save',
 | 
			
		||||
        le_error_info:            '#le-error-info',
 | 
			
		||||
        certificate_select:       'select[name="certificate_id"]',
 | 
			
		||||
        domain_names:             'input[name="domain_names"]',
 | 
			
		||||
        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: {
 | 
			
		||||
@@ -48,6 +62,35 @@ module.exports = Mn.View.extend({
 | 
			
		||||
            data.tcp_forwarding  = !!data.tcp_forwarding;
 | 
			
		||||
            data.udp_forwarding  = !!data.udp_forwarding;
 | 
			
		||||
 | 
			
		||||
            if (typeof data.meta === 'undefined') data.meta = {};
 | 
			
		||||
            data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
 | 
			
		||||
            data.meta.dns_challenge = true;
 | 
			
		||||
 | 
			
		||||
            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(',');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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.dns_challenge) {
 | 
			
		||||
                    data.domain_names.map(function (name) {
 | 
			
		||||
                        if (name.match(/\*/im)) {
 | 
			
		||||
                            domain_err = true;
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (domain_err) {
 | 
			
		||||
                    alert(i18n('ssl', 'no-wildcard-without-dns'));
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                data.certificate_id = parseInt(data.certificate_id, 10);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let method = App.Api.Nginx.Streams.create;
 | 
			
		||||
            let is_new = true;
 | 
			
		||||
 | 
			
		||||
@@ -70,10 +113,108 @@ 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 !== '' ? `<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');
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        'change @ui.certificate_select': function () {
 | 
			
		||||
            let id = this.ui.certificate_select.val();
 | 
			
		||||
            if (id === 'new') {
 | 
			
		||||
                this.ui.letsencrypt.show().find('input').prop('disabled', false);
 | 
			
		||||
                this.ui.domain_names.prop('required', 'required');
 | 
			
		||||
 | 
			
		||||
                this.ui.dns_challenge_switch
 | 
			
		||||
                    .prop('disabled', true)
 | 
			
		||||
                    .parents('.form-group')
 | 
			
		||||
                    .css('opacity', 0.5);
 | 
			
		||||
 | 
			
		||||
                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.letsencrypt.hide().find('input').prop('disabled', true);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        '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();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    templateContext: {
 | 
			
		||||
        getLetsencryptEmail: function () {
 | 
			
		||||
            return App.Cache.User.get('email');
 | 
			
		||||
        },
 | 
			
		||||
        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 () {
 | 
			
		||||
        let view = this;
 | 
			
		||||
 | 
			
		||||
        // 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',
 | 
			
		||||
            labelField:       'nice_name',
 | 
			
		||||
            searchField:      ['nice_name', 'domain_names'],
 | 
			
		||||
            create:           false,
 | 
			
		||||
            preload:          true,
 | 
			
		||||
            allowEmptyOption: true,
 | 
			
		||||
            render:           {
 | 
			
		||||
                option: function (item) {
 | 
			
		||||
                    item.i18n         = App.i18n;
 | 
			
		||||
                    item.formatDbDate = Helpers.formatDbDate;
 | 
			
		||||
                    return certListItemTemplate(item);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            load:             function (query, callback) {
 | 
			
		||||
                App.Api.Nginx.Certificates.getAll()
 | 
			
		||||
                    .then(rows => {
 | 
			
		||||
                        callback(rows);
 | 
			
		||||
                    })
 | 
			
		||||
                    .catch(err => {
 | 
			
		||||
                        console.error(err);
 | 
			
		||||
                        callback();
 | 
			
		||||
                    });
 | 
			
		||||
            },
 | 
			
		||||
            onLoad:           function () {
 | 
			
		||||
                view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    initialize: function (options) {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,10 @@
 | 
			
		||||
</td>
 | 
			
		||||
<td>
 | 
			
		||||
    <div>
 | 
			
		||||
        <% if (tcp_forwarding) { %>
 | 
			
		||||
        <% if (certificate) { %>
 | 
			
		||||
            <span class="tag"><%- i18n('streams', 'tcp+ssl') %></span>
 | 
			
		||||
        <% }
 | 
			
		||||
        else if (tcp_forwarding) { %>
 | 
			
		||||
            <span class="tag"><%- i18n('streams', 'tcp') %></span>
 | 
			
		||||
        <% }
 | 
			
		||||
        if (udp_forwarding) { %>
 | 
			
		||||
@@ -24,6 +27,9 @@
 | 
			
		||||
        <% } %>
 | 
			
		||||
    </div>
 | 
			
		||||
</td>
 | 
			
		||||
<td>
 | 
			
		||||
    <div><%- certificate && certificate_id ? i18n('ssl', certificate.provider) : i18n('all-hosts', 'none') %></div>
 | 
			
		||||
</td>
 | 
			
		||||
<td>
 | 
			
		||||
    <%
 | 
			
		||||
    var o = isOnline();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
    <th><%- i18n('streams', 'incoming-port') %></th>
 | 
			
		||||
    <th><%- i18n('str', 'destination') %></th>
 | 
			
		||||
    <th><%- i18n('streams', 'protocol') %></th>
 | 
			
		||||
    <th><%- i18n('str', 'ssl') %></th>
 | 
			
		||||
    <th><%- i18n('str', 'status') %></th>
 | 
			
		||||
    <% if (canManage) { %>
 | 
			
		||||
    <th> </th>
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ module.exports = Mn.View.extend({
 | 
			
		||||
    onRender: function () {
 | 
			
		||||
        let view = this;
 | 
			
		||||
 | 
			
		||||
        view.fetch(['owner'])
 | 
			
		||||
        view.fetch(['owner', 'certificate'])
 | 
			
		||||
            .then(response => {
 | 
			
		||||
                if (!view.isDestroyed()) {
 | 
			
		||||
                    if (response && response.length) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user