diff --git a/backend/app.js b/backend/app.js index 8f4890c..bbeb1c0 100644 --- a/backend/app.js +++ b/backend/app.js @@ -74,12 +74,10 @@ app.use(function (err, req, res, next) { } // Not every error is worth logging - but this is good for now until it gets annoying. - if (typeof err.stack !== 'undefined' && err.stack) { - if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { - log.debug(err.stack); - } else if (typeof err.public == 'undefined' || !err.public) { - log.warn(err.message); - } + if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { + log.debug(err); + } else if (typeof err.stack !== 'undefined' && err.stack && (typeof err.public == 'undefined' || !err.public)) { + log.warn(err.message); } res diff --git a/backend/internal/host.js b/backend/internal/host.js index f37b943..9c91b41 100644 --- a/backend/internal/host.js +++ b/backend/internal/host.js @@ -206,14 +206,21 @@ const internalHost = { if (existing_rows && existing_rows.length) { existing_rows.map(function (existing_row) { - existing_row.domain_names.map(function (existing_hostname) { + + function checkHostname(existing_hostname) { // Does this domain match? if (existing_hostname.toLowerCase() === hostname.toLowerCase()) { if (!ignore_id || ignore_id !== existing_row.id) { is_taken = true; } } - }); + } + + if (existing_row.domain_names) { + existing_row.domain_names.map(checkHostname); + } else if (existing_row.domain_name) { + checkHostname(existing_row.domain_name); + } }); } diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 9215df9..2c0c5f4 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -236,8 +236,8 @@ const internalNginx = { host = { all_passthrough_hosts: allHosts.map((host) => { // Replace dots in domain - host.escaped_name = host.domain_name.replace(/\./, '_'); host.forwarding_host = internalNginx.addIpv6Brackets(host.forwarding_host); + return host; }), } } else { diff --git a/backend/internal/ssl-passthrough-host.js b/backend/internal/ssl-passthrough-host.js index a4f0d57..a6b3f15 100644 --- a/backend/internal/ssl-passthrough-host.js +++ b/backend/internal/ssl-passthrough-host.js @@ -19,20 +19,12 @@ const internalPassthroughHost = { create: (access, data) => { return access.can('ssl_passthrough_hosts:create', data) .then(() => { - // Get a list of the domain names and check each of them against existing records - let domain_name_check_promises = []; - - data.domain_names.map(function (domain_name) { - domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name)); - }); - - return Promise.all(domain_name_check_promises) - .then((check_results) => { - check_results.map(function (result) { - if (result.is_taken) { - throw new error.ValidationError(result.hostname + ' is already in use'); - } - }); + // Get the domain name and check it against existing records + return internalHost.isHostnameTaken(data.domain_name) + .then((result) => { + if (result.is_taken) { + throw new error.ValidationError(result.hostname + ' is already in use'); + } }); }).then((/*access_data*/) => { data.owner_user_id = access.token.getUserId(1); @@ -57,7 +49,7 @@ const internalPassthroughHost = { // Add to audit log return internalAuditLog.add(access, { action: 'created', - object_type: 'ssl_passthrough_host', + object_type: 'ssl-passthrough-host', object_id: row.id, meta: data }) @@ -76,21 +68,13 @@ const internalPassthroughHost = { update: (access, data) => { return access.can('ssl_passthrough_hosts:update', data.id) .then((/*access_data*/) => { - // Get a list of the domain names and check each of them against existing records - let domain_name_check_promises = []; - - if (typeof data.domain_names !== 'undefined') { - data.domain_names.map(function (domain_name) { - domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'ssl_passthrough', data.id)); - }); - - return Promise.all(domain_name_check_promises) - .then((check_results) => { - check_results.map(function (result) { - if (result.is_taken) { - throw new error.ValidationError(result.hostname + ' is already in use'); - } - }); + // Get the domain name and check it against existing records + if (typeof data.domain_name !== 'undefined') { + return internalHost.isHostnameTaken(data.domain_name, 'ssl_passthrough', data.id) + .then((result) => { + if (result.is_taken) { + throw new error.ValidationError(result.hostname + ' is already in use'); + } }); } }).then((/*access_data*/) => { @@ -116,7 +100,7 @@ const internalPassthroughHost = { // Add to audit log return internalAuditLog.add(access, { action: 'updated', - object_type: 'ssl_passthrough_host', + object_type: 'ssl-passthrough-host', object_id: row.id, meta: data }) @@ -207,7 +191,7 @@ const internalPassthroughHost = { // Add to audit log return internalAuditLog.add(access, { action: 'deleted', - object_type: 'ssl_passthrough_host', + object_type: 'ssl-passthrough-host', object_id: row.id, meta: _.omit(row, omissions()) }); @@ -256,7 +240,7 @@ const internalPassthroughHost = { // Add to audit log return internalAuditLog.add(access, { action: 'enabled', - object_type: 'ssl_passthrough_host', + object_type: 'ssl-passthrough-host', object_id: row.id, meta: _.omit(row, omissions()) }); @@ -305,7 +289,7 @@ const internalPassthroughHost = { // Add to audit log return internalAuditLog.add(access, { action: 'disabled', - object_type: 'ssl_passthrough_host', + object_type: 'ssl-passthrough-host', object_id: row.id, meta: _.omit(row, omissions()) }); diff --git a/backend/migrations/20211010141200_ssl_passthrough_host.js b/backend/migrations/20211010141200_ssl_passthrough_host.js index 9a92442..3253868 100644 --- a/backend/migrations/20211010141200_ssl_passthrough_host.js +++ b/backend/migrations/20211010141200_ssl_passthrough_host.js @@ -20,13 +20,30 @@ exports.up = function (knex/*, Promise*/) { table.integer('owner_user_id').notNull().unsigned(); table.integer('is_deleted').notNull().unsigned().defaultTo(0); table.string('domain_name').notNull(); - table.string('forward_ip').notNull(); + table.string('forwarding_host').notNull(); table.integer('forwarding_port').notNull().unsigned(); + table.integer('enabled').notNull().unsigned().defaultTo(1); table.json('meta').notNull(); + }).then(() => { + logger.info('[' + migrate_name + '] Table created'); }) - .then(() => { - logger.info('[' + migrate_name + '] Table created'); - }); + .then(() => { + return knex.schema.table('user_permission', (table) => { + table.string('ssl_passthrough_hosts').notNull(); + }) + .then(() => { + return knex('user_permission').update('ssl_passthrough_hosts', knex.ref('streams')); + }) + .then(() => { + return knex.schema.alterTable('user_permission', (table) => { + table.string('ssl_passthrough_hosts').notNullable().alter(); + }); + }) + .then(() => { + logger.info('[' + migrate_name + '] permissions updated'); + }); + }) + ; }; /** @@ -39,8 +56,12 @@ exports.up = function (knex/*, Promise*/) { exports.down = function (knex/*, Promise*/) { logger.info('[' + migrate_name + '] Migrating Down...'); - return knex.schema.dropTable('stream') + return knex.schema.dropTable('stream').then(() => { + return knex.schema.table('user_permission', (table) => { + table.dropColumn('ssl_passthrough_hosts'); + }) + }) .then(function () { - logger.info('[' + migrate_name + '] Table altered'); + logger.info('[' + migrate_name + '] Table altered and permissions updated'); }); }; diff --git a/backend/routes/api/nginx/ssl_passthrough_hosts.js b/backend/routes/api/nginx/ssl_passthrough_hosts.js index 5eb75f7..dfa2eac 100644 --- a/backend/routes/api/nginx/ssl_passthrough_hosts.js +++ b/backend/routes/api/nginx/ssl_passthrough_hosts.js @@ -73,7 +73,7 @@ router * /api/nginx/ssl-passthrough-hosts/123 */ router - .route('/:ssl_passthrough_host_id') + .route('/:host_id') .options((req, res) => { res.sendStatus(204); }) @@ -86,7 +86,7 @@ router */ .get((req, res, next) => { validator({ - required: ['ssl_passthrough_host_id'], + required: ['host_id'], additionalProperties: false, properties: { host_id: { diff --git a/backend/schema/endpoints/ssl-passthrough-hosts.json b/backend/schema/endpoints/ssl-passthrough-hosts.json index 12306d0..5c20602 100644 --- a/backend/schema/endpoints/ssl-passthrough-hosts.json +++ b/backend/schema/endpoints/ssl-passthrough-hosts.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/ssl-passthough-hosts", + "$id": "endpoints/ssl-passthrough-hosts", "title": "SSL Passthrough Hosts", "description": "Endpoints relating to SSL Passthrough Hosts", "stability": "stable", diff --git a/backend/setup.js b/backend/setup.js index 4a2f948..769ca06 100644 --- a/backend/setup.js +++ b/backend/setup.js @@ -107,14 +107,15 @@ const setupDefaultUser = () => { }) .then(() => { return userPermissionModel.query().insert({ - user_id: user.id, - visibility: 'all', - proxy_hosts: 'manage', - redirection_hosts: 'manage', - dead_hosts: 'manage', - streams: 'manage', - access_lists: 'manage', - certificates: 'manage', + user_id: user.id, + visibility: 'all', + proxy_hosts: 'manage', + redirection_hosts: 'manage', + dead_hosts: 'manage', + ssl_passthrough_hosts: 'manage', + streams: 'manage', + access_lists: 'manage', + certificates: 'manage', }); }); }) @@ -229,7 +230,7 @@ const setupLogrotation = () => { * @returns {Promise} */ const setupSslPassthrough = () => { - return internalNginx.configure(passthroughHostModel, 'ssl_passthrough_host', {}); + return internalNginx.configure(passthroughHostModel, 'ssl_passthrough_host', {}).then(() => internalNginx.reload()); }; module.exports = function () { diff --git a/backend/templates/ssl_passthrough_host.conf b/backend/templates/ssl_passthrough_host.conf index 9ee872d..6dd2b34 100644 --- a/backend/templates/ssl_passthrough_host.conf +++ b/backend/templates/ssl_passthrough_host.conf @@ -4,16 +4,16 @@ map $ssl_preread_server_name $name { {% for host in all_passthrough_hosts %} -{% if enabled %} - {{ host.domain_name }} ssl_passthrough_{{ host.escaped_name }} +{% if host.enabled %} + {{ host.domain_name }} ssl_passthrough_{{ host.domain_name }}; {% endif %} {% endfor %} default https_default_backend; } {% for host in all_passthrough_hosts %} -{% if enabled %} -upstream ssl_passthrough_{{ host.escaped_name }} { +{% if host.enabled %} +upstream ssl_passthrough_{{ host.domain_name }} { server {{host.forwarding_host}}:{{host.forwarding_port}}; } {% endif %} @@ -34,6 +34,8 @@ server { proxy_pass $name; ssl_preread on; + error_log /data/logs/ssl-passthrough-hosts_error.log warn; + # Custom include /data/nginx/custom/server_ssl_passthrough[.]conf; } \ No newline at end of file diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 4914cd1..4d2e3a1 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -23,7 +23,7 @@ services: DB_MYSQL_USER: "npm" DB_MYSQL_PASSWORD: "npm" DB_MYSQL_NAME: "npm" - ENABLE_SSL_PASSTHROUGH: "true" + # ENABLE_SSL_PASSTHROUGH: "true" # DB_SQLITE_FILE: "/data/database.sqlite" # DISABLE_IPV6: "true" volumes: @@ -41,6 +41,8 @@ services: container_name: npm_db networks: - nginx_proxy_manager + ports: + - 33306:3306 environment: MYSQL_ROOT_PASSWORD: "npm" MYSQL_DATABASE: "npm" diff --git a/frontend/js/app/api.js b/frontend/js/app/api.js index af47a13..d689acd 100644 --- a/frontend/js/app/api.js +++ b/frontend/js/app/api.js @@ -516,6 +516,15 @@ module.exports = { }, SslPassthroughHosts: { + /** + * @param {Array} [expand] + * @param {String} [query] + * @returns {Promise} + */ + getFeatureEnabled: function () { + return fetch('get', 'ssl-passthrough-enabled'); + }, + /** * @param {Array} [expand] * @param {String} [query] diff --git a/frontend/js/app/nginx/ssl-passthrough/form.ejs b/frontend/js/app/nginx/ssl-passthrough/form.ejs index 3120002..6ba3586 100644 --- a/frontend/js/app/nginx/ssl-passthrough/form.ejs +++ b/frontend/js/app/nginx/ssl-passthrough/form.ejs @@ -21,7 +21,7 @@