Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
coldfire84 committed Nov 24, 2019
2 parents 46a5bc0 + 57e1915 commit 78b5262
Show file tree
Hide file tree
Showing 101 changed files with 8,120 additions and 2,706 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@ node_modules/*
.vscode/*
test.sh
test-aws.sh
.aws/*
config.json
node-red-208520-70f2b1da662d.json
config/node-red-208520-70f2b1da662d.json
views/fragments/de/privacy-policy.ejs
views/fragments/de/terms-of-service.ejs
views/fragments/es/privacy-policy.ejs
views/fragments/es/terms-of-service.ejs
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:8
FROM node:12.10

ENV NODE_ENV production

Expand Down
146 changes: 146 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
///////////////////////////////////////////////////////////////////////////
// Depends
///////////////////////////////////////////////////////////////////////////
var favicon = require('serve-favicon')
var flash = require('connect-flash');
var morgan = require('morgan');
var express = require('express');
const session = require('express-session');
const mongoStore = require('connect-mongo')(session);
var passport = require('passport');
var bodyParser = require('body-parser');
//var cookieParser = require('cookie-parser');
///////////////////////////////////////////////////////////////////////////
// MongoDB
///////////////////////////////////////////////////////////////////////////
var db = require('./config/db');
// Schema =======================
var Account = require('./models/account');
var Topics = require('./models/topics');
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var LocalStrategy = require('passport-local').Strategy;
var logger = require('./config/logger');
///////////////////////////////////////////////////////////////////////////
// Variables
///////////////////////////////////////////////////////////////////////////
var debug = (process.env.ALEXA_DEBUG || false);
// MongoDB Settings, used for expression session handler DB connection
var mongo_user = (process.env.MONGO_USER);
var mongo_password = (process.env.MONGO_PASSWORD);
var mongo_host = (process.env.MONGO_HOST || "mongodb");
var mongo_port = (process.env.MONGO_PORT || "27017");
// MQTT Settings
var mqtt_user = (process.env.MQTT_USER);
var mqtt_password = (process.env.MQTT_PASSWORD);
var mqtt_port = (process.env.MQTT_PORT || "1883");
var mqtt_url = (process.env.MQTT_URL || "mqtt://mosquitto:" + mqtt_port);
// Cookie Secret
var cookieSecret = (process.env.COOKIE_SECRET || 'ihytsrf334');
if (cookieSecret == 'ihytsrf334') {logger.log("warn", "[App] Using default Cookie Secret, please supply new secret using COOKIE_SECRET environment variable")}
else {logger.log("info", "[App] Using user-defined cookie secret")}
///////////////////////////////////////////////////////////////////////////
// Passport Configuration
///////////////////////////////////////////////////////////////////////////
passport.use(new LocalStrategy(Account.authenticate()));
passport.use(new BasicStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());
///////////////////////////////////////////////////////////////////////////
// Main
///////////////////////////////////////////////////////////////////////////
// Check admin account exists, if not create it using same credentials as MQTT user/password supplied
Account.findOne({username: mqtt_user}, function(error, account){
if (!error && !account) {
Account.register(new Account({username: mqtt_user, email: '', mqttPass: '', superuser: 1}),
mqtt_password, function(err, account){
var topics = new Topics({topics: [
'command/' +account.username+'/#',
'state/' + account.username + '/#',
'response/' + account.username + '/#',
'message/' + account.username + '/#'
]});
topics.save(function(err){
if (!err){
var s = Buffer.from(account.salt, 'hex').toString('base64');
var h = Buffer.from(account.hash, 'hex').toString(('base64'));
var mqttPass = "PBKDF2$sha256$901$" + account.salt + "$" + account.hash;
Account.updateOne(
{username: account.username},
{$set: {mqttPass: mqttPass, topics: topics._id}},
function(err, count){
if (err) {
logger.log('error', err);
}
}
);
}
});
});
} else {
logger.log('info', "[App] Superuser MQTT account, " + mqtt_user + " already exists");
}
});

var app = express();
app.set('view engine', 'ejs');
app.enable('trust proxy');
app.use(favicon('static/favicon.ico'));
app.use(morgan("combined", {stream: logger.stream})); // change to use Winston
//app.use(cookieParser(cookieSecret));
app.use(flash());
// Session handler
app.use(session({
store: new mongoStore({
url: "mongodb://" + mongo_user +":" + mongo_password + "@" + mongo_host + ":" + mongo_port + "/sessions"
}),
resave: true,
saveUninitialized: false,
secret: cookieSecret,
cookie: {
secure: true
}
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());

function requireHTTPS(req, res, next) {
if (req.get('X-Forwarded-Proto') === 'http') {
var url = 'https://' + req.get('host');
if (req.get('host') === 'localhost') {
url += ':' + port;
}
url += req.url;
return res.redirect(url);
}
next();
}

app.use(requireHTTPS);

app.use('/',express.static('static')); // Static content router
app.use('/octicons', express.static('node_modules/@primer/octicons/build'), express.static('node_modules/@primer/octicons/build/svg')); // Octicons router

///////////////////////////////////////////////////////////////////////////
// Load Routes
///////////////////////////////////////////////////////////////////////////
const rtDefault = require('./routes/default');
const rtAdmin = require('./routes/admin');
const rtAuth = require('./routes/auth');
const rtGhome = require('./routes/ghome');
const rtAlexa = require('./routes/alexa');
app.use('/', rtDefault);
app.use('/admin', rtAdmin); // Admin Interface
app.use('/auth', rtAuth); // OAuth endpoints
app.use('/api/ghome', rtGhome); // Google Home API
app.use('/api/v1', rtAlexa); // Alexa API

var state = require('./state'); // Load State API

module.exports = app;




53 changes: 53 additions & 0 deletions config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////
// Depends
///////////////////////////////////////////////////////////////////////////
var mongoose = require('mongoose');
var logger = require('./logger'); // Moved to own module
///////////////////////////////////////////////////////////////////////////
// Variables
///////////////////////////////////////////////////////////////////////////
// MongoDB Settings
var mongo_user = (process.env.MONGO_USER);
var mongo_password = (process.env.MONGO_PASSWORD);
var mongo_host = (process.env.MONGO_HOST || "mongodb");
var mongo_port = (process.env.MONGO_PORT || "27017");
mongo_url = "mongodb://" + mongo_user +":" + mongo_password + "@" + mongo_host + ":" + mongo_port + "/users";
mongoose.Promise = global.Promise;
var mongoose_connection = mongoose.connection;
///////////////////////////////////////////////////////////////////////////
// Connect to Mongo Instance
///////////////////////////////////////////////////////////////////////////
mongoose_connection.on('connecting', function() {
logger.log('info', "[Core] Connecting to MongoDB...");
});
mongoose_connection.on('error', function(error) {
logger.log('error', "[Core] MongoDB connection: " + error);
//mongoose.disconnect();
});
mongoose_connection.on('connected', function() {
logger.log('info', "[Core] MongoDB connected!");
});
mongoose_connection.once('open', function() {
logger.log('info', "[Core] MongoDB connection opened!");
});
mongoose_connection.on('reconnected', function () {
logger.log('info', "[Core] MongoDB reconnected!");
});
mongoose_connection.on('disconnected', function() {
logger.log('warn', "[Core] MongoDB disconnected!");
});

// Fix Mongoose Deprecation Warnings; https://mongoosejs.com/docs/deprecations.html
mongoose.set('useNewUrlParser', true);
mongoose.set('useCreateIndex', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useUnifiedTopology', true);

logger.log('info', "[Core] Connecting to MongoDB server: mongodb://" + mongo_host + ":" + mongo_port + "/users");
mongoose.connect(mongo_url, {
useNewUrlParser: true,
useUnifiedTopology: true,
autoReconnect: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 1000
});
64 changes: 64 additions & 0 deletions config/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
///////////////////////////////////////////////////////////////////////////
// Depends
///////////////////////////////////////////////////////////////////////////
const { format, createLogger, transports } = require('winston');
const fs = require('fs');
const crypto = require('crypto');
///////////////////////////////////////////////////////////////////////////
// Variables
///////////////////////////////////////////////////////////////////////////
var debug = (process.env.ALEXA_DEBUG || false);
var awscredentials = '/root/.aws/credentials'
var logGroup = (process.env.WEB_HOSTNAME || "node-red")
var startTime = new Date().toISOString();
var consoleLoglevel = "info";
if (debug == "true") {consoleLoglevel = "debug"};
///////////////////////////////////////////////////////////////////////////
// Exports
///////////////////////////////////////////////////////////////////////////
const logger = createLogger({
transports: [
// Console Transport
new transports.Console({
level: consoleLoglevel,
format: format.combine(
format.timestamp(),
format.colorize(),
format.simple()
),
handleExceptions: true
})
]
});
// Create logger stream object for use with morgan
logger.stream = {
write: function(message, encoding) {
// use the 'verbose' log level
logger.verbose(message);
},
};

// Check for AWS credentials
fs.access(awscredentials, fs.F_OK, (err) => {
if (err) {
logger.log('warn', '[Logger] AWS credentials file does not exist at ~/.aws/credentials. Cludwatch logging disabled.');
return
}
// Setup AWS CloudWatch Transport
const WinstonCloudwatch = require('winston-cloudwatch');
logger.add(new WinstonCloudwatch({
logGroupName: logGroup,
logStreamName: function() {
// Spread log streams across dates as the server stays up
let date = new Date().toISOString().split('T')[0];
return 'express-server-' + date + '-' +
crypto.createHash('md5')
.update(startTime)
.digest('hex');
},
awsRegion: 'eu-west-1',
jsonMessage: true
}));
})

module.exports = logger;
41 changes: 41 additions & 0 deletions config/redis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
// Depends
///////////////////////////////////////////////////////////////////////////
var logger = require('./logger'); // Moved to own module
///////////////////////////////////////////////////////////////////////////
// Redis Client Config
///////////////////////////////////////////////////////////////////////////
var client = require('redis').createClient({
host: 'redis',
retry_strategy: function (options) {
if (options.error && options.error.code === 'ECONNREFUSED') {
return new Error('The server refused the connection');
}
if (options.total_retry_time > 1000 * 60 * 60) {
//logger.log('error', "[REDIS] Retry time exhausted");
return new Error('Retry time exhausted');
}
if (options.attempt > 100) {
// End reconnecting with built in error
logger.log('error', "[Core] Redis server connection retry limit exhausted");
return undefined;
}
// reconnect after
//logger.log('error', "[REDIS] Attempting reconnection after set interval");
return Math.min(options.attempt * 1000, 10000);
}
});
client.on('connect', function() {
logger.log('info', "[Core] Connecting to Redis server...");
});
client.on('ready', function() {
logger.log('info', "[Core] Redis connection ready!");
});
client.on('reconnecting', function() {
logger.log('info', "[Core] Attempting to reconnect to Redis server");
});
client.on('error', function (err) {
logger.log('error', "[Core] Unable to connect to Redis server");
});

module.exports = client;

0 comments on commit 78b5262

Please sign in to comment.