Compare commits
No commits in common. "256e582ed0fa561a9a6e900a8fcd9af4b0c7b609" and "4aea6a8e4c67a178858d607581956eba5bf03a25" have entirely different histories.
256e582ed0
...
4aea6a8e4c
@ -1,4 +0,0 @@
|
|||||||
DB_name="eco_saver"
|
|
||||||
DB_storage="database_test.sqlite"
|
|
||||||
DB_dialect="sqlite"
|
|
||||||
DB_logginf=false
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
cert
|
cert
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes, Op } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
const { userModel } = require("./userModel");
|
const { userModel } = require("./userModel");
|
||||||
|
|
||||||
//sequelize.sync();
|
//sequelize.sync();
|
||||||
@ -16,7 +16,7 @@ const apikeyModel = sequelize.define(
|
|||||||
isNumeric: true,
|
isNumeric: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
userId: {
|
userid: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
@ -63,8 +63,6 @@ const apikeyModel = sequelize.define(
|
|||||||
);
|
);
|
||||||
apikeyModel.belongsTo(userModel);
|
apikeyModel.belongsTo(userModel);
|
||||||
|
|
||||||
apikeyModel.sync()
|
|
||||||
|
|
||||||
module.exports = { apikeyModel };
|
module.exports = { apikeyModel };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
const {
|
const {
|
||||||
isAlphaNumericWithSpacesAndDash,
|
isAlphaNumericWithSpacesAndDash,
|
||||||
isAddress,
|
isAddress,
|
||||||
@ -111,7 +111,4 @@ const userModel = sequelize.define(
|
|||||||
timestamps: true,
|
timestamps: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
userModel.sync()
|
|
||||||
|
|
||||||
module.exports = { userModel };
|
module.exports = { userModel };
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
const dotenv = require("dotenv");
|
const dotenv = require("dotenv");
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') });
|
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') })
|
||||||
const Sequelize = require("sequelize");
|
const Sequelize = require("sequelize");
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const sequelize = new Sequelize(
|
const sequelize = new Sequelize(
|
||||||
process.env.DB_name,
|
"eco_saver",
|
||||||
process.env.DB_USER,
|
process.env.DB_USER,
|
||||||
process.env.DB_PASS,
|
process.env.DB_PASS,
|
||||||
{
|
{
|
||||||
host: process.env.host, //"mpsqldatabase.mysql.database.azure.com",
|
host: "mpsqldatabase.mysql.database.azure.com",
|
||||||
dialect: process.env.DB_dialect,
|
dialect: 'mysql',
|
||||||
storage: process.env.DB_storage,
|
|
||||||
logging: process.env.DB_logging,
|
|
||||||
// attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy';
|
// attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy';
|
||||||
attributeBehavior: 'escape',
|
attributeBehavior: 'escape',
|
||||||
dialectOptions: {
|
dialectOptions: {
|
||||||
ssl: {
|
ssl: {
|
||||||
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt.pem')),
|
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt.pem')),
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
sequelize.authenticate().then(() => {
|
sequelize.authenticate().then(() => {
|
||||||
console.log(`Connection to ${process.env.DB_dialect} has been established successfully.`);
|
console.log('Connection has been established successfully.');
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error('Unable to connect to the database: ', error);
|
console.error('Unable to connect to the database: ', error);
|
||||||
});
|
});
|
@ -1,23 +0,0 @@
|
|||||||
const { hash, compareHash } = require("./bcrypt.js");
|
|
||||||
const { apikeyModel } = require("../database/model/apiKeyModel");
|
|
||||||
const { generateUUID } = require("./generateUUID.js");
|
|
||||||
|
|
||||||
//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);
|
|
||||||
|
|
||||||
let token = await apikeyModel.create({
|
|
||||||
userId: userId,
|
|
||||||
apikey: apikey,
|
|
||||||
permission: permission,
|
|
||||||
});
|
|
||||||
|
|
||||||
//user token with - tokenid is table id
|
|
||||||
return token.id + "-" + hashtoken;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addAPIKey
|
|
||||||
};
|
|
@ -1,45 +1,13 @@
|
|||||||
|
const { sequelize } = require("../database/mySql.js");
|
||||||
const { Op } = require('sequelize')
|
const { apikeyModel } = require("../database/model/apikeyModel.js");
|
||||||
const { hash, compareHash } = require("./bcrypt.js");
|
const { userModel } = require("../database/model/userModel.js");
|
||||||
const { addAPIKey } = require("./api");
|
const { Op, Sequelize } = require("sequelize");
|
||||||
const { userModel } = require("../database/model/userModel");
|
const { generateUUID } = require("../functions/generateUUID.js");
|
||||||
|
const {
|
||||||
|
hashPassword,
|
||||||
|
comparePassword,
|
||||||
//getuser
|
hashAPIKey,
|
||||||
//api/v0/user/me
|
} = require("../functions/bcrypt.js");
|
||||||
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
|
//getuser
|
||||||
//api/v0/user/me
|
//api/v0/user/me
|
||||||
@ -64,13 +32,13 @@ async function getUserID(userid) {
|
|||||||
*/
|
*/
|
||||||
async function addUser(user) {
|
async function addUser(user) {
|
||||||
//hash password
|
//hash password
|
||||||
let hashed = await hash(user.password);
|
let hash = await hashPassword(user.password);
|
||||||
|
|
||||||
const addRes = await userModel.create({
|
const addRes = await userModel.create({
|
||||||
firstname: user.firstname,
|
firstname: user.firstname,
|
||||||
lastname: user.lastname,
|
lastname: user.lastname,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
password: hashed,
|
password: hash,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
address: user.address,
|
address: user.address,
|
||||||
phone: user.phone,
|
phone: user.phone,
|
||||||
@ -102,7 +70,7 @@ async function loginUser(user) {
|
|||||||
if (!userRes) return false;
|
if (!userRes) return false;
|
||||||
|
|
||||||
// Compare passwords
|
// Compare passwords
|
||||||
let match = await compareHash(user.password, userRes.password);
|
let match = await comparePassword(user.password, userRes.password);
|
||||||
if (!match) return false;
|
if (!match) return false;
|
||||||
//console.log('loginUser', userRes.id, userRes.username);
|
//console.log('loginUser', userRes.id, userRes.username);
|
||||||
|
|
||||||
@ -121,6 +89,20 @@ async function loginUser(user) {
|
|||||||
6) store in database
|
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
|
//api/v0/user/update
|
||||||
async function updateProfile(user, body) {
|
async function updateProfile(user, body) {
|
||||||
@ -143,7 +125,7 @@ async function updateProfile(user, body) {
|
|||||||
if (!updateUser) return false;
|
if (!updateUser) return false;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
let hashed = await hash(body.password);
|
let hash = await hashPassword(body.password);
|
||||||
let updateUser = await userModel.update(
|
let updateUser = await userModel.update(
|
||||||
{
|
{
|
||||||
firstname: body.first_name,
|
firstname: body.first_name,
|
||||||
@ -152,7 +134,7 @@ async function updateProfile(user, body) {
|
|||||||
email: body.email,
|
email: body.email,
|
||||||
address: body.address,
|
address: body.address,
|
||||||
phone: body.phone,
|
phone: body.phone,
|
||||||
password: hashed,
|
password: hash,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
where: {
|
where: {
|
||||||
@ -170,4 +152,5 @@ module.exports = {
|
|||||||
addUser,
|
addUser,
|
||||||
loginUser,
|
loginUser,
|
||||||
updateProfile,
|
updateProfile,
|
||||||
|
addAPIKey,
|
||||||
};
|
};
|
@ -23,18 +23,23 @@ bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//hash for pass or token lol doesnt matter
|
//hash for pass or token lol doesnt matter
|
||||||
async function hash(password) {
|
async function hashPassword(password) {
|
||||||
return await bcrypt.hash(password, saltRounds);
|
return await bcrypt.hash(password, saltRounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function hashAPIKey(apikey) {
|
||||||
|
return await bcrypt.hash(apikey, saltRounds);
|
||||||
|
}
|
||||||
|
|
||||||
//can be used to compare password or token
|
//can be used to compare password or token
|
||||||
async function compareHash(password, hash) {
|
async function comparePassword(password, hash) {
|
||||||
return await bcrypt.compare(password, hash);
|
return await bcrypt.compare(password, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
hash,
|
hashPassword,
|
||||||
compareHash
|
hashAPIKey,
|
||||||
|
comparePassword
|
||||||
};
|
};
|
@ -1,55 +0,0 @@
|
|||||||
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,
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
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,
|
|
||||||
};
|
|
@ -1,75 +0,0 @@
|
|||||||
const {sensorModel} = require("../database/model/sensorModel");
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getSensor,
|
|
||||||
addSensor,
|
|
||||||
updateSensor,
|
|
||||||
deleteSensor,
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
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;
|
|
@ -1,27 +1,5 @@
|
|||||||
var validator = require("validator");
|
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) {
|
function isAlphaNumericwithSpaces(value) {
|
||||||
return validator.isAlphanumeric(value, ["en-US"], { ignore: " " });
|
return validator.isAlphanumeric(value, ["en-US"], { ignore: " " });
|
||||||
}
|
}
|
||||||
@ -66,8 +44,6 @@ module.exports = {
|
|||||||
isAlphaNumericwithSpaces,
|
isAlphaNumericwithSpaces,
|
||||||
isAlphaNumericWithSpacesAndDash,
|
isAlphaNumericWithSpacesAndDash,
|
||||||
isJson,
|
isJson,
|
||||||
isAddress,
|
isAddress
|
||||||
isValidDateString,
|
|
||||||
isMacAddress,
|
|
||||||
isNumber,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const { apikeyModel } = require("../database/model/apiKeyModel");
|
const { apikeyModel } = require("../database/model/apiKeyModel");
|
||||||
const { userModel } = require("../database/model/userModel");
|
const { userModel } = require("../database/model/userModel");
|
||||||
const { compareHash } = require("../functions/bcrypt");
|
const { comparePassword } = require("../functions/bcrypt");
|
||||||
|
|
||||||
async function auth(req, res, next){
|
async function auth(req, res, next){
|
||||||
try{
|
try{
|
||||||
@ -15,7 +15,7 @@ async function auth(req, res, next){
|
|||||||
if (!token) return false;
|
if (!token) return false;
|
||||||
|
|
||||||
//compare
|
//compare
|
||||||
let isMatch = await compareHash(suppliedToken, token.apikey);
|
let isMatch = await comparePassword(suppliedToken, token.apikey);
|
||||||
if (!isMatch) return false;
|
if (!isMatch) return false;
|
||||||
|
|
||||||
//else do logic
|
//else do logic
|
||||||
|
@ -1,46 +1,29 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const { rateLimit } = require("express-rate-limit");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
const ejs = require("ejs");
|
const ejs = require("ejs");
|
||||||
|
|
||||||
module.exports = app;
|
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.set("json spaces", 2);
|
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.
|
// 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");
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
// Have express server static content( images, CSS, browser JS) from the public
|
// Have express server static content( images, CSS, browser JS) from the public
|
||||||
app.use(express.static(path.join(__dirname, "./public")));
|
app.use(express.static(path.join(__dirname, "../public")));
|
||||||
|
|
||||||
|
//middleware logic ( called by next() )
|
||||||
|
const auth = require("../middleware/authChecker");
|
||||||
|
|
||||||
|
|
||||||
//route logic
|
//route logic
|
||||||
app.use("/api/seed/v0" ,require("./routes/seed_route.js"));
|
app.use("/api/v0", require("../routes/api_routes"));
|
||||||
app.use("/api/v0", require("./routes/api_routes"));
|
|
||||||
|
|
||||||
//render logic
|
//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
|
// Catch 404 and forward to error handler. If none of the above routes are
|
||||||
// used, this is what will be called.
|
// used, this is what will be called.
|
||||||
@ -86,5 +69,8 @@ app.use(function (err, req, res, next) {
|
|||||||
keyErrors,
|
keyErrors,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`app listening on port ${port}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { app };
|
3392
consumerWebsite/package-lock.json
generated
3392
consumerWebsite/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "consumerwebsite",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "app.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
|
||||||
"start-dev": "nodemon bin/www"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"devDependencies": {
|
|
||||||
"nodemon": "^3.0.3",
|
|
||||||
"sqlite3": "^5.1.7"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"bcrypt": "^5.1.1",
|
|
||||||
"date-fns": "^3.2.0",
|
|
||||||
"date-fns-tz": "^2.0.0",
|
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"ejs": "^3.1.9",
|
|
||||||
"express": "^4.18.2",
|
|
||||||
"express-rate-limit": "^7.1.5",
|
|
||||||
"mqtt": "^5.3.3",
|
|
||||||
"mysql2": "^3.7.1",
|
|
||||||
"nodemailer": "^6.9.8",
|
|
||||||
"sequelize": "^6.35.2",
|
|
||||||
"socket.io": "^4.7.4",
|
|
||||||
"validator": "^13.11.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,24 +10,6 @@ app.util = (function (app) {
|
|||||||
: decodeURIComponent(results[1].replace(/\+/g, " "));
|
: decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
function promisify(f) {
|
|
||||||
return function (...args) { // return a wrapper-function (*)
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
function callback(err, result) { // our custom callback for f (**)
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push(callback); // append our custom callback to the end of f arguments
|
|
||||||
|
|
||||||
f.call(this, ...args); // call the original function
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function actionMessage(message, $target, type, callback) {
|
function actionMessage(message, $target, type, callback) {
|
||||||
message = message || "";
|
message = message || "";
|
||||||
$target = $target.closest("div.iot-card").find(".actionMessage");
|
$target = $target.closest("div.iot-card").find(".actionMessage");
|
||||||
@ -70,13 +52,12 @@ app.util = (function (app) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUrlParameter,
|
getUrlParameter: getUrlParameter,
|
||||||
actionMessage,
|
actionMessage: actionMessage,
|
||||||
promisify
|
|
||||||
};
|
};
|
||||||
})(app);
|
})(app);
|
||||||
|
|
||||||
app.apiSync = (function (app) {
|
app.api = (function (app) {
|
||||||
var baseURL = "/api/v0/";
|
var baseURL = "/api/v0/";
|
||||||
|
|
||||||
function post(url, data, callback) {
|
function post(url, data, callback) {
|
||||||
@ -160,35 +141,20 @@ app.apiSync = (function (app) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { post: post, get: get, put: put, delete: remove };
|
||||||
post: app.util.promisify(post),
|
|
||||||
get: app.util.promisify(get),
|
|
||||||
put: app.util.promisify(put),
|
|
||||||
delete: app.util.promisify(remove),
|
|
||||||
};
|
|
||||||
})(app);
|
|
||||||
|
|
||||||
app.api = (function (app) {
|
|
||||||
return {
|
|
||||||
post: app.util.promisify(app.apiSync.post),
|
|
||||||
get: app.util.promisify(app.apiSync.get),
|
|
||||||
put: app.util.promisify(app.apiSync.put),
|
|
||||||
delete: app.util.promisify(app.apiSync.remove),
|
|
||||||
};
|
|
||||||
})(app);
|
})(app);
|
||||||
|
|
||||||
//socket.io
|
//socket.io
|
||||||
app.socket = (function (app) {
|
app.socket = (function (app) {
|
||||||
//need to replace with domain name of server when published
|
//need to replace with domain name of server when published
|
||||||
var socket = io();
|
var socket = io("localhost", {
|
||||||
|
transports: ["websocket"],
|
||||||
|
'Access-Control-Allow-Origin': 'http://localhost:3000',
|
||||||
|
});
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
console.log("disconnected");
|
console.log("disconnected");
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('connect', ()=>{
|
|
||||||
console.info('WS connected');
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.io.on("reconnect", () => {
|
socket.io.on("reconnect", () => {
|
||||||
console.log("reconnected");
|
console.log("reconnected");
|
||||||
});
|
});
|
||||||
@ -217,7 +183,7 @@ app.auth = (function (app) {
|
|||||||
|
|
||||||
function isLoggedIn(callback) {
|
function isLoggedIn(callback) {
|
||||||
if (getToken()) {
|
if (getToken()) {
|
||||||
return app.apiSync.get("user/me", function (error, data) {
|
return app.api.get("user/me", function (error, data) {
|
||||||
if (!error) app.auth.user = data;
|
if (!error) app.auth.user = data;
|
||||||
//for navbar to show username
|
//for navbar to show username
|
||||||
if (!location.pathname === "/login")
|
if (!location.pathname === "/login")
|
||||||
@ -301,7 +267,7 @@ app.auth = (function (app) {
|
|||||||
app.user = (function (app) {
|
app.user = (function (app) {
|
||||||
//delete profile
|
//delete profile
|
||||||
function deleteProfile() {
|
function deleteProfile() {
|
||||||
app.apiSync.delete("user/delete", function (error, data) {
|
app.api.delete("user/delete", function (error, data) {
|
||||||
if (error) {
|
if (error) {
|
||||||
app.util.actionMessage(error.message, $("#deleteProfile"), "danger");
|
app.util.actionMessage(error.message, $("#deleteProfile"), "danger");
|
||||||
} else {
|
} else {
|
||||||
@ -327,7 +293,7 @@ function formAJAX(btn, del) {
|
|||||||
|
|
||||||
//console.log('Data being sent to', $form.attr('action'), formData)
|
//console.log('Data being sent to', $form.attr('action'), formData)
|
||||||
|
|
||||||
app.apiSync[method]($form.attr("action"), formData, function (error, data) {
|
app.api[method]($form.attr("action"), formData, function (error, data) {
|
||||||
//console.log('Data back from the server', error, data)
|
//console.log('Data back from the server', error, data)
|
||||||
app.util.actionMessage(data.message, $form, error ? "danger" : "success"); //re-populate table
|
app.util.actionMessage(data.message, $form, error ? "danger" : "success"); //re-populate table
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
@ -1,22 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const { auth } = require("../middleware/authChecker")
|
const { auth } = require("../middleware/authChecker")
|
||||||
const { APIlogger } = require('../middleware/apiLogger.js');
|
|
||||||
|
|
||||||
router.use('/auth', require('./auth'));
|
router.use('/auth', require('./auth'));
|
||||||
|
|
||||||
router.use('/apikey', require('./apikey'));
|
router.use('/apikey', require('./apikey'));
|
||||||
|
|
||||||
router.use('/user', [auth, APIlogger], require('./user'));
|
router.use('/user', auth ,require('./user'));
|
||||||
|
|
||||||
//location route
|
|
||||||
router.use('/location', [auth, APIlogger], require('./location'));
|
|
||||||
|
|
||||||
//location route
|
|
||||||
router.use('/sensor', [auth, APIlogger], require('./sensor'));
|
|
||||||
|
|
||||||
//location route
|
|
||||||
router.use('/sensor-data', [auth, APIlogger], require('./sensorData'));
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { addAPIKey } = require("../functions/api");
|
const { getAPIKey , addAPIKey } = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { addUser, loginUser } = require("../functions/user");
|
const { addUser, loginUser } = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
@ -87,9 +87,5 @@ router.get("/api", function (req, res, next) {
|
|||||||
res.render("api");
|
res.render("api");
|
||||||
});
|
});
|
||||||
|
|
||||||
// sensor data
|
|
||||||
router.get("/sensor-data", function (req, res, next) {
|
|
||||||
res.render("sensor-data");
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { getUserID, updateProfile } = require("../functions/user");
|
const { getUserID, updateProfile } = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<div class="error-contents">
|
<div class="error-contents">
|
||||||
<h3>Unauthorized Access!</h3>
|
<h3>Unauthorized Access!</h3>
|
||||||
<div class="error-img">
|
<div class="error-img">
|
||||||
<img class="img-fluid" src="/images/401.png" alt="" />
|
<img class="img-fluid" src="images/401.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<p>Sorry, you don't have permission to access this resource. Please log in or provide valid credentials.</p>
|
<p>Sorry, you don't have permission to access this resource. Please log in or provide valid credentials.</p>
|
||||||
<a class="btn btn-primary" href="/"> Back To Homepage </a>
|
<a class="btn btn-primary" href="/"> Back To Homepage </a>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<div class="error-contents">
|
<div class="error-contents">
|
||||||
<h3>Oops! That page can’t be found.</h3>
|
<h3>Oops! That page can’t be found.</h3>
|
||||||
<div class="error-img">
|
<div class="error-img">
|
||||||
<img class="img-fluid" src="/images/404.png" alt="" />
|
<img class="img-fluid" src="images/404.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<p>We can’t find the page your are looking for. You can check out our <a href="/">Homepage</a>.</p>
|
<p>We can’t find the page your are looking for. You can check out our <a href="/">Homepage</a>.</p>
|
||||||
<a class="btn btn-primary" href="/"> Back To Homepage </a>
|
<a class="btn btn-primary" href="/"> Back To Homepage </a>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<ul class="footer_ul_amrc">
|
<ul class="footer_ul_amrc">
|
||||||
<li class="media">
|
<li class="media">
|
||||||
<div class="media-left">
|
<div class="media-left">
|
||||||
<img class="img-fluid" src="/images/post-img-01.jpg" alt="" />
|
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<p>Singapore's air quality ...</p>
|
<p>Singapore's air quality ...</p>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<ul class="footer_ul_amrc">
|
<ul class="footer_ul_amrc">
|
||||||
<li class="media">
|
<li class="media">
|
||||||
<div class="media-left">
|
<div class="media-left">
|
||||||
<img class="img-fluid" src="/images/post-img-01.jpg" alt="" />
|
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<p>Singapore Government ...</p>
|
<p>Singapore Government ...</p>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<ul class="footer_ul_amrc">
|
<ul class="footer_ul_amrc">
|
||||||
<li class="media">
|
<li class="media">
|
||||||
<div class="media-left">
|
<div class="media-left">
|
||||||
<img class="img-fluid" src="/images/post-img-01.jpg" alt="" />
|
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<p>High risk of severe ...</p>
|
<p>High risk of severe ...</p>
|
||||||
@ -81,7 +81,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script src="/js/search.js"></script>
|
<script src="js/search.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,5 +1,5 @@
|
|||||||
<%- include('top') %>
|
<%- include('top') %>
|
||||||
<link href="/css/contact.css" rel="stylesheet" />
|
<link href="css/contact.css" rel="stylesheet" />
|
||||||
|
|
||||||
<!-- full Title -->
|
<!-- full Title -->
|
||||||
<div class="full-title">
|
<div class="full-title">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<%- include('top') %>
|
<%- include('top') %>
|
||||||
<link href="/css/learnmore.css" rel="stylesheet" />
|
<link href="css/learnmore.css" rel="stylesheet" />
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<script src="/js/learnmore.js"></script>
|
<script src="js/learnmore.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<%- include('bot') %>
|
<%- include('bot') %>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
<link rel="shortcut icon" type="images/logo.ico" href="/images/logo.ico" />
|
<link rel="shortcut icon" type="images/logo.ico" href="images/logo.ico" />
|
||||||
<!-- Bootstrap core CSS -->
|
<!-- Bootstrap core CSS -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
<%- include('top') %>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#sensorDataList{
|
|
||||||
padding-top: 2.5em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<ul id="sensorDataList">
|
|
||||||
<li jq-repeat='sensorData'>
|
|
||||||
rowid: {{ id }}
|
|
||||||
sensorId: {{ sensorid }}
|
|
||||||
created: {{ createdAt }}
|
|
||||||
location: {{ locationid }}
|
|
||||||
<br/ >
|
|
||||||
co: {{ measurement.co }}
|
|
||||||
humidity: {{ measurement.humidity }}
|
|
||||||
no2: {{ measurement.no2 }}
|
|
||||||
o3: {{ measurement.o3 }}
|
|
||||||
psi: {{ measurement.psi }}
|
|
||||||
so2: {{ measurement.so2 }}
|
|
||||||
temperature: {{ measurement.temperature }}
|
|
||||||
windspeed: {{ measurement.windspeed }}
|
|
||||||
<hr />
|
|
||||||
</li>
|
|
||||||
<li jq-repeat-defualt='sensorData'>
|
|
||||||
Loading...
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(async function(){
|
|
||||||
$.scope.sensorData.push(...await app.api.get('sensor-data/data?order=DESC&limit=40'));
|
|
||||||
|
|
||||||
app.socket.on('sensordata:new', function(data){
|
|
||||||
$.scope.sensorData.unshift(data);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<%- include('bot') %>
|
|
@ -9,7 +9,7 @@
|
|||||||
<meta http-equiv="cleartype" content="on" />
|
<meta http-equiv="cleartype" content="on" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="shortcut icon" type="/images/logo.ico" href="/images/logo.ico" />
|
<link rel="shortcut icon" type="images/logo.ico" href="images/logo.ico" />
|
||||||
|
|
||||||
|
|
||||||
<!-- Bootstrap core CSS -->
|
<!-- Bootstrap core CSS -->
|
||||||
@ -17,8 +17,8 @@
|
|||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
||||||
|
|
||||||
<!-- Custom styles for this template -->
|
<!-- Custom styles for this template -->
|
||||||
<link href="/css/all.css" rel="stylesheet" />
|
<link href="css/all.css" rel="stylesheet" />
|
||||||
<link href="/css/style.css" rel="stylesheet" />
|
<link href="css/style.css" rel="stylesheet" />
|
||||||
<!-- weird api page cdn -->
|
<!-- weird api page cdn -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
@ -45,10 +45,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- jq-repeat -->
|
<!-- jq-repeat -->
|
||||||
<script src="/js/jq-repeat.js"></script>
|
<script src="js/jq-repeat.js"></script>
|
||||||
|
|
||||||
<!-- jquery app.js -->
|
<!-- jquery app.js -->
|
||||||
<script src="/js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<!-- javascript function to check if user is auth -->
|
<!-- javascript function to check if user is auth -->
|
||||||
<script>
|
<script>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="/">
|
||||||
<img src="/images/logo.png" alt="logo" />
|
<img src="images/logo.png" alt="logo" />
|
||||||
</a>
|
</a>
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
||||||
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
@ -128,3 +128,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -4,17 +4,16 @@
|
|||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const app = require('../app');
|
var app = require('../../webserver/modules/express.js');
|
||||||
const debug = require('debug')('proxy-api:server');
|
const index = require("../index.js")
|
||||||
const http = require('http');
|
var debug = require('debug')('proxy-api:server');
|
||||||
const path = require('path');
|
var http = require('http');
|
||||||
require('dotenv').config({ path: path.resolve(__dirname, '../../.env')})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get port from environment and store in Express.
|
* Get port from environment and store in Express.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var port = normalizePort(process.env.NODE_PORT || '3000');
|
const port = normalizePort(process.env.PORT || '80');
|
||||||
app.set('port', port);
|
app.set('port', port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,7 +22,18 @@ app.set('port', port);
|
|||||||
|
|
||||||
var server = http.createServer(app);
|
var server = http.createServer(app);
|
||||||
|
|
||||||
var io = require('socket.io')(server);
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.io = io;
|
app.io = io;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +103,6 @@ function onListening() {
|
|||||||
: 'port ' + addr.port;
|
: 'port ' + addr.port;
|
||||||
console.log('Listening on ' + bind);
|
console.log('Listening on ' + bind);
|
||||||
|
|
||||||
// execute list of functions when app is ready
|
|
||||||
for(let listener of app.onListen){
|
for(let listener of app.onListen){
|
||||||
listener()
|
listener()
|
||||||
}
|
}
|
65
webserver/database/model/apiKeyModel.js
Normal file
65
webserver/database/model/apiKeyModel.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"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 };
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
|
|
||||||
//sequelize.sync();
|
//sequelize.sync();
|
||||||
const api_log_Model = sequelize.define(
|
const api_log_Model = sequelize.define(
|
||||||
@ -68,6 +68,4 @@ const api_log_Model = sequelize.define(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
api_log_Model.sync()
|
|
||||||
|
|
||||||
module.exports = { api_log_Model };
|
module.exports = { api_log_Model };
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
const { isAlphaNumericwithSpaces } = require('../../functions/validateData')
|
const { isAlphaNumericwithSpaces } = require('../../functions/validateData')
|
||||||
|
|
||||||
//sequelize.sync();
|
//sequelize.sync();
|
||||||
@ -72,6 +72,4 @@ const locationModel = sequelize.define(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
locationModel.sync();
|
|
||||||
|
|
||||||
module.exports = { locationModel };
|
module.exports = { locationModel };
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
const { locationModel } = require("./locationModel");
|
const { locationModel } = require("./locationModel");
|
||||||
const { sensorModel } = require("./sensorModel");
|
const { sensorModel } = require("./sensorModel");
|
||||||
const { isJson } = require('../../functions/validateData');
|
const { isJson } = require('../../functions/validateData');
|
||||||
@ -74,6 +74,4 @@ const sensorDataModel = sequelize.define(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
sensorDataModel.sync()
|
|
||||||
|
|
||||||
module.exports = { sensorDataModel };
|
module.exports = { sensorDataModel };
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const { Sequelize, DataTypes } = require("sequelize");
|
const { Sequelize, DataTypes } = require("sequelize");
|
||||||
const { sequelize } = require("../mySql");
|
const { sequelize } = require("../mySQL");
|
||||||
const { locationModel } = require("./locationModel");
|
const { locationModel } = require("./locationModel");
|
||||||
const {
|
const {
|
||||||
isAlphaNumericwithSpaces,
|
isAlphaNumericwithSpaces,
|
||||||
@ -107,6 +107,4 @@ const sensorModel = sequelize.define(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
sensorModel.sync()
|
|
||||||
|
|
||||||
module.exports = { sensorModel };
|
module.exports = { sensorModel };
|
94
webserver/database/model/userModel.js
Normal file
94
webserver/database/model/userModel.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"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 };
|
35
webserver/database/mySQL.js
Normal file
35
webserver/database/mySQL.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
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 };
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
|
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 { Op, Sequelize } = require("sequelize");
|
||||||
const { sequelize } = require("../database/mySql.js");
|
|
||||||
const { sensorDataModel } = require("../database/model/sensorDataModel.js");
|
|
||||||
const io = require('../functions/socket');
|
|
||||||
// const { io } = require('../app')
|
|
||||||
|
|
||||||
//helper function to convert month name to month number
|
//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
|
//https://stackoverflow.com/questions/13566552/easiest-way-to-convert-month-name-to-month-number-in-js-jan-01
|
||||||
@ -13,23 +13,130 @@ function getMonthFromString(mon) {
|
|||||||
}
|
}
|
||||||
return -1;
|
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() {
|
async function getSensorData() {
|
||||||
const sensorData = await sensorDataModel.findAll();
|
const sensorData = await sensorDataModel.findAll();
|
||||||
return sensorData;
|
return sensorData;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addSensorData(id_sensor, id_location, sensordata) {
|
async function addSensorData(id, id_sensor, id_location, sensordata) {
|
||||||
const sensorData = await sensorDataModel.create({
|
const sensorData = await sensorDataModel.create({
|
||||||
|
id: id,
|
||||||
sensorid: id_sensor,
|
sensorid: id_sensor,
|
||||||
locationid: id_location,
|
locationid: id_location,
|
||||||
measurement: sensordata,
|
measurement: sensordata,
|
||||||
});
|
});
|
||||||
|
|
||||||
io().emit('sensordata:new', sensorData)
|
|
||||||
|
|
||||||
return sensorData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateSensorData(id, id_sensor, id_location, sensordata) {
|
async function updateSensorData(id, id_sensor, id_location, sensordata) {
|
||||||
@ -719,6 +826,16 @@ async function getDatabyRange(queryString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
getLocation,
|
||||||
|
addLocation,
|
||||||
|
updateLocation,
|
||||||
|
deleteLocation,
|
||||||
|
getLocationById,
|
||||||
|
getSensor,
|
||||||
|
addSensor,
|
||||||
|
updateSensor,
|
||||||
|
deleteSensor,
|
||||||
|
getSensorById,
|
||||||
getSensorData,
|
getSensorData,
|
||||||
addSensorData,
|
addSensorData,
|
||||||
updateSensorData,
|
updateSensorData,
|
||||||
@ -726,5 +843,4 @@ module.exports = {
|
|||||||
getSensorDataById,
|
getSensorDataById,
|
||||||
getData,
|
getData,
|
||||||
getDatabyRange,
|
getDatabyRange,
|
||||||
|
|
||||||
};
|
};
|
59
webserver/functions/Database.js
Normal file
59
webserver/functions/Database.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
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 };
|
38
webserver/functions/bcrypt.js
Normal file
38
webserver/functions/bcrypt.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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
|
||||||
|
};
|
17
webserver/functions/getAPIKey.js
Normal file
17
webserver/functions/getAPIKey.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//model for getting API key from database
|
||||||
|
|
||||||
|
async function getAPIKey() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { getAPIKey }
|
51
webserver/functions/validateData.js
Normal file
51
webserver/functions/validateData.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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,
|
||||||
|
};
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
const client = require("./modules/mqtt");
|
const client = require("./modules/mqtt");
|
||||||
const { isJson, isNumber } = require("./functions/validateData.js");
|
const { isJson, isNumber } = require("./functions/validateData.js");
|
||||||
const { addSensorData } = require("./functions/sensors.js");
|
const { insertDatatoDB } = require("./functions/database.js");
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
client.on("connect", () => {
|
client.on("connect", () => {
|
||||||
@ -37,7 +37,7 @@ client.on("message", (topic, message) => {
|
|||||||
if (isNumber(data)) {
|
if (isNumber(data)) {
|
||||||
{
|
{
|
||||||
//pass datas to database
|
//pass datas to database
|
||||||
insertDatatoDB(datas[key].sensorid, datas[key].locationid, datas[key]);
|
insertDatatoDB(datas[key]);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
65
webserver/middleware/apiKey.js
Normal file
65
webserver/middleware/apiKey.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
const { checkAPikey } = require("../functions/database.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
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
@ -1,5 +1,4 @@
|
|||||||
const { insertLogData } = require("../functions/logger.js");
|
const { insertLogData } = require("../functions/database.js");
|
||||||
|
|
||||||
const APIlogger = (req, res, next) => {
|
const APIlogger = (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const log = {
|
const log = {
|
91
webserver/modules/express.js
Normal file
91
webserver/modules/express.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
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}`);
|
||||||
|
});
|
||||||
|
*/
|
@ -4,7 +4,7 @@ const {
|
|||||||
getLocationById,
|
getLocationById,
|
||||||
updateLocation,
|
updateLocation,
|
||||||
deleteLocation,
|
deleteLocation,
|
||||||
} = require("../functions/location");
|
} = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
@ -1,6 +1,6 @@
|
|||||||
const { sequelize } = require("../database/mySql.js");
|
const { sequelize } = require("../Database/mySql.js");
|
||||||
const { locationModel } = require("../database/model/locationModel.js");
|
const { locationModel } = require("../Database/model/locationModel.js");
|
||||||
const { sensorModel } = require("../database/model/sensorModel.js");
|
const { sensorModel } = require("../Database/model/sensorModel.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
@ -1,7 +1,7 @@
|
|||||||
const { sequelize } = require("../database/mySql.js");
|
const { sequelize } = require("../Database/mySql.js");
|
||||||
const { locationModel } = require("../database/model/locationModel.js");
|
const { locationModel } = require("../Database/model/locationModel.js");
|
||||||
const { sensorModel } = require("../database/model/sensorModel.js");
|
const { sensorModel } = require("../Database/model/sensorModel.js");
|
||||||
const { sensorDataModel } = require("../database/model/sensorDataModel.js");
|
const { sensorDataModel } = require("../Database/model/sensorDataModel.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
@ -4,7 +4,7 @@ const {
|
|||||||
updateSensor,
|
updateSensor,
|
||||||
deleteSensor,
|
deleteSensor,
|
||||||
getSensorById
|
getSensorById
|
||||||
} = require("../functions/sensor.js");
|
} = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
@ -6,9 +6,10 @@ const {
|
|||||||
getSensorDataById,
|
getSensorDataById,
|
||||||
getData,
|
getData,
|
||||||
getDatabyRange,
|
getDatabyRange,
|
||||||
} = require("../functions/sensorData");
|
} = require("../functions/apiDatabase.js");
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
|
const { json } = require("body-parser");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", async (req, res, next) => {
|
router.get("/", async (req, res, next) => {
|
||||||
@ -23,9 +24,9 @@ router.get("/", async (req, res, next) => {
|
|||||||
|
|
||||||
router.post("/new", async (req, res, next) => {
|
router.post("/new", async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { id_sensor, id_location, sensordata } = req.body;
|
const { id, id_sensor, id_location, sensordata } = req.body;
|
||||||
let data = await addSensorData(id_sensor, id_location, sensordata);
|
await addSensorData(id, id_sensor, id_location, sensordata);
|
||||||
res.json({ message: "SensorData " + data.id + " added", ...data });
|
res.sendStatus(200).json({ message: "SensorData " + id + " added" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
next(error);
|
next(error);
|
77
webserver/routes/apiLog.js
Normal file
77
webserver/routes/apiLog.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
37
webserver/routes/api_route.js
Normal file
37
webserver/routes/api_route.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
'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;
|
@ -2,7 +2,7 @@
|
|||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
|
|
||||||
//location route
|
//location route
|
||||||
router.use('/sensor-data', require('./seedSensorData.js'));
|
router.use('/seedSensorData', require('./seedSensorData.js'));
|
||||||
|
|
||||||
router.use('/seed', require('./seedLocationAndSensor'));
|
router.use('/seed', require('./seedLocationAndSensor'));
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user