You've already forked nginx-proxy-manager
							
							
				mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-11-04 04:11:42 +03:00 
			
		
		
		
	@@ -3,13 +3,13 @@ const fs                    = require('fs');
 | 
			
		||||
const batchflow             = require('batchflow');
 | 
			
		||||
const logger                = require('../logger').access;
 | 
			
		||||
const error                 = require('../lib/error');
 | 
			
		||||
const utils                 = require('../lib/utils');
 | 
			
		||||
const accessListModel       = require('../models/access_list');
 | 
			
		||||
const accessListAuthModel   = require('../models/access_list_auth');
 | 
			
		||||
const accessListClientModel = require('../models/access_list_client');
 | 
			
		||||
const proxyHostModel        = require('../models/proxy_host');
 | 
			
		||||
const internalAuditLog      = require('./audit-log');
 | 
			
		||||
const internalNginx         = require('./nginx');
 | 
			
		||||
const utils                 = require('../lib/utils');
 | 
			
		||||
 | 
			
		||||
function omissions () {
 | 
			
		||||
	return ['is_deleted'];
 | 
			
		||||
@@ -27,13 +27,13 @@ const internalAccessList = {
 | 
			
		||||
			.then((/*access_data*/) => {
 | 
			
		||||
				return accessListModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch({
 | 
			
		||||
						name:          data.name,
 | 
			
		||||
						satisfy_any:   data.satisfy_any,
 | 
			
		||||
						pass_auth:     data.pass_auth,
 | 
			
		||||
						owner_user_id: access.token.getUserId(1)
 | 
			
		||||
					});
 | 
			
		||||
					})
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				data.id = row.id;
 | 
			
		||||
@@ -256,35 +256,31 @@ const internalAccessList = {
 | 
			
		||||
					.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
 | 
			
		||||
					.where('access_list.is_deleted', 0)
 | 
			
		||||
					.andWhere('access_list.id', data.id)
 | 
			
		||||
					.allowEager('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
 | 
			
		||||
					.omit(['access_list.is_deleted'])
 | 
			
		||||
					.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
 | 
			
		||||
						row = internalAccessList.maskItems(row);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
 | 
			
		||||
					row = internalAccessList.maskItems(row);
 | 
			
		||||
				}
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -381,8 +377,7 @@ const internalAccessList = {
 | 
			
		||||
					.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
 | 
			
		||||
					.where('access_list.is_deleted', 0)
 | 
			
		||||
					.groupBy('access_list.id')
 | 
			
		||||
					.omit(['access_list.is_deleted'])
 | 
			
		||||
					.allowEager('[owner,items,clients]')
 | 
			
		||||
					.allowGraph('[owner,items,clients]')
 | 
			
		||||
					.orderBy('access_list.name', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -397,10 +392,10 @@ const internalAccessList = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((rows) => {
 | 
			
		||||
				if (rows) {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ const internalAuditLog = {
 | 
			
		||||
					.orderBy('created_on', 'DESC')
 | 
			
		||||
					.orderBy('id', 'DESC')
 | 
			
		||||
					.limit(100)
 | 
			
		||||
					.allowEager('[user]');
 | 
			
		||||
					.allowGraph('[user]');
 | 
			
		||||
 | 
			
		||||
				// Query is used for searching
 | 
			
		||||
				if (typeof search_query === 'string') {
 | 
			
		||||
@@ -29,7 +29,7 @@ const internalAuditLog = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
 
 | 
			
		||||
@@ -121,8 +121,8 @@ const internalCertificate = {
 | 
			
		||||
 | 
			
		||||
				return certificateModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((certificate) => {
 | 
			
		||||
				if (certificate.provider === 'letsencrypt') {
 | 
			
		||||
@@ -269,8 +269,8 @@ const internalCertificate = {
 | 
			
		||||
 | 
			
		||||
				return certificateModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.patchAndFetchById(row.id, data)
 | 
			
		||||
					.then(utils.omitRow(omissions()))
 | 
			
		||||
					.then((saved_row) => {
 | 
			
		||||
						saved_row.meta = internalCertificate.cleanMeta(saved_row.meta);
 | 
			
		||||
						data.meta      = internalCertificate.cleanMeta(data.meta);
 | 
			
		||||
@@ -288,7 +288,7 @@ const internalCertificate = {
 | 
			
		||||
							meta:        _.omit(data, ['expires_on']) // this prevents json circular reference because expires_on might be raw
 | 
			
		||||
						})
 | 
			
		||||
							.then(() => {
 | 
			
		||||
								return _.omit(saved_row, omissions());
 | 
			
		||||
								return saved_row;
 | 
			
		||||
							});
 | 
			
		||||
					});
 | 
			
		||||
			});
 | 
			
		||||
@@ -313,30 +313,28 @@ const internalCertificate = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[owner]')
 | 
			
		||||
					.allowGraph('[owner]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -466,8 +464,7 @@ const internalCertificate = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[owner]')
 | 
			
		||||
					.allowGraph('[owner]')
 | 
			
		||||
					.orderBy('nice_name', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -482,10 +479,10 @@ const internalCertificate = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -662,7 +659,6 @@ const internalCertificate = {
 | 
			
		||||
							meta:         _.clone(row.meta) // Prevent the update method from changing this value that we'll use later
 | 
			
		||||
						})
 | 
			
		||||
							.then((certificate) => {
 | 
			
		||||
								console.log('ROWMETA:', row.meta);
 | 
			
		||||
								certificate.meta = row.meta;
 | 
			
		||||
								return internalCertificate.writeCustomCert(certificate);
 | 
			
		||||
							});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
const _                   = require('lodash');
 | 
			
		||||
const error               = require('../lib/error');
 | 
			
		||||
const utils               = require('../lib/utils');
 | 
			
		||||
const deadHostModel       = require('../models/dead_host');
 | 
			
		||||
const internalHost        = require('./host');
 | 
			
		||||
const internalNginx       = require('./nginx');
 | 
			
		||||
@@ -49,8 +50,8 @@ const internalDeadHost = {
 | 
			
		||||
 | 
			
		||||
				return deadHostModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (create_certificate) {
 | 
			
		||||
@@ -218,31 +219,28 @@ const internalDeadHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[owner,certificate]')
 | 
			
		||||
					.allowGraph('[owner,certificate]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					row = internalHost.cleanRowCertificateMeta(row);
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -404,8 +402,7 @@ const internalDeadHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[owner,certificate]')
 | 
			
		||||
					.allowGraph('[owner,certificate]')
 | 
			
		||||
					.orderBy('domain_names', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -420,10 +417,10 @@ const internalDeadHost = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((rows) => {
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@ const https         = require('https');
 | 
			
		||||
const fs            = require('fs');
 | 
			
		||||
const logger        = require('../logger').ip_ranges;
 | 
			
		||||
const error         = require('../lib/error');
 | 
			
		||||
const utils         = require('../lib/utils');
 | 
			
		||||
const internalNginx = require('./nginx');
 | 
			
		||||
const { Liquid }    = require('liquidjs');
 | 
			
		||||
 | 
			
		||||
const CLOUDFRONT_URL   = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
 | 
			
		||||
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
 | 
			
		||||
@@ -119,10 +119,7 @@ const internalIpRanges = {
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	generateConfig: (ip_ranges) => {
 | 
			
		||||
		let renderEngine = new Liquid({
 | 
			
		||||
			root: __dirname + '/../templates/'
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		const renderEngine = utils.getRenderEngine();
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			let template = null;
 | 
			
		||||
			let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ const fs         = require('fs');
 | 
			
		||||
const logger     = require('../logger').nginx;
 | 
			
		||||
const utils      = require('../lib/utils');
 | 
			
		||||
const error      = require('../lib/error');
 | 
			
		||||
const { Liquid } = require('liquidjs');
 | 
			
		||||
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
 | 
			
		||||
 | 
			
		||||
const internalNginx = {
 | 
			
		||||
@@ -29,7 +28,9 @@ const internalNginx = {
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				// Nginx is OK
 | 
			
		||||
				// We're deleting this config regardless.
 | 
			
		||||
				return internalNginx.deleteConfig(host_type, host); // Don't throw errors, as the file may not exist at all
 | 
			
		||||
				// Don't throw errors, as the file may not exist at all
 | 
			
		||||
				// Delete the .err file too
 | 
			
		||||
				return internalNginx.deleteConfig(host_type, host, false, true);
 | 
			
		||||
			})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				return internalNginx.generateConfig(host_type, host);
 | 
			
		||||
@@ -80,6 +81,9 @@ const internalNginx = {
 | 
			
		||||
							.patch({
 | 
			
		||||
								meta: combined_meta
 | 
			
		||||
							})
 | 
			
		||||
							.then(() => {
 | 
			
		||||
								internalNginx.renameConfigAsError(host_type, host);
 | 
			
		||||
							})
 | 
			
		||||
							.then(() => {
 | 
			
		||||
								return internalNginx.deleteConfig(host_type, host, true);
 | 
			
		||||
							});
 | 
			
		||||
@@ -121,13 +125,10 @@ const internalNginx = {
 | 
			
		||||
	 * @returns {String}
 | 
			
		||||
	 */
 | 
			
		||||
	getConfigName: (host_type, host_id) => {
 | 
			
		||||
		host_type = host_type.replace(new RegExp('-', 'g'), '_');
 | 
			
		||||
 | 
			
		||||
		if (host_type === 'default') {
 | 
			
		||||
			return '/data/nginx/default_host/site.conf';
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return '/data/nginx/' + host_type + '/' + host_id + '.conf';
 | 
			
		||||
		return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf';
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -136,8 +137,6 @@ const internalNginx = {
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	renderLocations: (host) => {
 | 
			
		||||
 | 
			
		||||
		//logger.info('host = ' + JSON.stringify(host, null, 2));
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			let template;
 | 
			
		||||
 | 
			
		||||
@@ -148,9 +147,7 @@ const internalNginx = {
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			let renderer          = new Liquid({
 | 
			
		||||
				root: __dirname + '/../templates/'
 | 
			
		||||
			});
 | 
			
		||||
			const renderEngine    = utils.getRenderEngine();
 | 
			
		||||
			let renderedLocations = '';
 | 
			
		||||
 | 
			
		||||
			const locationRendering = async () => {
 | 
			
		||||
@@ -168,10 +165,8 @@ const internalNginx = {
 | 
			
		||||
						locationCopy.forward_path = `/${splitted.join('/')}`;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					//logger.info('locationCopy = ' + JSON.stringify(locationCopy, null, 2));
 | 
			
		||||
 | 
			
		||||
					// eslint-disable-next-line
 | 
			
		||||
					renderedLocations += await renderer.parseAndRender(template, locationCopy);
 | 
			
		||||
					renderedLocations += await renderEngine.parseAndRender(template, locationCopy);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			};
 | 
			
		||||
@@ -187,24 +182,20 @@ const internalNginx = {
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	generateConfig: (host_type, host) => {
 | 
			
		||||
		host_type = host_type.replace(new RegExp('-', 'g'), '_');
 | 
			
		||||
		const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
 | 
			
		||||
 | 
			
		||||
		if (debug_mode) {
 | 
			
		||||
			logger.info('Generating ' + host_type + ' Config:', host);
 | 
			
		||||
			logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// logger.info('host = ' + JSON.stringify(host, null, 2));
 | 
			
		||||
 | 
			
		||||
		let renderEngine = new Liquid({
 | 
			
		||||
			root: __dirname + '/../templates/'
 | 
			
		||||
		});
 | 
			
		||||
		const renderEngine = utils.getRenderEngine();
 | 
			
		||||
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			let template = null;
 | 
			
		||||
			let filename = internalNginx.getConfigName(host_type, host.id);
 | 
			
		||||
			let filename = internalNginx.getConfigName(nice_host_type, host.id);
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'});
 | 
			
		||||
				template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', {encoding: 'utf8'});
 | 
			
		||||
			} catch (err) {
 | 
			
		||||
				reject(new error.ConfigurationError(err.message));
 | 
			
		||||
				return;
 | 
			
		||||
@@ -214,7 +205,7 @@ const internalNginx = {
 | 
			
		||||
			let origLocations;
 | 
			
		||||
 | 
			
		||||
			// Manipulate the data a bit before sending it to the template
 | 
			
		||||
			if (host_type !== 'default') {
 | 
			
		||||
			if (nice_host_type !== 'default') {
 | 
			
		||||
				host.use_default_location = true;
 | 
			
		||||
				if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
 | 
			
		||||
					host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
 | 
			
		||||
@@ -281,9 +272,7 @@ const internalNginx = {
 | 
			
		||||
			logger.info('Generating LetsEncrypt Request Config:', certificate);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let renderEngine = new Liquid({
 | 
			
		||||
			root: __dirname + '/../templates/'
 | 
			
		||||
		});
 | 
			
		||||
		const renderEngine = utils.getRenderEngine();
 | 
			
		||||
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			let template = null;
 | 
			
		||||
@@ -319,33 +308,39 @@ const internalNginx = {
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * A simple wrapper around unlinkSync that writes to the logger
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param   {String}  filename
 | 
			
		||||
	 */
 | 
			
		||||
	deleteFile: (filename) => {
 | 
			
		||||
		logger.debug('Deleting file: ' + filename);
 | 
			
		||||
		try {
 | 
			
		||||
			fs.unlinkSync(filename);
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			logger.debug('Could not delete file:', JSON.stringify(err, null, 2));
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param   {String} host_type
 | 
			
		||||
	 * @returns String
 | 
			
		||||
	 */
 | 
			
		||||
	getFileFriendlyHostType: (host_type) => {
 | 
			
		||||
		return host_type.replace(new RegExp('-', 'g'), '_');
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param   {Object}  certificate
 | 
			
		||||
	 * @param   {Boolean} [throw_errors]
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	deleteLetsEncryptRequestConfig: (certificate, throw_errors) => {
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			try {
 | 
			
		||||
				let config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
 | 
			
		||||
 | 
			
		||||
				if (debug_mode) {
 | 
			
		||||
					logger.warn('Deleting nginx config: ' + config_file);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				fs.unlinkSync(config_file);
 | 
			
		||||
			} catch (err) {
 | 
			
		||||
				if (debug_mode) {
 | 
			
		||||
					logger.warn('Could not delete config:', err.message);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (throw_errors) {
 | 
			
		||||
					reject(err);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
	deleteLetsEncryptRequestConfig: (certificate) => {
 | 
			
		||||
		const config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
 | 
			
		||||
		return new Promise((resolve/*, reject*/) => {
 | 
			
		||||
			internalNginx.deleteFile(config_file);
 | 
			
		||||
			resolve();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
@@ -353,35 +348,42 @@ const internalNginx = {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param   {String}  host_type
 | 
			
		||||
	 * @param   {Object}  [host]
 | 
			
		||||
	 * @param   {Boolean} [throw_errors]
 | 
			
		||||
	 * @param   {Boolean} [delete_err_file]
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	deleteConfig: (host_type, host, throw_errors) => {
 | 
			
		||||
		host_type = host_type.replace(new RegExp('-', 'g'), '_');
 | 
			
		||||
	deleteConfig: (host_type, host, delete_err_file) => {
 | 
			
		||||
		const config_file     = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
 | 
			
		||||
		const config_file_err = config_file + '.err';
 | 
			
		||||
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			try {
 | 
			
		||||
				let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id);
 | 
			
		||||
 | 
			
		||||
				if (debug_mode) {
 | 
			
		||||
					logger.warn('Deleting nginx config: ' + config_file);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				fs.unlinkSync(config_file);
 | 
			
		||||
			} catch (err) {
 | 
			
		||||
				if (debug_mode) {
 | 
			
		||||
					logger.warn('Could not delete config:', err.message);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (throw_errors) {
 | 
			
		||||
					reject(err);
 | 
			
		||||
				}
 | 
			
		||||
		return new Promise((resolve/*, reject*/) => {
 | 
			
		||||
			internalNginx.deleteFile(config_file);
 | 
			
		||||
			if (delete_err_file) {
 | 
			
		||||
				internalNginx.deleteFile(config_file_err);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			resolve();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param   {String}  host_type
 | 
			
		||||
	 * @param   {Object}  [host]
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	renameConfigAsError: (host_type, host) => {
 | 
			
		||||
		const config_file     = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
 | 
			
		||||
		const config_file_err = config_file + '.err';
 | 
			
		||||
 | 
			
		||||
		return new Promise((resolve/*, reject*/) => {
 | 
			
		||||
			fs.unlink(config_file, () => {
 | 
			
		||||
				// ignore result, continue
 | 
			
		||||
				fs.rename(config_file, config_file_err, () => {
 | 
			
		||||
					// also ignore result, as this is a debugging informative file anyway
 | 
			
		||||
					resolve();
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param   {String}  host_type
 | 
			
		||||
	 * @param   {Array}   hosts
 | 
			
		||||
@@ -399,13 +401,12 @@ const internalNginx = {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param   {String}  host_type
 | 
			
		||||
	 * @param   {Array}   hosts
 | 
			
		||||
	 * @param   {Boolean} [throw_errors]
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	bulkDeleteConfigs: (host_type, hosts, throw_errors) => {
 | 
			
		||||
	bulkDeleteConfigs: (host_type, hosts) => {
 | 
			
		||||
		let promises = [];
 | 
			
		||||
		hosts.map(function (host) {
 | 
			
		||||
			promises.push(internalNginx.deleteConfig(host_type, host, throw_errors));
 | 
			
		||||
			promises.push(internalNginx.deleteConfig(host_type, host, true));
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return Promise.all(promises);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
const _                   = require('lodash');
 | 
			
		||||
const error               = require('../lib/error');
 | 
			
		||||
const utils               = require('../lib/utils');
 | 
			
		||||
const proxyHostModel      = require('../models/proxy_host');
 | 
			
		||||
const internalHost        = require('./host');
 | 
			
		||||
const internalNginx       = require('./nginx');
 | 
			
		||||
@@ -49,8 +50,8 @@ const internalProxyHost = {
 | 
			
		||||
 | 
			
		||||
				return proxyHostModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (create_certificate) {
 | 
			
		||||
@@ -170,6 +171,7 @@ const internalProxyHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where({id: data.id})
 | 
			
		||||
					.patch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()))
 | 
			
		||||
					.then((saved_row) => {
 | 
			
		||||
						// Add to audit log
 | 
			
		||||
						return internalAuditLog.add(access, {
 | 
			
		||||
@@ -179,7 +181,7 @@ const internalProxyHost = {
 | 
			
		||||
							meta:        data
 | 
			
		||||
						})
 | 
			
		||||
							.then(() => {
 | 
			
		||||
								return _.omit(saved_row, omissions());
 | 
			
		||||
								return saved_row;
 | 
			
		||||
							});
 | 
			
		||||
					});
 | 
			
		||||
			})
 | 
			
		||||
@@ -223,31 +225,29 @@ const internalProxyHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[owner,access_list,access_list.[clients,items],certificate]')
 | 
			
		||||
					.allowGraph('[owner,access_list,access_list.[clients,items],certificate]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					row = internalHost.cleanRowCertificateMeta(row);
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				row = internalHost.cleanRowCertificateMeta(row);
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -409,8 +409,7 @@ const internalProxyHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[owner,access_list,certificate]')
 | 
			
		||||
					.allowGraph('[owner,access_list,certificate]')
 | 
			
		||||
					.orderBy('domain_names', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -425,10 +424,10 @@ const internalProxyHost = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((rows) => {
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
const _                    = require('lodash');
 | 
			
		||||
const error                = require('../lib/error');
 | 
			
		||||
const utils                = require('../lib/utils');
 | 
			
		||||
const redirectionHostModel = require('../models/redirection_host');
 | 
			
		||||
const internalHost         = require('./host');
 | 
			
		||||
const internalNginx        = require('./nginx');
 | 
			
		||||
@@ -49,8 +50,8 @@ const internalRedirectionHost = {
 | 
			
		||||
 | 
			
		||||
				return redirectionHostModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (create_certificate) {
 | 
			
		||||
@@ -65,9 +66,8 @@ const internalRedirectionHost = {
 | 
			
		||||
						.then(() => {
 | 
			
		||||
							return row;
 | 
			
		||||
						});
 | 
			
		||||
				} else {
 | 
			
		||||
					return row;
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				// re-fetch with cert
 | 
			
		||||
@@ -218,31 +218,29 @@ const internalRedirectionHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[owner,certificate]')
 | 
			
		||||
					.allowGraph('[owner,certificate]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					row = internalHost.cleanRowCertificateMeta(row);
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				row = internalHost.cleanRowCertificateMeta(row);
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -404,8 +402,7 @@ const internalRedirectionHost = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[owner,certificate]')
 | 
			
		||||
					.allowGraph('[owner,certificate]')
 | 
			
		||||
					.orderBy('domain_names', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -420,10 +417,10 @@ const internalRedirectionHost = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((rows) => {
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
const _                = require('lodash');
 | 
			
		||||
const error            = require('../lib/error');
 | 
			
		||||
const utils            = require('../lib/utils');
 | 
			
		||||
const streamModel      = require('../models/stream');
 | 
			
		||||
const internalNginx    = require('./nginx');
 | 
			
		||||
const internalAuditLog = require('./audit-log');
 | 
			
		||||
@@ -27,8 +28,8 @@ const internalStream = {
 | 
			
		||||
 | 
			
		||||
				return streamModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				// Configure nginx
 | 
			
		||||
@@ -71,8 +72,8 @@ const internalStream = {
 | 
			
		||||
 | 
			
		||||
				return streamModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.patchAndFetchById(row.id, data)
 | 
			
		||||
					.then(utils.omitRow(omissions()))
 | 
			
		||||
					.then((saved_row) => {
 | 
			
		||||
						return internalNginx.configure(streamModel, 'stream', saved_row)
 | 
			
		||||
							.then(() => {
 | 
			
		||||
@@ -88,7 +89,7 @@ const internalStream = {
 | 
			
		||||
							meta:        data
 | 
			
		||||
						})
 | 
			
		||||
							.then(() => {
 | 
			
		||||
								return _.omit(saved_row, omissions());
 | 
			
		||||
								return saved_row;
 | 
			
		||||
							});
 | 
			
		||||
					});
 | 
			
		||||
			});
 | 
			
		||||
@@ -113,30 +114,28 @@ const internalStream = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[owner]')
 | 
			
		||||
					.allowGraph('[owner]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
					query.andWhere('owner_user_id', access.token.getUserId(1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -298,8 +297,7 @@ const internalStream = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[owner]')
 | 
			
		||||
					.allowGraph('[owner]')
 | 
			
		||||
					.orderBy('incoming_port', 'ASC');
 | 
			
		||||
 | 
			
		||||
				if (access_data.permission_visibility !== 'all') {
 | 
			
		||||
@@ -314,10 +312,10 @@ const internalStream = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
const _                   = require('lodash');
 | 
			
		||||
const error               = require('../lib/error');
 | 
			
		||||
const utils               = require('../lib/utils');
 | 
			
		||||
const userModel           = require('../models/user');
 | 
			
		||||
const userPermissionModel = require('../models/user_permission');
 | 
			
		||||
const authModel           = require('../models/auth');
 | 
			
		||||
@@ -35,8 +36,8 @@ const internalUser = {
 | 
			
		||||
 | 
			
		||||
				return userModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.insertAndFetch(data);
 | 
			
		||||
					.insertAndFetch(data)
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((user) => {
 | 
			
		||||
				if (auth) {
 | 
			
		||||
@@ -140,11 +141,8 @@ const internalUser = {
 | 
			
		||||
 | 
			
		||||
				return userModel
 | 
			
		||||
					.query()
 | 
			
		||||
					.omit(omissions())
 | 
			
		||||
					.patchAndFetchById(user.id, data)
 | 
			
		||||
					.then((saved_user) => {
 | 
			
		||||
						return _.omit(saved_user, omissions());
 | 
			
		||||
					});
 | 
			
		||||
					.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				return internalUser.get(access, {id: data.id});
 | 
			
		||||
@@ -186,26 +184,24 @@ const internalUser = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.andWhere('id', data.id)
 | 
			
		||||
					.allowEager('[permissions]')
 | 
			
		||||
					.allowGraph('[permissions]')
 | 
			
		||||
					.first();
 | 
			
		||||
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					query.omit(data.omit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof data.expand !== 'undefined' && data.expand !== null) {
 | 
			
		||||
					query.eager('[' + data.expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + data.expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRow(omissions()));
 | 
			
		||||
			})
 | 
			
		||||
			.then((row) => {
 | 
			
		||||
				if (row) {
 | 
			
		||||
					return _.omit(row, omissions());
 | 
			
		||||
				} else {
 | 
			
		||||
				if (!row) {
 | 
			
		||||
					throw new error.ItemNotFoundError(data.id);
 | 
			
		||||
				}
 | 
			
		||||
				// Custom omissions
 | 
			
		||||
				if (typeof data.omit !== 'undefined' && data.omit !== null) {
 | 
			
		||||
					row = _.omit(row, data.omit);
 | 
			
		||||
				}
 | 
			
		||||
				return row;
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -322,8 +318,7 @@ const internalUser = {
 | 
			
		||||
					.query()
 | 
			
		||||
					.where('is_deleted', 0)
 | 
			
		||||
					.groupBy('id')
 | 
			
		||||
					.omit(['is_deleted'])
 | 
			
		||||
					.allowEager('[permissions]')
 | 
			
		||||
					.allowGraph('[permissions]')
 | 
			
		||||
					.orderBy('name', 'ASC');
 | 
			
		||||
 | 
			
		||||
				// Query is used for searching
 | 
			
		||||
@@ -335,10 +330,10 @@ const internalUser = {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (typeof expand !== 'undefined' && expand !== null) {
 | 
			
		||||
					query.eager('[' + expand.join(', ') + ']');
 | 
			
		||||
					query.withGraphFetched('[' + expand.join(', ') + ']');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return query;
 | 
			
		||||
				return query.then(utils.omitRows(omissions()));
 | 
			
		||||
			});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,8 +55,8 @@ module.exports = function (token_string) {
 | 
			
		||||
								.where('id', token_data.attrs.id)
 | 
			
		||||
								.andWhere('is_deleted', 0)
 | 
			
		||||
								.andWhere('is_disabled', 0)
 | 
			
		||||
								.allowEager('[permissions]')
 | 
			
		||||
								.eager('[permissions]')
 | 
			
		||||
								.allowGraph('[permissions]')
 | 
			
		||||
								.withGraphFetched('[permissions]')
 | 
			
		||||
								.first()
 | 
			
		||||
								.then((user) => {
 | 
			
		||||
									if (user) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
const exec     = require('child_process').exec;
 | 
			
		||||
const execFile = require('child_process').execFile;
 | 
			
		||||
const _          = require('lodash');
 | 
			
		||||
const exec       = require('child_process').exec;
 | 
			
		||||
const execFile   = require('child_process').execFile;
 | 
			
		||||
const { Liquid } = require('liquidjs');
 | 
			
		||||
const logger     = require('../logger').global;
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
 | 
			
		||||
@@ -20,12 +23,14 @@ module.exports = {
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param   {Array} cmd
 | 
			
		||||
	 * @param   {String} cmd
 | 
			
		||||
	 * @param   {Array}  args
 | 
			
		||||
	 * @returns {Promise}
 | 
			
		||||
	 */
 | 
			
		||||
	execFile: function (cmd) {
 | 
			
		||||
	execFile: function (cmd, args) {
 | 
			
		||||
		logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			execFile(cmd, function (err, stdout, /*stderr*/) {
 | 
			
		||||
			execFile(cmd, args, function (err, stdout, /*stderr*/) {
 | 
			
		||||
				if (err && typeof err === 'object') {
 | 
			
		||||
					reject(err);
 | 
			
		||||
				} else {
 | 
			
		||||
@@ -33,5 +38,64 @@ module.exports = {
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Used in objection query builder
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param   {Array}  omissions
 | 
			
		||||
	 * @returns {Function}
 | 
			
		||||
	 */
 | 
			
		||||
	omitRow: function (omissions) {
 | 
			
		||||
		/**
 | 
			
		||||
		 * @param   {Object} row
 | 
			
		||||
		 * @returns {Object}
 | 
			
		||||
		 */
 | 
			
		||||
		return (row) => {
 | 
			
		||||
			return _.omit(row, omissions);
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Used in objection query builder
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param   {Array}  omissions
 | 
			
		||||
	 * @returns {Function}
 | 
			
		||||
	 */
 | 
			
		||||
	omitRows: function (omissions) {
 | 
			
		||||
		/**
 | 
			
		||||
		 * @param   {Array} rows
 | 
			
		||||
		 * @returns {Object}
 | 
			
		||||
		 */
 | 
			
		||||
		return (rows) => {
 | 
			
		||||
			rows.forEach((row, idx) => {
 | 
			
		||||
				rows[idx] = _.omit(row, omissions);
 | 
			
		||||
			});
 | 
			
		||||
			return rows;
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @returns {Object} Liquid render engine
 | 
			
		||||
	 */
 | 
			
		||||
	getRenderEngine: function () {
 | 
			
		||||
		const renderEngine = new Liquid({
 | 
			
		||||
			root: __dirname + '/../templates/'
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * nginxAccessRule expects the object given to have 2 properties:
 | 
			
		||||
		 *
 | 
			
		||||
		 * directive  string
 | 
			
		||||
		 * address    string
 | 
			
		||||
		 */
 | 
			
		||||
		renderEngine.registerFilter('nginxAccessRule', (v) => {
 | 
			
		||||
			if (typeof v.directive !== 'undefined' && typeof v.address !== 'undefined' && v.directive && v.address) {
 | 
			
		||||
				return `${v.directive} ${v.address};`;
 | 
			
		||||
			}
 | 
			
		||||
			return '';
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return renderEngine;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,6 @@ class AccessList extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			items: {
 | 
			
		||||
@@ -59,9 +58,6 @@ class AccessList extends Model {
 | 
			
		||||
				join:       {
 | 
			
		||||
					from: 'access_list.id',
 | 
			
		||||
					to:   'access_list_auth.access_list_id'
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			clients: {
 | 
			
		||||
@@ -70,9 +66,6 @@ class AccessList extends Model {
 | 
			
		||||
				join:       {
 | 
			
		||||
					from: 'access_list.id',
 | 
			
		||||
					to:   'access_list_client.access_list_id'
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			proxy_hosts: {
 | 
			
		||||
@@ -84,19 +77,10 @@ class AccessList extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('proxy_host.is_deleted', 0);
 | 
			
		||||
					qb.omit(['is_deleted', 'meta']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get satisfy() {
 | 
			
		||||
		return this.satisfy_any ? 'satisfy any' : 'satisfy all';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get passauth() {
 | 
			
		||||
		return this.pass_auth ? '' : 'proxy_set_header Authorization "";';
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = AccessList;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,6 @@ class AccessListAuth extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('access_list.is_deleted', 0);
 | 
			
		||||
					qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -45,15 +45,10 @@ class AccessListClient extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('access_list.is_deleted', 0);
 | 
			
		||||
					qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get rule() {
 | 
			
		||||
		return `${this.directive} ${this.address}`;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = AccessListClient;
 | 
			
		||||
 
 | 
			
		||||
@@ -43,9 +43,6 @@ class AuditLog extends Model {
 | 
			
		||||
				join:       {
 | 
			
		||||
					from: 'audit_log.user_id',
 | 
			
		||||
					to:   'user.id'
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -74,9 +74,6 @@ class Auth extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				filter: {
 | 
			
		||||
					is_deleted: 0
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.omit(['is_deleted']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,6 @@ class Certificate extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,6 @@ class DeadHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			certificate: {
 | 
			
		||||
@@ -71,7 +70,6 @@ class DeadHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('certificate.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@ Model.knex(db);
 | 
			
		||||
 | 
			
		||||
module.exports = function () {
 | 
			
		||||
	if (config.database.knex && config.database.knex.client === 'sqlite3') {
 | 
			
		||||
		return Model.raw('datetime(\'now\',\'localtime\')');
 | 
			
		||||
	} else {
 | 
			
		||||
		return Model.raw('NOW()');
 | 
			
		||||
		// eslint-disable-next-line
 | 
			
		||||
		return Model.raw("datetime('now','localtime')");
 | 
			
		||||
	}
 | 
			
		||||
	return Model.raw('NOW()');
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,6 @@ class ProxyHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			access_list: {
 | 
			
		||||
@@ -72,7 +71,6 @@ class ProxyHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('access_list.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			certificate: {
 | 
			
		||||
@@ -84,7 +82,6 @@ class ProxyHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('certificate.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
 | 
			
		||||
// Objection Docs:
 | 
			
		||||
// http://vincit.github.io/objection.js/
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +60,6 @@ class RedirectionHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			certificate: {
 | 
			
		||||
@@ -71,7 +71,6 @@ class RedirectionHost extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('certificate.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,6 @@ class Stream extends Model {
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.where('user.is_deleted', 0);
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -83,8 +83,6 @@ module.exports = function () {
 | 
			
		||||
								// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
 | 
			
		||||
								// For 30 days at least, we need to replace 'all' with user.
 | 
			
		||||
								if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
 | 
			
		||||
									//console.log('Warning! Replacing "all" scope with "user"');
 | 
			
		||||
 | 
			
		||||
									token_data.scope = ['user'];
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,9 +43,6 @@ class User extends Model {
 | 
			
		||||
				join:       {
 | 
			
		||||
					from: 'user.id',
 | 
			
		||||
					to:   'user_permission.user_id'
 | 
			
		||||
				},
 | 
			
		||||
				modify: function (qb) {
 | 
			
		||||
					qb.omit(['id', 'created_on', 'modified_on', 'user_id']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -16,17 +16,17 @@
 | 
			
		||||
		"gravatar": "^1.8.0",
 | 
			
		||||
		"json-schema-ref-parser": "^8.0.0",
 | 
			
		||||
		"jsonwebtoken": "^9.0.0",
 | 
			
		||||
		"knex": "^2.4.0",
 | 
			
		||||
		"liquidjs": "^10.0.0",
 | 
			
		||||
		"knex": "2.4.2",
 | 
			
		||||
		"liquidjs": "10.6.1",
 | 
			
		||||
		"lodash": "^4.17.21",
 | 
			
		||||
		"moment": "^2.29.4",
 | 
			
		||||
		"mysql": "^2.18.1",
 | 
			
		||||
		"node-rsa": "^1.0.8",
 | 
			
		||||
		"nodemon": "^2.0.2",
 | 
			
		||||
		"objection": "^2.2.16",
 | 
			
		||||
		"objection": "3.0.1",
 | 
			
		||||
		"path": "^0.12.7",
 | 
			
		||||
		"signale": "^1.4.0",
 | 
			
		||||
		"sqlite3": "^4.1.1",
 | 
			
		||||
		"signale": "1.4.0",
 | 
			
		||||
		"sqlite3": "5.1.6",
 | 
			
		||||
		"temp-write": "^4.0.0"
 | 
			
		||||
	},
 | 
			
		||||
	"signale": {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								backend/templates/_access.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								backend/templates/_access.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
{% if access_list_id > 0 %}
 | 
			
		||||
    {% if access_list.items.length > 0 %}
 | 
			
		||||
    # Authorization
 | 
			
		||||
    auth_basic            "Authorization required";
 | 
			
		||||
    auth_basic_user_file  /data/access/{{ access_list_id }};
 | 
			
		||||
 | 
			
		||||
    {% if access_list.pass_auth == 0 %}
 | 
			
		||||
    proxy_set_header Authorization "";
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    # Access Rules: {{ access_list.clients | size }} total
 | 
			
		||||
    {% for client in access_list.clients %}
 | 
			
		||||
    {{client | nginxAccessRule}}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    deny all;
 | 
			
		||||
 | 
			
		||||
    # Access checks must...
 | 
			
		||||
    {% if access_list.satisfy_any == 1 %}
 | 
			
		||||
    satisfy any;
 | 
			
		||||
    {% else %}
 | 
			
		||||
    satisfy all;
 | 
			
		||||
    {% endif %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
@@ -6,30 +6,9 @@
 | 
			
		||||
    proxy_set_header X-Real-IP		$remote_addr;
 | 
			
		||||
    proxy_pass       {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
 | 
			
		||||
 | 
			
		||||
    {% if access_list_id > 0 %}
 | 
			
		||||
    {% if access_list.items.length > 0 %}
 | 
			
		||||
    # Authorization
 | 
			
		||||
    auth_basic            "Authorization required";
 | 
			
		||||
    auth_basic_user_file  /data/access/{{ access_list_id }};
 | 
			
		||||
 
 | 
			
		||||
    {{ access_list.passauth }}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 
 | 
			
		||||
    # Access Rules
 | 
			
		||||
    {% for client in access_list.clients %}
 | 
			
		||||
    {{- client.rule -}};
 | 
			
		||||
    {% endfor %}deny all;
 | 
			
		||||
 
 | 
			
		||||
    # Access checks must...
 | 
			
		||||
    {% if access_list.satisfy %}
 | 
			
		||||
    {{ access_list.satisfy }};
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% include "_access.conf" %}
 | 
			
		||||
    {% include "_assets.conf" %}
 | 
			
		||||
    {% include "_exploits.conf" %}
 | 
			
		||||
 | 
			
		||||
    {% include "_forced_ssl.conf" %}
 | 
			
		||||
    {% include "_hsts.conf" %}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,27 +30,7 @@ proxy_http_version 1.1;
 | 
			
		||||
 | 
			
		||||
  location / {
 | 
			
		||||
 | 
			
		||||
    {% if access_list_id > 0 %}
 | 
			
		||||
    {% if access_list.items.length > 0 %}
 | 
			
		||||
    # Authorization
 | 
			
		||||
    auth_basic            "Authorization required";
 | 
			
		||||
    auth_basic_user_file  /data/access/{{ access_list_id }};
 | 
			
		||||
 | 
			
		||||
    {{ access_list.passauth }}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    # Access Rules
 | 
			
		||||
    {% for client in access_list.clients %}
 | 
			
		||||
    {{- client.rule -}};
 | 
			
		||||
    {% endfor %}deny all;
 | 
			
		||||
 | 
			
		||||
    # Access checks must...
 | 
			
		||||
    {% if access_list.satisfy %}
 | 
			
		||||
    {{ access_list.satisfy }};
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
{% include "_access.conf" %}
 | 
			
		||||
{% include "_hsts.conf" %}
 | 
			
		||||
 | 
			
		||||
    {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -25,7 +25,7 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
 | 
			
		||||
	&& rm -rf /var/lib/apt/lists/*
 | 
			
		||||
 | 
			
		||||
# s6 overlay
 | 
			
		||||
COPY scripts/install-s6 /tmp/install-s6
 | 
			
		||||
COPY docker/scripts/install-s6 /tmp/install-s6
 | 
			
		||||
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
 | 
			
		||||
 | 
			
		||||
EXPOSE 80 81 443
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ ENV S6_LOGGING=0 \
 | 
			
		||||
 | 
			
		||||
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
 | 
			
		||||
	&& apt-get update \
 | 
			
		||||
	&& apt-get install -y certbot jq python3-pip logrotate \
 | 
			
		||||
	&& apt-get install -y jq python3-pip logrotate \
 | 
			
		||||
	&& apt-get clean \
 | 
			
		||||
	&& rm -rf /var/lib/apt/lists/*
 | 
			
		||||
 | 
			
		||||
@@ -21,9 +21,8 @@ RUN rm -f /etc/nginx/conf.d/production.conf
 | 
			
		||||
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
 | 
			
		||||
 | 
			
		||||
# s6 overlay
 | 
			
		||||
RUN curl -L -o /tmp/s6-overlay-amd64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz" \
 | 
			
		||||
	&& tar -xzf /tmp/s6-overlay-amd64.tar.gz -C /
 | 
			
		||||
COPY scripts/install-s6 /tmp/install-s6
 | 
			
		||||
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
 | 
			
		||||
 | 
			
		||||
EXPOSE 80 81 443
 | 
			
		||||
ENTRYPOINT [ "/init" ]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
#!/usr/bin/with-contenv bash
 | 
			
		||||
#!/command/with-contenv bash
 | 
			
		||||
# shellcheck shell=bash
 | 
			
		||||
 | 
			
		||||
mkdir -p /data/letsencrypt-acme-challenge
 | 
			
		||||
 | 
			
		||||
cd /app || echo
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
echo "❯ Starting backend ..."
 | 
			
		||||
if [ "$DEVELOPMENT" == "true" ]; then
 | 
			
		||||
	cd /app || exit 1
 | 
			
		||||
	# If yarn install fails: add --verbose --network-concurrency 1
 | 
			
		||||
							
								
								
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/backend/type
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/backend/type
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
longrun
 | 
			
		||||
@@ -1,4 +1,7 @@
 | 
			
		||||
#!/usr/bin/with-contenv bash
 | 
			
		||||
#!/command/with-contenv bash
 | 
			
		||||
# shellcheck shell=bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
# This service is DEVELOPMENT only.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/type
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/type
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
longrun
 | 
			
		||||
							
								
								
									
										7
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#!/command/with-contenv bash
 | 
			
		||||
# shellcheck shell=bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
echo "❯ Starting nginx ..."
 | 
			
		||||
exec nginx
 | 
			
		||||
							
								
								
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/type
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/type
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
longrun
 | 
			
		||||
							
								
								
									
										63
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/script.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										63
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/script.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
#!/command/with-contenv bash
 | 
			
		||||
# shellcheck shell=bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
DATA_PATH=/data
 | 
			
		||||
 | 
			
		||||
# Ensure /data is mounted
 | 
			
		||||
if [ ! -d "$DATA_PATH" ]; then
 | 
			
		||||
	echo '--------------------------------------'
 | 
			
		||||
	echo "ERROR: $DATA_PATH is not mounted! Check your docker configuration."
 | 
			
		||||
	echo '--------------------------------------'
 | 
			
		||||
	/run/s6/basedir/bin/halt
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "❯ Checking folder structure ..."
 | 
			
		||||
 | 
			
		||||
# Create required folders
 | 
			
		||||
mkdir -p /tmp/nginx/body \
 | 
			
		||||
	/run/nginx \
 | 
			
		||||
	/var/log/nginx \
 | 
			
		||||
	/data/nginx \
 | 
			
		||||
	/data/custom_ssl \
 | 
			
		||||
	/data/logs \
 | 
			
		||||
	/data/access \
 | 
			
		||||
	/data/nginx/default_host \
 | 
			
		||||
	/data/nginx/default_www \
 | 
			
		||||
	/data/nginx/proxy_host \
 | 
			
		||||
	/data/nginx/redirection_host \
 | 
			
		||||
	/data/nginx/stream \
 | 
			
		||||
	/data/nginx/dead_host \
 | 
			
		||||
	/data/nginx/temp \
 | 
			
		||||
	/var/lib/nginx/cache/public \
 | 
			
		||||
	/var/lib/nginx/cache/private \
 | 
			
		||||
	/var/cache/nginx/proxy_temp \
 | 
			
		||||
	/data/letsencrypt-acme-challenge
 | 
			
		||||
 | 
			
		||||
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
 | 
			
		||||
chown root /tmp/nginx
 | 
			
		||||
 | 
			
		||||
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
 | 
			
		||||
# thanks @tfmm
 | 
			
		||||
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ];
 | 
			
		||||
then
 | 
			
		||||
	echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
 | 
			
		||||
else
 | 
			
		||||
	echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Handle IPV6 settings
 | 
			
		||||
/bin/handle-ipv6-setting /etc/nginx/conf.d
 | 
			
		||||
/bin/handle-ipv6-setting /data/nginx
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "-------------------------------------
 | 
			
		||||
 _   _ ____  __  __
 | 
			
		||||
| \ | |  _ \|  \/  |
 | 
			
		||||
|  \| | |_) | |\/| |
 | 
			
		||||
| |\  |  __/| |  | |
 | 
			
		||||
|_| \_|_|   |_|  |_|
 | 
			
		||||
-------------------------------------
 | 
			
		||||
"
 | 
			
		||||
							
								
								
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/type
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/type
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
oneshot
 | 
			
		||||
							
								
								
									
										2
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/up
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/up
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
# shellcheck shell=bash
 | 
			
		||||
/etc/s6-overlay/s6-rc.d/prepare/script.sh
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
#!/usr/bin/execlineb -S1
 | 
			
		||||
if { s6-test ${1} -ne 0 }
 | 
			
		||||
if { s6-test ${1} -ne 256 }
 | 
			
		||||
 | 
			
		||||
s6-svscanctl -t /var/run/s6/services
 | 
			
		||||
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
#!/usr/bin/with-contenv bash
 | 
			
		||||
 | 
			
		||||
s6-svscanctl -t /var/run/s6/services
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
/bin/true
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
#!/usr/bin/with-contenv bash
 | 
			
		||||
 | 
			
		||||
# Create required folders
 | 
			
		||||
mkdir -p /tmp/nginx/body \
 | 
			
		||||
	/run/nginx \
 | 
			
		||||
	/var/log/nginx \
 | 
			
		||||
	/data/nginx \
 | 
			
		||||
	/data/custom_ssl \
 | 
			
		||||
	/data/logs \
 | 
			
		||||
	/data/access \
 | 
			
		||||
	/data/nginx/default_host \
 | 
			
		||||
	/data/nginx/default_www \
 | 
			
		||||
	/data/nginx/proxy_host \
 | 
			
		||||
	/data/nginx/redirection_host \
 | 
			
		||||
	/data/nginx/stream \
 | 
			
		||||
	/data/nginx/dead_host \
 | 
			
		||||
	/data/nginx/temp \
 | 
			
		||||
	/var/lib/nginx/cache/public \
 | 
			
		||||
	/var/lib/nginx/cache/private \
 | 
			
		||||
	/var/cache/nginx/proxy_temp
 | 
			
		||||
 | 
			
		||||
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
 | 
			
		||||
chown root /tmp/nginx
 | 
			
		||||
 | 
			
		||||
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
 | 
			
		||||
# thanks @tfmm
 | 
			
		||||
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ];
 | 
			
		||||
then
 | 
			
		||||
  echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
 | 
			
		||||
else
 | 
			
		||||
  echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Handle IPV6 settings
 | 
			
		||||
/bin/handle-ipv6-setting /etc/nginx/conf.d
 | 
			
		||||
/bin/handle-ipv6-setting /data/nginx
 | 
			
		||||
 | 
			
		||||
exec nginx
 | 
			
		||||
@@ -8,8 +8,8 @@ BLUE='\E[1;34m'
 | 
			
		||||
GREEN='\E[1;32m'
 | 
			
		||||
RESET='\E[0m'
 | 
			
		||||
 | 
			
		||||
S6_OVERLAY_VERSION=1.22.1.0
 | 
			
		||||
TARGETPLATFORM=$1
 | 
			
		||||
S6_OVERLAY_VERSION=3.1.4.1
 | 
			
		||||
TARGETPLATFORM=${1:unspecified}
 | 
			
		||||
 | 
			
		||||
# Determine the correct binary file for the architecture given
 | 
			
		||||
case $TARGETPLATFORM in
 | 
			
		||||
@@ -22,13 +22,17 @@ case $TARGETPLATFORM in
 | 
			
		||||
		;;
 | 
			
		||||
 | 
			
		||||
	*)
 | 
			
		||||
		S6_ARCH=amd64
 | 
			
		||||
		S6_ARCH=x86_64
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
echo -e "${BLUE}❯ ${CYAN}Installing S6-overlay v${S6_OVERLAY_VERSION} for ${YELLOW}${TARGETPLATFORM} (${S6_ARCH})${RESET}"
 | 
			
		||||
 | 
			
		||||
curl -L -o "/tmp/s6-overlay-${S6_ARCH}.tar.gz" "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.gz" \
 | 
			
		||||
	&& tar -xzf "/tmp/s6-overlay-${S6_ARCH}.tar.gz" -C /
 | 
			
		||||
curl -L -o '/tmp/s6-overlay-noarch.tar.xz' "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz"
 | 
			
		||||
curl -L -o "/tmp/s6-overlay-${S6_ARCH}.tar.xz" "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz"
 | 
			
		||||
tar -C / -Jxpf '/tmp/s6-overlay-noarch.tar.xz'
 | 
			
		||||
tar -C / -Jxpf "/tmp/s6-overlay-${S6_ARCH}.tar.xz"
 | 
			
		||||
 | 
			
		||||
rm -rf "/tmp/s6-overlay-${S6_ARCH}.tar.xz"
 | 
			
		||||
 | 
			
		||||
echo -e "${BLUE}❯ ${GREEN}S6-overlay install Complete${RESET}"
 | 
			
		||||
@@ -487,9 +487,9 @@ dns_powerdns_api_key = AbCbASsd!@34`,
 | 
			
		||||
		package_name:        'certbot-regru',
 | 
			
		||||
		version_requirement: '~=1.0.2',
 | 
			
		||||
		dependencies:        '',
 | 
			
		||||
		credentials:         `certbot_regru:dns_username=username
 | 
			
		||||
certbot_regru:dns_password=password`,
 | 
			
		||||
		full_plugin_name: 'certbot-regru:dns',
 | 
			
		||||
		credentials:         `dns_username=username
 | 
			
		||||
dns_password=password`,
 | 
			
		||||
		full_plugin_name: 'dns',
 | 
			
		||||
	},
 | 
			
		||||
	//####################################################//
 | 
			
		||||
	rfc2136: {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user