127.0.0.1:8000 smart-home-server / master server / smart-home-server.js
master

Tree @master (Download .tar.gz)

smart-home-server.js @masterraw · history · blame

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);
});