From d38423fa6d3d63e7f6e82cd5f227865ae9e57e66 Mon Sep 17 00:00:00 2001 From: newtbot Date: Fri, 26 Jan 2024 04:07:11 +0800 Subject: [PATCH] Update CSS, add relationship between sensorModel and locationModel, and remove console.log statements --- IoT-sensor/Database/mySQL.js | 6 +- api.MD | 2 +- consumerWebsite/app.js | 77 +++++++------ consumerWebsite/database/model/sensorModel.js | 2 + consumerWebsite/database/model/tokenModel.js | 2 +- consumerWebsite/database/mySQL.js | 4 +- consumerWebsite/functions/api.js | 65 ++++++----- consumerWebsite/functions/isValid.js | 26 ++--- consumerWebsite/functions/sensorData.js | 23 +++- consumerWebsite/functions/user.js | 9 +- consumerWebsite/middleware/authChecker.js | 60 +++------- consumerWebsite/public/css/all.css | 1 + consumerWebsite/public/js/app.js | 2 - consumerWebsite/routes/api_routes.js | 3 + consumerWebsite/routes/latestsensorData.js | 21 ++++ consumerWebsite/routes/user.js | 2 +- consumerWebsite/views/index.ejs | 106 ++++++++++-------- consumerWebsite/views/sensor-data.ejs | 5 +- consumerWebsite/views/top.ejs | 2 - 19 files changed, 213 insertions(+), 205 deletions(-) create mode 100644 consumerWebsite/routes/latestsensorData.js diff --git a/IoT-sensor/Database/mySQL.js b/IoT-sensor/Database/mySQL.js index 255dc3a..0f86d40 100644 --- a/IoT-sensor/Database/mySQL.js +++ b/IoT-sensor/Database/mySQL.js @@ -9,13 +9,13 @@ const sequelize = new Sequelize( process.env.DB_USER, process.env.DB_PASS, { - host: "mpsqldatabase.mysql.database.azure.com", - dialect: 'mysql', + host: "mpsqldatabasean.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')), + ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt_3.pem')), }, }, diff --git a/api.MD b/api.MD index c435b69..f6f8514 100644 --- a/api.MD +++ b/api.MD @@ -172,4 +172,4 @@ http://localhost/api/v0/sensor-data/data?week=1&sensorid=1&locationid=1&page=2&p curl localhost/api/v0/user/register -H "Content-Type: application/json" -X POST -d '{"username": "testuser123", "password": "thisisthesystemuserpasswordnoob", "email": "testuser123@ecosaver.com", "address": "Nanyang Polytechnic 180 Ang Mo Kio Avenue 8 Singapore 569830", "phone": "12345678"}' -curl localhost:3000/api/v0/token/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}' +curl localhost/api/v0/token/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}' diff --git a/consumerWebsite/app.js b/consumerWebsite/app.js index f8dc2a8..b214bc3 100644 --- a/consumerWebsite/app.js +++ b/consumerWebsite/app.js @@ -50,49 +50,48 @@ 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. app.use(function (req, res, next) { - //application/json; charset=utf-8 - if (req.is("application/json" || "application/json; charset=utf-8")) { - var err = new Error("Not Found"); - err.message = "Page not found"; - err.status = 404; - next(err); - } else { - res.status(404).render("404"); - } + //application/json; charset=utf-8 + 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.error(err.status || res.status, err.name, req.method, req.url); - 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 = 422; - } + // 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 = 422; + } - if (![404, 422].includes(err.status || res.status)) { - console.error(err.message); - console.error(err.stack); - console.error("========================================="); - } + if (![404, 401, 422].includes(err.status || res.status)) { + console.error(err.message); + console.error(err.stack); + console.error("========================================="); + } + res.status(err.status || 500); + // res.status(err.status || 500); - - res.status(err.status || 500); - res.json({ - name: err.name || "Unknown error", - message: err.message, - keyErrors, - }); -}); + if (req.get('Content-Type') && req.get('Content-Type').includes("json")) { + res.json({ + name: err.name || "Unknown error", + message: err.message, + keyErrors, + }); + } + else { + res.json({ + name: err.name || "Unknown error", + message: err.message, + keyErrors, + }); + } +}); \ No newline at end of file diff --git a/consumerWebsite/database/model/sensorModel.js b/consumerWebsite/database/model/sensorModel.js index 769c0dc..d1eb2c3 100644 --- a/consumerWebsite/database/model/sensorModel.js +++ b/consumerWebsite/database/model/sensorModel.js @@ -107,4 +107,6 @@ const sensorModel = sequelize.define( } ); +sensorModel.belongsTo(locationModel); + module.exports = { sensorModel }; diff --git a/consumerWebsite/database/model/tokenModel.js b/consumerWebsite/database/model/tokenModel.js index 26ec8af..17e6e4e 100644 --- a/consumerWebsite/database/model/tokenModel.js +++ b/consumerWebsite/database/model/tokenModel.js @@ -3,7 +3,7 @@ const { Sequelize, DataTypes } = require("sequelize"); const { sequelize } = require("../mySQL"); const { userModel } = require("./userModel"); -//sequelize.sync(); +sequelize.sync(); const tokenModel = sequelize.define( "token", { diff --git a/consumerWebsite/database/mySQL.js b/consumerWebsite/database/mySQL.js index 255dc3a..6bba43b 100644 --- a/consumerWebsite/database/mySQL.js +++ b/consumerWebsite/database/mySQL.js @@ -9,13 +9,13 @@ const sequelize = new Sequelize( process.env.DB_USER, process.env.DB_PASS, { - host: "mpsqldatabase.mysql.database.azure.com", + host: "mpsqldatabasean.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')), + ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt_3.pem')), }, }, diff --git a/consumerWebsite/functions/api.js b/consumerWebsite/functions/api.js index fcba1f3..5422d8b 100644 --- a/consumerWebsite/functions/api.js +++ b/consumerWebsite/functions/api.js @@ -1,19 +1,41 @@ -const { hash, compareHash } = require("./bcrypt.js"); const { tokenModel } = require("../database/model/tokenModel.js"); +const { userModel } = require("../database/model/userModel"); +const { hash, compareHash } = require("./bcrypt.js"); const { generateUUID } = require("./generateUUID.js"); +const { isValid } = require("./isValid"); -/* -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 addToken(userId, permission , expiry) { +async function getTokenByToken(token) { + const splitAuthToken = token.split("-"); + const rowid = splitAuthToken[0]; + const suppliedToken = splitAuthToken.slice(1).join("-"); + + token = await tokenModel.findByPk(rowid, { include: userModel }); + + token.isValid = await compareHash(suppliedToken, token.token); //true + console.log("function api getTokenByToken token", token.isValid); + token.isValid = token.isValid && isValid(token.expiration); + console.log("function api getTokenByToken token", token.isValid); + if (!token.isValid) { + //add boolean to token table + token.destroy(); + } + /* + console.log( + "function api getTokenByToken token", + await compareHash(suppliedToken, token.token), + isValid("token" , token.expiration) + ); + */ + console.log(token.isValid); + return token; +} + +async function addToken(userId, permission, expiry) { let uuid = await generateUUID(); let hashtoken = await hash(uuid); + //console.log("user id", userId); + // return { token: token, userid: userRes.id, username: userRes.username }; + // let token = await addToken(userRes.id , "canRead" , tokenToLive); let token = await tokenModel.create({ userid: userId, @@ -26,23 +48,4 @@ async function addToken(userId, permission , expiry) { return token.id + "-" + uuid; } -async function checkToken(Supplied, rowid) { - try { - const retrivedToken = await tokenModel.findOne({ - raw: true, - attributes: ["token", "permission"], - where: { - id: rowid, - }, - }); - //console.log(retrivedKey.apikey); - if (compareHash(Supplied, retrivedToken.token)) { - //return true; - return retrivedToken.permission; - } - } catch (error) { - console.error(error); - } -} - -module.exports = { addToken , checkToken }; \ No newline at end of file +module.exports = { addToken, getTokenByToken }; diff --git a/consumerWebsite/functions/isValid.js b/consumerWebsite/functions/isValid.js index 2d79e13..ae39ce1 100644 --- a/consumerWebsite/functions/isValid.js +++ b/consumerWebsite/functions/isValid.js @@ -1,20 +1,14 @@ -const moment = require("moment"); -const currentTime = moment().format("YYYY-MM-DD HH:mm:ss"); - //time is taken from the token -function isValid(time){ - const timeDiff = moment(currentTime).diff(time, "minutes"); - - if (timeDiff > 1) { - console.log(timeDiff); - return false; - } - - return true; +function isValid(time) { + if ( + Math.floor(new Date(time).getTime() / 1000) < + Math.floor(new Date().getTime() / 1000) + ) { + return false; + } + return true; + } - - - -module.exports = { isValid }; \ No newline at end of file +module.exports = { isValid }; diff --git a/consumerWebsite/functions/sensorData.js b/consumerWebsite/functions/sensorData.js index 28cf3a0..f59c28b 100644 --- a/consumerWebsite/functions/sensorData.js +++ b/consumerWebsite/functions/sensorData.js @@ -18,15 +18,19 @@ async function getSensorData() { const sensorData = await sensorDataModel.findAll(); return sensorData; } - +let dataArray = []; async function addSensorData(id_sensor, id_location, sensordata) { const sensorData = await sensorDataModel.create({ sensorid: id_sensor, - locationid: id_location, - measurement: sensordata, + locationid: id_location , + measurement: sensordata.measurement, }); - io().emit('sensorData:new', sensorData) - + //console.log("sensorData", sensorData); + //console.log("sensorData", sensordata); + dataArray.push(sensordata); + console.log("dataArray", dataArray); + + io().emit('sensorData:new', dataArray) return sensorData; } @@ -61,6 +65,14 @@ async function getSensorDataById(id) { }); return sensorData; } + +async function getLatestData() { + const sensorData = await sensorDataModel.findAll({ + limit: 1, + order: [["createdAt", "DESC"]], + }); + return sensorData; +} var ormQuery = {}; var whereClause = {}; var whereDate = {}; @@ -724,5 +736,6 @@ module.exports = { getSensorDataById, getData, getDatabyRange, + getLatestData, }; \ No newline at end of file diff --git a/consumerWebsite/functions/user.js b/consumerWebsite/functions/user.js index a7d16d1..c94e183 100644 --- a/consumerWebsite/functions/user.js +++ b/consumerWebsite/functions/user.js @@ -2,7 +2,6 @@ const { Op } = require('sequelize') const { hash, compareHash } = require("./bcrypt.js"); const { addToken } = require("./api"); const { userModel } = require("../database/model/userModel"); -moment = require('moment') @@ -71,9 +70,11 @@ async function loginUser(user) { if (!match) return false; //console.log('loginUser', userRes.id, userRes.username); - //generate token and permission and experiation time - const currentTime = moment().format('YYYY-MM-DD HH:mm:ss'); - let token = await addToken(userRes.id , "canRead" , currentTime); + //generate token and permission and experiation time + 30 mins + //let tokenToLive = moment().add(30, 'minutes').format(); + let currentDate = new Date(); + let tokenToLive = new Date(currentDate.getTime() + 30 * 60000); + let token = await addToken(userRes.id , "canRead" , tokenToLive); return { token: token, userid: userRes.id, username: userRes.username }; } diff --git a/consumerWebsite/middleware/authChecker.js b/consumerWebsite/middleware/authChecker.js index 2eea06e..cc9b3f9 100644 --- a/consumerWebsite/middleware/authChecker.js +++ b/consumerWebsite/middleware/authChecker.js @@ -1,68 +1,36 @@ -const { tokenModel } = require("../database/model/tokenModel"); -const { userModel } = require("../database/model/userModel"); -const { compareHash } = require("../functions/bcrypt"); -const { checkToken } = require("../functions/api"); -const { isValid } = require("../functions/isValid"); +const { getTokenByToken } = require("../functions/api"); +const permissionError = new Error('PermissionError') +permissionError.name = "Inadequate Permission Error" +permissionError.status = 401 +permissionError.message = "Inadequate permission to complete this response" async function auth(req, res, next) { try { - const authToken = req.header("auth-token"); - if (!authToken) { - const error = new Error("No Token key was supplied. Invalid request"); - throw error; + const token = await getTokenByToken(req.header("auth-token")); + + if (!token || !token.isValid){ + throw permissionError; } - const splitAuthToken = authToken.split("-"); - const rowid = splitAuthToken[0]; - const suppliedToken = splitAuthToken.slice(1).join("-"); - - const token = await tokenModel.findByPk(rowid, { include: userModel }); - - if (!token) { - const error = new Error("Token key not found. Invalid request"); - throw error; - } - - const isMatch = await compareHash(suppliedToken, token.token); - - console.log(isMatch); - if (!isMatch) { - const error = new Error("Token key not found. Invalid request"); - throw error; - } //if token is a match req.token = token; req.user = await token.getUser(); - const permission = await checkToken(suppliedToken, rowid); const route = req.originalUrl.split("?")[0]; // Removing query parameters //if route is from user/ and permission is canRead allow it to do CRUD - if (route.includes("/user/") && permission === "canRead") { - next(); + if (route.includes("/user/") && token.permission === "canRead") { + return next(); } - if ((req.method === "GET" && permission === "canRead") || (["GET", "POST", "PUT", "DELETE"].includes(req.method) && permission === "canWrite")) { - next(); - } - - if (!isValid(token.expiration)){ - req.token.destroy(); - throw new Error("Token expired"); + if ((req.method === "GET" && token.permission === "canRead") || (["GET", "POST", "PUT", "DELETE"].includes(req.method) && token.permission === "canWrite")) { + return next(); } + throw permissionError } catch (error) { next(error); } } - module.exports = { auth }; -/* - else { - const error = new Error("Insufficient permission"); - error.status = 401; - throw error; - } - -*/ \ No newline at end of file diff --git a/consumerWebsite/public/css/all.css b/consumerWebsite/public/css/all.css index a213d9c..e9f791c 100644 --- a/consumerWebsite/public/css/all.css +++ b/consumerWebsite/public/css/all.css @@ -3812,6 +3812,7 @@ .card-text { color: #000000; + font-size: 16px; } /* edit profile */ diff --git a/consumerWebsite/public/js/app.js b/consumerWebsite/public/js/app.js index 96ee7a4..0ffd8a2 100644 --- a/consumerWebsite/public/js/app.js +++ b/consumerWebsite/public/js/app.js @@ -186,9 +186,7 @@ app.auth = (function (app) { function isLoggedIn(callback) { if (getToken()) { - console.log("you shldnt appear at all"); return app.api.get("user/me", function (error, data) { - console.log(error, data); if (!error) app.auth.user = data; return callback(error, data); }); diff --git a/consumerWebsite/routes/api_routes.js b/consumerWebsite/routes/api_routes.js index 7715165..d91b34c 100644 --- a/consumerWebsite/routes/api_routes.js +++ b/consumerWebsite/routes/api_routes.js @@ -18,5 +18,8 @@ router.use('/sensor', [auth, APIlogger], require('./sensor.js')); //sensor data route router.use('/sensor-data', [auth, APIlogger], require('./sensorData.js')); +//latest sensor data to display on dashboard +router.use('/latest-sensor-data', [APIlogger], require('./latestsensorData.js')); + module.exports = router; diff --git a/consumerWebsite/routes/latestsensorData.js b/consumerWebsite/routes/latestsensorData.js new file mode 100644 index 0000000..b8d007c --- /dev/null +++ b/consumerWebsite/routes/latestsensorData.js @@ -0,0 +1,21 @@ +const { + getLatestData, + +} = require("../functions/sensorData"); + +const express = require("express"); +const router = express.Router(); + +router.get("/data", async (req, res, next) => { + try { + console.log(req.query); + const data = await getLatestData(); + res.status(200).json(data); + + } catch (error) { + console.error(error); + next(error); + } +}); + +module.exports = router; diff --git a/consumerWebsite/routes/user.js b/consumerWebsite/routes/user.js index ca0b940..a7cf3b6 100644 --- a/consumerWebsite/routes/user.js +++ b/consumerWebsite/routes/user.js @@ -8,7 +8,7 @@ const router = express.Router(); router.get("/me", async function (req, res, next) { try { let user = await getUserByID(req.user); - console.log(user); + //console.log(user); res.json({ user: user, }); diff --git a/consumerWebsite/views/index.ejs b/consumerWebsite/views/index.ejs index 921e105..c2e533a 100644 --- a/consumerWebsite/views/index.ejs +++ b/consumerWebsite/views/index.ejs @@ -1,9 +1,17 @@ <%- include('top') %> @@ -53,56 +61,56 @@
-
-

Services

- -
-
-
-

Air Quality Index

-
-

15 - 18 PSI

-
- +
+

Services

+ +
+
+
+

Air Quality Index

+
+

{{ measurement.psi }} PSI

-
-
-
-

Humidity

-
-

70% - 75%

-
- + -
-
-
-

Temperature

-
-

30° - 37°

-
- +
+
+
+
+

Humidity

+
+

{{ measurement.humidity }} %

-
-
-
-

Another Category

-
-

values

-
- + -
-
- +
+
+
+
+

Temperature

+
+

{{ measurement.temperature }}°

+
+ +
+
+
+
+

Wind Speed

+
+

{{ measurement.windspeed }} Km/h

+
+ +
+
+
+
diff --git a/consumerWebsite/views/sensor-data.ejs b/consumerWebsite/views/sensor-data.ejs index c46510b..2edee8d 100644 --- a/consumerWebsite/views/sensor-data.ejs +++ b/consumerWebsite/views/sensor-data.ejs @@ -8,10 +8,9 @@
  • - rowid: {{ id }} sensorId: {{ sensorid }} - created: {{ createdAt }} location: {{ locationid }} + created: {{ createdAt }}
    co: {{ measurement.co }} humidity: {{ measurement.humidity }} @@ -30,7 +29,7 @@