Added support for redirection and 404 hosts

This commit is contained in:
Jamie Curnow
2018-01-04 16:18:48 +10:00
parent 61820840e0
commit 64de096565
22 changed files with 453 additions and 31 deletions

View File

@ -54,12 +54,34 @@ module.exports = {
},
/**
* Show Host Form
* Show Proxy Host Form
*
* @param model
*/
showHostForm: function (model) {
require(['./main', './host/form'], function (App, View) {
showProxyHostForm: function (model) {
require(['./main', './host/proxy_form'], function (App, View) {
App.UI.showModalDialog(new View({model: model}));
});
},
/**
* Show Redirection Host Form
*
* @param model
*/
showRedirectionHostForm: function (model) {
require(['./main', './host/redirection_form'], function (App, View) {
App.UI.showModalDialog(new View({model: model}));
});
},
/**
* Show 404 Host Form
*
* @param model
*/
show404HostForm: function (model) {
require(['./main', './host/404_form'], function (App, View) {
App.UI.showModalDialog(new View({model: model}));
});
},

View File

@ -1,5 +1,9 @@
<td colspan="10" class="text-center">
<br><br>
<p>It looks like there are no hosts configured.</p>
<p><button type="button" class="btn btn-sm btn-success">Create your first Host</button></p>
<p>
<button type="button" class="btn btn-sm btn-success proxy">Create Proxy Host</button>
<button type="button" class="btn btn-sm btn-success redirection">Create Redirection Host</button>
<button type="button" class="btn btn-sm btn-success 404">Create 404 Host</button>
</p>
</td>

View File

@ -11,13 +11,25 @@ module.exports = Mn.View.extend({
tagName: 'tr',
ui: {
create: 'button'
proxy: 'button.proxy',
redirection: 'button.redirection',
'404': 'button.404'
},
events: {
'click @ui.create': function (e) {
'click @ui.proxy': function (e) {
e.preventDefault();
Controller.showHostForm(new HostModel.Model);
Controller.showProxyHostForm(new HostModel.Model);
},
'click @ui.redirection': function (e) {
e.preventDefault();
Controller.showRedirectionHostForm(new HostModel.Model);
},
'click @ui.404': function (e) {
e.preventDefault();
Controller.show404HostForm(new HostModel.Model);
}
}
});

View File

@ -1,10 +1,21 @@
<table class="table table-condensed table-striped">
<thead>
<th>Hostname</th>
<th>Forward</th>
<th>Destination</th>
<th>SSL</th>
<th>Access List</th>
<th class="text-right"><button type="button" class="btn btn-xs btn-info">Create Host</button></th>
<th class="text-right">
<div class="btn-group">
<button type="button" class="btn btn-xs btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Create Host <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" class="new-proxy">Proxy Host</a></li>
<li><a href="#" class="new-redirection">Redirection Host</a></li>
<li><a href="#" class="new-404">404 Host</a></li>
</ul>
</div>
</th>
</thead>
<tbody>
<!-- items -->

View File

@ -26,13 +26,25 @@ module.exports = Mn.View.extend({
},
ui: {
'create': 'th button'
new_proxy: 'th .new-proxy',
new_redirection: 'th .new-redirection',
new_404: 'th .new-404'
},
events: {
'click @ui.create': function (e) {
'click @ui.new_proxy': function (e) {
e.preventDefault();
Controller.showHostForm(new HostModel.Model);
Controller.showProxyHostForm(new HostModel.Model);
},
'click @ui.new_redirection': function (e) {
e.preventDefault();
Controller.showRedirectionHostForm(new HostModel.Model);
},
'click @ui.new_404': function (e) {
e.preventDefault();
Controller.show404HostForm(new HostModel.Model);
}
},

View File

@ -1,5 +1,15 @@
<td><a href="<%- ssl ? 'https' : 'http' %>://<%- hostname %>" target="_blank"><%- hostname %></a></td>
<td><span class="monospace"><%- forward_server %>:<%- forward_port %></span></td>
<td>
<span class="monospace">
<% if (type === 'proxy') { %>
<%- forward_server %>:<%- forward_port %>
<% } else if (type === 'redirection') { %>
<%- forward_host %>
<% } else if (type === '404') { %>
404
<% } %>
</span>
</td>
<td>
<% if (ssl && force_ssl) { %>
Forced

View File

@ -22,7 +22,17 @@ module.exports = Mn.View.extend({
events: {
'click @ui.edit': function (e) {
e.preventDefault();
Controller.showHostForm(this.model);
switch (this.model.get('type')) {
case 'proxy':
Controller.showProxyHostForm(this.model);
break;
case 'redirection':
Controller.showRedirectionHostForm(this.model);
break;
case '404':
Controller.show404HostForm(this.model);
break;
}
},
'click @ui.delete': function (e) {

View File

@ -0,0 +1,50 @@
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header text-left">
<h4 class="modal-title"><% if (typeof _id !== 'undefined') { %>Edit<% } else { %>Create<% } %> 404 Host</h4>
</div>
<div class="modal-body">
<p>A 404 host will simply return a 404 not found page for any hits to any path on the domain.</p>
<div class="form-group">
<label class="col-sm-4 control-label">Hostname</label>
<div class="col-sm-8">
<input type="text" class="form-control" placeholder="myhost.example.com" name="hostname" value="<%- hostname %>" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox" name="ssl" value="true"<%- ssl ? ' checked' : '' %>> Enable SSL with Letsencrypt
</label>
</div>
</div>
</div>
<div class="ssl_options"<%= ssl ? '' : ' style="display: none;"' %>>
<div class="form-group">
<label class="col-sm-4 control-label">Letsencrypt Email</label>
<div class="col-sm-8">
<input type="email" class="form-control" placeholder="" name="letsencrypt_email" value="<%- letsencrypt_email %>"<%- ssl ? ' required' : '' %>>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox" name="accept_tos" value="true"<%- ssl && typeof _id !== 'undefined' ? ' checked' : '' %><%- ssl ? ' required' : '' %>> I accept the <a href="https://letsencrypt.org/repository/" target="_blank">Letsencrypt Terms of Service</a>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-success save">Save</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,78 @@
'use strict';
import Mn from 'backbone.marionette';
const _ = require('lodash');
const template = require('./404_form.ejs');
const Controller = require('../controller');
const Api = require('../api');
const App = require('../main');
require('jquery-serializejson');
module.exports = Mn.View.extend({
template: template,
ui: {
form: 'form',
buttons: 'form button',
ssl_options: '.ssl_options',
ssl: 'input[name="ssl"]',
letsencrypt_email: 'input[name="letsencrypt_email"]',
accept_tos: 'input[name="accept_tos"]'
},
events: {
'change @ui.ssl': function (e) {
let inputs = this.ui.letsencrypt_email.add(this.ui.accept_tos);
if (this.ui.ssl.prop('checked')) {
this.ui.ssl_options.show();
inputs.prop('required', true);
} else {
this.ui.ssl_options.hide();
inputs.prop('required', false);
}
},
'submit @ui.form': function (e) {
e.preventDefault();
let data = _.extend({}, this.ui.form.serializeJSON());
// Change text true's to bools
_.map(data, function (val, key) {
if (val === 'true') {
data[key] = true;
}
});
// This is a 404 host
data.type = '404';
// accept_tos is not required for backend
delete data.accept_tos;
if (!data.ssl) {
delete data.letsencrypt_email;
}
this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
let method = Api.Hosts.create;
if (this.model.get('_id')) {
// edit
method = Api.Hosts.update;
data._id = this.model.get('_id');
}
method(data)
.then((/*result*/) => {
App.UI.closeModal();
Controller.showDashboard();
})
.catch(err => {
alert(err.message);
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
});
}
}
});

View File

@ -2,7 +2,7 @@
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header text-left">
<h4 class="modal-title"><% if (typeof _id !== 'undefined') { %>Edit<% } else { %>Create<% } %> Host</h4>
<h4 class="modal-title"><% if (typeof _id !== 'undefined') { %>Edit<% } else { %>Create<% } %> Proxy Host</h4>
</div>
<div class="modal-body">
<div class="form-group">
@ -62,7 +62,7 @@
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox" name="accept_tos" value="true"<%- accept_tos ? ' checked' : '' %><%- ssl ? ' required' : '' %>> I accept the <a href="https://letsencrypt.org/repository/" target="_blank">Letsencrypt Terms of Service</a>
<input type="checkbox" name="accept_tos" value="true"<%- ssl && typeof _id !== 'undefined' ? ' checked' : '' %><%- ssl ? ' required' : '' %>> I accept the <a href="https://letsencrypt.org/repository/" target="_blank">Letsencrypt Terms of Service</a>
</label>
</div>
<div class="checkbox">

View File

@ -3,7 +3,7 @@
import Mn from 'backbone.marionette';
const _ = require('lodash');
const template = require('./form.ejs');
const template = require('./proxy_form.ejs');
const Controller = require('../controller');
const Api = require('../api');
const App = require('../main');
@ -46,6 +46,8 @@ module.exports = Mn.View.extend({
}
});
data.type = 'proxy';
// Port is integer
data.forward_port = parseInt(data.forward_port, 10);

View File

@ -0,0 +1,62 @@
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header text-left">
<h4 class="modal-title"><% if (typeof _id !== 'undefined') { %>Edit<% } else { %>Create<% } %> Redirection Host</h4>
</div>
<div class="modal-body">
<p>A redirection host will forward browser requests on this hostname to the new hostname while keeping the same path.</p>
<div class="form-group">
<label class="col-sm-4 control-label">Hostname</label>
<div class="col-sm-8">
<input type="text" class="form-control" placeholder="myhost.example.com" name="hostname" value="<%- hostname %>" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Forwarding Hostname</label>
<div class="col-sm-8">
<input type="text" class="form-control" placeholder="mynewhost.example.com" name="forward_host" value="<%- forward_host %>" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox" name="block_exploits" value="true"<%- block_exploits ? ' checked' : '' %>> Block Common Exploits
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="ssl" value="true"<%- ssl ? ' checked' : '' %>> Enable SSL with Letsencrypt
</label>
</div>
</div>
</div>
<div class="ssl_options"<%= ssl ? '' : ' style="display: none;"' %>>
<div class="form-group">
<label class="col-sm-4 control-label">Letsencrypt Email</label>
<div class="col-sm-8">
<input type="email" class="form-control" placeholder="" name="letsencrypt_email" value="<%- letsencrypt_email %>"<%- ssl ? ' required' : '' %>>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox" name="accept_tos" value="true"<%- ssl && typeof _id !== 'undefined' ? ' checked' : '' %><%- ssl ? ' required' : '' %>> I accept the <a href="https://letsencrypt.org/repository/" target="_blank">Letsencrypt Terms of Service</a>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-success save">Save</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,78 @@
'use strict';
import Mn from 'backbone.marionette';
const _ = require('lodash');
const template = require('./redirection_form.ejs');
const Controller = require('../controller');
const Api = require('../api');
const App = require('../main');
require('jquery-serializejson');
module.exports = Mn.View.extend({
template: template,
ui: {
form: 'form',
buttons: 'form button',
ssl_options: '.ssl_options',
ssl: 'input[name="ssl"]',
letsencrypt_email: 'input[name="letsencrypt_email"]',
accept_tos: 'input[name="accept_tos"]'
},
events: {
'change @ui.ssl': function (e) {
let inputs = this.ui.letsencrypt_email.add(this.ui.accept_tos);
if (this.ui.ssl.prop('checked')) {
this.ui.ssl_options.show();
inputs.prop('required', true);
} else {
this.ui.ssl_options.hide();
inputs.prop('required', false);
}
},
'submit @ui.form': function (e) {
e.preventDefault();
let data = _.extend({}, this.ui.form.serializeJSON());
// Change text true's to bools
_.map(data, function (val, key) {
if (val === 'true') {
data[key] = true;
}
});
data.type = 'redirection';
// accept_tos is not required for backend
delete data.accept_tos;
if (!data.ssl) {
delete data.letsencrypt_email;
delete data.force_ssl;
}
this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
let method = Api.Hosts.create;
if (this.model.get('_id')) {
// edit
method = Api.Hosts.update;
data._id = this.model.get('_id');
}
method(data)
.then((/*result*/) => {
App.UI.closeModal();
Controller.showDashboard();
})
.catch((err) => {
alert(err.message);
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
});
}
}
});