iotsensor fixed but session valid broken

This commit is contained in:
newtbot 2024-01-25 03:26:56 +08:00
parent 7403f66c8a
commit 057fbe2afb
19 changed files with 173 additions and 237 deletions

View File

@ -1,9 +1,10 @@
const { run } = require("./modules/IoT-sensor");
const { IoTdataGenerator } = require("./modules/IoT-sensor");
const client = require("./modules/mqtt");
async function publishData() {
try {
const data = await run();
let iothub = new IoTdataGenerator();
let data = await iothub.generateData();
console.log(data);
client.publish("iot-data", JSON.stringify(data));
} catch (err) {

View File

@ -18,19 +18,19 @@ class IoTdataGenerator {
async generateData() {
try {
const { loc, sen } = await this.getLocationAndSensorId();
const dataAray = []; // create a new array for each call
for (let i = 0; i < sen.length; i++) {
//console.log(sen[i].id);
//console.log(loc[i].id);
//console.log("you should appear 6 times only")
dataAray.push(firstDataRow(sen[i].id, loc[i].id));
}
}
return dataAray;
} catch (err) {
console.error(err);
}
return dataAray;
}
}
//helper function to generate random data
function firstDataRow(sensorId, locationId) {
@ -57,15 +57,7 @@ function firstDataRow(sensorId, locationId) {
2) loop through each sensor id and location id and generate random data and pass to mqtt
*/
async function run() {
let iotData = new IoTdataGenerator();
const result = await iotData.generateData();
console.log(result);
return result;
}
module.exports = { run };
module.exports = { IoTdataGenerator };

2
api.MD
View File

@ -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/apikey/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}'
curl localhost:3000/api/v0/token/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}'

View File

@ -7,7 +7,7 @@ const ejs = require("ejs");
module.exports = app;
process.nextTick(() => require('./mqttApp'));
process.nextTick(() => require("./mqttApp"));
app.use(express.json());
app.set("json spaces", 2);
@ -16,12 +16,16 @@ app.set("json spaces", 2);
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
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')}];
app.onListen = [
function () {
console.log("Express is ready");
},
];
// Apply the rate limiting middleware to all requests.
app.use(limiter);
@ -36,10 +40,9 @@ 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")));
//route logic
app.use("/api/seed/v0" ,require("./routes/seed_route.js"));
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"));
@ -47,19 +50,17 @@ 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) {
if (req.is("application/json")) {
var err = new Error("Not Found");
err.message = "Page not found";
err.status = 404;
next(err);
}
else{
//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");
}
});
// 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);
@ -78,14 +79,20 @@ app.use(function (err, req, res, next) {
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("=========================================");
}
res.status(err.status || 500);
console.log(keyErrors);
res.json({
name: err.name,
name: err.name || "Unknown error",
message: err.message,
keyErrors,
});
});

View File

@ -4,8 +4,8 @@ const { sequelize } = require("../mySQL");
const { userModel } = require("./userModel");
//sequelize.sync();
const apikeyModel = sequelize.define(
"apikey",
const tokenModel = sequelize.define(
"token",
{
id: {
type: DataTypes.INTEGER,
@ -28,7 +28,7 @@ const apikeyModel = sequelize.define(
key: "id",
},
},
apikey: {
token: {
type: DataTypes.STRING,
allowNull: false,
length: 255,
@ -45,7 +45,14 @@ const apikeyModel = sequelize.define(
validate: {
notEmpty: true,
len: [1, 255],
isIn: [["canRead", "canWrite" , "auto-generated"]],
isIn: [["canRead", "canWrite",]],
},
},
expiration: {
type: DataTypes.DATE,
allowNull: false,
validate: {
isDate: true,
},
},
createdAt: {
@ -61,9 +68,9 @@ const apikeyModel = sequelize.define(
timestamps: true,
}
);
apikeyModel.belongsTo(userModel);
tokenModel.belongsTo(userModel);
module.exports = { apikeyModel };
module.exports = { tokenModel };
/*
class AuthToken extends Model {

View File

@ -1,5 +1,5 @@
const { hash, compareHash } = require("./bcrypt.js");
const { apikeyModel } = require("../database/model/apiKeyModel");
const { tokenModel } = require("../database/model/tokenModel.js");
const { generateUUID } = require("./generateUUID.js");
/*
@ -11,37 +11,38 @@ const { generateUUID } = require("./generateUUID.js");
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 hash(hashtoken);
async function addToken(userId, permission , expiry) {
let uuid = await generateUUID();
let hashtoken = await hash(uuid);
let token = await apikeyModel.create({
let token = await tokenModel.create({
userid: userId,
apikey: apikey,
token: hashtoken,
permission: permission,
expiration: expiry,
});
//user token with - tokenid is table id
return token.id + "-" + hashtoken;
return token.id + "-" + uuid;
}
async function checkAPikey(SuppliedKey, rowid) {
async function checkToken(Supplied, rowid) {
try {
const retrivedKey = await apikeyModel.findOne({
const retrivedToken = await tokenModel.findOne({
raw: true,
attributes: ["apikey", "permission"],
attributes: ["token", "permission"],
where: {
id: rowid,
},
});
//console.log(retrivedKey.apikey);
if (compareHash(SuppliedKey, retrivedKey.apikey)) {
if (compareHash(Supplied, retrivedToken.token)) {
//return true;
return retrivedKey.permission;
return retrivedToken.permission;
}
} catch (error) {
console.error(error);
}
}
module.exports = { addAPIKey , checkAPikey };
module.exports = { addToken , checkToken };

View File

@ -0,0 +1,20 @@
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;
}
module.exports = { isValid };

View File

@ -1,7 +1,8 @@
const { Op } = require('sequelize')
const { hash, compareHash } = require("./bcrypt.js");
const { addAPIKey } = require("./api");
const { addToken } = require("./api");
const { userModel } = require("../database/model/userModel");
moment = require('moment')
@ -70,9 +71,9 @@ async function loginUser(user) {
if (!match) return false;
//console.log('loginUser', userRes.id, userRes.username);
//generate token
let token = await addAPIKey(userRes.id, "auto-generated");
//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);
return { token: token, userid: userRes.id, username: userRes.username };
}

View File

@ -1,65 +0,0 @@
const { checkAPikey } = require("../functions/api.js");
async function apikeyCheck(req, res, next) {
//const authHeader = req.headers.authorization
try {
let apikey = req.headers.authorization;
if (!apikey) {
res.status(401).json({
message: "No API key was supplied. Invalid request",
});
//throw new Error("No API key was supplied. Invalid request");
} else {
//split the string by the -
let splitAPIkey = apikey.split("-");
let rowid = splitAPIkey[0];
//rejoin withouth the rowid
let SuppliedKey = splitAPIkey.slice(1).join("-");
if (checkAPikey(SuppliedKey, rowid)) {
//get permission
let permission = await checkAPikey(SuppliedKey, rowid);
console.log(permission);
if (req.method === "GET" && permission === "canRead") {
return next();
}
//['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)
if (
["GET", "POST", "PUT", "DELETE"].includes(req.method) &&
permission === "canWrite"
) {
console.log("write");
return next();
}
//throw status 403
res.status(403).json({
message:
"Your API key does not have the correct permissions to access this resource",
});
}
}
} catch (error) {
next(error);
}
}
module.exports = { apikeyCheck };
/*
//web server microservice
1) take user supplied rowid-apikey
2) split the string by -
3) get the rowid or table id
4) get the apikey
5) compare the apikey with the one in database
6) if match, return true
*/
/*
I plan to seed some data in user and api
Than use the system info and my API middleware will somehow check the supplied API key and check
If it's correct API key and has canWrite perms
I allow it to access put and post
*/

View File

@ -1,31 +1,65 @@
const { apikeyModel } = require("../database/model/apiKeyModel");
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");
async function auth(req, res, next){
try{
// let user = await Auth.checkToken({token: req.header('auth-token')});
let authToken = req.header('auth-token');
let splitAuthToken = authToken.split('-');
let rowid = splitAuthToken[0];
let suppliedToken = splitAuthToken.slice(1).join('-');
//get from db
let token = await apikeyModel.findByPk(rowid, {include: userModel});
if (!token) return false;
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");
error.status = 401;
throw error;
}
//compare
let isMatch = await compareHash(suppliedToken, token.apikey);
if (!isMatch) return false;
const splitAuthToken = authToken.split("-");
const rowid = splitAuthToken[0];
const suppliedToken = splitAuthToken.slice(1).join("-");
//else do logic
//pass hashed token to req.token (IMPORTANT ITS NOT PASSED TO CLIENT)
req.token = token
req.user = await token.getUser(); //taking user seq obj from usermodel
next();
}catch(error){
const token = await tokenModel.findByPk(rowid, { include: userModel });
if (!token) {
const error = new Error("Token key not found. Invalid request");
error.status = 401;
throw error;
}
const isMatch = await compareHash(suppliedToken, token.token);
if (!isMatch) {
const error = new Error("Token key not found. Invalid request");
error.status = 401;
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();
}
else if ((req.method === "GET" && permission === "canRead") || (["GET", "POST", "PUT", "DELETE"].includes(req.method) && permission === "canWrite")) {
next();
}
else {
const error = new Error("Insufficient permission");
error.status = 401;
throw error;
}
if (!isValid(token.expiration)){
req.token.destroy();
throw new Error("Token expired");
}
} catch (error) {
next(error);
}
}
module.exports = { auth };
module.exports = { auth };

View File

@ -9,8 +9,8 @@ let transporter = nodemailer.createTransport({
port: 587,
secure: false,
auth: {
user:
pass:
user: process.env.euser,
pass: process.env.epass
},
});
module.exports = { transporter };

View File

@ -165,6 +165,7 @@ app.socket = (function (app) {
});
return socket;
})(app);
//sensor data
app.sensordata = (function (app) {
@ -183,21 +184,11 @@ app.auth = (function (app) {
}
function isLoggedIn(callback) {
if (getToken()) {
return app.api.get("user/me", function (error, data) {
console.log(error, data);
if (!error) app.auth.user = data;
//for navbar to show username
if (!location.pathname === "/login")
{
$.scope.getUsername.update(data);
}
//for edit profile to show user details
//if not in edit profile page, it will not show
if (location.pathname === "/profile") {
$.scope.getUserDetails.update(data);
}
return callback(error, data);
});
} else {
@ -206,7 +197,7 @@ app.auth = (function (app) {
}
function logOut(callback) {
//call logout route
console.log("Logging out");
$.ajax({
type: "DELETE",
url: "/api/v0/user/logout",

View File

@ -2,42 +2,21 @@
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('/token', [auth, APIlogger], require('./token.js'));
router.use('/user', [auth, APIlogger], require('./user'));
//TO REFACTOR INTO ONE MIDDLWARE
//location route
router.use('/location', [auth, APIlogger], require('./location.js'));
//location route
router.use('/location', [apikeyCheck , APIlogger], require('./location.js'));
//location route
router.use('/sensor', [apikeyCheck , APIlogger], require('./sensor.js'));
router.use('/sensor', [auth, APIlogger], require('./sensor.js'));
//sensor data route
router.use('/sensor-data', [ APIlogger], require('./sensorData.js'));
router.use('/sensor-data', [auth, APIlogger], require('./sensorData.js'));
module.exports = router;
/*
'use strict';
const router = require('express').Router();
const { auth } = require("../middleware/authChecker")
router.use('/auth', require('./auth'));
router.use('/apikey', require('./apikey'));
router.use('/user', auth ,require('./user'));
module.exports = router;
*/

View File

@ -51,7 +51,6 @@ router.post("/login", async (req, res, next) => {
//contact
//auth/contact
router.post("/contact", async (req, res, next) => {
});

View File

@ -1,4 +1,4 @@
const { addAPIKey } = require("../functions/api");
const { addToken } = require("../functions/api");
const express = require("express");
@ -10,14 +10,13 @@ const router = express.Router();
3) hash the api key
4) store the api key in database
*/
//token/new
//curl localhost:3000/api/v0/token/new -H "Content-Type: application/json" -X POST -d
//'{"userid": "5", "permission": "canRead" ,}'
router.post("/new", async (req, res, next) => {
try {
//curl localhost/api/v0/apikey/new -H "Content-Type: application/json" -X POST -d
//'{"userid": 1, "permission": "canWrite"}'
const apikey = await addAPIKey(req.body.userid, req.body.permission);
//console.log(typeof req.body.userid);
//console.log(typeof req.body.permission);
res.json({apikey: apikey});
const token = await addToken(req.body.userid, req.body.permission , "2204-01-24 07:34:36" );
res.json({token: token});
} catch (error) {
console.error(error);
next(error);

View File

@ -11,11 +11,14 @@ router.get("/me", async function (req, res, next) {
if (!user) {
let error = new Error("User not found");
error.status = 400;
console.log(error);
return next(error);
}
if (user){
res.json({
user: user,
});
}
} catch (error) {
next(error);
}

View File

@ -1,4 +1,5 @@
<%- include('top') %>
<br>
<br>
<br>

View File

@ -57,6 +57,11 @@
//check if user is logged in
app.auth.isLoggedIn(function (error, data) {
if (data) {
$.scope.getUsername.update(data);
if (location.pathname == "/profile") {
$.scope.getUserDetails.update(data);
}
$("#cl-logout-button").show("fast");
$("#cl-api-button").show("fast");
$("#cl-profile-button").show("fast");
@ -127,4 +132,4 @@
</ul>
</div>
</div>
</nav>
</nav>

View File

@ -1,43 +1,4 @@
//import('dotenv').config({ path: path.resolve(__dirname, '../../../.env') })
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('form');
// Set the new value for the access_key input field
form.querySelector('input[name="access_key"]').value = process.env.emailKey;
form.addEventListener('submit', async (event) => {
event.preventDefault(); // Prevent default form submission
// Create a FormData object to include the key
const formData = new FormData(form);
// Submit the form using fetch API
try {
const response = await fetch('https://api.web3forms.com/submit', {
method: 'POST',
body: formData
});
const result = await response.json();
// Handle the API response
console.log(result);
if (result.success) {
// Form submitted successfully, display notification
alert('Form submitted successfully!');
location.reload()
} else {
// Form submission failed, display error notification
alert('Form submission failed. Please try again.');
}
} catch (error) {
//console.error('Error:', error);
}
});
});
moment = require('moment')
//current time
console.log(moment().format('hh:mm:ss a'))