Collected config

This commit is contained in:
Wyatt Johnson
2017-05-09 16:49:11 -06:00
parent 76d0fdfd67
commit 785e5a4ac8
15 changed files with 221 additions and 94 deletions
+4 -2
View File
@@ -9,13 +9,15 @@ const kue = require('../services/kue');
const mongoose = require('../services/mongoose');
const util = require('./util');
const {createSubscriptionManager} = require('../graph/subscriptions');
const {
PORT
} = require('../config');
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.TALK_PORT || '3000');
const port = normalizePort(PORT);
app.set('port', port);
/**
-5
View File
@@ -3,11 +3,6 @@ const dotenv = require('dotenv');
const fs = require('fs');
const program = require('commander');
// Perform rewrites to the runtime environment variables based on the contents
// of the process.env.REWRITE_ENV if it exists. This is done here as it is the
// entrypoint for the entire application.
require('env-rewrite').rewrite();
//==============================================================================
// Setting up the program command line arguments.
//==============================================================================
+147
View File
@@ -0,0 +1,147 @@
// This file serves as the entrypoint to all configuration loaded by the
// application. All defaults are assumed here, validation should also be
// completed here.
// Perform rewrites to the runtime environment variables based on the contents
// of the process.env.REWRITE_ENV if it exists. This is done here as it is the
// entrypoint for the entire applications configuration.
require('env-rewrite').rewrite();
//==============================================================================
// CONFIG INITIALIZATION
//==============================================================================
const CONFIG = {
//------------------------------------------------------------------------------
// JWT based configuration
//------------------------------------------------------------------------------
// JWT_SECRET is the secret used to sign and verify tokens issued by this
// application.
JWT_SECRET: process.env.TALK_JWT_SECRET || null,
// JWT_AUDIENCE is the value for the audience claim for the tokens that will be
// verified when decoding. If `JWT_AUDIENCE` is not in the environment, then it
// will default to `talk`.
JWT_AUDIENCE: process.env.TALK_JWT_AUDIENCE || 'talk',
// JWT_ISSUER is the value for the issuer for the tokens that will be verified
// when decoding. If `JWT_ISSUER` is not in the environment, then it will try
// `TALK_ROOT_URL`, otherwise, it will be undefined.
JWT_ISSUER: process.env.TALK_JWT_ISSUER || process.env.TALK_ROOT_URL || undefined,
// JWT_EXPIRY is the time for which a given token is valid for.
JWT_EXPIRY: process.env.TALK_JWT_EXPIRY || '1 day',
//------------------------------------------------------------------------------
// Installation locks
//------------------------------------------------------------------------------
INSTALL_LOCK: process.env.TALK_INSTALL_LOCK === 'TRUE',
//------------------------------------------------------------------------------
// External database url's
//------------------------------------------------------------------------------
MONGO_URL: process.env.TALK_MONGO_URL,
REDIS_URL: process.env.TALK_REDIS_URL,
//------------------------------------------------------------------------------
// Plugins
//------------------------------------------------------------------------------
PLUGINS_JSON: process.env.TALK_PLUGINS_JSON,
//------------------------------------------------------------------------------
// Server Config
//------------------------------------------------------------------------------
// Port to bind to.
PORT: process.env.TALK_PORT || '3000',
// The URL for this Talk Instance as viewable from the outside.
ROOT_URL: process.env.TALK_ROOT_URL,
//------------------------------------------------------------------------------
// Recaptcha configuration
//------------------------------------------------------------------------------
RECAPTCHA_ENABLED: false, // updated below
RECAPTCHA_PUBLIC: process.env.TALK_RECAPTCHA_PUBLIC,
RECAPTCHA_SECRET: process.env.TALK_RECAPTCHA_SECRET,
//------------------------------------------------------------------------------
// SMTP Server configuration
//------------------------------------------------------------------------------
SMTP_FROM_ADDRESS: process.env.TALK_SMTP_FROM_ADDRESS,
SMTP_HOST: process.env.TALK_SMTP_HOST,
SMTP_PASSWORD: process.env.TALK_SMTP_PASSWORD,
SMTP_PORT: process.env.TALK_SMTP_PORT,
SMTP_USERNAME: process.env.TALK_SMTP_USERNAME
};
//==============================================================================
// CONFIG VALIDATION
//==============================================================================
//------------------------------------------------------------------------------
// JWT based configuration
//------------------------------------------------------------------------------
if (process.env.NODE_ENV === 'test' && !CONFIG.JWT_SECRET) {
CONFIG.JWT_SECRET = 'keyboard cat';
} else if (!CONFIG.JWT_SECRET) {
throw new Error('TALK_JWT_SECRET must be provided in the environment to sign/verify tokens');
}
//------------------------------------------------------------------------------
// External database url's
//------------------------------------------------------------------------------
// Reset the mongo url in the event it hasn't been overrided and we are in a
// testing environment. Every new mongo instance comes with a test database by
// default, this is consistent with common testing and use case practices.
if (process.env.NODE_ENV === 'test' && !CONFIG.MONGO_URL) {
CONFIG.MONGO_URL = 'mongodb://localhost/test';
}
// Reset the redis url in the event it hasn't been overrided and we are in a
// testing environment.
if (process.env.NODE_ENV === 'test' && !CONFIG.REDIS_URL) {
CONFIG.REDIS_URL = 'redis://localhost';
}
//------------------------------------------------------------------------------
// Recaptcha configuration
//------------------------------------------------------------------------------
/**
* This is true when the recaptcha secret is provided and the Recaptcha feature
* is to be enabled.
*/
CONFIG.RECAPTCHA_ENABLED = CONFIG.RECAPTCHA_SECRET && CONFIG.RECAPTCHA_SECRET.length > 0 &&
CONFIG.RECAPTCHA_PUBLIC && CONFIG.RECAPTCHA_PUBLIC.length > 0;
if (!CONFIG.RECAPTCHA_ENABLED) {
console.warn('Recaptcha is not enabled for login/signup abuse prevention, set TALK_RECAPTCHA_SECRET and TALK_RECAPTCHA_PUBLIC to enable Recaptcha.');
}
//------------------------------------------------------------------------------
// SMTP Server configuration
//------------------------------------------------------------------------------
{
const requiredProps = [
'SMTP_FROM_ADDRESS',
'SMTP_USERNAME',
'SMTP_PASSWORD',
'SMTP_HOST'
];
if (requiredProps.some((prop) => !CONFIG[prop])) {
console.warn(`${requiredProps.map((v) => `TALK_${v}`).join(', ')} should be defined in the environment if you would like to send password reset emails from Talk`);
}
}
module.exports = CONFIG;
+4 -1
View File
@@ -4,6 +4,9 @@ const resolve = require('resolve');
const debug = require('debug')('talk:plugins');
const Joi = require('joi');
const amp = require('app-module-path');
const {
PLUGINS_JSON
} = require('./config');
// Add the current path to the module root.
amp.addPath(__dirname);
@@ -18,7 +21,7 @@ try {
let customPlugins = path.join(__dirname, 'plugins.json');
let defaultPlugins = path.join(__dirname, 'plugins.default.json');
if (process.env.TALK_PLUGINS_JSON && process.env.TALK_PLUGINS_JSON.length > 0) {
if (PLUGINS_JSON && PLUGINS_JSON.length > 0) {
debug('Now using TALK_PLUGINS_JSON environment variable for plugins');
plugins = require(envPlugins);
} else if (fs.existsSync(customPlugins)) {
+4 -1
View File
@@ -1,5 +1,8 @@
const express = require('express');
const router = express.Router();
const {
RECAPTCHA_PUBLIC
} = require('../../config');
// Get /email-confirmation expects a signed JWT in the hash
router.get('/confirm-email', (req, res) => {
@@ -17,7 +20,7 @@ router.get('/password-reset', (req, res) => {
router.get('*', (req, res) => {
const data = {
TALK_RECAPTCHA_PUBLIC: process.env.TALK_RECAPTCHA_PUBLIC
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC
};
res.render('admin', {basePath: '/client/coral-admin', data});
+4 -1
View File
@@ -4,6 +4,9 @@ const UsersService = require('../../../services/users');
const mailer = require('../../../services/mailer');
const authorization = require('../../../middleware/authorization');
const errors = require('../../../errors');
const {
ROOT_URL
} = require('../../../config');
//==============================================================================
// ROUTES
@@ -62,7 +65,7 @@ router.post('/password/reset', (req, res, next) => {
template: 'password-reset', // needed to know which template to render!
locals: { // specifies the template locals.
token,
rootURL: process.env.TALK_ROOT_URL
rootURL: ROOT_URL
},
subject: 'Password Reset',
to: email
+4 -1
View File
@@ -5,6 +5,9 @@ const CommentsService = require('../../../services/comments');
const mailer = require('../../../services/mailer');
const errors = require('../../../errors');
const authorization = require('../../../middleware/authorization');
const {
ROOT_URL
} = require('../../../config');
// get a list of users.
router.get('/', authorization.needed('ADMIN'), (req, res, next) => {
@@ -108,7 +111,7 @@ const SendEmailConfirmation = (app, userID, email, referer) => UsersService
template: 'email-confirm', // needed to know which template to render!
locals: { // specifies the template locals.
token,
rootURL: process.env.TALK_ROOT_URL,
rootURL: ROOT_URL,
email
},
subject: 'Email Confirmation',
+4 -1
View File
@@ -1,6 +1,9 @@
const express = require('express');
const router = express.Router();
const SettingsService = require('../../services/settings');
const {
RECAPTCHA_PUBLIC
} = require('../../config');
router.use('/:embed', (req, res, next) => {
switch (req.params.embed) {
@@ -8,7 +11,7 @@ router.use('/:embed', (req, res, next) => {
return SettingsService.retrieve()
.then(({customCssUrl}) => {
const data = {
TALK_RECAPTCHA_PUBLIC: process.env.TALK_RECAPTCHA_PUBLIC
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC
};
return res.render('embed/stream', {customCssUrl, data});
+13 -16
View File
@@ -5,16 +5,13 @@ const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const smtpRequiredProps = [
'TALK_SMTP_FROM_ADDRESS',
'TALK_SMTP_USERNAME',
'TALK_SMTP_PASSWORD',
'TALK_SMTP_HOST'
];
if (smtpRequiredProps.some(prop => !process.env[prop])) {
console.error(`${smtpRequiredProps.join(', ')} should be defined in the environment if you would like to send password reset emails from Talk`);
}
const {
SMTP_HOST,
SMTP_USERNAME,
SMTP_PORT,
SMTP_PASSWORD,
SMTP_FROM_ADDRESS
} = require('../config');
// load all the templates as strings
const templates = {
@@ -56,15 +53,15 @@ templates.render = (name, format = 'txt', context) => new Promise((resolve, reje
});
const options = {
host: process.env.TALK_SMTP_HOST,
host: SMTP_HOST,
auth: {
user: process.env.TALK_SMTP_USERNAME,
pass: process.env.TALK_SMTP_PASSWORD
user: SMTP_USERNAME,
pass: SMTP_PASSWORD
}
};
if (process.env.TALK_SMTP_PORT) {
options.port = process.env.TALK_SMTP_PORT;
if (SMTP_PORT) {
options.port = SMTP_PORT;
} else {
options.port = 25;
}
@@ -126,7 +123,7 @@ const mailer = module.exports = {
debug(`Starting to send mail for Job[${id}]`);
// Set the `from` field.
data.message.from = process.env.TALK_SMTP_FROM_ADDRESS;
data.message.from = SMTP_FROM_ADDRESS;
// Actually send the email.
defaultTransporter.sendMail(data.message, (err) => {
+6 -13
View File
@@ -1,7 +1,12 @@
const mongoose = require('mongoose');
const debug = require('debug')('talk:db');
const enabled = require('debug').enabled;
const queryDebuger = require('debug')('talk:db:query');
const {
MONGO_URL
} = require('../config');
// Loading the formatter from Mongoose:
//
// https://github.com/Automattic/mongoose/blob/1a93d1f4d12e441e17ddf451e96fbc5f6e8f54b8/lib/drivers/node-mongodb-native/collection.js#L182
@@ -24,18 +29,6 @@ function debugQuery(name, i, ...args) {
queryDebuger(functionCall + params);
}
const enabled = require('debug').enabled;
// Pull the mongo url out of the environment.
let url = process.env.TALK_MONGO_URL;
// Reset the mongo url in the event it hasn't been overrided and we are in a
// testing environment. Every new mongo instance comes with a test database by
// default, this is consistent with common testing and use case practices.
if (process.env.NODE_ENV === 'test' && !url) {
url = 'mongodb://localhost/test';
}
// Use native promises
mongoose.Promise = global.Promise;
@@ -48,7 +41,7 @@ if (enabled('talk:db')) {
}
// Connect to the Mongo instance.
mongoose.connect(url, (err) => {
mongoose.connect(MONGO_URL, (err) => {
if (err) {
throw err;
}
+8 -34
View File
@@ -9,25 +9,14 @@ const errors = require('../errors');
const uuid = require('uuid');
const debug = require('debug')('talk:passport');
// JWT_SECRET is the secret used to sign and verify tokens issued by this
// application.
const JWT_SECRET = process.env.JWT_SECRET || null;
if (JWT_SECRET === null) {
throw new Error('JWT_SECRET must be provided in the environment to sign/verify tokens');
}
// JWT_EXPIRY is the time for which a given token is valid for.
const JWT_EXPIRY = process.env.JWT_EXPIRY || '1 day';
// JWT_ISSUER is the value for the issuer for the tokens that will be verified
// when decoding. If `JWT_ISSUER` is not in the environment, then it will try
// `TALK_ROOT_URL`, otherwise, it will be undefined.
const JWT_ISSUER = process.env.JWT_ISSUER || process.env.TALK_ROOT_URL || undefined;
// JWT_AUDIENCE is the value for the audience claim for the tokens that will be
// verified when decoding. If `JWT_AUDIENCE` is not in the environment, then it
// will default to `talk`.
const JWT_AUDIENCE = process.env.JWT_AUDIENCE || 'talk';
const {
JWT_SECRET,
JWT_ISSUER,
JWT_EXPIRY,
JWT_AUDIENCE,
RECAPTCHA_SECRET,
RECAPTCHA_ENABLED
} = require('../config');
// GenerateToken will sign a token to include all the authorization information
// needed for the front end.
@@ -200,21 +189,6 @@ const CheckIfNeedsRecaptcha = (user, email) => {
return false;
};
/**
* This stores the Recaptcha secret.
*/
const RECAPTCHA_SECRET = process.env.TALK_RECAPTCHA_SECRET;
const RECAPTCHA_PUBLIC = process.env.TALK_RECAPTCHA_PUBLIC;
/**
* This is true when the recaptcha secret is provided and the Recaptcha feature
* is to be enabled.
*/
const RECAPTCHA_ENABLED = RECAPTCHA_SECRET && RECAPTCHA_SECRET.length > 0 && RECAPTCHA_PUBLIC && RECAPTCHA_PUBLIC.length > 0;
if (!RECAPTCHA_ENABLED) {
console.log('Recaptcha is not enabled for login/signup abuse prevention, set TALK_RECAPTCHA_SECRET and TALK_RECAPTCHA_PUBLIC to enable Recaptcha.');
}
/**
* This sends the request details down Google to check to see if the response is
* genuine or not.
+4 -2
View File
@@ -1,9 +1,11 @@
const redis = require('redis');
const debug = require('debug')('talk:redis');
const url = process.env.TALK_REDIS_URL || 'redis://localhost';
const {
REDIS_URL
} = require('../config');
const connectionOptions = {
url,
url: REDIS_URL,
retry_strategy: function(options) {
if (options.error && options.error.code === 'ECONNREFUSED') {
+4 -1
View File
@@ -2,6 +2,9 @@ const UsersService = require('./users');
const SettingsService = require('./settings');
const SettingsModel = require('../models/setting');
const errors = require('../errors');
const {
INSTALL_LOCK
} = require('../config');
/**
* This service is used when we want to setup the application. It is consumed by
@@ -15,7 +18,7 @@ module.exports = class SetupService {
static isAvailable() {
// Check if we have an install lock present.
if (process.env.TALK_INSTALL_LOCK === 'TRUE') {
if (INSTALL_LOCK) {
return Promise.reject(errors.ErrInstallLock);
}
+9 -15
View File
@@ -1,12 +1,14 @@
const assert = require('assert');
const uuid = require('uuid');
const bcrypt = require('bcrypt');
const url = require('url');
const jwt = require('jsonwebtoken');
const Wordlist = require('./wordlist');
const errors = require('../errors');
const uuid = require('uuid');
const {
JWT_SECRET,
ROOT_URL
} = require('../config');
const redis = require('./redis');
const redisClient = redis.createClient();
@@ -22,14 +24,6 @@ const SettingsService = require('./settings');
const ActionsService = require('./actions');
const MailerService = require('./mailer');
// In the event that the TALK_JWT_SECRET is missing but we are testing, then
// set the process.env.TALK_JWT_SECRET.
if (process.env.NODE_ENV === 'test' && !process.env.TALK_JWT_SECRET) {
process.env.TALK_JWT_SECRET = 'keyboard cat';
} else if (!process.env.TALK_JWT_SECRET) {
throw new Error('TALK_JWT_SECRET must be defined to encode JSON Web Tokens and other auth functionality');
}
const EMAIL_CONFIRM_JWT_SUBJECT = 'email_confirm';
const PASSWORD_RESET_JWT_SUBJECT = 'password_reset';
@@ -564,7 +558,7 @@ module.exports = class UsersService {
version: user.__v
};
return jwt.sign(payload, process.env.TALK_JWT_SECRET, {
return jwt.sign(payload, JWT_SECRET, {
algorithm: 'HS256',
expiresIn: '1d',
subject: PASSWORD_RESET_JWT_SUBJECT
@@ -583,7 +577,7 @@ module.exports = class UsersService {
// Set the allowed algorithms.
options.algorithms = ['HS256'];
jwt.verify(token, process.env.TALK_JWT_SECRET, options, (err, decoded) => {
jwt.verify(token, JWT_SECRET, options, (err, decoded) => {
if (err) {
return reject(err);
}
@@ -697,7 +691,7 @@ module.exports = class UsersService {
* @param {String} email The email that we are needing to get confirmed.
* @return {Promise}
*/
static createEmailConfirmToken(userID = null, email, referer = process.env.TALK_ROOT_URL) {
static createEmailConfirmToken(userID = null, email, referer = ROOT_URL) {
if (!email || typeof email !== 'string') {
return Promise.reject('email is required when creating a JWT for resetting passord');
}
@@ -740,7 +734,7 @@ module.exports = class UsersService {
email,
referer,
userID: user.id
}, process.env.TALK_JWT_SECRET, tokenOptions);
}, JWT_SECRET, tokenOptions);
});
}
+6 -1
View File
@@ -9,13 +9,18 @@ const webpack = require('webpack');
// Possibly load the config from the .env file (if there is one).
require('dotenv').config();
// Load the config after dotenv has does it's thing.
const {
PLUGINS_JSON
} = require('./config');
let pluginsConfigPath;
let envPlugins = path.join(__dirname, 'plugins.env.js');
let customPlugins = path.join(__dirname, 'plugins.json');
let defaultPlugins = path.join(__dirname, 'plugins.default.json');
if (process.env.TALK_PLUGINS_JSON && process.env.TALK_PLUGINS_JSON.length > 0) {
if (PLUGINS_JSON && PLUGINS_JSON.length > 0) {
pluginsConfigPath = envPlugins;
} else if (fs.existsSync(customPlugins)) {
pluginsConfigPath = customPlugins;