require('dotenv').config();
const express = require("express");
const app = express();
const router = express.Router();
const bodyParser = require('body-parser');
const buildRoutes = require('./buildRoutes');
const mysql = require('mysql');
const rateLimit = require("express-rate-limit");
const path = require('path');
const utils = require('./utils');
const ifttt = require('./utils/ifttt');
const time = require('./utils/time');
const PORT = process.env.PORT || 4669; // HOME
global.MYSQL_POOL = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: process.env.SQL_USER,
password: process.env.SQL_PASS,
database: 'smart_home'
});
// Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
// see https://expressjs.com/en/guide/behind-proxies.html
app.set('trust proxy', true);
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
// Apply to all requests
app.use(limiter);
app.use(function(req, res, next) {
res.locals.ip = req.header("X-Forwarded-For");
console.log(time.toString(), "-", res.locals.ip, "made a", req.method, "to", req.url);
next();
});
// Enable json parsing
app.use(bodyParser.json());
// Prevent ifttt spam. Might make this dispatch emails sometime idk
let no_auth_ips = {};
function sendUnauthorized(req, res, message) {
console.warn(message);
console.warn(req.body);
if (!no_auth_ips[res.locals.ip]) {
ifttt({
event: "notification",
data: message
});
}
no_auth_ips[res.locals.ip] = setTimeout(function() {
delete no_auth_ips[res.locals.ip];
}, 1000 * 60 * 30); // 30 minutes
res.status(403);
res.send('Unauthorized');
}
const bypass_auth_urls = utils.enumify([
// hue urls are authenticated within the route using the transaction state
"/hue/auth-callback",
"/hue/reauthenticate"
], {
mapify: true
});
console.log("bypass_auth_urls:", bypass_auth_urls);
// 0: node
// 1: this file
let args = process.argv.slice(2).map(function(arg) {
return arg.toUpperCase();
});
console.log("Started with args:", args);
if (args.includes("DEBUG")) {
console.warn("Debug mode, no auth required");
} else {
app.use(function(req, res, next) {
if (bypass_auth_urls[req.url]) {
next();
} else if (req.method === "POST") {
utils.query("SELECT api_key, name FROM users where ?", {
user_id: req.body.user_id
}).then(function(rows) {
if (rows.length) {
let api_key = rows[0].api_key;
if (req.body.auth === api_key) {
// We don't need to carry this around
delete req.body.auth;
console.log("Process request from", rows[0].name);
next();
} else {
sendUnauthorized(req, res,
`Unauthorized request from ${res.locals.ip} - api_key didn't match`
);
}
} else {
sendUnauthorized(req, res,
`Unauthorized request from ${res.locals.ip} - Unknown user_id`
);
}
}).catch(function(error) {
console.error(error);
res.status(500);
res.send('Internal Server Error');
});
} else {
next();
}
});
}
// Build all html routes defined in /routes/html
router.use(buildRoutes("/", [
// "cameras",
"lights",
"location",
"neato",
"reminders",
"hue"
], true));
// Server will serve these pages now
app.use(router);
app.get("/robots.txt", function(req, res) {
res.sendFile(path.join(__dirname, "static_files/robots.txt"));
});
// Start the server :D
app.listen(PORT, function() {
console.log("Server running on port " + PORT);
});