diff --git a/src/backend/internal/audit-log.js b/src/backend/internal/audit-log.js index 926773e..ad67d0f 100644 --- a/src/backend/internal/audit-log.js +++ b/src/backend/internal/audit-log.js @@ -19,6 +19,7 @@ const internalAuditLog = { let query = auditLogModel .query() .orderBy('created_on', 'DESC') + .orderBy('id', 'DESC') .limit(100) .allowEager('[user]'); diff --git a/src/backend/internal/dead-host.js b/src/backend/internal/dead-host.js index 3d95a6a..455937e 100644 --- a/src/backend/internal/dead-host.js +++ b/src/backend/internal/dead-host.js @@ -1,11 +1,12 @@ 'use strict'; -const _ = require('lodash'); -const error = require('../lib/error'); -const deadHostModel = require('../models/dead_host'); -const internalHost = require('./host'); -const internalNginx = require('./nginx'); -const internalAuditLog = require('./audit-log'); +const _ = require('lodash'); +const error = require('../lib/error'); +const deadHostModel = require('../models/dead_host'); +const internalHost = require('./host'); +const internalNginx = require('./nginx'); +const internalAuditLog = require('./audit-log'); +const internalCertificate = require('./certificate'); function omissions () { return ['is_deleted']; @@ -19,6 +20,12 @@ const internalDeadHost = { * @returns {Promise} */ create: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('dead_hosts:create', data) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -46,14 +53,40 @@ const internalDeadHost = { .omit(omissions()) .insertAndFetch(data); }) + .then(row => { + if (create_certificate) { + return internalCertificate.createQuickCertificate(access, data) + .then(cert => { + // update host with cert id + return internalDeadHost.update(access, { + id: row.id, + certificate_id: cert.id + }); + }) + .then(() => { + return row; + }); + } else { + return row; + } + }) + .then(row => { + // re-fetch with cert + return internalDeadHost.get(access, { + id: row.id, + expand: ['certificate', 'owner'] + }); + }) .then(row => { // Configure nginx return internalNginx.configure(deadHostModel, 'dead_host', row) .then(() => { - return internalDeadHost.get(access, {id: row.id, expand: ['owner']}); + return row; }); }) .then(row => { + data.meta = _.assign({}, data.meta || {}, row.meta); + // Add to audit log return internalAuditLog.add(access, { action: 'created', @@ -71,11 +104,15 @@ const internalDeadHost = { * @param {Access} access * @param {Object} data * @param {Integer} data.id - * @param {String} [data.email] - * @param {String} [data.name] * @return {Promise} */ update: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('dead_hosts:update', data.id) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -105,13 +142,33 @@ const internalDeadHost = { throw new error.InternalValidationError('404 Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id); } + if (create_certificate) { + return internalCertificate.createQuickCertificate(access, { + domain_names: data.domain_names || row.domain_names, + meta: _.assign({}, row.meta, data.meta) + }) + .then(cert => { + // update host with cert id + data.certificate_id = cert.id; + }) + .then(() => { + return row; + }); + } else { + return row; + } + }) + .then(row => { + // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here. + data = _.assign({}, { + domain_names: row.domain_names + },data); + return deadHostModel .query() - .omit(omissions()) - .patchAndFetchById(row.id, data) + .where({id: data.id}) + .patch(data) .then(saved_row => { - saved_row.meta = internalHost.cleanMeta(saved_row.meta); - // Add to audit log return internalAuditLog.add(access, { action: 'updated', @@ -123,6 +180,19 @@ const internalDeadHost = { return _.omit(saved_row, omissions()); }); }); + }) + .then(() => { + return internalDeadHost.get(access, { + id: data.id, + expand: ['owner', 'certificate'] + }) + .then(row => { + // Configure nginx + return internalNginx.configure(deadHostModel, 'dead_host', row) + .then(() => { + return _.omit(row, omissions()); + }); + }); }); }, @@ -165,7 +235,6 @@ const internalDeadHost = { }) .then(row => { if (row) { - row.meta = internalHost.cleanMeta(row.meta); return _.omit(row, omissions()); } else { throw new error.ItemNotFoundError(data.id); @@ -205,8 +274,6 @@ const internalDeadHost = { }) .then(() => { // Add to audit log - row.meta = internalHost.cleanMeta(row.meta); - return internalAuditLog.add(access, { action: 'deleted', object_type: 'dead-host', @@ -220,40 +287,6 @@ const internalDeadHost = { }); }, - /** - * @param {Access} access - * @param {Object} data - * @param {Integer} data.id - * @param {Object} data.files - * @returns {Promise} - */ - setCerts: (access, data) => { - return internalDeadHost.get(access, {id: data.id}) - .then(row => { - _.map(data.files, (file, name) => { - if (internalHost.allowed_ssl_files.indexOf(name) !== -1) { - row.meta[name] = file.data.toString(); - } - }); - - return internalDeadHost.update(access, { - id: data.id, - meta: row.meta - }); - }) - .then(row => { - return internalAuditLog.add(access, { - action: 'updated', - object_type: 'dead-host', - object_id: row.id, - meta: data - }) - .then(() => { - return _.pick(row.meta, internalHost.allowed_ssl_files); - }); - }); - }, - /** * All Hosts * @@ -289,13 +322,6 @@ const internalDeadHost = { } return query; - }) - .then(rows => { - rows.map(row => { - row.meta = internalHost.cleanMeta(row.meta); - }); - - return rows; }); }, diff --git a/src/backend/internal/proxy-host.js b/src/backend/internal/proxy-host.js index cdbf4f3..dc26ab2 100644 --- a/src/backend/internal/proxy-host.js +++ b/src/backend/internal/proxy-host.js @@ -105,8 +105,6 @@ const internalProxyHost = { * @param {Access} access * @param {Object} data * @param {Integer} data.id - * @param {String} [data.email] - * @param {String} [data.name] * @return {Promise} */ update: (access, data) => { @@ -162,6 +160,11 @@ const internalProxyHost = { } }) .then(row => { + // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here. + data = _.assign({}, { + domain_names: row.domain_names + },data); + return proxyHostModel .query() .where({id: data.id}) @@ -190,7 +193,7 @@ const internalProxyHost = { .then(() => { return _.omit(row, omissions()); }); - }) + }); }); }, diff --git a/src/backend/internal/redirection-host.js b/src/backend/internal/redirection-host.js index 64ece1a..50ea3df 100644 --- a/src/backend/internal/redirection-host.js +++ b/src/backend/internal/redirection-host.js @@ -6,6 +6,7 @@ const redirectionHostModel = require('../models/redirection_host'); const internalHost = require('./host'); const internalNginx = require('./nginx'); const internalAuditLog = require('./audit-log'); +const internalCertificate = require('./certificate'); function omissions () { return ['is_deleted']; @@ -19,6 +20,12 @@ const internalRedirectionHost = { * @returns {Promise} */ create: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('redirection_hosts:create', data) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -46,14 +53,40 @@ const internalRedirectionHost = { .omit(omissions()) .insertAndFetch(data); }) + .then(row => { + if (create_certificate) { + return internalCertificate.createQuickCertificate(access, data) + .then(cert => { + // update host with cert id + return internalRedirectionHost.update(access, { + id: row.id, + certificate_id: cert.id + }); + }) + .then(() => { + return row; + }); + } else { + return row; + } + }) + .then(row => { + // re-fetch with cert + return internalRedirectionHost.get(access, { + id: row.id, + expand: ['certificate', 'owner'] + }); + }) .then(row => { // Configure nginx return internalNginx.configure(redirectionHostModel, 'redirection_host', row) .then(() => { - return internalRedirectionHost.get(access, {id: row.id, expand: ['owner']}); + return row; }); }) .then(row => { + data.meta = _.assign({}, data.meta || {}, row.meta); + // Add to audit log return internalAuditLog.add(access, { action: 'created', @@ -71,11 +104,15 @@ const internalRedirectionHost = { * @param {Access} access * @param {Object} data * @param {Integer} data.id - * @param {String} [data.email] - * @param {String} [data.name] * @return {Promise} */ update: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('redirection_hosts:update', data.id) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -105,13 +142,33 @@ const internalRedirectionHost = { throw new error.InternalValidationError('Redirection Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id); } + if (create_certificate) { + return internalCertificate.createQuickCertificate(access, { + domain_names: data.domain_names || row.domain_names, + meta: _.assign({}, row.meta, data.meta) + }) + .then(cert => { + // update host with cert id + data.certificate_id = cert.id; + }) + .then(() => { + return row; + }); + } else { + return row; + } + }) + .then(row => { + // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here. + data = _.assign({}, { + domain_names: row.domain_names + },data); + return redirectionHostModel .query() - .omit(omissions()) - .patchAndFetchById(row.id, data) + .where({id: data.id}) + .patch(data) .then(saved_row => { - saved_row.meta = internalHost.cleanMeta(saved_row.meta); - // Add to audit log return internalAuditLog.add(access, { action: 'updated', @@ -123,6 +180,19 @@ const internalRedirectionHost = { return _.omit(saved_row, omissions()); }); }); + }) + .then(() => { + return internalRedirectionHost.get(access, { + id: data.id, + expand: ['owner', 'certificate'] + }) + .then(row => { + // Configure nginx + return internalNginx.configure(redirectionHostModel, 'redirection_host', row) + .then(() => { + return _.omit(row, omissions()); + }); + }); }); }, @@ -165,7 +235,6 @@ const internalRedirectionHost = { }) .then(row => { if (row) { - row.meta = internalHost.cleanMeta(row.meta); return _.omit(row, omissions()); } else { throw new error.ItemNotFoundError(data.id); @@ -205,8 +274,6 @@ const internalRedirectionHost = { }) .then(() => { // Add to audit log - row.meta = internalHost.cleanMeta(row.meta); - return internalAuditLog.add(access, { action: 'deleted', object_type: 'redirection-host', @@ -220,40 +287,6 @@ const internalRedirectionHost = { }); }, - /** - * @param {Access} access - * @param {Object} data - * @param {Integer} data.id - * @param {Object} data.files - * @returns {Promise} - */ - setCerts: (access, data) => { - return internalRedirectionHost.get(access, {id: data.id}) - .then(row => { - _.map(data.files, (file, name) => { - if (internalHost.allowed_ssl_files.indexOf(name) !== -1) { - row.meta[name] = file.data.toString(); - } - }); - - return internalRedirectionHost.update(access, { - id: data.id, - meta: row.meta - }); - }) - .then(row => { - return internalAuditLog.add(access, { - action: 'updated', - object_type: 'redirection-host', - object_id: row.id, - meta: data - }) - .then(() => { - return _.pick(row.meta, internalHost.allowed_ssl_files); - }); - }); - }, - /** * All Hosts * @@ -289,13 +322,6 @@ const internalRedirectionHost = { } return query; - }) - .then(rows => { - rows.map(row => { - row.meta = internalHost.cleanMeta(row.meta); - }); - - return rows; }); }, diff --git a/src/backend/internal/stream.js b/src/backend/internal/stream.js index 91d104f..27dfa15 100644 --- a/src/backend/internal/stream.js +++ b/src/backend/internal/stream.js @@ -57,8 +57,6 @@ const internalStream = { * @param {Access} access * @param {Object} data * @param {Integer} data.id - * @param {String} [data.email] - * @param {String} [data.name] * @return {Promise} */ update: (access, data) => { diff --git a/src/backend/routes/api/nginx/dead_hosts.js b/src/backend/routes/api/nginx/dead_hosts.js index c65dc2c..0101530 100644 --- a/src/backend/routes/api/nginx/dead_hosts.js +++ b/src/backend/routes/api/nginx/dead_hosts.js @@ -147,38 +147,4 @@ router .catch(next); }); -/** - * Specific dead-host Certificates - * - * /api/nginx/dead-hosts/123/certificates - */ -router - .route('/:host_id/certificates') - .options((req, res) => { - res.sendStatus(204); - }) - .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes - - /** - * POST /api/nginx/dead-hosts/123/certificates - * - * Upload certifications - */ - .post((req, res, next) => { - if (!req.files) { - res.status(400) - .send({error: 'No files were uploaded'}); - } else { - internalDeadHost.setCerts(res.locals.access, { - id: parseInt(req.params.host_id, 10), - files: req.files - }) - .then(result => { - res.status(200) - .send(result); - }) - .catch(next); - } - }); - module.exports = router; diff --git a/src/backend/routes/api/nginx/redirection_hosts.js b/src/backend/routes/api/nginx/redirection_hosts.js index d2ec0d3..acd5a67 100644 --- a/src/backend/routes/api/nginx/redirection_hosts.js +++ b/src/backend/routes/api/nginx/redirection_hosts.js @@ -147,38 +147,4 @@ router .catch(next); }); -/** - * Specific redirection-host Certificates - * - * /api/nginx/redirection-hosts/123/certificates - */ -router - .route('/:host_id/certificates') - .options((req, res) => { - res.sendStatus(204); - }) - .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes - - /** - * POST /api/nginx/redirection-hosts/123/certificates - * - * Upload certifications - */ - .post((req, res, next) => { - if (!req.files) { - res.status(400) - .send({error: 'No files were uploaded'}); - } else { - internalRedirectionHost.setCerts(res.locals.access, { - id: parseInt(req.params.host_id, 10), - files: req.files - }) - .then(result => { - res.status(200) - .send(result); - }) - .catch(next); - } - }); - module.exports = router; diff --git a/src/backend/schema/endpoints/dead-hosts.json b/src/backend/schema/endpoints/dead-hosts.json index 6fbe130..b15adca 100644 --- a/src/backend/schema/endpoints/dead-hosts.json +++ b/src/backend/schema/endpoints/dead-hosts.json @@ -18,15 +18,12 @@ "domain_names": { "$ref": "../definitions.json#/definitions/domain_names" }, - "ssl_enabled": { - "$ref": "../definitions.json#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "../definitions.json#/definitions/certificate_id" }, "ssl_forced": { "$ref": "../definitions.json#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "../definitions.json#/definitions/ssl_provider" - }, "meta": { "type": "object", "additionalProperties": false, @@ -54,15 +51,12 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "meta": { "$ref": "#/definitions/meta" } @@ -105,15 +99,12 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "meta": { "$ref": "#/definitions/meta" } @@ -142,15 +133,12 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "meta": { "$ref": "#/definitions/meta" } diff --git a/src/backend/schema/endpoints/redirection-hosts.json b/src/backend/schema/endpoints/redirection-hosts.json index 4dbe0da..24bd88e 100644 --- a/src/backend/schema/endpoints/redirection-hosts.json +++ b/src/backend/schema/endpoints/redirection-hosts.json @@ -26,15 +26,12 @@ "example": true, "type": "boolean" }, - "ssl_enabled": { - "$ref": "../definitions.json#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "../definitions.json#/definitions/certificate_id" }, "ssl_forced": { "$ref": "../definitions.json#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "../definitions.json#/definitions/ssl_provider" - }, "block_exploits": { "$ref": "../definitions.json#/definitions/block_exploits" }, @@ -71,15 +68,12 @@ "preserve_path": { "$ref": "#/definitions/preserve_path" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "block_exploits": { "$ref": "#/definitions/block_exploits" }, @@ -132,15 +126,12 @@ "preserve_path": { "$ref": "#/definitions/preserve_path" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "block_exploits": { "$ref": "#/definitions/block_exploits" }, @@ -178,15 +169,12 @@ "preserve_path": { "$ref": "#/definitions/preserve_path" }, - "ssl_enabled": { - "$ref": "#/definitions/ssl_enabled" + "certificate_id": { + "$ref": "#/definitions/certificate_id" }, "ssl_forced": { "$ref": "#/definitions/ssl_forced" }, - "ssl_provider": { - "$ref": "#/definitions/ssl_provider" - }, "block_exploits": { "$ref": "#/definitions/block_exploits" }, diff --git a/src/frontend/js/app/audit-log/meta.ejs b/src/frontend/js/app/audit-log/meta.ejs index ce08b90..98a2d97 100644 --- a/src/frontend/js/app/audit-log/meta.ejs +++ b/src/frontend/js/app/audit-log/meta.ejs @@ -6,12 +6,12 @@