| 
							
							
							
						 |  |  | @@ -1,11 +1,11 @@ | 
		
	
		
			
				|  |  |  |  | const _                       = require('lodash'); | 
		
	
		
			
				|  |  |  |  | const fs                      = require('fs'); | 
		
	
		
			
				|  |  |  |  | const logger                  = require('../logger').nginx; | 
		
	
		
			
				|  |  |  |  | const utils                   = require('../lib/utils'); | 
		
	
		
			
				|  |  |  |  | const error                   = require('../lib/error'); | 
		
	
		
			
				|  |  |  |  | const { Liquid }              = require('liquidjs'); | 
		
	
		
			
				|  |  |  |  | const passthroughHostModel    = require('../models/ssl_passthrough_host'); | 
		
	
		
			
				|  |  |  |  | const debug_mode              = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG; | 
		
	
		
			
				|  |  |  |  | const _                    = require('lodash'); | 
		
	
		
			
				|  |  |  |  | const fs                   = require('fs'); | 
		
	
		
			
				|  |  |  |  | const logger               = require('../logger').nginx; | 
		
	
		
			
				|  |  |  |  | const utils                = require('../lib/utils'); | 
		
	
		
			
				|  |  |  |  | const error                = require('../lib/error'); | 
		
	
		
			
				|  |  |  |  | const { Liquid }           = require('liquidjs'); | 
		
	
		
			
				|  |  |  |  | const passthroughHostModel = require('../models/ssl_passthrough_host'); | 
		
	
		
			
				|  |  |  |  | const debug_mode           = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | const internalNginx = { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -24,7 +24,7 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 	 * @returns {Promise} | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	configure: (model, host_type, host) => { | 
		
	
		
			
				|  |  |  |  | 		let combined_meta = {}; | 
		
	
		
			
				|  |  |  |  | 		let combined_meta           = {}; | 
		
	
		
			
				|  |  |  |  | 		const sslPassthroughEnabled = internalNginx.sslPassthroughEnabled(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		return internalNginx.test() | 
		
	
	
		
			
				
					
					|  |  |  | @@ -34,7 +34,7 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 				return internalNginx.deleteConfig(host_type, host); // Don't throw errors, as the file may not exist at all | 
		
	
		
			
				|  |  |  |  | 			}) | 
		
	
		
			
				|  |  |  |  | 			.then(() => { | 
		
	
		
			
				|  |  |  |  | 				if(host_type === 'ssl_passthrough_host' && !sslPassthroughEnabled){ | 
		
	
		
			
				|  |  |  |  | 				if (host_type === 'ssl_passthrough_host' && !sslPassthroughEnabled){ | 
		
	
		
			
				|  |  |  |  | 					// ssl passthrough is disabled | 
		
	
		
			
				|  |  |  |  | 					const meta = { | 
		
	
		
			
				|  |  |  |  | 						nginx_online: false, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -64,7 +64,7 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 							nginx_err:    null | 
		
	
		
			
				|  |  |  |  | 						}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						if(host_type === 'ssl_passthrough_host'){ | 
		
	
		
			
				|  |  |  |  | 						if (host_type === 'ssl_passthrough_host'){ | 
		
	
		
			
				|  |  |  |  | 							// If passthrough is disabled we have already marked the hosts as offline | 
		
	
		
			
				|  |  |  |  | 							if (sslPassthroughEnabled) { | 
		
	
		
			
				|  |  |  |  | 								return passthroughHostModel | 
		
	
	
		
			
				
					
					|  |  |  | @@ -109,7 +109,7 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 							nginx_err:    valid_lines.join('\n') | 
		
	
		
			
				|  |  |  |  | 						}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						if(host_type === 'ssl_passthrough_host'){ | 
		
	
		
			
				|  |  |  |  | 						if (host_type === 'ssl_passthrough_host'){ | 
		
	
		
			
				|  |  |  |  | 							return passthroughHostModel | 
		
	
		
			
				|  |  |  |  | 								.query() | 
		
	
		
			
				|  |  |  |  | 								.where('is_deleted', 0) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -235,7 +235,7 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 	 * @param   {Object}  host | 
		
	
		
			
				|  |  |  |  | 	 * @returns {Promise} | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	generateConfig: (host_type, host) => { | 
		
	
		
			
				|  |  |  |  | 	generateConfig: async (host_type, host) => { | 
		
	
		
			
				|  |  |  |  | 		host_type = host_type.replace(new RegExp('-', 'g'), '_'); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (debug_mode) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -248,90 +248,87 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 			root: __dirname + '/../templates/' | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		return new Promise(async (resolve, reject) => { | 
		
	
		
			
				|  |  |  |  | 			let template = null; | 
		
	
		
			
				|  |  |  |  | 			let filename = internalNginx.getConfigName(host_type, host.id); | 
		
	
		
			
				|  |  |  |  | 		let template = null; | 
		
	
		
			
				|  |  |  |  | 		let filename = internalNginx.getConfigName(host_type, host.id); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			try { | 
		
	
		
			
				|  |  |  |  | 				template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'}); | 
		
	
		
			
				|  |  |  |  | 			} catch (err) { | 
		
	
		
			
				|  |  |  |  | 				reject(new error.ConfigurationError(err.message)); | 
		
	
		
			
				|  |  |  |  | 				return; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		try { | 
		
	
		
			
				|  |  |  |  | 			template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'}); | 
		
	
		
			
				|  |  |  |  | 		} catch (err) { | 
		
	
		
			
				|  |  |  |  | 			throw new error.ConfigurationError(err.message); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			let locationsPromise; | 
		
	
		
			
				|  |  |  |  | 			let origLocations; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			// Manipulate the data a bit before sending it to the template | 
		
	
		
			
				|  |  |  |  | 			if (host_type === 'ssl_passthrough_host') { | 
		
	
		
			
				|  |  |  |  | 				if(internalNginx.sslPassthroughEnabled()){ | 
		
	
		
			
				|  |  |  |  | 					const allHosts = await passthroughHostModel | 
		
	
		
			
				|  |  |  |  | 						.query() | 
		
	
		
			
				|  |  |  |  | 						.where('is_deleted', 0) | 
		
	
		
			
				|  |  |  |  | 						.groupBy('id') | 
		
	
		
			
				|  |  |  |  | 						.omit(['is_deleted']); | 
		
	
		
			
				|  |  |  |  | 					host = { | 
		
	
		
			
				|  |  |  |  | 						all_passthrough_hosts: allHosts.map((host) => { | 
		
	
		
			
				|  |  |  |  | 							// Replace dots in domain | 
		
	
		
			
				|  |  |  |  | 							host.forwarding_host = internalNginx.addIpv6Brackets(host.forwarding_host); | 
		
	
		
			
				|  |  |  |  | 							return host; | 
		
	
		
			
				|  |  |  |  | 						}), | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  | 				} else { | 
		
	
		
			
				|  |  |  |  | 					internalNginx.deleteConfig(host_type, host, false) | 
		
	
		
			
				|  |  |  |  | 				} | 
		
	
		
			
				|  |  |  |  | 				 | 
		
	
		
			
				|  |  |  |  | 			} else if (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); | 
		
	
		
			
				|  |  |  |  | 				} | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			if (host.locations) { | 
		
	
		
			
				|  |  |  |  | 				//logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2)); | 
		
	
		
			
				|  |  |  |  | 				origLocations    = [].concat(host.locations); | 
		
	
		
			
				|  |  |  |  | 				locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => { | 
		
	
		
			
				|  |  |  |  | 					host.locations = renderedLocations; | 
		
	
		
			
				|  |  |  |  | 				}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				// Allow someone who is using / custom location path to use it, and skip the default / location | 
		
	
		
			
				|  |  |  |  | 				_.map(host.locations, (location) => { | 
		
	
		
			
				|  |  |  |  | 					if (location.path === '/') { | 
		
	
		
			
				|  |  |  |  | 						host.use_default_location = false; | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  | 				}); | 
		
	
		
			
				|  |  |  |  | 		let locationsPromise; | 
		
	
		
			
				|  |  |  |  | 		let origLocations; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// Manipulate the data a bit before sending it to the template | 
		
	
		
			
				|  |  |  |  | 		if (host_type === 'ssl_passthrough_host') { | 
		
	
		
			
				|  |  |  |  | 			if (internalNginx.sslPassthroughEnabled()){ | 
		
	
		
			
				|  |  |  |  | 				const allHosts = await passthroughHostModel | 
		
	
		
			
				|  |  |  |  | 					.query() | 
		
	
		
			
				|  |  |  |  | 					.where('is_deleted', 0) | 
		
	
		
			
				|  |  |  |  | 					.groupBy('id') | 
		
	
		
			
				|  |  |  |  | 					.omit(['is_deleted']); | 
		
	
		
			
				|  |  |  |  | 				host           = { | 
		
	
		
			
				|  |  |  |  | 					all_passthrough_hosts: allHosts.map((host) => { | 
		
	
		
			
				|  |  |  |  | 						// Replace dots in domain | 
		
	
		
			
				|  |  |  |  | 						host.forwarding_host = internalNginx.addIpv6Brackets(host.forwarding_host); | 
		
	
		
			
				|  |  |  |  | 						return host; | 
		
	
		
			
				|  |  |  |  | 					}), | 
		
	
		
			
				|  |  |  |  | 				}; | 
		
	
		
			
				|  |  |  |  | 			} else { | 
		
	
		
			
				|  |  |  |  | 				locationsPromise = Promise.resolve(); | 
		
	
		
			
				|  |  |  |  | 				internalNginx.deleteConfig(host_type, host, false); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			 | 
		
	
		
			
				|  |  |  |  | 		} else if (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); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			// Set the IPv6 setting for the host | 
		
	
		
			
				|  |  |  |  | 			host.ipv6 = internalNginx.ipv6Enabled(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			locationsPromise.then(() => { | 
		
	
		
			
				|  |  |  |  | 				renderEngine | 
		
	
		
			
				|  |  |  |  | 					.parseAndRender(template, host) | 
		
	
		
			
				|  |  |  |  | 					.then((config_text) => { | 
		
	
		
			
				|  |  |  |  | 						fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						if (debug_mode) { | 
		
	
		
			
				|  |  |  |  | 							logger.success('Wrote config:', filename, config_text); | 
		
	
		
			
				|  |  |  |  | 						} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						// Restore locations array | 
		
	
		
			
				|  |  |  |  | 						host.locations = origLocations; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						resolve(true); | 
		
	
		
			
				|  |  |  |  | 					}) | 
		
	
		
			
				|  |  |  |  | 					.catch((err) => { | 
		
	
		
			
				|  |  |  |  | 						if (debug_mode) { | 
		
	
		
			
				|  |  |  |  | 							logger.warn('Could not write ' + filename + ':', err.message); | 
		
	
		
			
				|  |  |  |  | 						} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						reject(new error.ConfigurationError(err.message)); | 
		
	
		
			
				|  |  |  |  | 					}); | 
		
	
		
			
				|  |  |  |  | 		if (host.locations) { | 
		
	
		
			
				|  |  |  |  | 			//logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2)); | 
		
	
		
			
				|  |  |  |  | 			origLocations    = [].concat(host.locations); | 
		
	
		
			
				|  |  |  |  | 			locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => { | 
		
	
		
			
				|  |  |  |  | 				host.locations = renderedLocations; | 
		
	
		
			
				|  |  |  |  | 			}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			// Allow someone who is using / custom location path to use it, and skip the default / location | 
		
	
		
			
				|  |  |  |  | 			_.map(host.locations, (location) => { | 
		
	
		
			
				|  |  |  |  | 				if (location.path === '/') { | 
		
	
		
			
				|  |  |  |  | 					host.use_default_location = false; | 
		
	
		
			
				|  |  |  |  | 				} | 
		
	
		
			
				|  |  |  |  | 			}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		} else { | 
		
	
		
			
				|  |  |  |  | 			locationsPromise = Promise.resolve(); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// Set the IPv6 setting for the host | 
		
	
		
			
				|  |  |  |  | 		host.ipv6 = internalNginx.ipv6Enabled(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		return locationsPromise.then(() => { | 
		
	
		
			
				|  |  |  |  | 			renderEngine | 
		
	
		
			
				|  |  |  |  | 				.parseAndRender(template, host) | 
		
	
		
			
				|  |  |  |  | 				.then((config_text) => { | 
		
	
		
			
				|  |  |  |  | 					fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					if (debug_mode) { | 
		
	
		
			
				|  |  |  |  | 						logger.success('Wrote config:', filename, config_text); | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					// Restore locations array | 
		
	
		
			
				|  |  |  |  | 					host.locations = origLocations; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					return true; | 
		
	
		
			
				|  |  |  |  | 				}) | 
		
	
		
			
				|  |  |  |  | 				.catch((err) => { | 
		
	
		
			
				|  |  |  |  | 					if (debug_mode) { | 
		
	
		
			
				|  |  |  |  | 						logger.warn('Could not write ' + filename + ':', err.message); | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					throw new error.ConfigurationError(err.message); | 
		
	
		
			
				|  |  |  |  | 				}); | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  | 	}, | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -514,12 +511,12 @@ const internalNginx = { | 
		
	
		
			
				|  |  |  |  | 	 * Helper function to add brackets to an IP if it is IPv6 | 
		
	
		
			
				|  |  |  |  | 	 * @returns {string} | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	 addIpv6Brackets: function (ip) { | 
		
	
		
			
				|  |  |  |  | 	addIpv6Brackets: function (ip) { | 
		
	
		
			
				|  |  |  |  | 		// Only run check if ipv6 is enabled | 
		
	
		
			
				|  |  |  |  | 		if (internalNginx.ipv6Enabled()) { | 
		
	
		
			
				|  |  |  |  | 			const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/gi; | 
		
	
		
			
				|  |  |  |  | 			if(ipv6Regex.test(ip)){ | 
		
	
		
			
				|  |  |  |  | 				return `[${ip}]` | 
		
	
		
			
				|  |  |  |  | 			if (ipv6Regex.test(ip)){ | 
		
	
		
			
				|  |  |  |  | 				return `[${ip}]`; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		return ip; | 
		
	
	
		
			
				
					
					|  |  |  |   |