Initial work for disabling hosts

This commit is contained in:
Jamie Curnow 2019-01-03 20:27:43 +10:00
parent 48f2bb4cd8
commit 981d5a199f
11 changed files with 368 additions and 31 deletions

View File

@ -104,7 +104,7 @@ const internalProxyHost = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @return {Promise} * @return {Promise}
*/ */
update: (access, data) => { update: (access, data) => {
@ -202,7 +202,7 @@ const internalProxyHost = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {Array} [data.expand] * @param {Array} [data.expand]
* @param {Array} [data.omit] * @param {Array} [data.omit]
* @return {Promise} * @return {Promise}
@ -249,7 +249,7 @@ const internalProxyHost = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {String} [data.reason] * @param {String} [data.reason]
* @returns {Promise} * @returns {Promise}
*/ */
@ -291,6 +291,101 @@ const internalProxyHost = {
}); });
}, },
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
enable: (access, data) => {
return access.can('proxy_hosts:update', data.id)
.then(() => {
return internalProxyHost.get(access, {id: data.id});
})
.then(row => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (row.enabled) {
throw new error.ValidationError('Host is already enabled');
}
row.enabled = 1;
return proxyHostModel
.query()
.where('id', row.id)
.patch({
enabled: 1
})
.then(() => {
// Configure nginx
return internalNginx.configure(proxyHostModel, 'proxy_host', row);
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'enabled',
object_type: 'proxy-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
disable: (access, data) => {
return access.can('proxy_hosts:update', data.id)
.then(() => {
return internalProxyHost.get(access, {id: data.id});
})
.then(row => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (!row.enabled) {
throw new error.ValidationError('Host is already disabled');
}
row.enabled = 0;
return proxyHostModel
.query()
.where('id', row.id)
.patch({
enabled: 0
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('proxy_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'disabled',
object_type: 'proxy-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/** /**
* All Hosts * All Hosts
* *
@ -339,7 +434,7 @@ const internalProxyHost = {
/** /**
* Report use * Report use
* *
* @param {Integer} user_id * @param {Number} user_id
* @param {String} visibility * @param {String} visibility
* @returns {Promise} * @returns {Promise}
*/ */

View File

@ -0,0 +1,57 @@
'use strict';
const migrate_name = 'disabled';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex/*, Promise*/) {
logger.info('[' + migrate_name + '] Migrating Up...');
return knex.schema.table('proxy_host', function (proxy_host) {
proxy_host.integer('enabled').notNull().unsigned().defaultTo(1);
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table altered');
return knex.schema.table('redirection_host', function (redirection_host) {
redirection_host.integer('enabled').notNull().unsigned().defaultTo(1);
});
})
.then(() => {
logger.info('[' + migrate_name + '] redirection_host Table altered');
return knex.schema.table('dead_host', function (dead_host) {
dead_host.integer('enabled').notNull().unsigned().defaultTo(1);
});
})
.then(() => {
logger.info('[' + migrate_name + '] dead_host Table altered');
return knex.schema.table('stream', function (stream) {
stream.integer('enabled').notNull().unsigned().defaultTo(1);
});
})
.then(() => {
logger.info('[' + migrate_name + '] stream Table altered');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
return Promise.resolve(true);
};

View File

@ -20,7 +20,7 @@ router
.options((req, res) => { .options((req, res) => {
res.sendStatus(204); res.sendStatus(204);
}) })
.all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes .all(jwtdecode())
/** /**
* GET /api/nginx/proxy-hosts * GET /api/nginx/proxy-hosts
@ -79,7 +79,7 @@ router
.options((req, res) => { .options((req, res) => {
res.sendStatus(204); res.sendStatus(204);
}) })
.all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes .all(jwtdecode())
/** /**
* GET /api/nginx/proxy-hosts/123 * GET /api/nginx/proxy-hosts/123
@ -147,4 +147,52 @@ router
.catch(next); .catch(next);
}); });
/**
* Enable proxy-host
*
* /api/nginx/proxy-hosts/123/enable
*/
router
.route('/:host_id/enable')
.options((req, res) => {
res.sendStatus(204);
})
.all(jwtdecode())
/**
* POST /api/nginx/proxy-hosts/123/enable
*/
.post((req, res, next) => {
internalProxyHost.enable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
.then(result => {
res.status(200)
.send(result);
})
.catch(next);
});
/**
* Disable proxy-host
*
* /api/nginx/proxy-hosts/123/disable
*/
router
.route('/:host_id/disable')
.options((req, res) => {
res.sendStatus(204);
})
.all(jwtdecode())
/**
* POST /api/nginx/proxy-hosts/123/disable
*/
.post((req, res, next) => {
internalProxyHost.disable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
.then(result => {
res.status(200)
.send(result);
})
.catch(next);
});
module.exports = router; module.exports = router;

View File

@ -172,6 +172,11 @@
"pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$" "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$"
} }
}, },
"enabled": {
"description": "Is Enabled",
"example": true,
"type": "boolean"
},
"ssl_enabled": { "ssl_enabled": {
"description": "Is SSL Enabled", "description": "Is SSL Enabled",
"example": true, "example": true,

View File

@ -58,6 +58,9 @@
"advanced_config": { "advanced_config": {
"type": "string" "type": "string"
}, },
"enabled": {
"$ref": "../definitions.json#/definitions/enabled"
},
"meta": { "meta": {
"type": "object" "type": "object"
} }
@ -108,6 +111,9 @@
"advanced_config": { "advanced_config": {
"$ref": "#/definitions/advanced_config" "$ref": "#/definitions/advanced_config"
}, },
"enabled": {
"$ref": "#/definitions/enabled"
},
"meta": { "meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
} }
@ -186,6 +192,9 @@
"advanced_config": { "advanced_config": {
"$ref": "#/definitions/advanced_config" "$ref": "#/definitions/advanced_config"
}, },
"enabled": {
"$ref": "#/definitions/enabled"
},
"meta": { "meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
} }
@ -247,6 +256,9 @@
"advanced_config": { "advanced_config": {
"$ref": "#/definitions/advanced_config" "$ref": "#/definitions/advanced_config"
}, },
"enabled": {
"$ref": "#/definitions/enabled"
},
"meta": { "meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
} }
@ -271,6 +283,34 @@
"targetSchema": { "targetSchema": {
"type": "boolean" "type": "boolean"
} }
},
{
"title": "Enable",
"description": "Enables a existing Proxy Host",
"href": "/nginx/proxy-hosts/{definitions.identity.example}/enable",
"access": "private",
"method": "POST",
"rel": "update",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "boolean"
}
},
{
"title": "Disable",
"description": "Disables a existing Proxy Host",
"href": "/nginx/proxy-hosts/{definitions.identity.example}/disable",
"access": "private",
"method": "POST",
"rel": "update",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "boolean"
}
} }
] ]
} }

View File

@ -1,5 +1,6 @@
{% include "_header_comment.conf" %} {% include "_header_comment.conf" %}
{% if enabled %}
server { server {
set $forward_scheme {{ forward_scheme }}; set $forward_scheme {{ forward_scheme }};
set $server "{{ forward_host }}"; set $server "{{ forward_host }}";
@ -33,3 +34,4 @@ server {
include conf.d/include/proxy.conf; include conf.d/include/proxy.conf;
} }
} }
{% endif %}

View File

@ -7,7 +7,7 @@ const Tokens = require('./tokens');
/** /**
* @param {String} message * @param {String} message
* @param {*} debug * @param {*} debug
* @param {Integer} code * @param {Number} code
* @constructor * @constructor
*/ */
const ApiError = function (message, debug, code) { const ApiError = function (message, debug, code) {
@ -241,7 +241,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -251,7 +251,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
@ -260,7 +260,7 @@ module.exports = {
/** /**
* *
* @param {Integer} id * @param {Number} id
* @param {Object} auth * @param {Object} auth
* @returns {Promise} * @returns {Promise}
*/ */
@ -269,7 +269,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
loginAs: function (id) { loginAs: function (id) {
@ -278,7 +278,7 @@ module.exports = {
/** /**
* *
* @param {Integer} id * @param {Number} id
* @param {Object} perms * @param {Object} perms
* @returns {Promise} * @returns {Promise}
*/ */
@ -308,7 +308,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -318,11 +318,35 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
return fetch('delete', 'nginx/proxy-hosts/' + id); return fetch('delete', 'nginx/proxy-hosts/' + id);
},
/**
* @param {Number} id
* @returns {Promise}
*/
get: function (id) {
return fetch('get', 'nginx/proxy-hosts/' + id);
},
/**
* @param {Number} id
* @returns {Promise}
*/
enable: function (id) {
return fetch('post', 'nginx/proxy-hosts/' + id + '/enable');
},
/**
* @param {Number} id
* @returns {Promise}
*/
disable: function (id) {
return fetch('post', 'nginx/proxy-hosts/' + id + '/disable');
} }
}, },
@ -345,7 +369,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -355,7 +379,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
@ -363,12 +387,28 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @param {FormData} form_data * @param {FormData} form_data
* @params {Promise} * @params {Promise}
*/ */
setCerts: function (id, form_data) { setCerts: function (id, form_data) {
return FileUpload('nginx/redirection-hosts/' + id + '/certificates', form_data); return FileUpload('nginx/redirection-hosts/' + id + '/certificates', form_data);
},
/**
* @param {Number} id
* @returns {Promise}
*/
enable: function (id) {
return fetch('post', 'nginx/redirection-hosts/' + id + '/enable');
},
/**
* @param {Number} id
* @returns {Promise}
*/
disable: function (id) {
return fetch('post', 'nginx/redirection-hosts/' + id + '/disable');
} }
}, },
@ -391,7 +431,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -401,11 +441,27 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
return fetch('delete', 'nginx/streams/' + id); return fetch('delete', 'nginx/streams/' + id);
},
/**
* @param {Number} id
* @returns {Promise}
*/
enable: function (id) {
return fetch('post', 'nginx/streams/' + id + '/enable');
},
/**
* @param {Number} id
* @returns {Promise}
*/
disable: function (id) {
return fetch('post', 'nginx/streams/' + id + '/disable');
} }
}, },
@ -428,7 +484,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -438,7 +494,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
@ -446,12 +502,28 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @param {FormData} form_data * @param {FormData} form_data
* @params {Promise} * @params {Promise}
*/ */
setCerts: function (id, form_data) { setCerts: function (id, form_data) {
return FileUpload('nginx/dead-hosts/' + id + '/certificates', form_data); return FileUpload('nginx/dead-hosts/' + id + '/certificates', form_data);
},
/**
* @param {Number} id
* @returns {Promise}
*/
enable: function (id) {
return fetch('post', 'nginx/dead-hosts/' + id + '/enable');
},
/**
* @param {Number} id
* @returns {Promise}
*/
disable: function (id) {
return fetch('post', 'nginx/dead-hosts/' + id + '/disable');
} }
}, },
@ -474,7 +546,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -484,7 +556,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
@ -511,7 +583,7 @@ module.exports = {
/** /**
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @returns {Promise} * @returns {Promise}
*/ */
update: function (data) { update: function (data) {
@ -521,7 +593,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @returns {Promise} * @returns {Promise}
*/ */
delete: function (id) { delete: function (id) {
@ -529,7 +601,7 @@ module.exports = {
}, },
/** /**
* @param {Integer} id * @param {Number} id
* @param {FormData} form_data * @param {FormData} form_data
* @params {Promise} * @params {Promise}
*/ */

View File

@ -34,7 +34,9 @@
<td> <td>
<% <%
var o = isOnline(); var o = isOnline();
if (o === true) { %> if (!enabled) { %>
<span class="status-icon bg-warning"></span> <%- i18n('str', 'disabled') %>
<% } else if (o === true) { %>
<span class="status-icon bg-success"></span> <%- i18n('str', 'online') %> <span class="status-icon bg-success"></span> <%- i18n('str', 'online') %>
<% } else if (o === false) { %> <% } else if (o === false) { %>
<span title="<%- getOfflineError() %>"><span class="status-icon bg-danger"></span> <%- i18n('str', 'offline') %></span> <span title="<%- getOfflineError() %>"><span class="status-icon bg-danger"></span> <%- i18n('str', 'offline') %></span>
@ -48,7 +50,7 @@
<a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a> <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
<div class="dropdown-menu dropdown-menu-right"> <div class="dropdown-menu dropdown-menu-right">
<a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a> <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
<!--<a href="#" class="logs dropdown-item"><i class="dropdown-icon fe fe-book"></i> <%- i18n('str', 'logs') %></a>--> <a href="#" class="able dropdown-item"><i class="dropdown-icon fe fe-power"></i> <%- i18n('str', enabled ? 'disable' : 'enable') %></a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a> <a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
</div> </div>

View File

@ -9,12 +9,25 @@ module.exports = Mn.View.extend({
tagName: 'tr', tagName: 'tr',
ui: { ui: {
able: 'a.able',
edit: 'a.edit', edit: 'a.edit',
delete: 'a.delete', delete: 'a.delete',
host_link: '.host-link' host_link: '.host-link'
}, },
events: { events: {
'click @ui.able': function (e) {
e.preventDefault();
let id = this.model.get('id');
App.Api.Nginx.ProxyHosts[this.model.get('enabled') ? 'disable' : 'enable'](id)
.then(() => {
return App.Api.Nginx.ProxyHosts.get(id)
.then(row => {
this.model.set(row);
});
});
},
'click @ui.edit': function (e) { 'click @ui.edit': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showNginxProxyForm(this.model); App.Controller.showNginxProxyForm(this.model);

View File

@ -14,6 +14,8 @@
"save": "Save", "save": "Save",
"cancel": "Cancel", "cancel": "Cancel",
"close": "Close", "close": "Close",
"enable": "Enable",
"disable": "Disable",
"sure": "Yes I'm Sure", "sure": "Yes I'm Sure",
"disabled": "Disabled", "disabled": "Disabled",
"choose-file": "Choose file", "choose-file": "Choose file",

View File

@ -22,6 +22,7 @@ const model = Backbone.Model.extend({
block_exploits: false, block_exploits: false,
http2_support: false, http2_support: false,
advanced_config: '', advanced_config: '',
enabled: true,
meta: {}, meta: {},
// The following are expansions: // The following are expansions:
owner: null, owner: null,