mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	Refactor configuration
- No longer use config npm package - Prefer config from env vars, though still has support for config file - No longer writes a config file for database config - Writes keys to a new file in /data folder - Removes a lot of cruft and improves config understanding
This commit is contained in:
		| @@ -2,6 +2,7 @@ const express     = require('express'); | ||||
| const bodyParser  = require('body-parser'); | ||||
| const fileUpload  = require('express-fileupload'); | ||||
| const compression = require('compression'); | ||||
| const config      = require('./lib/config'); | ||||
| const log         = require('./logger').express; | ||||
|  | ||||
| /** | ||||
| @@ -24,7 +25,7 @@ app.enable('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); | ||||
| app.enable('strict routing'); | ||||
|  | ||||
| // pretty print JSON when not live | ||||
| if (process.env.NODE_ENV !== 'production') { | ||||
| if (config.debug()) { | ||||
| 	app.set('json spaces', 2); | ||||
| } | ||||
|  | ||||
| @@ -65,7 +66,7 @@ app.use(function (err, req, res, next) { | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	if (process.env.NODE_ENV === 'development' || (req.baseUrl + req.path).includes('nginx/certificates')) { | ||||
| 	if (config.debug() || (req.baseUrl + req.path).includes('nginx/certificates')) { | ||||
| 		payload.debug = { | ||||
| 			stack:    typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null, | ||||
| 			previous: err.previous | ||||
| @@ -74,7 +75,7 @@ app.use(function (err, req, res, next) { | ||||
|  | ||||
| 	// Not every error is worth logging - but this is good for now until it gets annoying. | ||||
| 	if (typeof err.stack !== 'undefined' && err.stack) { | ||||
| 		if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { | ||||
| 		if (config.debug()) { | ||||
| 			log.debug(err.stack); | ||||
| 		} else if (typeof err.public == 'undefined' || !err.public) { | ||||
| 			log.warn(err.message); | ||||
|   | ||||
| @@ -1,33 +1,27 @@ | ||||
| const config = require('config'); | ||||
| const config = require('./lib/config'); | ||||
|  | ||||
| if (!config.has('database')) { | ||||
| 	throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md'); | ||||
| 	throw new Error('Database config does not exist! Please read the instructions: https://nginxproxymanager.com/setup/'); | ||||
| } | ||||
|  | ||||
| function generateDbConfig() { | ||||
| 	if (config.database.engine === 'knex-native') { | ||||
| 		return config.database.knex; | ||||
| 	} else | ||||
| 		return { | ||||
| 			client:     config.database.engine, | ||||
| 			connection: { | ||||
| 				host:     config.database.host, | ||||
| 				user:     config.database.user, | ||||
| 				password: config.database.password, | ||||
| 				database: config.database.name, | ||||
| 				port:     config.database.port | ||||
| 			}, | ||||
| 			migrations: { | ||||
| 				tableName: 'migrations' | ||||
| 			} | ||||
| 		}; | ||||
| 	const cfg = config.get('database'); | ||||
| 	if (cfg.engine === 'knex-native') { | ||||
| 		return cfg.knex; | ||||
| 	} | ||||
| 	return { | ||||
| 		client:     cfg.engine, | ||||
| 		connection: { | ||||
| 			host:     cfg.host, | ||||
| 			user:     cfg.user, | ||||
| 			password: cfg.password, | ||||
| 			database: cfg.name, | ||||
| 			port:     cfg.port | ||||
| 		}, | ||||
| 		migrations: { | ||||
| 			tableName: 'migrations' | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|  | ||||
| let data = generateDbConfig(); | ||||
|  | ||||
| if (typeof config.database.version !== 'undefined') { | ||||
| 	data.version = config.database.version; | ||||
| } | ||||
|  | ||||
| module.exports = require('knex')(data); | ||||
| module.exports = require('knex')(generateDbConfig()); | ||||
|   | ||||
| @@ -1,11 +1,9 @@ | ||||
| #!/usr/bin/env node | ||||
|  | ||||
| const fs     = require('fs'); | ||||
| const logger = require('./logger').global; | ||||
|  | ||||
| async function appStart () { | ||||
| 	// Create config file db settings if environment variables have been set | ||||
| 	await createDbConfigFromEnvironment(); | ||||
|  | ||||
| 	const migrate             = require('./migrate'); | ||||
| 	const setup               = require('./setup'); | ||||
| 	const app                 = require('./app'); | ||||
| @@ -42,90 +40,6 @@ async function appStart () { | ||||
| 		}); | ||||
| } | ||||
|  | ||||
| async function createDbConfigFromEnvironment() { | ||||
| 	return new Promise((resolve, reject) => { | ||||
| 		const envMysqlHost = process.env.DB_MYSQL_HOST || null; | ||||
| 		const envMysqlPort = process.env.DB_MYSQL_PORT || null; | ||||
| 		const envMysqlUser = process.env.DB_MYSQL_USER || null; | ||||
| 		const envMysqlName = process.env.DB_MYSQL_NAME || null; | ||||
| 		let envSqliteFile  = process.env.DB_SQLITE_FILE || null; | ||||
|  | ||||
| 		const fs       = require('fs'); | ||||
| 		const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json'; | ||||
| 		let configData = {}; | ||||
|  | ||||
| 		try { | ||||
| 			configData = require(filename); | ||||
| 		} catch (err) { | ||||
| 			// do nothing | ||||
| 		} | ||||
|  | ||||
| 		if (configData.database && configData.database.engine && !configData.database.fromEnv) { | ||||
| 			logger.info('Manual db configuration already exists, skipping config creation from environment variables'); | ||||
| 			resolve(); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if ((!envMysqlHost || !envMysqlPort || !envMysqlUser || !envMysqlName) && !envSqliteFile){ | ||||
| 			envSqliteFile = '/data/database.sqlite'; | ||||
| 			logger.info(`No valid environment variables for database provided, using default SQLite file '${envSqliteFile}'`); | ||||
| 		} | ||||
|  | ||||
| 		if (envMysqlHost && envMysqlPort && envMysqlUser && envMysqlName) { | ||||
| 			const newConfig = { | ||||
| 				fromEnv:  true, | ||||
| 				engine:   'mysql', | ||||
| 				host:     envMysqlHost, | ||||
| 				port:     envMysqlPort, | ||||
| 				user:     envMysqlUser, | ||||
| 				password: process.env.DB_MYSQL_PASSWORD, | ||||
| 				name:     envMysqlName, | ||||
| 			}; | ||||
|  | ||||
| 			if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) { | ||||
| 				// Config is unchanged, skip overwrite | ||||
| 				resolve(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			logger.info('Generating MySQL knex configuration from environment variables'); | ||||
| 			configData.database = newConfig; | ||||
|  | ||||
| 		} else { | ||||
| 			const newConfig = { | ||||
| 				fromEnv: true, | ||||
| 				engine:  'knex-native', | ||||
| 				knex:    { | ||||
| 					client:     'sqlite3', | ||||
| 					connection: { | ||||
| 						filename: envSqliteFile | ||||
| 					}, | ||||
| 					useNullAsDefault: true | ||||
| 				} | ||||
| 			}; | ||||
| 			if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) { | ||||
| 				// Config is unchanged, skip overwrite | ||||
| 				resolve(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			logger.info('Generating SQLite knex configuration'); | ||||
| 			configData.database = newConfig; | ||||
| 		} | ||||
|  | ||||
| 		// Write config | ||||
| 		fs.writeFile(filename, JSON.stringify(configData, null, 2), (err) => { | ||||
| 			if (err) { | ||||
| 				logger.error('Could not write db config to config file: ' + filename); | ||||
| 				reject(err); | ||||
| 			} else { | ||||
| 				logger.debug('Wrote db configuration to config file: ' + filename); | ||||
| 				resolve(); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| try { | ||||
| 	appStart(); | ||||
| } catch (err) { | ||||
|   | ||||
| @@ -1,22 +1,24 @@ | ||||
| const _                  = require('lodash'); | ||||
| const fs                 = require('fs'); | ||||
| const https              = require('https'); | ||||
| const tempWrite          = require('temp-write'); | ||||
| const moment             = require('moment'); | ||||
| const logger             = require('../logger').ssl; | ||||
| const error              = require('../lib/error'); | ||||
| const utils              = require('../lib/utils'); | ||||
| const certificateModel   = require('../models/certificate'); | ||||
| const dnsPlugins         = require('../global/certbot-dns-plugins'); | ||||
| const internalAuditLog   = require('./audit-log'); | ||||
| const internalNginx      = require('./nginx'); | ||||
| const internalHost       = require('./host'); | ||||
| const letsencryptStaging = process.env.NODE_ENV !== 'production'; | ||||
| const _                = require('lodash'); | ||||
| const fs               = require('fs'); | ||||
| const https            = require('https'); | ||||
| const tempWrite        = require('temp-write'); | ||||
| const moment           = require('moment'); | ||||
| const logger           = require('../logger').ssl; | ||||
| const config           = require('../lib/config'); | ||||
| const error            = require('../lib/error'); | ||||
| const utils            = require('../lib/utils'); | ||||
| const certificateModel = require('../models/certificate'); | ||||
| const dnsPlugins       = require('../global/certbot-dns-plugins'); | ||||
| const internalAuditLog = require('./audit-log'); | ||||
| const internalNginx    = require('./nginx'); | ||||
| const internalHost     = require('./host'); | ||||
| const archiver         = require('archiver'); | ||||
| const path             = require('path'); | ||||
| const { isArray }      = require('lodash'); | ||||
|  | ||||
| const letsencryptStaging = config.useLetsencryptStaging(); | ||||
| const letsencryptConfig  = '/etc/letsencrypt.ini'; | ||||
| const certbotCommand     = 'certbot'; | ||||
| const archiver           = require('archiver'); | ||||
| const path               = require('path'); | ||||
| const { isArray }        = require('lodash'); | ||||
|  | ||||
| function omissions() { | ||||
| 	return ['is_deleted']; | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| const _          = require('lodash'); | ||||
| const fs         = require('fs'); | ||||
| const logger     = require('../logger').nginx; | ||||
| const utils      = require('../lib/utils'); | ||||
| const error      = require('../lib/error'); | ||||
| const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG; | ||||
| const _      = require('lodash'); | ||||
| const fs     = require('fs'); | ||||
| const logger = require('../logger').nginx; | ||||
| const config = require('../lib/config'); | ||||
| const utils  = require('../lib/utils'); | ||||
| const error  = require('../lib/error'); | ||||
|  | ||||
| const internalNginx = { | ||||
|  | ||||
| @@ -65,7 +65,7 @@ const internalNginx = { | ||||
| 							} | ||||
| 						}); | ||||
|  | ||||
| 						if (debug_mode) { | ||||
| 						if (config.debug()) { | ||||
| 							logger.error('Nginx test failed:', valid_lines.join('\n')); | ||||
| 						} | ||||
|  | ||||
| @@ -101,7 +101,7 @@ const internalNginx = { | ||||
| 	 * @returns {Promise} | ||||
| 	 */ | ||||
| 	test: () => { | ||||
| 		if (debug_mode) { | ||||
| 		if (config.debug()) { | ||||
| 			logger.info('Testing Nginx configuration'); | ||||
| 		} | ||||
|  | ||||
| @@ -184,7 +184,7 @@ const internalNginx = { | ||||
| 	generateConfig: (host_type, host) => { | ||||
| 		const nice_host_type = internalNginx.getFileFriendlyHostType(host_type); | ||||
|  | ||||
| 		if (debug_mode) { | ||||
| 		if (config.debug()) { | ||||
| 			logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2)); | ||||
| 		} | ||||
|  | ||||
| @@ -239,7 +239,7 @@ const internalNginx = { | ||||
| 					.then((config_text) => { | ||||
| 						fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); | ||||
|  | ||||
| 						if (debug_mode) { | ||||
| 						if (config.debug()) { | ||||
| 							logger.success('Wrote config:', filename, config_text); | ||||
| 						} | ||||
|  | ||||
| @@ -249,7 +249,7 @@ const internalNginx = { | ||||
| 						resolve(true); | ||||
| 					}) | ||||
| 					.catch((err) => { | ||||
| 						if (debug_mode) { | ||||
| 						if (config.debug()) { | ||||
| 							logger.warn('Could not write ' + filename + ':', err.message); | ||||
| 						} | ||||
|  | ||||
| @@ -268,7 +268,7 @@ const internalNginx = { | ||||
| 	 * @returns {Promise} | ||||
| 	 */ | ||||
| 	generateLetsEncryptRequestConfig: (certificate) => { | ||||
| 		if (debug_mode) { | ||||
| 		if (config.debug()) { | ||||
| 			logger.info('Generating LetsEncrypt Request Config:', certificate); | ||||
| 		} | ||||
|  | ||||
| @@ -292,14 +292,14 @@ const internalNginx = { | ||||
| 				.then((config_text) => { | ||||
| 					fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); | ||||
|  | ||||
| 					if (debug_mode) { | ||||
| 					if (config.debug()) { | ||||
| 						logger.success('Wrote config:', filename, config_text); | ||||
| 					} | ||||
|  | ||||
| 					resolve(true); | ||||
| 				}) | ||||
| 				.catch((err) => { | ||||
| 					if (debug_mode) { | ||||
| 					if (config.debug()) { | ||||
| 						logger.warn('Could not write ' + filename + ':', err.message); | ||||
| 					} | ||||
|  | ||||
| @@ -416,8 +416,8 @@ const internalNginx = { | ||||
| 	 * @param   {string}  config | ||||
| 	 * @returns {boolean} | ||||
| 	 */ | ||||
| 	advancedConfigHasDefaultLocation: function (config) { | ||||
| 		return !!config.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im); | ||||
| 	advancedConfigHasDefaultLocation: function (cfg) { | ||||
| 		return !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im); | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
|   | ||||
							
								
								
									
										181
									
								
								backend/lib/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								backend/lib/config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| const fs      = require('fs'); | ||||
| const NodeRSA = require('node-rsa'); | ||||
| const { config } = require('process'); | ||||
| const logger  = require('../logger').global; | ||||
|  | ||||
| const keysFile = '/data/keys.json'; | ||||
|  | ||||
| let instance = null; | ||||
|  | ||||
| // 1. Load from config file first (not recommended anymore) | ||||
| // 2. Use config env variables next | ||||
| const configure = () => { | ||||
| 	const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json'; | ||||
| 	if (fs.existsSync(filename)) { | ||||
| 		let configData; | ||||
| 		try { | ||||
| 			configData = require(filename); | ||||
| 		} catch (err) { | ||||
| 			// do nothing | ||||
| 		} | ||||
| 		if (configData?.database && configData?.database?.engine) { | ||||
| 			logger.info(`Using configuration from file: ${filename}`); | ||||
| 			instance = configData; | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	const envMysqlHost = process.env.DB_MYSQL_HOST || null; | ||||
| 	const envMysqlUser = process.env.DB_MYSQL_USER || null; | ||||
| 	const envMysqlName = process.env.DB_MYSQL_NAME || null; | ||||
| 	if (envMysqlHost && envMysqlUser && envMysqlName) { | ||||
| 		// we have enough mysql creds to go with mysql | ||||
| 		logger.info('Using MySQL configuration'); | ||||
| 		instance = { | ||||
| 			database: { | ||||
| 				engine:   'mysql', | ||||
| 				host:     envMysqlHost, | ||||
| 				port:     process.env.DB_MYSQL_PORT || 3306, | ||||
| 				user:     envMysqlUser, | ||||
| 				password: process.env.DB_MYSQL_PASSWORD, | ||||
| 				name:     envMysqlName, | ||||
| 			} | ||||
| 		}; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite'; | ||||
| 	logger.info(`Using Sqlite: ${envSqliteFile}`); | ||||
| 	instance = { | ||||
| 		database: { | ||||
| 			engine:  'knex-native', | ||||
| 			knex:    { | ||||
| 				client:     'sqlite3', | ||||
| 				connection: { | ||||
| 					filename: envSqliteFile | ||||
| 				}, | ||||
| 				useNullAsDefault: true | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	// Get keys from file | ||||
| 	if (!fs.existsSync(keysFile)) { | ||||
| 		generateKeys(); | ||||
| 	} else if (!!process.env.DEBUG) { | ||||
| 		logger.info('Keys file exists OK'); | ||||
| 	} | ||||
| 	try { | ||||
| 		instance.keys = require(keysFile); | ||||
| 	} catch (err) { | ||||
| 		logger.error('Could not read JWT key pair from config file: ' + keysFile, err); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
|  | ||||
| 	logger.debug('Configuration: ' + JSON.stringify(instance, null, 2)); | ||||
| }; | ||||
|  | ||||
| const generateKeys = () => { | ||||
| 	logger.info('Creating a new JWT key pair...'); | ||||
| 	// Now create the keys and save them in the config. | ||||
| 	const key = new NodeRSA({ b: 2048 }); | ||||
| 	key.generateKeyPair(); | ||||
|  | ||||
| 	const keys = { | ||||
| 		key: key.exportKey('private').toString(), | ||||
| 		pub: key.exportKey('public').toString(), | ||||
| 	}; | ||||
|  | ||||
| 	// Write keys config | ||||
| 	try { | ||||
| 		fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2)); | ||||
| 	} catch (err) { | ||||
| 		logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 	logger.info('Wrote JWT key pair to config file: ' + keysFile); | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
|  | ||||
| 	/** | ||||
| 	 * | ||||
| 	 * @param   {string}  key   ie: 'database' or 'database.engine' | ||||
| 	 * @returns {boolean} | ||||
| 	 */ | ||||
| 	has: function(key) { | ||||
| 		instance === null && configure(); | ||||
| 		const keys = key.split('.'); | ||||
| 		let level = instance; | ||||
| 		let has = true; | ||||
| 		keys.forEach((keyItem) =>{ | ||||
| 			if (typeof level[keyItem] === 'undefined') { | ||||
| 				has = false; | ||||
| 			} else { | ||||
| 				level = level[keyItem]; | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		return has; | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a specific key from the top level | ||||
| 	 * | ||||
| 	 * @param {string} key | ||||
| 	 * @returns {*} | ||||
| 	 */ | ||||
| 	get: function (key) { | ||||
| 		instance === null && configure(); | ||||
| 		if (key && typeof instance[key] !== 'undefined') { | ||||
| 			return instance[key]; | ||||
| 		} | ||||
| 		return instance; | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * Is this a sqlite configuration? | ||||
| 	 * | ||||
| 	 * @returns {boolean} | ||||
| 	 */ | ||||
| 	isSqlite: function () { | ||||
| 		instance === null && configure(); | ||||
| 		return instance.database?.knex && instance.database?.knex?.client === 'sqlite3'; | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * Are we running in debug mdoe? | ||||
| 	 * | ||||
| 	 * @returns {boolean} | ||||
| 	 */ | ||||
| 	debug: function () { | ||||
| 		return !!process.env.DEBUG; | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns a public key | ||||
| 	 * | ||||
| 	 * @returns {string} | ||||
| 	 */ | ||||
| 	getPublicKey: function () { | ||||
| 		instance === null && configure(); | ||||
| 		return instance?.keys?.pub | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns a private key | ||||
| 	 * | ||||
| 	 * @returns {string} | ||||
| 	 */ | ||||
| 	getPrivateKey: function () { | ||||
| 		instance === null && configure(); | ||||
| 		return instance?.keys?.key; | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * @returns {boolean} | ||||
| 	 */ | ||||
| 	useLetsencryptStaging: function () { | ||||
| 		return !!process.env.LE_STAGING; | ||||
| 	} | ||||
| }; | ||||
| @@ -5,7 +5,7 @@ const definitions = require('../../schema/definitions.json'); | ||||
| RegExp.prototype.toJSON = RegExp.prototype.toString; | ||||
|  | ||||
| const ajv = require('ajv')({ | ||||
| 	verbose:     true, //process.env.NODE_ENV === 'development', | ||||
| 	verbose:     true, | ||||
| 	allErrors:   true, | ||||
| 	format:      'full',  // strict regexes for format checks | ||||
| 	coerceTypes: true, | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| const db     = require('../db'); | ||||
| const config = require('config'); | ||||
| const config = require('../lib/config'); | ||||
| const Model  = require('objection').Model; | ||||
|  | ||||
| Model.knex(db); | ||||
|  | ||||
| module.exports = function () { | ||||
| 	if (config.database.knex && config.database.knex.client === 'sqlite3') { | ||||
| 	if (config.isSqlite()) { | ||||
| 		// eslint-disable-next-line | ||||
| 		return Model.raw("datetime('now','localtime')"); | ||||
| 	} | ||||
|   | ||||
| @@ -6,44 +6,36 @@ | ||||
| const _      = require('lodash'); | ||||
| const jwt    = require('jsonwebtoken'); | ||||
| const crypto = require('crypto'); | ||||
| const config = require('../lib/config'); | ||||
| const error  = require('../lib/error'); | ||||
| const logger = require('../logger').global; | ||||
| const ALGO   = 'RS256'; | ||||
|  | ||||
| let public_key  = null; | ||||
| let private_key = null; | ||||
|  | ||||
| function checkJWTKeyPair() { | ||||
| 	if (!public_key || !private_key) { | ||||
| 		let config  = require('config'); | ||||
| 		public_key  = config.get('jwt.pub'); | ||||
| 		private_key = config.get('jwt.key'); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| module.exports = function () { | ||||
|  | ||||
| 	let token_data = {}; | ||||
|  | ||||
| 	let self = { | ||||
| 	const self = { | ||||
| 		/** | ||||
| 		 * @param {Object}  payload | ||||
| 		 * @returns {Promise} | ||||
| 		 */ | ||||
| 		create: (payload) => { | ||||
| 			if (!config.getPrivateKey()) { | ||||
| 				logger.error('Private key is empty!') | ||||
| 			} | ||||
| 			// sign with RSA SHA256 | ||||
| 			let options = { | ||||
| 			const options = { | ||||
| 				algorithm: ALGO, | ||||
| 				expiresIn: payload.expiresIn || '1d' | ||||
| 			}; | ||||
|  | ||||
| 			payload.jti = crypto.randomBytes(12) | ||||
| 				.toString('base64') | ||||
| 				.substr(-8); | ||||
|  | ||||
| 			checkJWTKeyPair(); | ||||
| 				.substring(-8); | ||||
|  | ||||
| 			return new Promise((resolve, reject) => { | ||||
| 				jwt.sign(payload, private_key, options, (err, token) => { | ||||
| 				jwt.sign(payload, config.getPrivateKey(), options, (err, token) => { | ||||
| 					if (err) { | ||||
| 						reject(err); | ||||
| 					} else { | ||||
| @@ -62,13 +54,15 @@ module.exports = function () { | ||||
| 		 * @returns {Promise} | ||||
| 		 */ | ||||
| 		load: function (token) { | ||||
| 			if (!config.getPublicKey()) { | ||||
| 				logger.error('Public key is empty!') | ||||
| 			} | ||||
| 			return new Promise((resolve, reject) => { | ||||
| 				checkJWTKeyPair(); | ||||
| 				try { | ||||
| 					if (!token || token === null || token === 'null') { | ||||
| 						reject(new error.AuthError('Empty token')); | ||||
| 					} else { | ||||
| 						jwt.verify(token, public_key, {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => { | ||||
| 						jwt.verify(token, config.getPublicKey(), {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => { | ||||
| 							if (err) { | ||||
|  | ||||
| 								if (err.name === 'TokenExpiredError') { | ||||
| @@ -132,7 +126,7 @@ module.exports = function () { | ||||
| 		 * @returns {Integer} | ||||
| 		 */ | ||||
| 		getUserId: (default_value) => { | ||||
| 			let attrs = self.get('attrs'); | ||||
| 			const attrs = self.get('attrs'); | ||||
| 			if (attrs && typeof attrs.id !== 'undefined' && attrs.id) { | ||||
| 				return attrs.id; | ||||
| 			} | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
| 		"bcrypt": "^5.0.0", | ||||
| 		"body-parser": "^1.19.0", | ||||
| 		"compression": "^1.7.4", | ||||
| 		"config": "^3.3.1", | ||||
| 		"express": "^4.17.3", | ||||
| 		"express-fileupload": "^1.1.9", | ||||
| 		"gravatar": "^1.8.0", | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| const fs                  = require('fs'); | ||||
| const NodeRSA             = require('node-rsa'); | ||||
| const config              = require('config'); | ||||
| const config              = require('./lib/config'); | ||||
| const logger              = require('./logger').setup; | ||||
| const certificateModel    = require('./models/certificate'); | ||||
| const userModel           = require('./models/user'); | ||||
| @@ -9,62 +7,6 @@ const utils               = require('./lib/utils'); | ||||
| const authModel           = require('./models/auth'); | ||||
| const settingModel        = require('./models/setting'); | ||||
| const dns_plugins         = require('./global/certbot-dns-plugins'); | ||||
| const debug_mode          = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG; | ||||
|  | ||||
| /** | ||||
|  * Creates a new JWT RSA Keypair if not alread set on the config | ||||
|  * | ||||
|  * @returns {Promise} | ||||
|  */ | ||||
| const setupJwt = () => { | ||||
| 	return new Promise((resolve, reject) => { | ||||
| 		// Now go and check if the jwt gpg keys have been created and if not, create them | ||||
| 		if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) { | ||||
| 			logger.info('Creating a new JWT key pair...'); | ||||
|  | ||||
| 			// jwt keys are not configured properly | ||||
| 			const filename  = config.util.getEnv('NODE_CONFIG_DIR') + '/' + (config.util.getEnv('NODE_ENV') || 'default') + '.json'; | ||||
| 			let config_data = {}; | ||||
|  | ||||
| 			try { | ||||
| 				config_data = require(filename); | ||||
| 			} catch (err) { | ||||
| 				// do nothing | ||||
| 				if (debug_mode) { | ||||
| 					logger.debug(filename + ' config file could not be required'); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Now create the keys and save them in the config. | ||||
| 			let key = new NodeRSA({ b: 2048 }); | ||||
| 			key.generateKeyPair(); | ||||
|  | ||||
| 			config_data.jwt = { | ||||
| 				key: key.exportKey('private').toString(), | ||||
| 				pub: key.exportKey('public').toString(), | ||||
| 			}; | ||||
|  | ||||
| 			// Write config | ||||
| 			fs.writeFile(filename, JSON.stringify(config_data, null, 2), (err) => { | ||||
| 				if (err) { | ||||
| 					logger.error('Could not write JWT key pair to config file: ' + filename); | ||||
| 					reject(err); | ||||
| 				} else { | ||||
| 					logger.info('Wrote JWT key pair to config file: ' + filename); | ||||
| 					delete require.cache[require.resolve('config')]; | ||||
| 					resolve(); | ||||
| 				} | ||||
| 			}); | ||||
| 		} else { | ||||
| 			// JWT key pair exists | ||||
| 			if (debug_mode) { | ||||
| 				logger.debug('JWT Keypair already exists'); | ||||
| 			} | ||||
|  | ||||
| 			resolve(); | ||||
| 		} | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Creates a default admin users if one doesn't already exist in the database | ||||
| @@ -119,8 +61,8 @@ const setupDefaultUser = () => { | ||||
| 					.then(() => { | ||||
| 						logger.info('Initial admin setup completed'); | ||||
| 					}); | ||||
| 			} else if (debug_mode) { | ||||
| 				logger.debug('Admin user setup not required'); | ||||
| 			} else if (config.debug()) { | ||||
| 				logger.info('Admin user setup not required'); | ||||
| 			} | ||||
| 		}); | ||||
| }; | ||||
| @@ -151,8 +93,8 @@ const setupDefaultSettings = () => { | ||||
| 						logger.info('Default settings added'); | ||||
| 					}); | ||||
| 			} | ||||
| 			if (debug_mode) { | ||||
| 				logger.debug('Default setting setup not required'); | ||||
| 			if (config.debug()) { | ||||
| 				logger.info('Default setting setup not required'); | ||||
| 			} | ||||
| 		}); | ||||
| }; | ||||
| @@ -225,8 +167,7 @@ const setupLogrotation = () => { | ||||
| }; | ||||
|  | ||||
| module.exports = function () { | ||||
| 	return setupJwt() | ||||
| 		.then(setupDefaultUser) | ||||
| 	return setupDefaultUser() | ||||
| 		.then(setupDefaultSettings) | ||||
| 		.then(setupCertbotPlugins) | ||||
| 		.then(setupLogrotation); | ||||
|   | ||||
| @@ -677,13 +677,6 @@ concat-map@0.0.1: | ||||
|   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | ||||
|   integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | ||||
|  | ||||
| config@^3.3.1: | ||||
|   version "3.3.1" | ||||
|   resolved "https://registry.yarnpkg.com/config/-/config-3.3.1.tgz#b6a70e2908a43b98ed20be7e367edf0cc8ed5a19" | ||||
|   integrity sha512-+2/KaaaAzdwUBE3jgZON11L1ggLLhpf2FsGrfqYFHZW22ySGv/HqYIXrBwKKvn+XZh1UBUjHwAcrfsSkSygT+Q== | ||||
|   dependencies: | ||||
|     json5 "^2.1.1" | ||||
|  | ||||
| configstore@^5.0.1: | ||||
|   version "5.0.1" | ||||
|   resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" | ||||
| @@ -1769,11 +1762,6 @@ json-stable-stringify-without-jsonify@^1.0.1: | ||||
|   resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" | ||||
|   integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= | ||||
|  | ||||
| json5@^2.1.1: | ||||
|   version "2.2.3" | ||||
|   resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" | ||||
|   integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== | ||||
|  | ||||
| jsonwebtoken@^9.0.0: | ||||
|   version "9.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user