Compare commits

..

1 Commits

Author SHA1 Message Date
snyk-bot
6b97548f24
fix: upgrade sharp from 0.30.7 to 0.31.3
Snyk has created this PR to upgrade sharp from 0.30.7 to 0.31.3.

See this package in npm:
https://www.npmjs.com/package/sharp

See this project in Snyk:
https://app.snyk.io/org/mystikfluu/project/c5b23892-809c-4121-9c2f-67962c7a4953?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-03-04 16:42:11 +00:00
22 changed files with 2260 additions and 9143 deletions

3
.gitignore vendored
View File

@ -7,5 +7,4 @@ ignore/*
avatars/* avatars/*
etc/* etc/*
*newrelic* *newrelic*
user_uploads/* user_uploads/*
swagger-api.json

View File

@ -1,3 +1,3 @@
# IPost # IPost
IPost, formerly known as "authwebsite" is a chatting platform that also server as a gateway for me to have authentication for my other projects. IPost, formerly known as "authwebsite" is a chatting platform that mainly has one thing in mind: privacy.
You can visit IPost under https://ipost.rocks You can visit IPost under https://ipost.rocks

View File

@ -4,7 +4,7 @@
403: login error (no cookie) 403: login error (no cookie)
404: invalid url / not found 404: invalid url / not found
410-419: argument/data error 410-419: argument/data error
420: invalid authentication object 420: invalid authetication object
429: ratelimit 429: ratelimit
500: server error 500: server error

617
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,23 @@
{ {
"dependencies": { "dependencies": {
"body-parser": "^1.20.2", "body-parser": "^1.20.1",
"clean-css": "^5.3.2", "clean-css": "^5.3.2",
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"ejs": "^3.1.9", "ejs": "^3.1.8",
"express": "^4.18.2", "express": "^4.18.2",
"express-fileupload": "^1.3.1", "express-fileupload": "^1.3.1",
"express-useragent": "^1.0.15", "express-useragent": "^1.0.15",
"hcaptcha": "^0.1.1", "hcaptcha": "^0.1.1",
"hsts": "^2.2.0", "html-minifier-terser": "^7.1.0",
"newrelic": "^9.15.0", "lru-cache": "^7.14.1",
"html-minifier-terser": "^7.2.0", "mysql2": "^3.1.2",
"lru-cache": "^9.1.2", "newrelic": "^9.8.1",
"mysql2": "^3.3.5", "sharp": "^0.31.3",
"newrelic": "^9.11.0",
"sharp": "^0.30.7",
"spdy": "^4.0.2", "spdy": "^4.0.2",
"swagger-autogen": "^2.23.1",
"uglify-js": "^3.17.4", "uglify-js": "^3.17.4",
"unsafe_encrypt": "^1.0.4", "unsafe_encrypt": "^1.0.4",
"ws": "^8.13.0" "ws": "^8.12.0"
}, },
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",

View File

@ -10,67 +10,76 @@ export const setup = function (router, con, server) {
router.use("/*", (req, res, next) => { router.use("/*", (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
let unsigned; let unsigned;
if(typeof req.get("ipost-auth-token") === "string") { if (req.body.user === undefined || req.body.pass === undefined) {
try{ if(typeof req.get("ipost-auth-token") === "string") {
req.body.auth = JSON.parse(req.get("ipost-auth-token"))
} catch(err) {
console.log("error parsing header",err)
}
}
if(req.body.auth !== undefined && req.originalUrl !== "/redeemauthcode") {
if(typeof req.body.auth === "string") {
try{ try{
req.body.auth = JSON.parse(req.body.auth) req.body.auth = JSON.parse(req.get("ipost-auth-token"))
} catch(err) { } catch(err) {
console.log("error parsing",err) console.log("error parsing header",err)
} }
} else }
if( if(req.body.auth !== undefined && req.originalUrl !== "/redeemauthcode") {
typeof req.body.auth !== "object" || if(typeof req.body.auth === "string") {
typeof req.body.auth.secret !== "string" || try{
typeof req.body.auth.appid !== "number" || req.body.auth = JSON.parse(req.body.auth)
typeof req.body.auth.auth_token !== "string" || } catch(err) {
req.body.auth.secret.length !== 200 || console.log("error parsing",err)
req.body.auth.auth_token.length !== 200 ||
Buffer.from(req.body.auth.secret,"base64").length !== 150
) {
res.status(420).send("invalid authentication object")
return;
} else {
//secret : string(200 chars)
//appid : number
//auth_token: string(200 chars)
let sql = "select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.auth_tokens inner join ipost.application on auth_token_isfrom_application_id=application_id inner join ipost.users on auth_token_u_id=User_ID where auth_token=? and application_secret=? and application_id=?"
con.query(sql,[SHA256(req.body.auth.auth_token,req.body.auth.appid, HASHES_DB),SHA256(req.body.auth.secret,req.body.auth.appid, HASHES_DB),req.body.auth.appid],(err,result) => {
if(err) throw err;
if(result.length !== 1) {
res.status(420).send("invalid authentication object (or server error?)")
return;
} }
} else
if(
typeof req.body.auth !== "object" ||
typeof req.body.auth.secret !== "string" ||
typeof req.body.auth.appid !== "number" ||
typeof req.body.auth.auth_token !== "string" ||
req.body.auth.secret.length !== 200 ||
req.body.auth.auth_token.length !== 200 ||
Buffer.from(req.body.auth.secret,"base64").length !== 150
) {
res.status(420).send("invalid authentication object")
return;
} else {
//secret : string(200 chars)
//appid : number
//auth_token: string(200 chars)
let sql = "select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.auth_tokens inner join ipost.application on auth_token_isfrom_application_id=application_id inner join ipost.users on auth_token_u_id=User_ID where auth_token=? and application_secret=? and application_id=?"
con.query(sql,[SHA256(req.body.auth.auth_token,req.body.auth.appid, HASHES_DB),SHA256(req.body.auth.secret,req.body.auth.appid, HASHES_DB),req.body.auth.appid],(err,result) => {
if(err) throw err;
res.locals.userid = result[0].User_ID; if(result.length !== 1) {
res.locals.username = result[0].User_Name; res.status(420).send("invalid authentication object (or server error?)")
res.locals.bio = result[0].User_Bio || ""; return;
res.locals.avatar = result[0].User_Avatar || ""; }
res.locals.settings = result[0].User_Settings || {};
res.locals.isbot = true; //only apps/bots use auth tokens res.locals.userid = result[0].User_ID;
res.locals.username = result[0].User_Name;
res.locals.bio = result[0].User_Bio || "";
res.locals.avatar = result[0].User_Avatar || "";
res.locals.settings = result[0].User_Settings || {};
res.locals.isbot = true; //only apps/bots use auth tokens
next()
})
return;
}
} else {
if(!req.cookies.AUTH_COOKIE) {
next() next()
}) return
return; }
} unsigned = unsign(req.cookies.AUTH_COOKIE, req, res);
} else { if (!unsigned){
if(!req.cookies.AUTH_COOKIE) { next()
next() return
return }
}
unsigned = unsign(req.cookies.AUTH_COOKIE, req, res);
if (!unsigned){
next()
return
} }
}
else {
unsigned = `${req.body.user} ${SHA256(req.body.pass, req.body.user, HASHES_COOKIE)}`;
res.set("message","user+pass authentication is deprecated as of february 2023, consider switching to auth tokens")
//basically we generate the unsigned cookie
res.locals.isbot = true; //only bots use user+pass
} }
let sql = `select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`; let sql = `select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`;
let values = unsigned.split(" "); let values = unsigned.split(" ");
@ -109,9 +118,6 @@ export const setup = function (router, con, server) {
res.status(402); res.status(402);
res.json({ "error": "you cannot access the api without being logged in" }); res.json({ "error": "you cannot access the api without being logged in" });
} }
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
}; };
export default { export default {

View File

@ -20,9 +20,6 @@ export const setup = function (router, con, server) {
throw err; throw err;
res.json(result); res.json(result);
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/dms/conversations", function (req, res) { router.get("/api/dms/conversations", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
@ -33,16 +30,10 @@ export const setup = function (router, con, server) {
throw err; throw err;
res.json(result); res.json(result);
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/dms/encrypt.js", function (req, res) { router.get("/api/dms/encrypt.js", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
res.send(web_version()); res.send(web_version());
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
// //
router.get("/api/dms/getDM", function (req, res) { router.get("/api/dms/getDM", function (req, res) {
@ -61,9 +52,6 @@ export const setup = function (router, con, server) {
res.json({ "error": "there is no such dm!" }); res.json({ "error": "there is no such dm!" });
} }
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
}; };
export default { export default {

View File

@ -19,9 +19,6 @@ export const setup = function (router, con, server) {
router.get("/api/dms/pid", function (req, res) { router.get("/api/dms/pid", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
res.json({ "pid": createPID() }); res.json({ "pid": createPID() });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.post("/api/dms/post", function (req, res) { router.post("/api/dms/post", function (req, res) {
if (!req.body.message) { if (!req.body.message) {
@ -92,10 +89,6 @@ export const setup = function (router, con, server) {
console.log(5, `posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username), otherperson)}`); console.log(5, `posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username), otherperson)}`);
}); });
//TODO: bring dms up-to-date with normal posts //TODO: bring dms up-to-date with normal posts
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
return createPID return createPID
}; };

View File

@ -31,8 +31,8 @@ async function addTextOnImage(text,buf) {
} }
export const setup = function (router, con, server) { export const setup = function (router, con, server) {
router.get("/api/getFileIcon/:icon",async function(req,res){ router.get("/api/getFileIcon/*",async function(req,res){
let path = req.params.icon let path = req.path.split("/api/getFileIcon/")[1]
if(path.length > 4) { if(path.length > 4) {
res.status(410).json({"error":"file ending is too long"}) res.status(410).json({"error":"file ending is too long"})
return; return;
@ -41,8 +41,5 @@ export const setup = function (router, con, server) {
res.set("content-type","image/png") res.set("content-type","image/png")
res.send(buf) res.send(buf)
}) })
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}) })
} }

View File

@ -1,4 +1,8 @@
export const setup = function (router, con, server) { export const setup = function (router, con, server) {
router.get("/api/getPosts/*", function (_req, res) {
res.set("Access-Control-Allow-Origin", "");
res.redirect("/api/getPosts");
});
router.get("/api/getPosts", function (req, res) { router.get("/api/getPosts", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
if (req.query.channel !== undefined) { if (req.query.channel !== undefined) {
@ -17,9 +21,6 @@ export const setup = function (router, con, server) {
res.json(result); res.json(result);
}); });
} }
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/getPostsLowerThan", function (req, res) { router.get("/api/getPostsLowerThan", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
@ -39,9 +40,6 @@ export const setup = function (router, con, server) {
res.json(result); res.json(result);
}); });
} }
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/getPost", function (req, res) { router.get("/api/getPost", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
@ -58,8 +56,5 @@ export const setup = function (router, con, server) {
res.json({ "error": "there is no such post!" }); res.json({ "error": "there is no such post!" });
} }
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
} }

View File

@ -32,9 +32,6 @@ export const setup = function (router, con, server) {
router.get("/api/pid", function (req, res) { router.get("/api/pid", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
res.json({ "pid": createPID() }); res.json({ "pid": createPID() });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
function validateMessage(message) { function validateMessage(message) {
@ -207,9 +204,6 @@ export const setup = function (router, con, server) {
res.json({"error":"internal server error", "status": 500}) res.json({"error":"internal server error", "status": 500})
} }
} }
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
return createPID return createPID
}; };

View File

@ -34,9 +34,5 @@ export const setup = function (router, con, server) {
else { else {
res.json({ "error": "invalid type passed along, expected `user` or `post`", "message": "search has been deprecated as of 11/30/2022"}); res.json({ "error": "invalid type passed along, expected `user` or `post`", "message": "search has been deprecated as of 11/30/2022"});
} }
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
} }

View File

@ -4,10 +4,6 @@ const allowed_settings = {
export const setup = function (router, con, server) { export const setup = function (router, con, server) {
router.get("/api/settings", function (req, res) { router.get("/api/settings", function (req, res) {
res.json(res.locals.settings); res.json(res.locals.settings);
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.post("/api/settings", function (req, res) { router.post("/api/settings", function (req, res) {
if (!req.body.setting) { if (!req.body.setting) {
@ -49,10 +45,6 @@ export const setup = function (router, con, server) {
} }
res.json({ "status": "success" }); res.json({ "status": "success" });
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
}; };
export default { export default {

View File

@ -47,16 +47,10 @@ export const setup = function (router, con, server) {
res.json({ "success": "updated avatar" }); res.json({ "success": "updated avatar" });
}); });
}) })
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/getuser", function (_req, res) { router.get("/api/getuser", function (_req, res) {
res.json({ "username": res.locals.username, "bio": res.locals.bio, "avatar": res.locals.avatar, "userid": res.locals.userid }); res.json({ "username": res.locals.username, "bio": res.locals.bio, "avatar": res.locals.avatar, "userid": res.locals.userid });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/getalluserinformation", function (req, res) { router.get("/api/getalluserinformation", function (req, res) {
res.set("Access-Control-Allow-Origin", ""); //we don't want that here res.set("Access-Control-Allow-Origin", ""); //we don't want that here
@ -79,9 +73,6 @@ export const setup = function (router, con, server) {
res.json({ "error": "you cannot access the api without being logged in" }); res.json({ "error": "you cannot access the api without being logged in" });
} }
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.get("/api/getotheruser", function (req, res) { router.get("/api/getotheruser", function (req, res) {
res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Origin", "*");
@ -118,9 +109,6 @@ export const setup = function (router, con, server) {
throw err; throw err;
res.json({ "success": "updated bio" }); res.json({ "success": "updated bio" });
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.post("/api/changePW", (req, res) => { router.post("/api/changePW", (req, res) => {
res.set("Access-Control-Allow-Origin", ""); res.set("Access-Control-Allow-Origin", "");
@ -161,9 +149,6 @@ export const setup = function (router, con, server) {
res.json({ "error": "invalid password" }); res.json({ "error": "invalid password" });
} }
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
router.post("/api/changeUsername", function (req, res) { router.post("/api/changeUsername", function (req, res) {
res.set("Access-Control-Allow-Origin", ""); res.set("Access-Control-Allow-Origin", "");
@ -227,8 +212,5 @@ export const setup = function (router, con, server) {
res.json({ "error": "invalid password" }); res.json({ "error": "invalid password" });
} }
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
} }

View File

@ -20,10 +20,10 @@ export const setup = function (router, con, server) {
if(typeof appid === "number") { if(typeof appid === "number") {
const token = randomBytes(150).toString("base64") const token = randomBytes(150).toString("base64")
let tokencode; let tokencode;
while(tokencode===undefined || temp_code_to_token[tokencode]!==undefined) { while(tokencode===undefined || temp_code_to_token[tokencode]!==undefined) {
tokencode = randomBytes(15).toString("base64").replaceAll("/","f").replaceAll("+","A") //"/" and "+" may break some apps tokencode = randomBytes(15).toString("base64")
} }
temp_code_to_token[tokencode]={ temp_code_to_token[tokencode]={
"userid":res.locals.userid, "userid":res.locals.userid,
@ -35,7 +35,7 @@ export const setup = function (router, con, server) {
if(data !== undefined && data.token===token && data.appid === appid && data.userid === res.locals.userid) { if(data !== undefined && data.token===token && data.appid === appid && data.userid === res.locals.userid) {
temp_code_to_token[tokencode]=undefined temp_code_to_token[tokencode]=undefined
} }
}, 1000*60*5); }, 300000); //wait for 5 minutes
const sql = "SELECT application_auth_url FROM ipost.application where application_id=?" const sql = "SELECT application_auth_url FROM ipost.application where application_id=?"
@ -45,24 +45,16 @@ export const setup = function (router, con, server) {
res.redirect(`/authorize?id=${req.body.application_id}`) res.redirect(`/authorize?id=${req.body.application_id}`)
return return
} }
let extra = "" res.redirect(`${result[0].application_auth_url}?code=${tokencode}`)
if(req.body.application_extra !== "") {
extra = "&extra="+String(req.body.application_extra)
}
res.redirect(`${result[0].application_auth_url}?code=${tokencode}${extra}`)
}) })
return return
} }
} }
res.redirect(`/authorize?id=${req.body.application_id}`) res.redirect(`/authorize?id=${req.body.application_id}`)
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}) })
router.post("/redeemauthcode", (req,res) => { router.post("/redeemauthcode", (req,res) => {
@ -79,12 +71,12 @@ export const setup = function (router, con, server) {
} catch(err) { } catch(err) {
console.log("error parsing",err) console.log("error parsing",err)
} }
} }
if( if(
typeof req.body.auth !== "object" || typeof req.body.auth !== "object" ||
typeof req.body.auth.secret !== "string" || typeof req.body.auth.secret !== "string" ||
typeof req.body.auth.appid !== "number" || typeof req.body.auth.appid !== "number" ||
req.body.auth.secret.length !== 200 || req.body.auth.secret.length !== 200 ||
Buffer.from(req.body.auth.secret,"base64").length !== 150 || Buffer.from(req.body.auth.secret,"base64").length !== 150 ||
req.body.auth.appid !== temp_code_to_token[req.body.authcode].appid req.body.auth.appid !== temp_code_to_token[req.body.authcode].appid
) { ) {
@ -110,10 +102,10 @@ export const setup = function (router, con, server) {
let data = temp_code_to_token[req.body.authcode] let data = temp_code_to_token[req.body.authcode]
temp_code_to_token[req.body.authcode] = undefined temp_code_to_token[req.body.authcode] = undefined
const sql = "INSERT INTO `ipost`.`auth_tokens`(`auth_token`,`auth_token_u_id`,`auth_token_isfrom_application_id`) VALUES(?,?,?);" const sql = "INSERT INTO `ipost`.`auth_tokens`(`auth_token`,`auth_token_u_id`,`auth_token_isfrom_application_id`) VALUES(?,?,?);"
const values = [SHA256(data.token,appid,10000),data.userid,data.appid] //token,id,appid const values = [SHA256(data.token,appid,10000),data.userid,data.appid] //token,id,appid
con.query(sql,values,(err,result) => { con.query(sql,values,(err,result) => {
if(err) { if(err) {
@ -125,11 +117,7 @@ export const setup = function (router, con, server) {
}) })
}) })
}) })
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
} }

View File

@ -5,43 +5,43 @@ export const setup = function (router, con, server) {
const __dirname = server.dirname const __dirname = server.dirname
const dir = __dirname + "/" const dir = __dirname + "/"
router.get("/users/:user", function (req, res) { router.get("/users/*", function (req, res) {
if (!increaseUSERCall(req, res)) if (!increaseUSERCall(req, res))
return; return;
res.sendFile(dir + "views/otheruser.html"); res.sendFile(dir + "views/otheruser.html");
}); });
router.get("/css/:file", (request, response) => { router.get("/css/*", (request, response) => {
if (!increaseUSERCall(request, response)) if (!increaseUSERCall(request, response))
return; return;
if (existsSync(`${__dirname}/css/${request.params.file}`)) { if (existsSync(__dirname + request.originalUrl)) {
response.sendFile(`${__dirname}/css/${request.params.file}`); 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");
} }
return; return;
}); });
router.get("/js/:file", (request, response) => { router.get("/js/*", (request, response) => {
if (!increaseUSERCall(request, response)) if (!increaseUSERCall(request, response))
return; return;
if (existsSync(`${__dirname}/js/${request.params.file}`)) { if (existsSync(__dirname + request.originalUrl)) {
response.sendFile(`${__dirname}/js/${request.params.file}`); 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");
} }
return; return;
}); });
router.get("/images/:file", (request, response) => { router.get("/images/*", (request, response) => {
if (!increaseUSERCall(request, response)) if (!increaseUSERCall(request, response))
return; return;
if (existsSync(`${__dirname}/images/${request.params.file}`)) { if (existsSync(__dirname + request.originalUrl)) {
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
response.sendFile(`${__dirname}/images/${request.params.file}`); response.sendFile(__dirname + request.originalUrl);
} }
else if(existsSync(`${__dirname}/images/${request.params.file.toLowerCase()}`)){ else if(existsSync(__dirname + request.originalUrl.toLowerCase())){
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
response.sendFile(`${__dirname}/images/${request.params.file.toLowerCase()}`); response.sendFile(__dirname + request.originalUrl.toLowerCase());
} }
else { else {
response.status(404).send("no file with that name found"); response.status(404).send("no file with that name found");
@ -49,12 +49,12 @@ export const setup = function (router, con, server) {
return; return;
}); });
router.get("/user_uploads/:file", (request, response) => { router.get("/user_uploads/*", (request, response) => {
if (!increaseUSERCall(request, response)) if (!increaseUSERCall(request, response))
return; return;
if (existsSync(`${__dirname}/user_uploads/${request.params.file}`)) { if (existsSync(__dirname + request.originalUrl)) {
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
response.sendFile(`${__dirname}/user_uploads/${request.params.file}`); 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");
@ -62,12 +62,13 @@ export const setup = function (router, con, server) {
return; return;
}); });
router.get("/avatars/:avatar", (request, response) => { router.get("/avatars/*", (request, response) => {
if (!increaseUSERCall(request, response)) if (!increaseUSERCall(request, response))
return; 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
if (existsSync(`${__dirname}/avatars/${request.params.avatar}`)) { let originalUrl = request.originalUrl.split("?").shift();
return response.sendFile(`${__dirname}/avatars/${request.params.avatar}`); if (existsSync(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");
}); });

View File

@ -1,5 +1,5 @@
import ejs from "ejs" import ejs from "ejs"
import { LRUCache as LRU} from "lru-cache" import LRU from "lru-cache"
import {minify as min_js} from "uglify-js" import {minify as min_js} from "uglify-js"
import Clean from 'clean-css'; import Clean from 'clean-css';
import Minifier from 'html-minifier-terser'; import Minifier from 'html-minifier-terser';
@ -25,27 +25,27 @@ export const setup = function (router, con, server) {
updateAgeOnHas: true updateAgeOnHas: true
}) })
function load_var(filePath) { function load_var(fina) {
if (load_var_cache.has(filePath)) { if(load_var_cache.get(fina))return load_var_cache.get(fina)
return load_var_cache.get(filePath); if(!existsSync(fina)) {
console.log(1,"tried loading non-existent file",fina)
load_var_cache.set(fina,"")
return "";
}
let out = readFileSync(fina)
if(fina.endsWith(".js")) {
out = min_js(out.toString()).code
}
else if(fina.endsWith(".css")) {
const {
styles,
} = new Clean({}).minify(out.toString());
out = styles
} }
if (!existsSync(filePath)) { load_var_cache.set(fina,out)
console.log(1,'Tried loading non-existent file', filePath);
load_var_cache.set(filePath, ''); return out
return '';
}
let output = readFileSync(filePath);
if (filePath.endsWith('.js')) {
output = min_js(output.toString()).code;
} else if (filePath.endsWith('.css')) {
const { styles } = new Clean({}).minify(output.toString());
output = styles;
}
load_var_cache.set(filePath, output);
return output;
} }
function get_channels(){ function get_channels(){
@ -70,10 +70,6 @@ export const setup = function (router, con, server) {
function getAppWithId(appid) { function getAppWithId(appid) {
appid = Number(appid) appid = Number(appid)
return new Promise((res,rej) => { return new Promise((res,rej) => {
if(isNaN(appid)) {
res({})
return
}
if(appId_Cache.has(appid)) { if(appId_Cache.has(appid)) {
res(appId_Cache.get(appid) || {}) res(appId_Cache.get(appid) || {})
return return
@ -115,13 +111,11 @@ export const setup = function (router, con, server) {
if (!increaseUSERCall(request, response))return; if (!increaseUSERCall(request, response))return;
if(typeof overrideurl !== "string")overrideurl = undefined; if(typeof overrideurl !== "string")overrideurl = undefined;
let originalUrl = overrideurl let originalUrl = overrideurl || request.originalUrl.split("?").shift();
|| request.params.file
|| request.originalUrl.split("?").shift(); //backup in case anything goes wrong
let path = "" let path = ""
if (existsSync(dir + "views/" + originalUrl)) { if (existsSync(dir + "views" + originalUrl)) {
path = dir + "views/" + originalUrl path = dir + "views" + originalUrl
//send .txt files as plaintext to help browsers interpret it correctly //send .txt files as plaintext to help browsers interpret it correctly
if(originalUrl.endsWith(".txt")) { if(originalUrl.endsWith(".txt")) {
response.set('Content-Type', 'text/plain'); response.set('Content-Type', 'text/plain');
@ -142,11 +136,10 @@ export const setup = function (router, con, server) {
path = dir + "views" + originalUrl + ".html" path = dir + "views" + originalUrl + ".html"
} }
if(path !== "" && originalUrl !== "favicon.ico" && originalUrl !== "api_documentation" && originalUrl !== "api_documentation.html") { if(path !== "" && originalUrl !== "/favicon.ico" && originalUrl !== "/api/documentation/") {
console.log(originalUrl)
global_page_variables.user = { "username": response.locals.username, "bio": response.locals.bio, "avatar": response.locals.avatar } global_page_variables.user = { "username": response.locals.username, "bio": response.locals.bio, "avatar": response.locals.avatar }
global_page_variables.query = request.query global_page_variables.query = request.query
if(originalUrl === "authorize") { if(originalUrl === "/authorize") {
global_page_variables.application = await getAppWithId(request.query.id) global_page_variables.application = await getAppWithId(request.query.id)
} }
ejs.renderFile(path,global_page_variables,{async: true},async function(err,str){ ejs.renderFile(path,global_page_variables,{async: true},async function(err,str){
@ -183,20 +176,20 @@ export const setup = function (router, con, server) {
}) })
return; return;
} }
if(originalUrl === "api_documentation" || originalUrl === "api_documentation.html") { if(originalUrl === "/favicon.ico") {
response.set('Cache-Control', 'public, max-age=2592000');
response.set('Content-Type', 'text/html')
response.send(load_var("./views/api_documentation.html"))
return
}
if(originalUrl === "favicon.ico") {
response.set('Cache-Control', 'public, max-age=2592000'); response.set('Cache-Control', 'public, max-age=2592000');
response.sendFile(dir + "/views/favicon.ico") response.sendFile(dir + "/views/favicon.ico")
return return
} }
if(originalUrl === "/api/documentation/") {
readFile(path,function(_err,res){
response.send(res.toString())
})
return
}
console.log(5,"no file found",originalUrl); console.log(5,"no file found",originalUrl);
try { try {
response.status(404).send("No file with that name found"); response.status(404).send("No file with that name found");
@ -204,18 +197,13 @@ export const setup = function (router, con, server) {
console.error(err) console.error(err)
} }
} }
/** /**
* Handle default URI as /index (interpreted redirect: "localhost" -> "localhost/index" ) * Handle default URI as /index (interpreted redirect: "localhost" -> "localhost/index" )
*/ */
router.get("/", (req, res) => { router.get("/", function (req, res) {
req.params.file = "index"
handleUserFiles(req,res,"/index") handleUserFiles(req,res,"/index")
}); });
router.get("/:file", handleUserFiles); router.get("/*", handleUserFiles);
router.get("/:folder/:file", (req, res) => {
req.params.file = req.params.folder+"/"+req.params.file
handleUserFiles(req,res)
});
} }

View File

@ -14,7 +14,6 @@ import { readFileSync, appendFile } from "fs";
import { format } from "util"; import { format } from "util";
import { setup as SETUP_ROUTES} from "./routes/setup_all_routes.js" import { setup as SETUP_ROUTES} from "./routes/setup_all_routes.js"
import { verify as verifyHCaptcha_int } from "hcaptcha" import { verify as verifyHCaptcha_int } from "hcaptcha"
import hsts from "hsts"
import { ensureExists } from "./extra_modules/ensureExists.js" import { ensureExists } from "./extra_modules/ensureExists.js"
@ -263,26 +262,6 @@ app.use(fileUpload({
} }
})); }));
const hstsMiddleware = hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
})
app.use((req, res, next) => {
res.set("x-powered-by", "ipost");
res.set("X-Frame-Options","DENY");
res.set("X-XSS-Protection","1; mode=block");
res.set("X-Content-Type-Options","nosniff");
res.set("Referrer-Policy","no-referrer");
if (req.secure) {
hstsMiddleware(req, res, next)
} else {
next()
}
})
app.use(bodyParser.default.json({ limit: "100mb" })); app.use(bodyParser.default.json({ limit: "100mb" }));
app.use(bodyParser.default.urlencoded({ limit: "100mb", extended: true })); app.use(bodyParser.default.urlencoded({ limit: "100mb", extended: true }));
app.use(cookieParser(cookiesecret)); app.use(cookieParser(cookiesecret));
@ -325,6 +304,7 @@ app.use((req, res, next) => {
}); });
app.use("/*", function (req, res, next) { app.use("/*", function (req, res, next) {
res.set("x-powered-by", "ipost");
for (let i = 0; i < blocked_headers.length; i++) { for (let i = 0; i < blocked_headers.length; i++) {
if (req.header(blocked_headers[i]) !== undefined) { if (req.header(blocked_headers[i]) !== undefined) {
res.json({ "error": "we don't allow proxies on our website." }); res.json({ "error": "we don't allow proxies on our website." });
@ -378,9 +358,6 @@ router.get("/api/getChannels", function (_req, res) {
throw err; throw err;
res.json(result); res.json(result);
}); });
/* #swagger.security = [{
"appTokenAuthHeader": []
}] */
}); });
/* /*

View File

@ -155,8 +155,8 @@
"level": 5 "level": 5
}, },
"ssl": { "ssl": {
"privateKey": "/etc/letsencrypt/live/ipost.rocks-0002/privkey.pem", "privateKey": "./etc/letsencrypt/live/ipost.rocks/privkey.pem",
"certificate" : "/etc/letsencrypt/live/ipost.rocks-0002/fullchain.pem" "certificate" : "./etc/letsencrypt/live/ipost.rocks/fullchain.pem"
}, },
"ports": { "ports": {
"http": 9999, "http": 9999,

View File

@ -1,78 +0,0 @@
const fs = require('fs');
const swaggerAutogen = require('swagger-autogen')();
const doc = {
info: {
title: 'IPost API',
description: 'the official IPost.rocks API documentation',
},
host: 'ipost.rocks',
schemes: ['https'],
securityDefinitions: {
appTokenAuthHeader: {
type: 'apiKey',
in: 'header', // can be 'header', 'query' or 'cookie'
name: 'ipost-auth-token', // name of the header, query parameter or cookie
description: 'authenticate using the authentication object in the header'
}
}
};
const outputFile = './swagger-api.json';
const tempFile = './swagger-output.json';
const endpointsFiles = ['./server.js'];
function pushdirectory(currentpath) {
fs.readdirSync(currentpath, {
withFileTypes: true
}).forEach(dirent => {
if (dirent.isFile()) {
endpointsFiles.push(currentpath + dirent.name);
} else {
pushdirectory(currentpath + dirent.name + "/");
}
});
}
pushdirectory("./routes/");
swaggerAutogen(tempFile, endpointsFiles, doc);
/*
Replace some error codes with own error codes, as described in error_codes.txt
*/
const to_replace = {
"401": "login error (invalid cookie)",
"402": "login error (bad cookie)",
"403": "login error (no cookie)",
"410": "argument/data error",
"411": "argument/data error",
"412": "argument/data error",
"413": "argument/data error",
"414": "argument/data error",
"415": "argument/data error",
"416": "argument/data error",
"417": "argument/data error",
"418": "argument/data error",
"419": "argument/data error",
"420": "invalid authetication object",
}
let file = JSON.parse(fs.readFileSync(tempFile, 'utf8'));
for (let path in file.paths) {
for (let method in file.paths[path]) {
for (let response in file.paths[path][method].responses) {
if (to_replace[response]) {
file.paths[path][method].responses[response].description = to_replace[response];
}
}
}
}
file = JSON.stringify(file);
console.log(file)
fs.writeFileSync(outputFile, file);
fs.rmSync(tempFile);

View File

@ -27,7 +27,6 @@
<p>Please authorize the app "<%= application.application_name %>" to access your information:</p> <p>Please authorize the app "<%= application.application_name %>" to access your information:</p>
<form action="/authorize" method="post"> <form action="/authorize" method="post">
<input type="number" value=<%= query.id %> class="hidden" name="application_id" id="application_id"> <input type="number" value=<%= query.id %> class="hidden" name="application_id" id="application_id">
<input type="number" value=<%= query.extra || "" %> class="hidden" name="application_extra" id="application_extra">
<div class="h-captcha" data-sitekey="<%- hcaptcha_sitekey %>"></div> <div class="h-captcha" data-sitekey="<%- hcaptcha_sitekey %>"></div>
<input type="submit" value="Authorize"> <input type="submit" value="Authorize">
</form> </form>