rewrite to a module

This commit is contained in:
Mystikfluu 2022-08-19 19:29:14 +02:00
parent c78f4cba3a
commit 6ed17497c5
13 changed files with 1522 additions and 540 deletions

View File

@ -1,5 +1,4 @@
const crypto = require('crypto'); import crypto from "crypto";
/** /**
* hashes with the secure hashing algorithm 256 * hashes with the secure hashing algorithm 256
* @param {string} str string to hash * @param {string} str string to hash
@ -7,19 +6,21 @@ const crypto = require('crypto');
* @param {number} num amount of times to hash, defaults to 1 * @param {number} num amount of times to hash, defaults to 1
* @returns {string} base64 digested hash * @returns {string} base64 digested hash
*/ */
function SHA256(str,salt,num) { function SHA256(str, salt, num) {
if(!num && num!==0)num=1; if (!num && num !== 0)
if(!str)return; num = 1;
let ret = str; if (!str)
for (let i = 0; i < num; i++) { return;
ret = crypto let ret = str;
.createHash("sha256") for (let i = 0; i < num; i++) {
.update(ret+salt) ret = crypto
.digest("base64"); .createHash("sha256")
} .update(ret + salt)
return ret; .digest("base64");
} }
return ret;
module.exports = {
SHA256: SHA256
} }
export { SHA256 };
export default {
SHA256: SHA256
};

View File

@ -1,15 +1,14 @@
const fs = require('fs'); import fs from "fs";
const config = JSON.parse(fs.readFileSync("server_config.json")) const config = JSON.parse(fs.readFileSync("server_config.json"));
/** /**
* gets ip of a request * gets ip of a request
* @param {request} req * @param {request} req
* @returns ip of the given request, after taking preferred headers into account * @returns ip of the given request, after taking preferred headers into account
*/ */
function getIP(req) { function getIP(req) {
let ip = req.socket.remoteAddress; let ip = req.socket.remoteAddress;
if(req.headers[config.preferred_ip_header] != undefined && ip == config.only_prefer_when_ip)ip = req.headers[config.preferred_ip_header] if (req.headers[config.preferred_ip_header] != undefined && ip == config.only_prefer_when_ip)
return ip ip = req.headers[config.preferred_ip_header];
} return ip;
}
module.exports = getIP export default getIP;

View File

@ -1,7 +1,7 @@
const signature = require('cookie-signature') import * as signature from "cookie-signature";
const fs = require('fs'); import fs from "fs";
const cookiesecret = fs.readFileSync("cookiesecret.txt").toString() import getIP from "./getip.js";
const getIP = require("./getip.js") const cookiesecret = fs.readFileSync("cookiesecret.txt").toString();
/** /**
* usignes a string * usignes a string
* @param {string} text text to unsign * @param {string} text text to unsign
@ -9,40 +9,41 @@ const getIP = require("./getip.js")
* @param {response} res response object * @param {response} res response object
* @return {string/boolean} unsigned text, or if unsigning was unsuccessful, false * @return {string/boolean} unsigned text, or if unsigning was unsuccessful, false
*/ */
function unsign(text,req,res) { function unsign(text, req, res) {
let ip = getIP(req) let ip = getIP(req);
let unsigned = signature.unsign(text,cookiesecret+ip) let unsigned = signature.unsign(text, cookiesecret + ip);
if(!unsigned) { if (!unsigned) {
return false return false;
} }
return unsigned return unsigned;
} }
/** /**
* unsignes the auth cookie of a request, also sends json response if auth cookie was invalid * unsignes the auth cookie of a request, also sends json response if auth cookie was invalid
* @param {request} req request object * @param {request} req request object
* @param {response} res response object * @param {response} res response object
* @return {string/boolean} unsigned cookie, or if unsigning was unsuccessful, false * @return {string/boolean} unsigned cookie, or if unsigning was unsuccessful, false
*/ */
function getunsigned(req,res) { function getunsigned(req, res) {
let cookie = req.cookies.AUTH_COOKIE let cookie = req.cookies.AUTH_COOKIE;
if(!cookie){ if (!cookie) {
res.status(400) res.status(400);
res.json({"error":"you are not logged in! (no cookie)"}) res.json({ "error": "you are not logged in! (no cookie)" });
return return;
} }
let unsigned = unsign(cookie,req,res) let unsigned = unsign(cookie, req, res);
if(!unsigned){ if (!unsigned) {
try { try {
res.status(400) res.status(400);
res.json({"error":"Bad auth cookie set"}) res.json({ "error": "Bad auth cookie set" });
} catch (ignored) {} //sometimes it errors, gotta debug soon }
return false catch (ignored) { } //sometimes it errors, gotta debug soon
} return false;
return decodeURIComponent(unsigned) }
} return decodeURIComponent(unsigned);
module.exports = {
unsign: unsign,
getunsigned: getunsigned
} }
export { unsign };
export { getunsigned };
export default {
unsign: unsign,
getunsigned: getunsigned
};

View File

@ -1,27 +1,19 @@
function XOR_hex(a, b) { function XOR_hex(a, b) {
var res = "", var res = "", i = a.length, j = b.length;
i = a.length, while (i-- > 0 && j-- > 0)
j = b.length;
while (i-->0 && j-->0)
res = (parseInt(a.charAt(i), 16) ^ parseInt(b.charAt(j), 16)).toString(16) + res; res = (parseInt(a.charAt(i), 16) ^ parseInt(b.charAt(j), 16)).toString(16) + res;
return res; return res;
} }
function hexEncode(a) {
function hexEncode(a){
let hex; let hex;
let result = ""; let result = "";
for (let i=0; i<a.length; i++) { for (let i = 0; i < a.length; i++) {
hex = a.charCodeAt(i).toString(16); hex = a.charCodeAt(i).toString(16);
result += ("000"+hex).slice(-4); result += ("000" + hex).slice(-4);
} }
return result;
return result
} }
function xor(a, b) {
function xor(a,b) { return XOR_hex(hexEncode(a), hexEncode(b)).toString("hex");
return XOR_hex(hexEncode(a),hexEncode(b)).toString("hex")
} }
export default xor;
module.exports = xor

View File

@ -16,6 +16,7 @@
"start": "node server.js", "start": "node server.js",
"test": "node tests" "test": "node tests"
}, },
"type": "module",
"name": "ipost", "name": "ipost",
"description": "IPost is a revolutionary open-source chatting platform featuring an innovative design", "description": "IPost is a revolutionary open-source chatting platform featuring an innovative design",
"version": "1.0.0", "version": "1.0.0",

View File

@ -1,51 +1,57 @@
const fs = require('fs'); import fs from "fs";
const SHA = require("../../extra_modules/SHA.js") import SHA from "../../extra_modules/SHA.js";
const unsign = require("../../extra_modules/unsign.js") import unsign from "../../extra_modules/unsign.js";
const config = JSON.parse(fs.readFileSync("server_config.json")) const config = JSON.parse(fs.readFileSync("server_config.json"));
const HASHES_DB = config.cookies.server_hashes const HASHES_DB = config.cookies.server_hashes;
const HASHES_COOKIE = config.cookies.client_hashes const HASHES_COOKIE = config.cookies.client_hashes;
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE const HASHES_DIFF = HASHES_DB - HASHES_COOKIE;
export const setup = function (router, con, server) {
module.exports = { router.use("/api/*", async function (req, res, next) {
"setup": function(router,con,server) { res.set("Access-Control-Allow-Origin", "*"); //we'll allow it for now
router.use("/api/*",async function(req,res,next) { if (config["allow_getotheruser_without_cookie"] && req.originalUrl.split("\?")[0] == "/api/getotheruser") {
res.set("Access-Control-Allow-Origin","*") //we'll allow it for now next();
if(config["allow_getotheruser_without_cookie"] && req.originalUrl.split("\?")[0] == "/api/getotheruser") { return;
next()
return
}
if(!server.increaseAPICall(req,res))return;
let unsigned;
if(req.body.user == undefined || req.body.pass == undefined) {
unsigned = unsign.getunsigned(req,res)
if(!unsigned)return
} else {
unsigned = `${req.body.user} ${SHA.SHA256(req.body.pass,req.body.user,HASHES_COOKIE)}`
//basically we generate the unsigned cookie
res.locals.isbot = true //only bots use user+pass
}
let sql = `select User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`
let values = unsigned.split(" ")
values[1] = SHA.SHA256(values[1],values[0],HASHES_DIFF)
res.locals.bio = ""
res.locals.avatar = ""
res.locals.settings = {}
con.query(sql, values, function (err, result) {
if (err) throw err;
if(result[0] && result[0].User_Name && result[0].User_Name == values[0]) {
res.locals.username = values[0];
res.locals.bio = result[0].User_Bio || ""
res.locals.avatar = result[0].User_Avatar || ""
res.locals.settings = JSON.parse(result[0].User_Settings)
if(res.locals.settings == "null")res.locals.settings = {}
if(res.locals.settings == null)res.locals.settings = {}
next()
} else {
res.status(400)
res.json({"error":"you cannot access the api without being logged in"})
} }
}); if (!server.increaseAPICall(req, res))
}) return;
} let unsigned;
} if (req.body.user == undefined || req.body.pass == undefined) {
unsigned = unsign.getunsigned(req, res);
if (!unsigned)
return;
}
else {
unsigned = `${req.body.user} ${SHA.SHA256(req.body.pass, req.body.user, HASHES_COOKIE)}`;
//basically we generate the unsigned cookie
res.locals.isbot = true; //only bots use user+pass
}
let sql = `select User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`;
let values = unsigned.split(" ");
values[1] = SHA.SHA256(values[1], values[0], HASHES_DIFF);
res.locals.bio = "";
res.locals.avatar = "";
res.locals.settings = {};
con.query(sql, values, function (err, result) {
if (err)
throw err;
if (result[0] && result[0].User_Name && result[0].User_Name == values[0]) {
res.locals.username = values[0];
res.locals.bio = result[0].User_Bio || "";
res.locals.avatar = result[0].User_Avatar || "";
res.locals.settings = JSON.parse(result[0].User_Settings);
if (res.locals.settings == "null")
res.locals.settings = {};
if (res.locals.settings == null)
res.locals.settings = {};
next();
}
else {
res.status(400);
res.json({ "error": "you cannot access the api without being logged in" });
}
});
});
};
export default {
setup
};

View File

@ -1,66 +1,62 @@
import {web_version} from "unsafe_encrypt" //const web_version = require("unsafe_encrypt").web_version
import { web_version } from "unsafe_encrypt";
module.exports = { export const setup = function (router, con, server) {
"setup": function(router,con,server) { router.get("/api/getPersonalPosts", async function (req, res) {
router.get("/api/getPersonalPosts", async function(req,res) { res.set("Access-Control-Allow-Origin", "");
res.set("Access-Control-Allow-Origin","") let otherperson = encodeURIComponent(req.query.otherperson || "");
if (typeof otherperson != "string" || otherperson.length > 100 || otherperson == "") {
let otherperson = encodeURIComponent(req.query.otherperson||"") res.status(400).json({ "error": "invalid otherperson given" });
return;
if(typeof otherperson != "string" || otherperson.length > 100 || otherperson=="") { }
res.status(400).json({"error": "invalid otherperson given"}) const columns = [
return "dms_user_name", "dms_text", "dms_time", "dms_special_text", "dms_id", "dms_from_bot", "dms_reply_id"
} ];
//dms_user_name = sender
const columns = [ //dms_receiver = receiver
"dms_user_name","dms_text","dms_time","dms_special_text","dms_id","dms_from_bot","dms_reply_id" //if (sender == current and receiver == other) or (receiver == current and sender == other)
] let sql = `select ${columns.join(",")} from ipost.dms where ((dms_receiver = ? and dms_user_name = ?) or (dms_receiver = ? and dms_user_name = ?)) order by dms_id desc;`;
//dms_user_name = sender con.query(sql, [otherperson, encodeURIComponent(res.locals.username), encodeURIComponent(res.locals.username), otherperson], function (err, result) {
//dms_receiver = receiver if (err)
//if (sender == current and receiver == other) or (receiver == current and sender == other) throw err;
let sql = `select ${columns.join(",")} from ipost.dms where ((dms_receiver = ? and dms_user_name = ?) or (dms_receiver = ? and dms_user_name = ?)) order by dms_id desc;` res.json(result);
con.query(sql, [otherperson,encodeURIComponent(res.locals.username),encodeURIComponent(res.locals.username),otherperson], function (err, result) { });
if (err) throw err; });
res.json(result) router.get("/api/dms/conversations", async function (req, res) {
}); res.set("Access-Control-Allow-Origin", "*");
}) const columns = [
"dms_user_name", "dms_receiver"
router.get("/api/dms/conversations", async function(req,res) { ];
res.set("Access-Control-Allow-Origin","*") let uriencusername = encodeURIComponent(res.locals.username);
let sql = `select ${columns.join(",")} from ipost.dms where ((dms_receiver = ?) or (dms_user_name = ?)) group by dms_receiver,dms_user_name;`;
const columns = [ con.query(sql, [uriencusername, uriencusername], function (err, result) {
"dms_user_name","dms_receiver" if (err)
] throw err;
res.json(result);
let uriencusername = encodeURIComponent(res.locals.username) });
});
let sql = `select ${columns.join(",")} from ipost.dms where ((dms_receiver = ?) or (dms_user_name = ?)) group by dms_receiver,dms_user_name;` router.get("/api/dms/encrypt.js", async function (req, res) {
con.query(sql, [uriencusername,uriencusername], function (err, result) { res.set("Access-Control-Allow-Origin", "*");
if (err) throw err; res.send(web_version());
res.json(result) });
}); //
}) router.get("/api/dms/getDM", async function (req, res) {
res.set("Access-Control-Allow-Origin", "*");
router.get("/api/dms/encrypt.js", async function(req,res) { let arg = req.query.id;
res.set("Access-Control-Allow-Origin","*") let uriencusername = encodeURIComponent(res.locals.username);
res.send(web_version()) let sql = `select dms_user_name,dms_text,dms_time,dms_special_text,dms_id,dms_from_bot,dms_reply_id,dms_receiver from ipost.dms where dms_id=? and (dms_user_name=? or dms_receiver=?);`;
}) con.query(sql, [arg, uriencusername, uriencusername], function (err, result) {
if (err)
// throw err;
router.get("/api/dms/getDM", async function(req,res) { if (result[0]) {
res.set("Access-Control-Allow-Origin","*")
let arg = req.query.id
let uriencusername = encodeURIComponent(res.locals.username)
let sql = `select dms_user_name,dms_text,dms_time,dms_special_text,dms_id,dms_from_bot,dms_reply_id,dms_receiver from ipost.dms where dms_id=? and (dms_user_name=? or dms_receiver=?);`
con.query(sql, [arg,uriencusername,uriencusername], function (err, result) {
if (err) throw err;
if(result[0]) {
res.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish res.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
res.json(result[0]) res.json(result[0]);
} else { }
res.json({"error":"there is no such dm!"}) else {
} res.json({ "error": "there is no such dm!" });
}); }
}) });
} });
} };
export default {
setup
};

View File

@ -1,106 +1,96 @@
const xor = require("../../../extra_modules/xor.js") import xor from "../../../extra_modules/xor.js";
export const setup = function (router, con, server) {
module.exports = { const PIDS = {}; //[pid]: true/"already_used"
"setup": function(router,con,server) { router.get("/api/dms/pid", async function (req, res) {
res.set("Access-Control-Allow-Origin", "*");
const PIDS = {} //[pid]: true/"already_used" let pid = server.genstring(10); //collision chance is low enough, but we'll check anyways
while (PIDS[pid] != undefined) {
router.get("/api/dms/pid", async function(req,res) { pid = server.genstring(10);
res.set("Access-Control-Allow-Origin","*") console.log(5, "pid collision");
let pid = server.genstring(10) //collision chance is low enough, but we'll check anyways }
while (PIDS[pid] != undefined){ PIDS[pid] = true;
pid = server.genstring(10) setTimeout(function () {
console.log(5,"pid collision"); PIDS[pid] = undefined;
} }, 40000);
PIDS[pid] = true res.json({ "pid": pid });
setTimeout(function() { });
PIDS[pid]=undefined router.post("/api/dms/post", async function (req, res) {
},40000) if (!req.body.message) {
res.json({"pid":pid}) res.json({ "error": "no message to post" });
}) return;
}
router.post("/api/dms/post", async function(req,res) { if ((typeof req.body.message) != "string") {
if(!req.body.message) { res.json({ "error": "no message to post" });
res.json({"error":"no message to post"}) return;
return }
} if ((typeof req.body.pid) != "string") {
if((typeof req.body.message) != "string") { res.json({ "error": "no pid given" });
res.json({"error":"no message to post"}) return;
return }
} if (req.body.pid.length != 10 || PIDS[req.body.pid] !== true) {
if((typeof req.body.pid) != "string") { res.json({ "error": "invalid pid given" });
res.json({"error":"no pid given"}) return;
return }
} PIDS[req.body.pid] = "already_used";
if(req.body.pid.length != 10 || PIDS[req.body.pid] !== true) { let reply_id;
res.json({"error":"invalid pid given"}) if (!req.body.reply_id || req.body.reply_id < 0) {
return reply_id = 0;
} }
PIDS[req.body.pid] = "already_used" else {
reply_id = req.body.reply_id;
let reply_id }
if(!req.body.reply_id || req.body.reply_id < 0) { if ((typeof reply_id) != "number") {
reply_id = 0 res.json({ "error": "no valid reply id given" });
} else { return;
reply_id = req.body.reply_id }
} if (req.body.message.length > 1000) {
res.json({ "error": "message too long" });
if((typeof reply_id) != "number") { return;
res.json({"error":"no valid reply id given"}) }
return req.body.message = encodeURIComponent(req.body.message.trim());
} if (req.body.message.length > 3000) {
res.json({ "error": "message too long" }); //check again after URI encoding it
if(req.body.message.length > 1000) { return;
res.json({"error":"message too long"}) }
return req.body.receiver = encodeURIComponent(req.body.receiver || "");
} if (req.body.receiver == "" || req.body.receiver == encodeURIComponent(res.locals.username) || req.body.receiver.length > 100) {
res.status(400).json({ "error": "invalid receiver given" });
req.body.message = encodeURIComponent(req.body.message.trim()) return;
}
if(req.body.message.length > 3000) { let otherperson = req.body.receiver;
res.json({"error":"message too long"}) //check again after URI encoding it if (!req.body.message) {
return res.json({ "error": "no message to post" });
} return;
}
req.body.receiver = encodeURIComponent(req.body.receiver||"") let sql = `insert into ipost.dms (dms_user_name,dms_text,dms_time,dms_receiver,dms_from_bot,dms_reply_id) values (?,?,?,?,?,?);`;
if(req.body.receiver == "" || req.body.receiver == encodeURIComponent(res.locals.username) || req.body.receiver.length > 100) { let values = [encodeURIComponent(res.locals.username), req.body.message, Date.now(), otherperson, res.locals.isbot, reply_id];
res.status(400).json({"error": "invalid receiver given"}) con.query(sql, values, function (err, result) {
return if (err)
} throw err;
let otherperson = req.body.receiver // let post_obj = {
// post_user_name: encodeURIComponent(res.locals.username),
if(!req.body.message) { // post_text: req.body.message,
res.json({"error":"no message to post"}) // post_time: Date.now(),
return // post_special_text: "",
} // post_receiver_name: req.body.receiver,
// post_from_bot: res.locals.isbot,
let sql = `insert into ipost.dms (dms_user_name,dms_text,dms_time,dms_receiver,dms_from_bot,dms_reply_id) values (?,?,?,?,?,?);` // post_reply_id: reply_id
let values = [encodeURIComponent(res.locals.username),req.body.message,Date.now(),otherperson,res.locals.isbot,reply_id] // }
con.query(sql, values, function (err, result) { // let message = {
if (err) throw err; // message: "new_post",
// let post_obj = { // data: post_obj
// post_user_name: encodeURIComponent(res.locals.username), // }
// post_text: req.body.message, // let messagestr = JSON.stringify(message)
// post_time: Date.now(), // server.wss.clients.forEach(function(ws) {
// post_special_text: "", // if(ws.channel == decodeURIComponent(req.body.receiver)) {
// post_receiver_name: req.body.receiver, // ws.send(messagestr)
// post_from_bot: res.locals.isbot, // }
// post_reply_id: reply_id // });
// } res.json({ "success": "successfully posted dm" });
console.log(5, `posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username), otherperson)}`);
// let message = { });
// message: "new_post", });
// data: post_obj };
// } export default {
// let messagestr = JSON.stringify(message) setup
// server.wss.clients.forEach(function(ws) { };
// if(ws.channel == decodeURIComponent(req.body.receiver)) {
// ws.send(messagestr)
// }
// });
res.json({"success":"successfully posted dm"})
console.log(5,`posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username),otherperson)}`);
});
})
}
}

View File

@ -1,57 +1,18 @@
function allowAllTraffic(router,str,type) { function allowAllTraffic(router, str, type) {
router.options(str,async function(req,res,next) { router.options(str, async function (req, res, next) {
res.set("Access-Control-Allow-Origin","*") //we'll allow it for now res.set("Access-Control-Allow-Origin", "*"); //we'll allow it for now
res.set("Access-Control-Allow-Methods",type || "GET") res.set("Access-Control-Allow-Methods", type || "GET");
res.set("Access-Control-Allow-Headers","Content-Type") res.set("Access-Control-Allow-Headers", "Content-Type");
res.status(200).send("") res.status(200).send("");
}) });
} }
function setup(router, con, server) {
module.exports = { allowAllTraffic(router, "/api/pid");
"setup": function(router,con,server) { allowAllTraffic(router, "/api/post", "POST");
// router.options("/api/pid",async function(req,res,next) { allowAllTraffic(router, "/api/getotheruser");
// res.set("Access-Control-Allow-Origin","*") //we'll allow it for now allowAllTraffic(router, "/api/getPost");
// res.set("Access-Control-Allow-Methods","GET") allowAllTraffic(router, "/api/getPostsLowerThan");
// res.set("Access-Control-Allow-Headers","Content-Type") allowAllTraffic(router, "/api/settings");
// res.status(200).send("") allowAllTraffic(router, "/api/settings", "POST");
// })
// router.options("/api/post",async function(req,res,next) {
// res.set("Access-Control-Allow-Origin","*") //we'll allow it for now
// res.set("Access-Control-Allow-Methods","POST")
// res.set("Access-Control-Allow-Headers","Content-Type")
// res.status(200).send("")
// })
// router.options("/api/getotheruser",async function(req,res,next) {
// res.set("Access-Control-Allow-Origin","*") //we'll allow it for now
// res.set("Access-Control-Allow-Methods","GET")
// res.set("Access-Control-Allow-Headers","Content-Type")
// res.status(200).send("")
// })
// router.options("/api/getPost",async function(req,res,next) {
// res.set("Access-Control-Allow-Origin","*") //we'll allow it for now
// res.set("Access-Control-Allow-Methods","GET")
// res.set("Access-Control-Allow-Headers","Content-Type")
// res.status(200).send("")
// })
//
// router.options("/api/getPostsLowerThan",async function(req,res,next) {
// res.set("Access-Control-Allow-Origin","*") //we'll allow it for now
// res.set("Access-Control-Allow-Methods","GET")
// res.set("Access-Control-Allow-Headers","Content-Type")
// res.status(200).send("")
// })
allowAllTraffic(router,"/api/pid")
allowAllTraffic(router,"/api/post","POST")
allowAllTraffic(router,"/api/getotheruser")
allowAllTraffic(router,"/api/getPost")
allowAllTraffic(router,"/api/getPostsLowerThan")
allowAllTraffic(router,"/api/settings")
allowAllTraffic(router,"/api/settings","POST")
}
} }
export { setup };

View File

@ -1,101 +1,93 @@
module.exports = { export const setup = function (router, con, server) {
"setup": function(router,con,server) { const PIDS = {}; //[pid]: true/"already_used"
router.get("/api/pid", async function (req, res) {
const PIDS = {} //[pid]: true/"already_used" res.set("Access-Control-Allow-Origin", "*");
let pid = server.genstring(10); //collision chance is low enough, but we'll check anyways
router.get("/api/pid", async function(req,res) { while (PIDS[pid] != undefined) {
res.set("Access-Control-Allow-Origin","*") pid = server.genstring(10);
let pid = server.genstring(10) //collision chance is low enough, but we'll check anyways console.log(5, "pid collision");
while (PIDS[pid] != undefined){ }
pid = server.genstring(10) PIDS[pid] = true;
console.log(5,"pid collision"); setTimeout(function () {
} PIDS[pid] = undefined;
PIDS[pid] = true }, 40000);
setTimeout(function() { res.json({ "pid": pid });
PIDS[pid]=undefined });
},40000) router.post("/api/post", async function (req, res) {
res.json({"pid":pid}) if (!req.body.message) {
}) res.json({ "error": "no message to post" });
return;
router.post("/api/post", async function(req,res) { }
if(!req.body.message) { if ((typeof req.body.message) != "string") {
res.json({"error":"no message to post"}) res.json({ "error": "no message to post" });
return return;
} }
if((typeof req.body.message) != "string") { if ((typeof req.body.pid) != "string") {
res.json({"error":"no message to post"}) res.json({ "error": "no pid given" });
return return;
} }
if((typeof req.body.pid) != "string") { if (req.body.pid.length != 10 || PIDS[req.body.pid] !== true) {
res.json({"error":"no pid given"}) res.json({ "error": "invalid pid given" });
return return;
} }
if(req.body.pid.length != 10 || PIDS[req.body.pid] !== true) { PIDS[req.body.pid] = "already_used";
res.json({"error":"invalid pid given"}) let reply_id;
return if (!req.body.reply_id || req.body.reply_id < 0) {
} reply_id = 0;
PIDS[req.body.pid] = "already_used" }
else {
let reply_id reply_id = req.body.reply_id;
if(!req.body.reply_id || req.body.reply_id < 0) { }
reply_id = 0 if ((typeof req.body.reply_id) != "number") {
} else { res.json({ "error": "no valid reply id given" });
reply_id = req.body.reply_id return;
} }
if (req.body.message.length > 1000) {
if((typeof req.body.reply_id) != "number") { res.json({ "error": "message too long" });
res.json({"error":"no valid reply id given"}) return;
return }
} req.body.message = encodeURIComponent(req.body.message.trim());
if (req.body.message.length > 3000) {
if(req.body.message.length > 1000) { res.json({ "error": "message too long" }); //check again after URI encoding it
res.json({"error":"message too long"}) return;
return }
} req.body.receiver = encodeURIComponent(req.body.receiver || "");
if (req.body.receiver == "")
req.body.message = encodeURIComponent(req.body.message.trim()) req.body.receiver = "everyone";
if (!req.body.message) {
if(req.body.message.length > 3000) { res.json({ "error": "no message to post" });
res.json({"error":"message too long"}) //check again after URI encoding it return;
return }
} let sql = `insert into ipost.posts (post_user_name,post_text,post_time,post_receiver_name,post_from_bot,post_reply_id) values (?,?,?,?,?,?);`;
let values = [encodeURIComponent(res.locals.username), req.body.message, Date.now(), req.body.receiver, res.locals.isbot, reply_id];
req.body.receiver = encodeURIComponent(req.body.receiver||"") con.query(sql, values, function (err, result) {
if(req.body.receiver == "")req.body.receiver="everyone" if (err)
throw err;
if(!req.body.message) { let post_obj = {
res.json({"error":"no message to post"}) post_user_name: encodeURIComponent(res.locals.username),
return post_text: req.body.message,
} post_time: Date.now(),
post_special_text: "",
let sql = `insert into ipost.posts (post_user_name,post_text,post_time,post_receiver_name,post_from_bot,post_reply_id) values (?,?,?,?,?,?);` post_receiver_name: req.body.receiver,
let values = [encodeURIComponent(res.locals.username),req.body.message,Date.now(),req.body.receiver,res.locals.isbot,reply_id] post_from_bot: res.locals.isbot,
con.query(sql, values, function (err, result) { post_reply_id: reply_id
if (err) throw err; };
let post_obj = { let message = {
post_user_name: encodeURIComponent(res.locals.username), message: "new_post",
post_text: req.body.message, data: post_obj
post_time: Date.now(), };
post_special_text: "", let messagestr = JSON.stringify(message);
post_receiver_name: req.body.receiver, let channel = decodeURIComponent(req.body.receiver);
post_from_bot: res.locals.isbot, server.wss.clients.forEach(async function (ws) {
post_reply_id: reply_id if (ws.channel == channel) {
ws.send(messagestr);
} }
let message = {
message: "new_post",
data: post_obj
}
let messagestr = JSON.stringify(message)
let channel = decodeURIComponent(req.body.receiver)
server.wss.clients.forEach(async function(ws) {
if(ws.channel == channel) {
ws.send(messagestr)
}
});
res.json({"success":"successfully posted message"})
console.log(5,`posted new message by ${res.locals.username} : ${req.body.message}`);
}); });
}) res.json({ "success": "successfully posted message" });
} console.log(5, `posted new message by ${res.locals.username} : ${req.body.message}`);
} });
});
};
export default {
setup
};

View File

@ -1,55 +1,48 @@
const allowed_settings = { //"settingname":["validtypes"] const allowed_settings = {
"ACCR": ["boolean"] "ACCR": ["boolean"]
} };
export const setup = function (router, con, server) {
module.exports = { router.get("/api/settings", function (req, res) {
"setup": function(router,con,server) { res.json(res.locals.settings);
router.get("/api/settings",function(req,res) { });
res.json(res.locals.settings) router.post("/api/settings", function (req, res) {
}) if (!req.body.setting) {
res.json({ "error": "no setting to change" });
router.post("/api/settings",function(req,res) { return;
}
if(!req.body.setting) { if ((typeof req.body.setting) != "string") {
res.json({"error":"no setting to change"}) res.json({ "error": "no setting to change" });
return return;
}
let types = allowed_settings[req.body.setting];
let allowed = false;
let got = typeof req.body.value;
for (let index = 0; index < types.length; index++) {
if (types[index] == got) {
allowed = true;
break;
} }
if((typeof req.body.setting) != "string") { }
res.json({"error":"no setting to change"}) if (!allowed) {
return console.log(5, "incorrect type given, received, expected", typeof req.body.value, allowed_settings[req.body.setting]);
res.json({ "error": "no new setting value given" });
return;
}
let setting_to_change = req.body.setting;
let setting_new_value = req.body.value;
res.locals.settings[setting_to_change] = setting_new_value;
console.log(5, "changing settings", setting_to_change, setting_new_value, res.locals.settings);
let sql = "update ipost.users set User_Settings=? where User_Name=?";
let values = [JSON.stringify(res.locals.settings), res.locals.username];
con.query(sql, values, function (err, result) {
if (err) {
res.json({ "status": "error", "code": err });
return;
} }
res.json({ "status": "success" });
let types = allowed_settings[req.body.setting] });
let allowed = false });
let got = typeof req.body.value };
for (let index = 0; index < types.length; index++) { export default {
if(types[index] == got) { setup
allowed = true; };
break;
}
}
if(!allowed) {
console.log(5,"incorrect type given, received, expected", typeof req.body.value, allowed_settings[req.body.setting])
res.json({"error":"no new setting value given"})
return
}
let setting_to_change = req.body.setting
let setting_new_value = req.body.value
res.locals.settings[setting_to_change] = setting_new_value
console.log(5,"changing settings", setting_to_change, setting_new_value, res.locals.settings)
let sql = "update ipost.users set User_Settings=? where User_Name=?"
let values = [JSON.stringify(res.locals.settings),res.locals.username]
con.query(sql, values, function (err, result) {
if(err) {
res.json({"status":"error","code":err})
return
}
res.json({"status":"success"})
})
})
}
}

View File

@ -1,5 +1,5 @@
const fs = require("fs"); import "fs"
const util = require('util'); import {format} from "util"
/** /**
@ -14,7 +14,7 @@ function ensureExists(path, mask, cb) {
cb = mask; cb = mask;
mask = 0o744; mask = 0o744;
} }
fs.mkdir(path, mask, function(err) { mkdir(path, mask, function(err) {
if (err) { if (err) {
if (err.code == 'EEXIST') cb(null); // Ignore the error if the folder already exists if (err.code == 'EEXIST') cb(null); // Ignore the error if the folder already exists
else cb(err); // Something else went wrong else cb(err); // Something else went wrong
@ -22,7 +22,7 @@ function ensureExists(path, mask, cb) {
}); });
} }
const config = JSON.parse(fs.readFileSync("server_config.json")) const config = JSON.parse(readFileSync("server_config.json"))
const time = Date.now() const time = Date.now()
const original_log = console.log const original_log = console.log
@ -41,13 +41,13 @@ function log_info(level, ...info) {
level = 5 level = 5
} }
if(config["logs"] && config["logs"]["level"] && config["logs"]["level"] >= level) { if(config["logs"] && config["logs"]["level"] && config["logs"]["level"] >= level) {
let tolog = `[INFO] [${Date.now()}] : ${util.format(text)} \n` let tolog = `[INFO] [${Date.now()}] : ${format(text)} \n`
original_log(tolog) //still has some nicer colors original_log(tolog) //still has some nicer colors
ensureExists(__dirname + '/logs/', function(err) { ensureExists(__dirname + '/logs/', function(err) {
if(err) { if(err) {
process.stderr.write(tolog) //just write it to stderr process.stderr.write(tolog) //just write it to stderr
} else { } else {
fs.appendFile(__dirname+"/logs/"+time,tolog,function(err){ appendFile(__dirname+"/logs/"+time,tolog,function(err){
if(err){ if(err){
process.stderr.write(err) process.stderr.write(err)
} }
@ -67,7 +67,6 @@ console.log(5,"starting up")
const http = require('http'); const http = require('http');
const https = require('https'); const https = require('https');
const crypto = require("crypto");
const express = require("express"); const express = require("express");
const useragent = require('express-useragent'); const useragent = require('express-useragent');
const fileUpload = require('express-fileupload'); const fileUpload = require('express-fileupload');
@ -93,12 +92,12 @@ const con = mysql.createPool({
connectionLimit : config.mysql.connections, connectionLimit : config.mysql.connections,
host: config.mysql.host, host: config.mysql.host,
user: config.mysql.user, user: config.mysql.user,
password: fs.readFileSync(config.mysql.password_file).toString() password: readFileSync(config.mysql.password_file).toString()
}); });
const dir = __dirname + "/" const dir = __dirname + "/"
const cookiesecret = fs.readFileSync("cookiesecret.txt").toString() const cookiesecret = readFileSync("cookiesecret.txt").toString()
const SHA = require("./extra_modules/SHA.js") const SHA = require("./extra_modules/SHA.js")
@ -419,19 +418,34 @@ var commonfunctions = {
genstring genstring
} }
const toLoad = [ import {setup as optionssetup} from "./routes/api/options.js"
"api/options.js", import {setup as allsetup} from "./routes/api/all.js"
"api/all.js", import {setup as settingshandlersetup} from "./routes/api/settingshandler.js"
"api/settingshandler.js", import {setup as postsetup} from "./routes/api/post.js"
"api/post.js", import {setup as dmsPersonalMessagessetup} from "./routes/api/dms/PersonalMessages.js"
"api/dms/PersonalMessages.js", import {setup as dmspostsetup} from "./routes/api/dms/post.js"
"api/dms/post.js",
]
for (let i = 0; i < toLoad.length; i++) { optionssetup(router,con,commonfunctions)
require("./routes/"+toLoad[i]).setup(router,con,commonfunctions) allsetup(router,con,commonfunctions)
} settingshandlersetup(router,con,commonfunctions)
postsetup(router,con,commonfunctions)
dmsPersonalMessagessetup(router,con,commonfunctions)
dmspostsetup(router,con,commonfunctions)
// const toLoad = [
// "api/options.js",
// "api/all.js",
// "api/settingshandler.js",
// "api/post.js",
// "api/dms/PersonalMessages.js",
// "api/dms/post.js",
// ]
// for (let i = 0; i < toLoad.length; i++) {
// require("./routes/"+toLoad[i]).setup(router,con,commonfunctions)
// }
// let options = require("./routes/api/options.js") // let options = require("./routes/api/options.js")
// options.setup(router,con,commonfunctions) // options.setup(router,con,commonfunctions)
@ -494,10 +508,10 @@ router.post("/api/setavatar",function(req,res) {
return res.status(500).json({"error":"there's been an internal server error."}) return res.status(500).json({"error":"there's been an internal server error."})
} }
if(res.locals.avatar) { if(res.locals.avatar) {
fs.unlinkSync(avatars + res.locals.avatar) unlinkSync(avatars + res.locals.avatar)
} }
let filename = genstring(96) + ".png" let filename = genstring(96) + ".png"
while(fs.existsSync(avatars + "/" + filename) || filename == ".png") { while(existsSync(avatars + "/" + filename) || filename == ".png") {
console.log(5,"already have file: ",filename); console.log(5,"already have file: ",filename);
original_log("already have file: ",filename) original_log("already have file: ",filename)
filename = genstring(96) + ".png" filename = genstring(96) + ".png"
@ -513,7 +527,7 @@ router.post("/api/setavatar",function(req,res) {
con.query(sql, [filename,encodeURIComponent(res.locals.username)], function (err, result) { con.query(sql, [filename,encodeURIComponent(res.locals.username)], function (err, result) {
if (err) throw err; if (err) throw err;
res.json({"success":"updated avatar"}) res.json({"success":"updated avatar"})
fs.unlinkSync(avatars+"temp_"+filename) unlinkSync(avatars+"temp_"+filename)
}); });
}) })
}) })
@ -769,7 +783,7 @@ router.get("/users/*", async function(req,res) {
router.get("/css/*", (request, response) => { router.get("/css/*", (request, response) => {
if(!increaseUSERCall(request,response))return if(!increaseUSERCall(request,response))return
if(fs.existsSync(__dirname + request.originalUrl)){ if(existsSync(__dirname + request.originalUrl)){
response.sendFile(__dirname + request.originalUrl); response.sendFile(__dirname + request.originalUrl);
} else { } else {
response.status(404).send("no file with that name found") response.status(404).send("no file with that name found")
@ -779,7 +793,7 @@ router.get("/css/*", (request, response) => {
router.get("/js/*", (request, response) => { router.get("/js/*", (request, response) => {
if(!increaseUSERCall(request,response))return if(!increaseUSERCall(request,response))return
if(fs.existsSync(__dirname + request.originalUrl)){ if(existsSync(__dirname + request.originalUrl)){
response.sendFile(__dirname + request.originalUrl); response.sendFile(__dirname + request.originalUrl);
} else { } else {
response.status(404).send("no file with that name found") response.status(404).send("no file with that name found")
@ -789,7 +803,7 @@ router.get("/js/*", (request, response) => {
router.get("/images/*", (request, response) => { router.get("/images/*", (request, response) => {
if(!increaseUSERCall(request,response))return if(!increaseUSERCall(request,response))return
if(fs.existsSync(__dirname + request.originalUrl)){ if(existsSync(__dirname + request.originalUrl)){
response.sendFile(__dirname + request.originalUrl); response.sendFile(__dirname + request.originalUrl);
} else { } else {
response.status(404).send("no file with that name found") response.status(404).send("no file with that name found")
@ -801,10 +815,10 @@ router.get("/avatars/*", (request, response, next) => {
if(!increaseUSERCall(request,response))return if(!increaseUSERCall(request,response))return
response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
let originalUrl = request.originalUrl.split("?").shift() let originalUrl = request.originalUrl.split("?").shift()
if(fs.existsSync(dir + originalUrl + ".png")) { if(existsSync(dir + originalUrl + ".png")) {
return response.sendFile(dir + originalUrl + ".png"); return response.sendFile(dir + originalUrl + ".png");
} }
if(fs.existsSync(dir + originalUrl)) { if(existsSync(dir + originalUrl)) {
return response.sendFile(dir + originalUrl); return response.sendFile(dir + originalUrl);
} }
response.status(404).send("No avatar with that name found") response.status(404).send("No avatar with that name found")
@ -818,16 +832,16 @@ router.get("/logout",async function(req,res) {
router.get("/*", (request, response, next) => { router.get("/*", (request, response, next) => {
if(!increaseUSERCall(request,response))return if(!increaseUSERCall(request,response))return
let originalUrl = request.originalUrl.split("?").shift() let originalUrl = request.originalUrl.split("?").shift()
if(fs.existsSync(dir + "views/"+originalUrl+".html")) { if(existsSync(dir + "views/"+originalUrl+".html")) {
return response.sendFile(dir + "views/"+originalUrl+".html"); return response.sendFile(dir + "views/"+originalUrl+".html");
} }
if(fs.existsSync(dir + "views"+originalUrl)) { if(existsSync(dir + "views"+originalUrl)) {
return response.sendFile(dir + "views"+originalUrl); return response.sendFile(dir + "views"+originalUrl);
} }
if(fs.existsSync(dir + "views"+originalUrl+".html")) { if(existsSync(dir + "views"+originalUrl+".html")) {
return response.sendFile(dir + "views"+originalUrl+".html"); return response.sendFile(dir + "views"+originalUrl+".html");
} }
if(fs.existsSync(dir + "views"+originalUrl)) { if(existsSync(dir + "views"+originalUrl)) {
return response.sendFile(dir + "views"+originalUrl); return response.sendFile(dir + "views"+originalUrl);
} }
response.status(404).send("No file with that name found") response.status(404).send("No file with that name found")
@ -986,8 +1000,8 @@ httpServer.listen(config["ports"]["http"],function(){
console.log(5,"HTTP Server is listening") console.log(5,"HTTP Server is listening")
}); });
const privateKey = fs.readFileSync(config["ssl"]["privateKey"]).toString() const privateKey = readFileSync(config["ssl"]["privateKey"]).toString()
const certificate = fs.readFileSync(config["ssl"]["certificate"]).toString() const certificate = readFileSync(config["ssl"]["certificate"]).toString()
const credentials = {key: privateKey, cert: certificate}; const credentials = {key: privateKey, cert: certificate};

1036
server_esm.js Normal file

File diff suppressed because it is too large Load Diff