Custom session for distributed servers

- Adding custom session login for the distributed server system.
- Added Sessions table to backup
This commit is contained in:
sairajzero 2022-01-18 05:11:34 +05:30
parent abb82b0b34
commit 348cc989c9
3 changed files with 123 additions and 129 deletions

View File

@ -8,10 +8,11 @@ PRIMARY KEY(floID)
); );
CREATE TABLE Sessions ( CREATE TABLE Sessions (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL, floID CHAR(34) NOT NULL,
proxyKey CHAR(66) NOT NULL, proxyKey CHAR(66) NOT NULL,
session_id VARCHAR(100) UNIQUE,
session_time DATETIME DEFAULT CURRENT_TIMESTAMP, session_time DATETIME DEFAULT CURRENT_TIMESTAMP,
KEY (id),
PRIMARY KEY(floID), PRIMARY KEY(floID),
FOREIGN KEY (floID) REFERENCES Users(floID) FOREIGN KEY (floID) REFERENCES Users(floID)
); );
@ -129,8 +130,7 @@ tag VARCHAR(50) NOT NULL,
sellPriority INT, sellPriority INT,
buyPriority INT, buyPriority INT,
api TINYTEXT, api TINYTEXT,
PRIMARY KEY(tag), PRIMARY KEY(tag)
KEY (id)
); );
CREATE TABLE Tags ( CREATE TABLE Tags (
@ -184,6 +184,13 @@ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(t_name, id) PRIMARY KEY(t_name, id)
); );
CREATE TRIGGER Sessions_I AFTER INSERT ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Sessions_U AFTER UPDATE ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Sessions_D AFTER DELETE ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER Cash_I AFTER INSERT ON Cash CREATE TRIGGER Cash_I AFTER INSERT ON Cash
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Cash_U AFTER UPDATE ON Cash CREATE TRIGGER Cash_U AFTER UPDATE ON Cash

View File

@ -1,9 +1,8 @@
'use strict'; 'use strict';
const express = require('express'); const express = require('express');
const cookieParser = require("cookie-parser"); //const cookieParser = require("cookie-parser");
const sessions = require('express-session'); //const sessions = require('express-session');
const Request = require('./request'); const Request = require('./request');
const WebSocket = require('ws');
const REFRESH_INTERVAL = 5 * 1000; //10 * 60 * 1000; const REFRESH_INTERVAL = 5 * 1000; //10 * 60 * 1000;
@ -12,16 +11,15 @@ module.exports = function App(secret, DB) {
if (!(this instanceof App)) if (!(this instanceof App))
return new App(secret, DB); return new App(secret, DB);
var server = null, var server = null;
wss = null;
const app = express(); const app = express();
//session middleware //session middleware
app.use(sessions({ /*app.use(sessions({
secret: secret, secret: secret,
saveUninitialized: true, saveUninitialized: true,
resave: false, resave: false,
name: "session" name: "session"
})); }));*/
// parsing the incoming data // parsing the incoming data
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded({ app.use(express.urlencoded({
@ -30,12 +28,17 @@ module.exports = function App(secret, DB) {
//serving public file //serving public file
app.use(express.static(PUBLIC_DIR)); app.use(express.static(PUBLIC_DIR));
// cookie parser middleware // cookie parser middleware
app.use(cookieParser()); //app.use(cookieParser());
/* Decentralising - Users will load from user-end files and request via APIs only
//Initital page loading //Initital page loading
app.get('/', (req, res) => res.sendFile('home.html', { app.get('/', (req, res) => res.sendFile('home.html', {
root: PUBLIC_DIR root: PUBLIC_DIR
})); }));
*/
//get code for login or signup
app.get('/get-login-code', Request.getLoginCode);
//signup request //signup request
app.post('/signup', Request.SignUp); app.post('/signup', Request.SignUp);
@ -76,6 +79,7 @@ module.exports = function App(secret, DB) {
app.post('/remove-tag', Request.removeUserTag); app.post('/remove-tag', Request.removeUserTag);
Request.DB = DB; Request.DB = DB;
Request.secret = secret;
//Properties //Properties
var periodInstance = null; var periodInstance = null;

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const market = require("./market"); const market = require("./market");
var DB, trustedIDs; //container for database var DB, trustedIDs, secret; //container for database
global.INVALID = function(message) { global.INVALID = function(message) {
if (!(this instanceof INVALID)) if (!(this instanceof INVALID))
@ -28,6 +28,8 @@ function validateRequestFromFloID(request, sign, floID, proxy = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!serving) if (!serving)
return reject(INVALID(INVALID_SERVER_MSG)); return reject(INVALID(INVALID_SERVER_MSG));
else if (!floCrypto.validateAddr(floID))
return res.status(INVALID.e_code).send("Invalid floID");
DB.query("SELECT " + (proxy ? "proxyKey AS pubKey FROM Sessions" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => { DB.query("SELECT " + (proxy ? "proxyKey AS pubKey FROM Sessions" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => {
if (result.length < 1) if (result.length < 1)
return reject(INVALID(proxy ? "Session not active" : "User not registered")); return reject(INVALID(proxy ? "Session not active" : "User not registered"));
@ -57,18 +59,26 @@ function storeRequest(floID, req_str, sign) {
.then(_ => null).catch(error => console.error(error)); .then(_ => null).catch(error => console.error(error));
} }
function getLoginCode(req, res) {
let randID = floCrypto.randString(8, true) + Math.round(Date.now() / 1000);
let hash = Crypto.SHA1(randID + secret);
res.status(INVALID.e_code).send({
code: randID,
hash: hash
});
}
function SignUp(req, res) { function SignUp(req, res) {
if (!serving) if (!serving)
return res.status(INVALID.e_code).send(INVALID_SERVER_MSG); return res.status(INVALID.e_code).send(INVALID_SERVER_MSG);
let data = req.body, let data = req.body;
session = req.session;
if (floCrypto.getFloID(data.pubKey) !== data.floID) if (floCrypto.getFloID(data.pubKey) !== data.floID)
return res.status(INVALID.e_code).send("Invalid Public Key"); return res.status(INVALID.e_code).send("Invalid Public Key");
if (!session.random) if (!data.code || data.hash != Crypto.SHA1(data.code + secret))
return res.status(INVALID.e_code).send("Invalid Session"); return res.status(INVALID.e_code).send("Invalid Code");
let req_str = validateRequest({ let req_str = validateRequest({
type: "create_account", type: "create_account",
random: session.random, random: data.code,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.pubKey); }, data.sign, data.pubKey);
if (req_str instanceof INVALID) if (req_str instanceof INVALID)
@ -90,22 +100,18 @@ function SignUp(req, res) {
} }
function Login(req, res) { function Login(req, res) {
let data = req.body, let data = req.body;
session = req.session; if (!data.code || data.hash != Crypto.SHA1(data.code + secret))
if (!session.random) return res.status(INVALID.e_code).send("Invalid Code");
return res.status(INVALID.e_code).send("Invalid Session");
validateRequestFromFloID({ validateRequestFromFloID({
type: "login", type: "login",
random: session.random, random: data.code,
proxyKey: data.proxyKey, proxyKey: data.proxyKey,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID, false).then(req_str => { }, data.sign, data.floID, false).then(req_str => {
DB.query("INSERT INTO Sessions (floID, session_id, proxyKey) VALUES (?, ?, ?) " + DB.query("INSERT INTO Sessions (floID, proxyKey) VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE session_id=?, session_time=DEFAULT, proxyKey=?", "ON DUPLICATE KEY UPDATE session_time=DEFAULT, proxyKey=?",
[data.floID, req.sessionID, data.proxyKey, req.sessionID, data.proxyKey]).then(_ => { [data.floID, data.code, data.proxyKey, data.code, data.proxyKey]).then(_ => {
if (data.saveSession)
session.cookie.maxAge = maxSessionTimeout;
session.user_id = data.floID;
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send("Login Successful"); res.send("Login Successful");
}).catch(error => { }).catch(error => {
@ -123,32 +129,38 @@ function Login(req, res) {
} }
function Logout(req, res) { function Logout(req, res) {
let session = req.session; validateRequestFromFloID({
if (!session.user_id) type: "logout",
return res.status(INVALID.e_code).send("No logged in user found in this session"); timestamp: data.timestamp
DB.query("DELETE FROM Sessions WHERE floID=?", [session.user_id]).then(_ => { }, data.sign, data.floID).then(req_str => {
session.destroy(); DB.query("DELETE FROM Sessions WHERE floID=?", [data.floID]).then(_ => {
res.send('Logout successful'); storeRequest(data.floID, req_str, data.sign);
res.send('Logout successful');
}).catch(error => {
console.error(error);
res.status(INTERNAL.e_code).send("Logout failed! Try again later! Contact support if this error occurs frequently");
});
}).catch(error => { }).catch(error => {
console.error(error); if (error instanceof INVALID)
res.status(INTERNAL.e_code).send("Logout failed! Try again later! Contact support if this error occurs frequently"); res.status(INVALID.e_code).send(error.message);
else {
console.error(error);
res.status(INTERNAL.e_code).send("Request processing failed! Try again later!");
}
}); });
} }
function PlaceSellOrder(req, res) { function PlaceSellOrder(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "sell_order", type: "sell_order",
quantity: data.quantity, quantity: data.quantity,
min_price: data.min_price, min_price: data.min_price,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.addSellOrder(session.user_id, data.quantity, data.min_price) market.addSellOrder(data.floID, data.quantity, data.min_price)
.then(result => { .then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send('Sell Order placed successfully'); res.send('Sell Order placed successfully');
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -169,19 +181,16 @@ function PlaceSellOrder(req, res) {
} }
function PlaceBuyOrder(req, res) { function PlaceBuyOrder(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "buy_order", type: "buy_order",
quantity: data.quantity, quantity: data.quantity,
max_price: data.max_price, max_price: data.max_price,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.addBuyOrder(session.user_id, data.quantity, data.max_price) market.addBuyOrder(data.floID, data.quantity, data.max_price)
.then(result => { .then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send('Buy Order placed successfully'); res.send('Buy Order placed successfully');
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -202,19 +211,16 @@ function PlaceBuyOrder(req, res) {
} }
function CancelOrder(req, res) { function CancelOrder(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "cancel_order", type: "cancel_order",
order: data.orderType, order: data.orderType,
id: data.orderID, id: data.orderID,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.cancelOrder(data.orderType, data.orderID, session.user_id) market.cancelOrder(data.orderType, data.orderID, data.floID)
.then(result => { .then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -263,54 +269,42 @@ function getRate(req, res) {
} }
function Account(req, res) { function Account(req, res) {
if (!serving) let data = req.body;
return res.status(INVALID.e_code).send(INVALID_SERVER_MSG); validateRequestFromFloID({
const setLogin = function(message) { type: "get_account",
let randID = floCrypto.randString(16, true); timestamp: data.timestamp
req.session.random = randID; }, data.sign, data.floID).then(req_str => {
res.status(INVALID.e_code).send({ DB.query("SELECT session_time FROM Sessions WHERE floID=?", [data.floID]).then(result => {
message, if (result.length < 1)
sid: randID
});
}
if (!req.session.user_id)
setLogin("Login required");
else {
DB.query("SELECT session_id, session_time FROM Sessions WHERE floID=?", [req.session.user_id]).then(result => {
if (result.length < 1) {
res.status(INVALID.e_code).send("floID not registered"); res.status(INVALID.e_code).send("floID not registered");
return; else if (result[0].session_time + maxSessionTimeout < Date.now())
} res.status(INVALID.e_code).send("Session Expired! Re-login required");
let { else
session_id, market.getAccountDetails(data.floID).then(result => {
session_time if (trustedIDs.includes(data.floID))
} = result.pop();
if (!session_id || session_id != req.sessionID || session_time + maxSessionTimeout < Date.now())
setLogin("Session Expired! Re-login required");
else {
let floID = req.session.user_id;
market.getAccountDetails(floID).then(result => {
if (trustedIDs.includes(floID))
result.subAdmin = true; result.subAdmin = true;
res.send(result) res.send(result);
}); });
}
}).catch(_ => res.status(INTERNAL.e_code).send("Try again later!")); }).catch(_ => res.status(INTERNAL.e_code).send("Try again later!"));
} }).catch(error => {
if (error instanceof INVALID)
res.status(INVALID.e_code).send(error.message);
else {
console.error(error);
res.status(INTERNAL.e_code).send("Request processing failed! Try again later!");
}
});
} }
function DepositFLO(req, res) { function DepositFLO(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "deposit_FLO", type: "deposit_FLO",
txid: data.txid, txid: data.txid,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.depositFLO(session.user_id, data.txid).then(result => { market.depositFLO(data.floID, data.txid).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -331,17 +325,14 @@ function DepositFLO(req, res) {
} }
function WithdrawFLO(req, res) { function WithdrawFLO(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "withdraw_FLO", type: "withdraw_FLO",
amount: data.amount, amount: data.amount,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.withdrawFLO(session.user_id, data.amount).then(result => { market.withdrawFLO(data.floID, data.amount).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -362,17 +353,14 @@ function WithdrawFLO(req, res) {
} }
function DepositRupee(req, res) { function DepositRupee(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "deposit_Rupee", type: "deposit_Rupee",
txid: data.txid, txid: data.txid,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.depositRupee(session.user_id, data.txid).then(result => { market.depositRupee(data.floID, data.txid).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -393,17 +381,14 @@ function DepositRupee(req, res) {
} }
function WithdrawRupee(req, res) { function WithdrawRupee(req, res) {
let data = req.body, let data = req.body;
session = req.session;
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
validateRequestFromFloID({ validateRequestFromFloID({
type: "withdraw_Rupee", type: "withdraw_Rupee",
amount: data.amount, amount: data.amount,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.withdrawRupee(session.user_id, data.amount).then(result => { market.withdrawRupee(data.floID, data.amount).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -424,20 +409,17 @@ function WithdrawRupee(req, res) {
} }
function addUserTag(req, res) { function addUserTag(req, res) {
let data = req.body, let data = req.body;
session = req.session; if (!trustedIDs.includes(data.floID))
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
else if (!trustedIDs.includes(session.user_id))
return res.status(INVALID.e_code).send("Access Denied"); return res.status(INVALID.e_code).send("Access Denied");
validateRequestFromFloID({ validateRequestFromFloID({
command: "add_Tag", command: "add_Tag",
user: data.user, user: data.user,
tag: data.tag, tag: data.tag,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.group.addTag(data.user, data.tag).then(result => { market.group.addTag(data.user, data.tag).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -458,11 +440,8 @@ function addUserTag(req, res) {
} }
function removeUserTag(req, res) { function removeUserTag(req, res) {
let data = req.body, let data = req.body;
session = req.session; if (!trustedIDs.includes(data.floID))
if (!session.user_id)
return res.status(INVALID.e_code).send("Login required");
else if (!trustedIDs.includes(session.user_id))
return res.status(INVALID.e_code).send("Access Denied"); return res.status(INVALID.e_code).send("Access Denied");
else else
validateRequestFromFloID({ validateRequestFromFloID({
@ -470,9 +449,9 @@ function removeUserTag(req, res) {
user: data.user, user: data.user,
tag: data.tag, tag: data.tag,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, session.user_id).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.group.removeTag(data.user, data.tag).then(result => { market.group.removeTag(data.user, data.tag).then(result => {
storeRequest(session.user_id, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
if (error instanceof INVALID) if (error instanceof INVALID)
@ -493,6 +472,7 @@ function removeUserTag(req, res) {
} }
module.exports = { module.exports = {
getLoginCode,
SignUp, SignUp,
Login, Login,
Logout, Logout,
@ -518,6 +498,9 @@ module.exports = {
DB = db; DB = db;
market.DB = db; market.DB = db;
}, },
set secret(s) {
secret = s;
},
pause() { pause() {
serving = false; serving = false;
}, },