diff --git a/consumerWebsite/modules/app.js b/consumerWebsite/app.js similarity index 60% rename from consumerWebsite/modules/app.js rename to consumerWebsite/app.js index 3b3d8ba..dc3c301 100644 --- a/consumerWebsite/modules/app.js +++ b/consumerWebsite/app.js @@ -1,29 +1,46 @@ const express = require("express"); +const { rateLimit } = require("express-rate-limit"); const path = require("path"); const app = express(); const port = 3000; const ejs = require("ejs"); +module.exports = app; app.use(express.json()); app.set("json spaces", 2); +//express-rate-limit stolen from docs +const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + limit: 600, // Limit each IP to 100 requests per `window` (here, per 15 minutes). + standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header + legacyHeaders: false, // Disable the `X-RateLimit-*` headers. +}); + +// Hold list of functions to run when the server is ready +app.onListen = [function(){console.log('Express is ready')}]; + +// Apply the rate limiting middleware to all requests. +app.use(limiter); + +//disable x-powered-by header for security reasons +app.disable("x-powered-by"); + // Set up the templating engine to build HTML for the front end. -app.set("views", path.join(__dirname, "../views")); +app.set("views", path.join(__dirname, "./views")); app.set("view engine", "ejs"); // Have express server static content( images, CSS, browser JS) from the public -app.use(express.static(path.join(__dirname, "../public"))); - -//middleware logic ( called by next() ) -const auth = require("../middleware/authChecker"); +app.use(express.static(path.join(__dirname, "./public"))); //route logic -app.use("/api/v0", require("../routes/api_routes")); +app.use("/api/seed/v0" ,require("./routes/seed_route.js")); +app.use("/api/v0", require("./routes/api_routes")); //render logic -app.use("/", require("../routes/render")); +app.use("/", require("./routes/render")); // Catch 404 and forward to error handler. If none of the above routes are // used, this is what will be called. @@ -69,8 +86,4 @@ app.use(function (err, req, res, next) { keyErrors, }); }); -app.listen(port, () => { - console.log(`app listening on port ${port}`); -}); -module.exports = { app }; diff --git a/webserver/bin/www b/consumerWebsite/bin/www similarity index 75% rename from webserver/bin/www rename to consumerWebsite/bin/www index 92b78f8..ae5fa70 100644 --- a/webserver/bin/www +++ b/consumerWebsite/bin/www @@ -4,36 +4,28 @@ * Module dependencies. */ -var app = require('../../webserver/modules/express.js'); -const index = require("../index.js") -var debug = require('debug')('proxy-api:server'); -var http = require('http'); +const app = require('../app'); +const mqttApp = require('../mqttApp'); +const debug = require('debug')('proxy-api:server'); +const http = require('http'); +const path = require('path'); +require('dotenv').config({ path: path.resolve(__dirname, '../../.env')}) /** * Get port from environment and store in Express. */ -const port = normalizePort(process.env.PORT || '80'); +var port = normalizePort(process.env.NODE_PORT || '3000'); app.set('port', port); /** * Create HTTP server. */ +//create server with app var server = http.createServer(app); -const io = require('socket.io')(server - , { - cors: { - //replace with domain name when deployed - origin: 'http://localhost:3000', // client! - methods: ["GET"], - allowedHeaders: ["my-custom-header"], - credentials: true - - } -}); - +var io = require('socket.io')(server); app.io = io; /** @@ -103,7 +95,8 @@ function onListening() { : 'port ' + addr.port; console.log('Listening on ' + bind); + // execute list of functions when app is ready for(let listener of app.onListen){ listener() } -} +} \ No newline at end of file diff --git a/webserver/database/model/apiLogModel.js b/consumerWebsite/database/model/apiLogModel.js similarity index 100% rename from webserver/database/model/apiLogModel.js rename to consumerWebsite/database/model/apiLogModel.js diff --git a/webserver/database/model/locationModel.js b/consumerWebsite/database/model/locationModel.js similarity index 100% rename from webserver/database/model/locationModel.js rename to consumerWebsite/database/model/locationModel.js diff --git a/webserver/database/model/sensorDataModel.js b/consumerWebsite/database/model/sensorDataModel.js similarity index 100% rename from webserver/database/model/sensorDataModel.js rename to consumerWebsite/database/model/sensorDataModel.js diff --git a/webserver/database/model/sensorModel.js b/consumerWebsite/database/model/sensorModel.js similarity index 100% rename from webserver/database/model/sensorModel.js rename to consumerWebsite/database/model/sensorModel.js diff --git a/consumerWebsite/functions/api.js b/consumerWebsite/functions/api.js new file mode 100644 index 0000000..4ba3737 --- /dev/null +++ b/consumerWebsite/functions/api.js @@ -0,0 +1,47 @@ +const { hash, compareHash } = require("./bcrypt.js"); +const { apikeyModel } = require("../database/model/apiKeyModel"); +const { generateUUID } = require("./generateUUID.js"); + +/* +1) take userid +2) generate random api key +3) hash the api key +4) append userid with - and api key +5) you give the user rowid-uuidv4 +6) store in database +*/ +//can be used for api key or token. Both are the same logic +async function addAPIKey(userId, permission) { + let hashtoken = await generateUUID(); + let apikey = await hashAPIKey(hashtoken); + + let token = await apikeyModel.create({ + userid: userId, + apikey: apikey, + permission: permission, + }); + + //user token with - tokenid is table id + return token.id + "-" + hashtoken; +} + +async function checkAPikey(SuppliedKey, rowid) { + try { + const retrivedKey = await apikeyModel.findOne({ + raw: true, + attributes: ["apikey", "permission"], + where: { + id: rowid, + }, + }); + //console.log(retrivedKey.apikey); + if (compareHash(SuppliedKey, retrivedKey.apikey)) { + //return true; + return retrivedKey.permission; + } + } catch (error) { + console.error(error); + } +} + +module.exports = { addAPIKey , checkAPikey }; \ No newline at end of file diff --git a/consumerWebsite/functions/bcrypt.js b/consumerWebsite/functions/bcrypt.js index f0b72a3..f5fa6ae 100644 --- a/consumerWebsite/functions/bcrypt.js +++ b/consumerWebsite/functions/bcrypt.js @@ -23,23 +23,18 @@ bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) { */ //hash for pass or token lol doesnt matter -async function hashPassword(password) { +async function hash(password) { return await bcrypt.hash(password, saltRounds); } -async function hashAPIKey(apikey) { - return await bcrypt.hash(apikey, saltRounds); -} - //can be used to compare password or token -async function comparePassword(password, hash) { +async function compareHash(password, hash) { return await bcrypt.compare(password, hash); } module.exports = { - hashPassword, - hashAPIKey, - comparePassword + hash, + compareHash }; \ No newline at end of file diff --git a/consumerWebsite/functions/location.js b/consumerWebsite/functions/location.js new file mode 100644 index 0000000..e13c659 --- /dev/null +++ b/consumerWebsite/functions/location.js @@ -0,0 +1,55 @@ +const {locationModel} = require("../database/model/locationModel"); + +async function getLocation() { + const location = await locationModel.findAll(); + return location; +} + +async function addLocation(name, added_by, description) { + const location = await locationModel.create({ + name: name, + added_by: added_by, + description: description, + }); +} + +async function updateLocation(id, name, added_by, description) { + const location = await locationModel.update( + { + name: name, + added_by: added_by, + description: description, + }, + { + where: { + id: id, + }, + } + ); +} + +async function deleteLocation(id) { + //delete by id + const location = await locationModel.destroy({ + where: { + id: id, + }, + }); +} + +async function getLocationById(id) { + const location = await locationModel.findAll({ + where: { + id: id, + }, + }); + return location; +} + +module.exports = { + getLocation, + addLocation, + updateLocation, + deleteLocation, + getLocationById, +}; \ No newline at end of file diff --git a/consumerWebsite/functions/logger.js b/consumerWebsite/functions/logger.js new file mode 100644 index 0000000..57a9c24 --- /dev/null +++ b/consumerWebsite/functions/logger.js @@ -0,0 +1,23 @@ +const { api_log_Model } = require("../database/model/apiLogModel.js"); + + +async function insertLogData(log) { + try { + api_log_Model.create({ + ip: log.ip, + time: log.time, + method: log.method, + host: log.host, + statusCode: log.statusCode, + Responsesize: log.Responsesize, + referrer: log.referrer, + userAgent: log.userAgent, + }); + } catch (error) { + console.error(error); + } +} + +module.exports = { + insertLogData, +}; \ No newline at end of file diff --git a/consumerWebsite/functions/sensor.js b/consumerWebsite/functions/sensor.js new file mode 100644 index 0000000..66994eb --- /dev/null +++ b/consumerWebsite/functions/sensor.js @@ -0,0 +1,75 @@ +const {sensorModel} = require("../database/model/sensorModel"); + + +async function getSensor() { + const sensor = await sensorModel.findAll(); + return sensor; +} + +async function addSensor( + sensorname, + added_by, + mac_address, + description, + location +) { + const sensor = await sensorModel.create({ + name: sensorname, + added_by: added_by, + mac_address: mac_address, + description: description, + location: location, + }); +} + +async function updateSensor( + id, + sensorname, + added_by, + mac_address, + description, + location +) { + const sensor = await sensorModel.update( + { + name: sensorname, + added_by: added_by, + mac_address: mac_address, + description: description, + location: location, + }, + { + where: { + id: id, + }, + } + ); +} + +async function deleteSensor(id) { + //delete by id + const sensor = await sensorModel.destroy({ + where: { + id: id, + }, + }); + + console.error(error); +} + +async function getSensorById(id) { + const sensor = await sensorModel.findAll({ + where: { + id: id, + }, + }); + return sensor; +} + +module.exports = { + getSensor, + addSensor, + updateSensor, + deleteSensor, + getSensorById, +}; \ No newline at end of file diff --git a/webserver/functions/APIDatabase.js b/consumerWebsite/functions/sensorData.js similarity index 88% rename from webserver/functions/APIDatabase.js rename to consumerWebsite/functions/sensorData.js index d357188..f913ce0 100644 --- a/webserver/functions/APIDatabase.js +++ b/consumerWebsite/functions/sensorData.js @@ -1,8 +1,7 @@ -const { sequelize } = require("../Database/mySql.js"); -const { locationModel } = require("../Database/model/locationModel.js"); -const { sensorModel } = require("../Database/model/sensorModel.js"); -const { sensorDataModel } = require("../Database/model/sensorDataModel.js"); const { Op, Sequelize } = require("sequelize"); +const { sequelize } = require("../database/mySQL.js"); +const { sensorDataModel } = require("../database/model/sensorDataModel.js"); +const io = require('../functions/socket'); //helper function to convert month name to month number //https://stackoverflow.com/questions/13566552/easiest-way-to-convert-month-name-to-month-number-in-js-jan-01 @@ -13,130 +12,22 @@ function getMonthFromString(mon) { } return -1; } -async function getLocation() { - const location = await locationModel.findAll(); - return location; -} -async function addLocation(name, added_by, description) { - const location = await locationModel.create({ - name: name, - added_by: added_by, - description: description, - }); -} - -async function updateLocation(id, name, added_by, description) { - const location = await locationModel.update( - { - name: name, - added_by: added_by, - description: description, - }, - { - where: { - id: id, - }, - } - ); -} - -async function deleteLocation(id) { - //delete by id - const location = await locationModel.destroy({ - where: { - id: id, - }, - }); -} - -async function getLocationById(id) { - const location = await locationModel.findAll({ - where: { - id: id, - }, - }); - return location; -} - -async function getSensor() { - const sensor = await sensorModel.findAll(); - return sensor; - console.error(error); -} - -async function addSensor( - sensorname, - added_by, - mac_address, - description, - location -) { - const sensor = await sensorModel.create({ - name: sensorname, - added_by: added_by, - mac_address: mac_address, - description: description, - location: location, - }); -} - -async function updateSensor( - id, - sensorname, - added_by, - mac_address, - description, - location -) { - const sensor = await sensorModel.update( - { - name: sensorname, - added_by: added_by, - mac_address: mac_address, - description: description, - location: location, - }, - { - where: { - id: id, - }, - } - ); -} - -async function deleteSensor(id) { - //delete by id - const sensor = await sensorModel.destroy({ - where: { - id: id, - }, - }); - - console.error(error); -} - -async function getSensorById(id) { - const sensor = await sensorModel.findAll({ - where: { - id: id, - }, - }); - return sensor; -} async function getSensorData() { const sensorData = await sensorDataModel.findAll(); return sensorData; } -async function addSensorData(id, id_sensor, id_location, sensordata) { +async function addSensorData(id_sensor, id_location, sensordata) { const sensorData = await sensorDataModel.create({ - id: id, sensorid: id_sensor, locationid: id_location, measurement: sensordata, }); + io().emit('sensordata:new', sensorData) + + return sensorData; } async function updateSensorData(id, id_sensor, id_location, sensordata) { @@ -826,16 +717,6 @@ async function getDatabyRange(queryString) { } module.exports = { - getLocation, - addLocation, - updateLocation, - deleteLocation, - getLocationById, - getSensor, - addSensor, - updateSensor, - deleteSensor, - getSensorById, getSensorData, addSensorData, updateSensorData, @@ -843,4 +724,5 @@ module.exports = { getSensorDataById, getData, getDatabyRange, -}; + +}; \ No newline at end of file diff --git a/consumerWebsite/functions/socket.js b/consumerWebsite/functions/socket.js new file mode 100644 index 0000000..acba88e --- /dev/null +++ b/consumerWebsite/functions/socket.js @@ -0,0 +1,17 @@ +const app = require("../app"); +const io = ()=> app.io; + +// We have to wait for the express HTTP server to be finished starting before we +// can use any of the socket.io stuff. +app.onListen.push(function(){ + app.io.on('connection', (socket) => { + console.log('User connected via WebsSocket') + + socket.on('disconnect', (socket) => { + console.log('User disconnect via WebsSocket') + }); + }); +}); + + +module.exports = io; \ No newline at end of file diff --git a/consumerWebsite/functions/apiDatabase.js b/consumerWebsite/functions/user.js similarity index 69% rename from consumerWebsite/functions/apiDatabase.js rename to consumerWebsite/functions/user.js index 5cadaa5..44582e1 100644 --- a/consumerWebsite/functions/apiDatabase.js +++ b/consumerWebsite/functions/user.js @@ -1,13 +1,44 @@ -const { sequelize } = require("../database/mySql.js"); -const { apikeyModel } = require("../database/model/apikeyModel.js"); -const { userModel } = require("../database/model/userModel.js"); -const { Op, Sequelize } = require("sequelize"); -const { generateUUID } = require("../functions/generateUUID.js"); -const { - hashPassword, - comparePassword, - hashAPIKey, -} = require("../functions/bcrypt.js"); +const { Op } = require('sequelize') +const { hash, compareHash } = require("./bcrypt.js"); +const { addAPIKey } = require("./api"); +const { userModel } = require("../database/model/userModel"); + + + +//getuser +//api/v0/user/me +async function getUserID(userid) { + //console.log(userid); + //console.log(userid.id); + let userRes = await userModel.findByPk(userid.id, { + attributes: { + exclude: ["password"], + }, + }); + + if (!userRes) return false; + return userRes; +} + +async function addUser(user) { + //hash password + let hashed = await hash(user.password); + + const addRes = await userModel.create({ + firstname: user.firstname, + lastname: user.lastname, + username: user.username, + password: hashed, + email: user.email, + address: user.address, + phone: user.phone, + }); + if (addRes) { + return true; + } else { + return false; + } +} //getuser //api/v0/user/me @@ -32,13 +63,13 @@ async function getUserID(userid) { */ async function addUser(user) { //hash password - let hash = await hashPassword(user.password); + let hashed = await hash(user.password); const addRes = await userModel.create({ firstname: user.firstname, lastname: user.lastname, username: user.username, - password: hash, + password: hashed, email: user.email, address: user.address, phone: user.phone, @@ -70,7 +101,7 @@ async function loginUser(user) { if (!userRes) return false; // Compare passwords - let match = await comparePassword(user.password, userRes.password); + let match = await compareHash(user.password, userRes.password); if (!match) return false; //console.log('loginUser', userRes.id, userRes.username); @@ -89,20 +120,6 @@ async function loginUser(user) { 6) store in database */ -//can be used for api key or token. Both are the same logic -async function addAPIKey(userId, permission) { - let hashtoken = await generateUUID(); - let apikey = await hashAPIKey(hashtoken); - - let token = await apikeyModel.create({ - userid: userId, - apikey: apikey, - permission: permission, - }); - - //user token with - tokenid is table id - return token.id + "-" + hashtoken; -} //api/v0/user/update async function updateProfile(user, body) { @@ -125,7 +142,7 @@ async function updateProfile(user, body) { if (!updateUser) return false; return true; } else { - let hash = await hashPassword(body.password); + let hashed = await hash(body.password); let updateUser = await userModel.update( { firstname: body.first_name, @@ -134,7 +151,7 @@ async function updateProfile(user, body) { email: body.email, address: body.address, phone: body.phone, - password: hash, + password: hashed, }, { where: { @@ -152,5 +169,4 @@ module.exports = { addUser, loginUser, updateProfile, - addAPIKey, -}; +}; \ No newline at end of file diff --git a/consumerWebsite/functions/validateData.js b/consumerWebsite/functions/validateData.js index d95fa58..d3f255f 100644 --- a/consumerWebsite/functions/validateData.js +++ b/consumerWebsite/functions/validateData.js @@ -1,5 +1,27 @@ var validator = require("validator"); +const dateRegex = /^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/; + +function isValidDateString(value) { + return dateRegex.test(value); +} + + +function isMacAddress(value) { + // Joi.string().regex(/^([0-9a-f]{2}-){5}([0-9a-f]{2})$/i).lowercase() + //return validator.isMACAddress(value, { no_separators: true, eui: 48 }); + const macAddress = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/; + const valid = macAddress.test(value); + return valid; +} + + +function isNumber(value) { + if (typeof value === "number") { + return true; + } +} + function isAlphaNumericwithSpaces(value) { return validator.isAlphanumeric(value, ["en-US"], { ignore: " " }); } @@ -16,7 +38,6 @@ function isAlphaNumericWithSpacesAndDash(value) { function isJson(value) { //check if its object if(typeof value === "object"){ - console.log("its an object") return true } @@ -44,6 +65,8 @@ module.exports = { isAlphaNumericwithSpaces, isAlphaNumericWithSpacesAndDash, isJson, - isAddress -}; - + isAddress, + isValidDateString, + isMacAddress, + isNumber, +}; \ No newline at end of file diff --git a/webserver/middleware/apiKey.js b/consumerWebsite/middleware/apiKey.js similarity index 96% rename from webserver/middleware/apiKey.js rename to consumerWebsite/middleware/apiKey.js index 042514d..4d91dcb 100644 --- a/webserver/middleware/apiKey.js +++ b/consumerWebsite/middleware/apiKey.js @@ -1,4 +1,4 @@ -const { checkAPikey } = require("../functions/database.js"); +const { checkAPikey } = require("../functions/api.js"); async function apikeyCheck(req, res, next) { //const authHeader = req.headers.authorization try { diff --git a/webserver/middleware/apiLogger.js b/consumerWebsite/middleware/apiLogger.js similarity index 93% rename from webserver/middleware/apiLogger.js rename to consumerWebsite/middleware/apiLogger.js index bfe7f2f..21c3e33 100644 --- a/webserver/middleware/apiLogger.js +++ b/consumerWebsite/middleware/apiLogger.js @@ -1,4 +1,4 @@ -const { insertLogData } = require("../functions/database.js"); +const { insertLogData } = require("../functions/logger.js"); const APIlogger = (req, res, next) => { try { const log = { diff --git a/consumerWebsite/middleware/authChecker.js b/consumerWebsite/middleware/authChecker.js index 3f77691..7855998 100644 --- a/consumerWebsite/middleware/authChecker.js +++ b/consumerWebsite/middleware/authChecker.js @@ -1,6 +1,6 @@ const { apikeyModel } = require("../database/model/apiKeyModel"); const { userModel } = require("../database/model/userModel"); -const { comparePassword } = require("../functions/bcrypt"); +const { compareHash } = require("../functions/bcrypt"); async function auth(req, res, next){ try{ @@ -15,7 +15,7 @@ async function auth(req, res, next){ if (!token) return false; //compare - let isMatch = await comparePassword(suppliedToken, token.apikey); + let isMatch = await compareHash(suppliedToken, token.apikey); if (!isMatch) return false; //else do logic @@ -28,4 +28,4 @@ async function auth(req, res, next){ } } -module.exports = { auth }; +module.exports = { auth }; \ No newline at end of file diff --git a/webserver/modules/mqtt.js b/consumerWebsite/modules/mqtt.js similarity index 95% rename from webserver/modules/mqtt.js rename to consumerWebsite/modules/mqtt.js index f5f9e4a..26b347b 100644 --- a/webserver/modules/mqtt.js +++ b/consumerWebsite/modules/mqtt.js @@ -17,6 +17,4 @@ const options = { const client = mqtt.connect(brokerUrl, options); -module.exports = client; - - +module.exports = client; \ No newline at end of file diff --git a/webserver/index.js b/consumerWebsite/mqttApp.js similarity index 87% rename from webserver/index.js rename to consumerWebsite/mqttApp.js index c3c7fa8..2b13ef8 100644 --- a/webserver/index.js +++ b/consumerWebsite/mqttApp.js @@ -1,6 +1,6 @@ -const client = require("./modules/mqtt"); +const client = require("./modules/mqtt.js"); const { isJson, isNumber } = require("./functions/validateData.js"); -const { insertDatatoDB } = require("./functions/database.js"); +const { addSensorData } = require("./functions/sensorData"); // Event handlers client.on("connect", () => { @@ -37,7 +37,7 @@ client.on("message", (topic, message) => { if (isNumber(data)) { { //pass datas to database - insertDatatoDB(datas[key]); + addSensorData(datas[key].sensorid, datas[key].locationid, datas[key]); } } else { @@ -63,3 +63,4 @@ client.on("end", () => { console.log("Disconnected from MQTT broker"); client.reconnect(); }); + diff --git a/consumerWebsite/public/js/app.js b/consumerWebsite/public/js/app.js index eed6158..5aed168 100644 --- a/consumerWebsite/public/js/app.js +++ b/consumerWebsite/public/js/app.js @@ -144,17 +144,19 @@ app.api = (function (app) { return { post: post, get: get, put: put, delete: remove }; })(app); +//socket.io //socket.io app.socket = (function (app) { //need to replace with domain name of server when published - var socket = io("localhost", { - transports: ["websocket"], - 'Access-Control-Allow-Origin': 'http://localhost:3000', - }); + var socket = io(); socket.on("disconnect", () => { console.log("disconnected"); }); + socket.on('connect', ()=>{ + console.info('WS connected'); + }) + socket.io.on("reconnect", () => { console.log("reconnected"); }); @@ -163,7 +165,6 @@ app.socket = (function (app) { }); return socket; })(app); - //sensor data app.sensordata = (function (app) { diff --git a/consumerWebsite/routes/api_routes.js b/consumerWebsite/routes/api_routes.js index 4edf988..080c427 100644 --- a/consumerWebsite/routes/api_routes.js +++ b/consumerWebsite/routes/api_routes.js @@ -1,3 +1,31 @@ +'use strict'; +const router = require('express').Router(); +const { auth } = require("../middleware/authChecker") +const { APIlogger } = require('../middleware/apiLogger.js'); +const { apikeyCheck } = require('../middleware/apiKey.js'); + +router.use('/auth', require('./auth')); + +router.use('/apikey', require('./apikey')); + +router.use('/user', [auth, APIlogger], require('./user')); + +//TO REFACTOR INTO ONE MIDDLWARE + +//location route +router.use('/location', [apikeyCheck , APIlogger], require('./location.js')); + +//location route +router.use('/sensor', [apikeyCheck , APIlogger], require('./sensor.js')); + +//location route +router.use('/sensor-data', [apikeyCheck, APIlogger], require('./sensorData.js')); + +module.exports = router; + + +/* + 'use strict'; const router = require('express').Router(); const { auth } = require("../middleware/authChecker") @@ -12,3 +40,4 @@ router.use('/user', auth ,require('./user')); module.exports = router; +*/ \ No newline at end of file diff --git a/consumerWebsite/routes/apikey.js b/consumerWebsite/routes/apikey.js index 3ee6c43..521cfdb 100644 --- a/consumerWebsite/routes/apikey.js +++ b/consumerWebsite/routes/apikey.js @@ -1,19 +1,9 @@ -const { getAPIKey , addAPIKey } = require("../functions/apiDatabase.js"); +const { addAPIKey } = require("../functions/api"); const express = require("express"); const router = express.Router(); -router.get("/", async (req, res, next) => { - try { - const location = await getAPIKey(); - res.status(200).json(location); - } catch (error) { - console.error(error); - next(error); - } -}); - /* 1) ensure user is logged in (frontend session validation blah or wtv) 2) when user click on generate api key button, it will generate a random api key. how to get userid can be done by session or wtv @@ -34,9 +24,6 @@ router.post("/new", async (req, res, next) => { } }); -//update -//delete -//getbyid module.exports = router; diff --git a/consumerWebsite/routes/auth.js b/consumerWebsite/routes/auth.js index 2484c16..863d863 100644 --- a/consumerWebsite/routes/auth.js +++ b/consumerWebsite/routes/auth.js @@ -1,4 +1,4 @@ -const { addUser, loginUser } = require("../functions/apiDatabase.js"); +const { addUser, loginUser } = require("../functions/user"); const express = require("express"); const router = express.Router(); diff --git a/webserver/routes/Location.js b/consumerWebsite/routes/location.js similarity index 97% rename from webserver/routes/Location.js rename to consumerWebsite/routes/location.js index 486cff9..cc7ce2b 100644 --- a/webserver/routes/Location.js +++ b/consumerWebsite/routes/location.js @@ -4,7 +4,7 @@ const { getLocationById, updateLocation, deleteLocation, -} = require("../functions/apiDatabase.js"); +} = require("../functions/location"); const express = require("express"); const router = express.Router(); diff --git a/consumerWebsite/routes/render.js b/consumerWebsite/routes/render.js index d347453..8e6f74b 100644 --- a/consumerWebsite/routes/render.js +++ b/consumerWebsite/routes/render.js @@ -87,5 +87,9 @@ router.get("/api", function (req, res, next) { res.render("api"); }); +// sensor data +router.get("/sensor-data", function (req, res, next) { + res.render("sensor-data"); +}); -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/webserver/routes/SeedLocationAndSensor.js b/consumerWebsite/routes/seedLocationAndSensor.js similarity index 86% rename from webserver/routes/SeedLocationAndSensor.js rename to consumerWebsite/routes/seedLocationAndSensor.js index 11c2aa3..a092f9e 100644 --- a/webserver/routes/SeedLocationAndSensor.js +++ b/consumerWebsite/routes/seedLocationAndSensor.js @@ -1,6 +1,6 @@ -const { sequelize } = require("../Database/mySql.js"); -const { locationModel } = require("../Database/model/locationModel.js"); -const { sensorModel } = require("../Database/model/sensorModel.js"); +const { sequelize } = require("../database/mySQL.js"); +const { locationModel } = require("../database/model/locationModel.js"); +const { sensorModel } = require("../database/model/sensorModel.js"); const express = require("express"); const router = express.Router(); @@ -38,4 +38,4 @@ router.post("/new", async (req, res, next) => { -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/consumerWebsite/routes/seed_route.js b/consumerWebsite/routes/seed_route.js new file mode 100644 index 0000000..b10714d --- /dev/null +++ b/consumerWebsite/routes/seed_route.js @@ -0,0 +1,14 @@ +'use strict'; +const router = require('express').Router(); + +//location route +router.use('/seedSensorData', require('./seedsensorData.js')); + +router.use('/seed', require('./seedLocationAndSensor.js')); + + + + + + +module.exports = router; \ No newline at end of file diff --git a/webserver/routes/SeedsensorData.js b/consumerWebsite/routes/seedsensorData.js similarity index 93% rename from webserver/routes/SeedsensorData.js rename to consumerWebsite/routes/seedsensorData.js index 7bfaec7..8504935 100644 --- a/webserver/routes/SeedsensorData.js +++ b/consumerWebsite/routes/seedsensorData.js @@ -1,7 +1,7 @@ -const { sequelize } = require("../Database/mySql.js"); -const { locationModel } = require("../Database/model/locationModel.js"); -const { sensorModel } = require("../Database/model/sensorModel.js"); -const { sensorDataModel } = require("../Database/model/sensorDataModel.js"); +const { sequelize } = require("../database/mySQL.js"); +const { locationModel } = require("../database/model/locationModel.js"); +const { sensorModel } = require("../database/model/sensorModel.js"); +const { sensorDataModel } = require("../database/model/sensorDataModel.js"); const express = require("express"); const router = express.Router(); diff --git a/webserver/routes/Sensor.js b/consumerWebsite/routes/sensor.js similarity index 95% rename from webserver/routes/Sensor.js rename to consumerWebsite/routes/sensor.js index cc1c076..dea9ca9 100644 --- a/webserver/routes/Sensor.js +++ b/consumerWebsite/routes/sensor.js @@ -4,7 +4,7 @@ const { updateSensor, deleteSensor, getSensorById -} = require("../functions/apiDatabase.js"); +} = require("../functions/sensor.js"); const express = require("express"); const router = express.Router(); @@ -63,4 +63,4 @@ router.get("/:id", async (req, res, next) => { } }); -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/webserver/routes/SensorData.js b/consumerWebsite/routes/sensorData.js similarity index 86% rename from webserver/routes/SensorData.js rename to consumerWebsite/routes/sensorData.js index c54717d..c3862f5 100644 --- a/webserver/routes/SensorData.js +++ b/consumerWebsite/routes/sensorData.js @@ -6,10 +6,9 @@ const { getSensorDataById, getData, getDatabyRange, -} = require("../functions/apiDatabase.js"); +} = require("../functions/sensorData"); const express = require("express"); -const { json } = require("body-parser"); const router = express.Router(); router.get("/", async (req, res, next) => { @@ -24,9 +23,9 @@ router.get("/", async (req, res, next) => { router.post("/new", async (req, res, next) => { try { - const { id, id_sensor, id_location, sensordata } = req.body; - await addSensorData(id, id_sensor, id_location, sensordata); - res.sendStatus(200).json({ message: "SensorData " + id + " added" }); + const { id_sensor, id_location, sensordata } = req.body; + let data = await addSensorData(id_sensor, id_location, sensordata); + res.json({ message: "SensorData " + data.id + " added", ...data }); } catch (error) { console.error(error); next(error); @@ -91,4 +90,3 @@ router.get("/:id", async (req, res, next) => { }); module.exports = router; - diff --git a/consumerWebsite/routes/user.js b/consumerWebsite/routes/user.js index 03913fd..474b905 100644 --- a/consumerWebsite/routes/user.js +++ b/consumerWebsite/routes/user.js @@ -1,4 +1,4 @@ -const { getUserID, updateProfile } = require("../functions/apiDatabase.js"); +const { getUserID, updateProfile } = require("../functions/user"); const express = require("express"); const router = express.Router(); diff --git a/consumerWebsite/views/index.ejs b/consumerWebsite/views/index.ejs index c31da5b..921e105 100644 --- a/consumerWebsite/views/index.ejs +++ b/consumerWebsite/views/index.ejs @@ -2,6 +2,7 @@ +<%- include('bot') %> \ No newline at end of file diff --git a/webserver/database/model/apiKeyModel.js b/webserver/database/model/apiKeyModel.js deleted file mode 100644 index 69e45d9..0000000 --- a/webserver/database/model/apiKeyModel.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -const { Sequelize, DataTypes } = require("sequelize"); -const { sequelize } = require("../mySQL"); -const { userModel } = require("./userModel"); - -//sequelize.sync(); -const apikeyModel = sequelize.define( - "apikey", - { - id: { - type: DataTypes.INTEGER, - allowNull: true, - primaryKey: true, - autoIncrement: true, - validate: { - isNumeric: true, - }, - }, - userid: { - type: DataTypes.INTEGER, - allowNull: false, - validate: { - isNumeric: true, - }, - //fk - references: { - model: userModel, - key: "id", - }, - }, - apikey: { - type: DataTypes.STRING, - allowNull: false, - length: 255, - unique: true, - validate: { - notEmpty: true, - len: [1, 255], - }, - }, - permission: { - type: DataTypes.STRING, - allowNull: false, - length: 255, - validate: { - notEmpty: true, - len: [1, 255], - isIn: [["canRead", "canWrite" , "auto-generated"]], - }, - }, - createdAt: { - type: DataTypes.DATE, - allowNull: true, - }, - updatedAt: { - type: DataTypes.DATE, - allowNull: true, - }, - }, - { - timestamps: true, - } -); - -module.exports = { apikeyModel }; diff --git a/webserver/database/model/userModel.js b/webserver/database/model/userModel.js deleted file mode 100644 index 561890c..0000000 --- a/webserver/database/model/userModel.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; -const { Sequelize, DataTypes } = require("sequelize"); -const { sequelize } = require("../mySQL"); -const { - isAlphaNumericWithSpacesAndDash, - isAddress, -} = require("../../functions/validateData"); - -//sequelize.sync(); -const userModel = sequelize.define( - "user", - { - id: { - type: DataTypes.INTEGER, - allowNull: true, - primaryKey: true, - autoIncrement: true, - validate: { - isNumeric: true, - }, - }, - username: { - type: DataTypes.STRING, - allowNull: false, - length: 60, - validate: { - notEmpty: true, - len: [1, 60], - isAlphaNumericWithSpacesAndDash(value) { - if (!isAlphaNumericWithSpacesAndDash(value)) { - throw new Error("Invalid characters in username"); - } - }, - }, - }, - password: { - type: DataTypes.STRING, - allowNull: false, - length: 255, - validate: { - notEmpty: true, - len: [1, 255], - }, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - length: 60, - unique: true, - validate: { - notEmpty: true, - len: [1, 60], - isEmail: true, - }, - }, - address: { - type: DataTypes.STRING, - allowNull: true, - length: 255, - validate: { - notEmpty: true, - len: [1, 255], - isAddress(value) { - if (!isAddress(value)) { - throw new Error("Invalid address"); - } - }, - }, - }, - phone: { - type: DataTypes.STRING, - allowNull: true, - length: 20, - validate: { - notEmpty: true, - len: [1, 20], - isNumeric: true, - }, - }, - //utc time - createdAt: { - type: DataTypes.DATE, - allowNull: true, - }, - updatedAt: { - type: DataTypes.DATE, - allowNull: true, - }, - }, - { - timestamps: true, - } -); -module.exports = { userModel }; diff --git a/webserver/database/mySQL.js b/webserver/database/mySQL.js deleted file mode 100644 index 9b2f098..0000000 --- a/webserver/database/mySQL.js +++ /dev/null @@ -1,35 +0,0 @@ -const dotenv = require("dotenv"); -const path = require('path') -require('dotenv').config({ path: path.resolve(__dirname, '../../.env') }) -const Sequelize = require("sequelize"); -const fs = require('fs'); -const { escape } = require("querystring"); - -const sequelize = new Sequelize( - "eco_saver", - process.env.DB_USER, - process.env.DB_PASS, - { - host: "mpsqldatabase.mysql.database.azure.com", - dialect: 'mysql', - // attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy'; - attributeBehavior: 'escape', - dialectOptions: { - ssl: { - ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt.pem')), - }, - - }, - }, - - -); - -sequelize.authenticate().then(() => { - console.log('Connection has been established successfully.'); -}).catch((error) => { - console.error('Unable to connect to the database: ', error); -}); - -module.exports = { sequelize }; - diff --git a/webserver/functions/Database.js b/webserver/functions/Database.js deleted file mode 100644 index e401ada..0000000 --- a/webserver/functions/Database.js +++ /dev/null @@ -1,59 +0,0 @@ -const { sequelize } = require("../Database/mySql.js"); -const { api_log_Model } = require("../Database/model/apiLogModel.js"); -const { sensorDataModel } = require("../Database/model/sensorDataModel.js"); -const { apikeyModel } = require("../Database/model/apiKeyModel.js"); -const { compareAPIKey } = require("./bcrypt.js"); - -async function insertLogData(log) { - try { - api_log_Model.create({ - ip: log.ip, - time: log.time, - method: log.method, - host: log.host, - statusCode: log.statusCode, - Responsesize: log.Responsesize, - referrer: log.referrer, - userAgent: log.userAgent, - }); - } catch (error) { - console.error(error); - } -} - -async function insertDatatoDB(data) { - try { - const app = require("../modules/express.js"); - - sensorDataModel.create({ - sensorid: data.sensorid, - locationid: data.locationid, - measurement: data.measurement, - }); - //ws broadcast event except to the sender. - app.io.emit("sensorData:new", data); - } catch (error) { - console.error(error); - } -} - -async function checkAPikey(SuppliedKey, rowid) { - try { - const retrivedKey = await apikeyModel.findOne({ - raw: true, - attributes: ["apikey", "permission"], - where: { - id: rowid, - }, - }); - //console.log(retrivedKey.apikey); - if (compareAPIKey(SuppliedKey, retrivedKey.apikey)) { - //return true; - return retrivedKey.permission; - } - } catch (error) { - console.error(error); - } -} - -module.exports = { insertLogData, insertDatatoDB, checkAPikey }; diff --git a/webserver/functions/bcrypt.js b/webserver/functions/bcrypt.js deleted file mode 100644 index 34afc86..0000000 --- a/webserver/functions/bcrypt.js +++ /dev/null @@ -1,38 +0,0 @@ -const bcrypt = require('bcrypt'); -const saltRounds = 10; -//https://github.com/kelektiv/node.bcrypt.js#readme - - -/* -// Load hash from your password DB. -bcrypt.compare(myPlaintextPassword, hash, function(err, result) { - // result == true -}); -bcrypt.compare(someOtherPlaintextPassword, hash, function(err, result) { - // result == false -}); -*/ - - -/* -//hash with salt -bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) { - // Store hash in your password DB. -}); - -*/ - -async function hashAPIKey(apikey) { - return await bcrypt.hash(apikey, saltRounds); -} - -async function compareAPIKey(apikey, hash) { - return await bcrypt.compare(apikey, hash); -} - - - -module.exports = { - hashAPIKey, - compareAPIKey -}; \ No newline at end of file diff --git a/webserver/functions/getAPIKey.js b/webserver/functions/getAPIKey.js deleted file mode 100644 index 4c62ddc..0000000 --- a/webserver/functions/getAPIKey.js +++ /dev/null @@ -1,17 +0,0 @@ -//model for getting API key from database - -async function getAPIKey() { - - -} - - - - - - - - - - -module.exports = { getAPIKey } \ No newline at end of file diff --git a/webserver/functions/validateData.js b/webserver/functions/validateData.js deleted file mode 100644 index 33ad8e1..0000000 --- a/webserver/functions/validateData.js +++ /dev/null @@ -1,51 +0,0 @@ -var validator = require("validator"); - -const dateRegex = /^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/; - -function isValidDateString(value) { - return dateRegex.test(value); -} - -function isAlphaNumericwithSpaces(value) { - return validator.isAlphanumeric(value, ["en-US"], { ignore: " " }); -} - -//allow alphanumeric and spaces and - -function isAlphaNumericWithSpacesAndDash(value) { - const alphanumeric = /^[a-zA-Z0-9]+$/; - const valid = value - .split("") - .every((char) => alphanumeric.test(char) || char === " " || char === "-"); - return valid; -} - -function isMacAddress(value) { - // Joi.string().regex(/^([0-9a-f]{2}-){5}([0-9a-f]{2})$/i).lowercase() - //return validator.isMACAddress(value, { no_separators: true, eui: 48 }); - const macAddress = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/; - const valid = macAddress.test(value); - return valid; -} - -function isJson(value) { - //check if its object - if(typeof value === "object"){ - return true - } -} - -function isNumber(value) { - if (typeof value === "number") { - return true; - } -} - -module.exports = { - isValidDateString, - isAlphaNumericwithSpaces, - isAlphaNumericWithSpacesAndDash, - isMacAddress, - isJson, - isNumber, -}; - diff --git a/webserver/modules/express.js b/webserver/modules/express.js deleted file mode 100644 index 80a497b..0000000 --- a/webserver/modules/express.js +++ /dev/null @@ -1,91 +0,0 @@ -const express = require("express"); -//const helmet = require("helmet"); -var cors = require('cors'); -const { rateLimit } = require("express-rate-limit"); -const { APIlogger } = require('../middleware/apiLogger.js'); -const { apikeyCheck } = require('../middleware/apiKey.js'); - -const app = express(); -//app.use(cors()); -//allow cors from localhost:3000 -//app.use(helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } })); -const port = 80; - -// Hold list of functions to run when the server is ready -app.onListen = [function(){console.log('hello')}]; - -module.exports = app; - -//handle cors - - -//express-rate-limit stolen from docs -const limiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - limit: 600, // Limit each IP to 100 requests per `window` (here, per 15 minutes). - standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header - legacyHeaders: false, // Disable the `X-RateLimit-*` headers. -}) - - -// Apply the rate limiting middleware to all requests. -app.use(limiter) - -//disable x-powered-by header for security reasons -app.disable("x-powered-by"); - -//parse json body format -app.use(express.json()); -app.set("json spaces", 2); - - -/* -middleware logic ( called by next() ) -*/ -app.use("/api/seed/v0", [ apikeyCheck , APIlogger] ,require("../routes/seed_route.js")); -app.use('/api/v0', [apikeyCheck, APIlogger] ,require("../routes/api_route.js")); - - - -// Catch 404 and forward to error handler. If none of the above routes are -// used, this is what will be called. -app.use(function (req, res, next) { - var err = new Error("Not Found"); - err.message = "Page not found"; - err.status = 404; - next(err); -}); - -// Error handler. This is where `next()` will go on error -app.use(function(err, req, res, next) { - console.error(err.status || res.status, err.name, req.method, req.url); - if(![ 404].includes(err.status || res.status)){ - console.error(err.message); - console.error(err.stack); - console.error('========================================='); - } - - console.log(err.name + " validation error"); - // Parse key error for Sequilzw - let keyErrors = {} - if(['SequelizeValidationError'].includes(err.name) && err.errors){ - for(let item of err.errors){ - if(item.path){ - keyErrors[item.path] = item.message - } - } - } - - res.status(err.status || 500); - console.log(keyErrors); - res.json({ - name: err.name, - message: err.message, - keyErrors, - }); - }); -/* -app.listen(port, () => { - console.log(`app listening on port ${port}`); -}); -*/ diff --git a/webserver/routes/apiLog.js b/webserver/routes/apiLog.js deleted file mode 100644 index 80ed39a..0000000 --- a/webserver/routes/apiLog.js +++ /dev/null @@ -1,77 +0,0 @@ -const { - -} = require("../functions/apiDatabase.js"); - -const express = require("express"); -const router = express.Router(); - - - -module.exports = router; - -/* - -//get location -router.get("/", async (req, res, next) => { - try { - const location = await getLocation(); - //res send json and status code - res.status(200).json(location); - } catch (error) { - console.error(error); - next(error); - } -}); - - -//add location -router.post("/new", async (req, res, next) => { - try { - const { name, added_by, description } = req.body; - await addLocation(name, added_by, description); - res.sendStatus(200) - } catch (error) { - console.error(error); - next(error); - } -}); - -//update location -router.put("/update", async (req, res, next) => { - try { - const { id, name, added_by, description } = req.body; - await updateLocation(id, name, added_by, description); - res.status(200).json({ message: "Location " + id + " updated" }); - } catch (error) { - console.error(error); - next(error); - } -}); - -//delete location -router.delete("/delete", async (req, res, next) => { - try { - const { id } = req.body; - await deleteLocation(id); - res.status(200).json({ message: "Location " + id + " deleted" }); - } catch (error) { - console.error(error); - next(error); - } -}); - - - -//get location by id -router.get("/:id", async (req, res, next) => { - try { - //get params - const { id } = req.params; - const location = await getLocationById(id); - res.status(200).json(location); - } catch (error) { - console.error(error); - next(error); - } -}); -*/ \ No newline at end of file diff --git a/webserver/routes/api_route.js b/webserver/routes/api_route.js deleted file mode 100644 index 1144957..0000000 --- a/webserver/routes/api_route.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -'use strict'; - -const router = require('express').Router(); -const middleware = require('../middleware/auth'); - -router.use('/runner', require('./runner')); -router.use('/worker', require('./worker')); -router.use('/auth', require('./auth')); -router.use('/user', middleware.auth, require('./user')); -router.use('/token',middleware.auth, require('./token')); - -module.exports = router; - -*/ - -'use strict'; -const router = require('express').Router(); - -//location route -router.use('/location', require('./location')); - -//sensor route -router.use('/sensor', require('./sensor')) - -//sensor data route -router.use('/sensor-data', require('./sensorData')); - -//log route -//router.use('/log', require('./logLog')); - - - - - - -module.exports = router; \ No newline at end of file diff --git a/webserver/routes/seed_route.js b/webserver/routes/seed_route.js deleted file mode 100644 index e89f904..0000000 --- a/webserver/routes/seed_route.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -const router = require('express').Router(); - -//location route -router.use('/seedSensorData', require('./seedSensorData.js')); - -router.use('/seed', require('./seedLocationAndSensor')); - - - - - - -module.exports = router; \ No newline at end of file