diff --git a/src/backend/internal/certificate.js b/src/backend/internal/certificate.js index 474afd1..f36f366 100644 --- a/src/backend/internal/certificate.js +++ b/src/backend/internal/certificate.js @@ -27,6 +27,10 @@ const internalCertificate = { .then(() => { data.owner_user_id = access.token.get('attrs').id; + if (data.provider === 'letsencrypt') { + data.nice_name = data.domain_names.sort().join(', '); + } + return certificateModel .query() .omit(omissions()) @@ -246,6 +250,22 @@ const internalCertificate = { }); }, + /** + * @param {Access} access + * @param {Object} data + * @param {Array} data.domain_names + * @param {String} data.meta.letsencrypt_email + * @param {Boolean} data.meta.letsencrypt_agree + * @returns {Promise} + */ + createQuickCertificate: (access, data) => { + return internalCertificate.create(access, { + provider: 'letsencrypt', + domain_names: data.domain_names, + meta: data.meta + }); + }, + /** * Validates that the certs provided are good. * No access required here, nothing is changed or stored. diff --git a/src/backend/internal/proxy-host.js b/src/backend/internal/proxy-host.js index 68ca822..cdbf4f3 100644 --- a/src/backend/internal/proxy-host.js +++ b/src/backend/internal/proxy-host.js @@ -1,11 +1,12 @@ 'use strict'; -const _ = require('lodash'); -const error = require('../lib/error'); -const proxyHostModel = require('../models/proxy_host'); -const internalHost = require('./host'); -const internalNginx = require('./nginx'); -const internalAuditLog = require('./audit-log'); +const _ = require('lodash'); +const error = require('../lib/error'); +const proxyHostModel = require('../models/proxy_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 internalProxyHost = { * @returns {Promise} */ create: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('proxy_hosts:create', data) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -46,14 +53,39 @@ const internalProxyHost = { .omit(omissions()) .insertAndFetch(data); }) + .then(row => { + if (create_certificate) { + return internalCertificate.createQuickCertificate(access, data) + .then(cert => { + // update host with cert id + return internalProxyHost.update(access, { + id: row.id, + certificate_id: cert.id + }); + }) + .then(() => { + return row; + }); + } else { + return row; + } + }) + .then(row => { + // re-fetch with cert + return internalProxyHost.get(access, { + id: row.id, + expand: ['certificate', 'owner'] + }); + }) .then(row => { // Configure nginx return internalNginx.configure(proxyHostModel, 'proxy_host', row) .then(() => { - return internalProxyHost.get(access, {id: row.id, expand: ['owner']}); + return row; }); }) .then(row => { + // Audit log data.meta = _.assign({}, data.meta || {}, row.meta); // Add to audit log @@ -78,6 +110,12 @@ const internalProxyHost = { * @return {Promise} */ update: (access, data) => { + let create_certificate = data.certificate_id === 'new'; + + if (create_certificate) { + delete data.certificate_id; + } + return access.can('proxy_hosts:update', data.id) .then(access_data => { // Get a list of the domain names and check each of them against existing records @@ -107,13 +145,28 @@ const internalProxyHost = { throw new error.InternalValidationError('Proxy 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 => { return proxyHostModel .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', @@ -125,6 +178,19 @@ const internalProxyHost = { return _.omit(saved_row, omissions()); }); }); + }) + .then(() => { + return internalProxyHost.get(access, { + id: data.id, + expand: ['owner', 'certificate'] + }) + .then(row => { + // Configure nginx + return internalNginx.configure(proxyHostModel, 'proxy_host', row) + .then(() => { + return _.omit(row, omissions()); + }); + }) }); }, @@ -167,7 +233,6 @@ const internalProxyHost = { }) .then(row => { if (row) { - row.meta = internalHost.cleanMeta(row.meta); return _.omit(row, omissions()); } else { throw new error.ItemNotFoundError(data.id); @@ -207,8 +272,6 @@ const internalProxyHost = { }) .then(() => { // Add to audit log - row.meta = internalHost.cleanMeta(row.meta); - return internalAuditLog.add(access, { action: 'deleted', object_type: 'proxy-host', @@ -257,13 +320,6 @@ const internalProxyHost = { } return query; - }) - .then(rows => { - rows.map(row => { - row.meta = internalHost.cleanMeta(row.meta); - }); - - return rows; }); }, diff --git a/src/backend/schema/definitions.json b/src/backend/schema/definitions.json index 75c148b..272b4c4 100644 --- a/src/backend/schema/definitions.json +++ b/src/backend/schema/definitions.json @@ -116,6 +116,20 @@ "type": "integer", "minimum": 1 }, + "certificate_id": { + "description": "Certificate ID", + "example": 1234, + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "string", + "pattern": "^new$" + } + ] + }, "access_list_id": { "description": "Access List ID", "example": 1234, diff --git a/src/backend/schema/endpoints/proxy-hosts.json b/src/backend/schema/endpoints/proxy-hosts.json index 3f45960..d5352c8 100644 --- a/src/backend/schema/endpoints/proxy-hosts.json +++ b/src/backend/schema/endpoints/proxy-hosts.json @@ -27,15 +27,12 @@ "minimum": 1, "maximum": 65535 }, - "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" }, @@ -46,17 +43,7 @@ "$ref": "../definitions.json#/definitions/access_list_id" }, "meta": { - "type": "object", - "additionalProperties": false, - "properties": { - "letsencrypt_email": { - "type": "string", - "format": "email" - }, - "letsencrypt_agree": { - "type": "boolean" - } - } + "type": "object" } }, "properties": { @@ -78,15 +65,12 @@ "forward_port": { "$ref": "#/definitions/forward_port" }, - "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" }, @@ -146,15 +130,12 @@ "forward_port": { "$ref": "#/definitions/forward_port" }, - "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" }, @@ -198,15 +179,12 @@ "forward_port": { "$ref": "#/definitions/forward_port" }, - "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/nginx/proxy/delete.ejs b/src/frontend/js/app/nginx/proxy/delete.ejs index 61f1ca1..2fe099f 100644 --- a/src/frontend/js/app/nginx/proxy/delete.ejs +++ b/src/frontend/js/app/nginx/proxy/delete.ejs @@ -8,7 +8,7 @@