255 lines
9.5 KiB
JavaScript
255 lines
9.5 KiB
JavaScript
const express = require("express");
|
|
const app = express();
|
|
const config = require("./config")
|
|
const fs = require("node:fs")
|
|
const bcrypt = require("bcrypt")
|
|
const bodyParser = require("body-parser")
|
|
|
|
// Middleware
|
|
app.use(express.json());
|
|
app.disable("x-powered-by")
|
|
|
|
let ipLog = {}
|
|
let adminCodes = {}
|
|
let accounts = JSON.parse(fs.readFileSync("./db/useraccounts.json"))
|
|
let apikeys = JSON.parse(fs.readFileSync("./db/apikeys.json"))
|
|
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
|
|
app.use(
|
|
bodyParser.urlencoded({extended:true})
|
|
);
|
|
// Route handler
|
|
app.get("/v1/auth", (req, res) => {
|
|
let logTime = getLogTime()
|
|
console.log(logTime);
|
|
|
|
|
|
|
|
// Simple ratelimit
|
|
if(ipLog[req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]] !== undefined){
|
|
if(ipLog[req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]] > Date.now()){
|
|
ipLog[req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]] = Date.now() + config.ratelimit
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} HIT RATE LIMIT\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
}
|
|
|
|
ipLog[req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]] = Date.now() + config.ratelimit
|
|
let passed = true
|
|
if(req.headers.username === undefined || req.headers.username.trim() === "" || req.headers.password === undefined || req.headers.password.trim() === "")
|
|
passed = false
|
|
|
|
if(accounts[req.headers.username] === undefined)
|
|
passed = false
|
|
|
|
if(!bcrypt.compareSync(req.headers.password, accounts[req.headers.username]))
|
|
passed = false
|
|
|
|
|
|
if(passed){
|
|
res.status(200).json(apikeys);
|
|
}
|
|
else{
|
|
res.status(401).send("You are not authorised");
|
|
}
|
|
|
|
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} API KEY REQUEST ${passed?"SUCCESS":"FAILED"}\n`, { flag: "a" }, callback => {});
|
|
});
|
|
|
|
app.get("/admin", (req, res) => {
|
|
let logTime = getLogTime()
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} ACCESSED ADMIN PANEL\n`, { flag: "a" }, callback => {});
|
|
res.sendFile(__dirname + "/ui/index.html")
|
|
})
|
|
|
|
|
|
app.get("/v1/admin-auth", (req,res) => {
|
|
let logTime = getLogTime()
|
|
let passed = false
|
|
|
|
if(req.headers.password === undefined || req.headers.password.trim() === ""){
|
|
res.status(400).json({response:"Password field missing or empty", code:1})
|
|
return
|
|
}
|
|
|
|
if(bcrypt.compareSync(req.headers.password, accounts.admin)){
|
|
passed = true
|
|
let code = ""
|
|
for (let i = 0; i < 28; i++) {
|
|
code += chars[Math.floor(Math.random() * chars.length)]
|
|
}
|
|
adminCodes[code] = Date.now()
|
|
res.json({auth:code, code:0})
|
|
}else{
|
|
res.status(401).json({response:"Unauthorised", code:1})
|
|
}
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} LOGGED IN TO ADMIN PANEL ${passed?"SUCCESS":"FAILED"}\n`, { flag: "a" }, callback => {});
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// API KEYS
|
|
app.put("/v1/api-key", (req, res) => {
|
|
req.body = JSON.parse(Object.keys(req.body)[0])
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO ADD NEW API KEY : ${req.body.field} ${req.body.value}\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
if(req.body.value === undefined || req.body.value.trim() === "" || req.body.field === undefined || req.body.field.trim() === ""){
|
|
res.json({response:"please make sure to set the fields 'value' and 'field' in the request body", code:1})
|
|
return
|
|
}
|
|
|
|
apikeys[req.body.field] = req.body.value
|
|
fs.writeFile("./db/apikeys.json", JSON.stringify(apikeys, null, 4), "utf8", c => {})
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} ADDED A NEW API KEY : ${req.body.field} ${req.body.value}\n`, { flag: "a" }, callback => {});
|
|
res.json({response:"key added", code:0})
|
|
})
|
|
|
|
app.delete("/v1/api-key", (req, res) => {
|
|
req.body = JSON.parse(Object.keys(req.body)[0])
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO DELETE API KEY : ${req.body.field}\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
if(req.body.field === undefined || req.body.field.trim() === ""){
|
|
res.json({response:"please make sure to set the field 'field' in the request body", code:1})
|
|
return
|
|
}
|
|
|
|
delete apikeys[req.body.field]
|
|
fs.writeFile("./db/apikeys.json", JSON.stringify(apikeys, null, 4), "utf8", c => {})
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} DELETED API KEY : ${req.body.field}\n`, { flag: "a" }, callback => {});
|
|
res.json({response:"key removed", code:0})
|
|
})
|
|
|
|
app.get("/v1/api-key", (req, res) => {
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO GET API KEYS\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
res.json(apikeys)
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ACCOUNT MANAGEMENT
|
|
app.put("/v1/user", (req, res) => {
|
|
req.body = JSON.parse(Object.keys(req.body)[0])
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO ADD NEW USER : ${req.body.username}\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
if(req.body.username === undefined || req.body.username.trim() === "" || req.body.password === undefined || req.body.password.trim() === ""){
|
|
res.json({response:"please make sure to set the fields 'username' and 'password' in the request body", code:1})
|
|
return
|
|
}
|
|
|
|
accounts[req.body.username] = bcrypt.hashSync(req.body.password, 12)
|
|
fs.writeFile("./db/useraccounts.json", JSON.stringify(accounts, null, 4), "utf8", c => {})
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} ADDED A NEW USER : ${req.body.username}\n`, { flag: "a" }, callback => {});
|
|
res.json({response:"user added", code:0})
|
|
})
|
|
|
|
app.delete("/v1/user", (req, res) => {
|
|
req.body = JSON.parse(Object.keys(req.body)[0])
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO DELETE USER : ${req.body.username}\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
if(req.body.username === undefined || req.body.username.trim() === ""){
|
|
res.json({response:"please make sure to set the field 'field' in the request body", code:1})
|
|
return
|
|
}
|
|
|
|
delete accounts[req.body.username]
|
|
fs.writeFile("./db/useraccounts.json", JSON.stringify(accounts, null, 4), "utf8", c => {})
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} DELETED USER : ${req.body.field}\n`, { flag: "a" }, callback => {});
|
|
res.json({response:"user removed", code:0})
|
|
})
|
|
|
|
app.get("/v1/user", (req, res) => {
|
|
let logTime = getLogTime()
|
|
let keypassed = checkKey(req.headers.key)
|
|
if(!keypassed){
|
|
fs.writeFile("access.log", `${logTime} : ${req.headers["x-forwarded-for"] == undefined ? req.ip : req.headers["x-forwarded-for"]} TRIED TO GET USERS\n`, { flag: "a" }, callback => {});
|
|
return
|
|
}
|
|
res.json(accounts)
|
|
})
|
|
|
|
|
|
|
|
// Run server
|
|
app.listen(config.port, () => {
|
|
console.log(
|
|
`------------------------------
|
|
Server listening on port ${config.port}
|
|
-------------------------------`)
|
|
});
|
|
|
|
|
|
|
|
function getLogTime(){
|
|
let curTime = new Date();
|
|
return `${curTime.getDate()<10?"0" + curTime.getDate(): curTime.getDate()}/${(curTime.getMonth()+1) < 10 ? "0" + (curTime.getMonth()+1) : curTime.getMonth()+1}/${curTime.getFullYear()} ${curTime.getHours() < 10 ? "0" + curTime.getHours() : curTime.getHours()}:${curTime.getMinutes() < 10 ? "0" + curTime.getMinutes() : curTime.getMinutes()}:${curTime.getSeconds() < 10 ? "0" + curTime.getSeconds() : curTime.getSeconds()}.${curTime.getMilliseconds() < 100 ? (curTime.getMilliseconds()+"").padStart(3,"0") : curTime.getMilliseconds()}`
|
|
}
|
|
|
|
function checkKey(key){
|
|
if(key.trim() === "" || key === undefined)
|
|
return false
|
|
if(adminCodes[key] === undefined)
|
|
return false
|
|
if(adminCodes[key] < Date.now() - config.keyDuration)
|
|
return false
|
|
return true
|
|
}
|
|
|
|
|
|
|
|
// Admin auth key cleanup
|
|
setInterval(() => {
|
|
Object.keys(adminCodes).forEach(el => {
|
|
if(adminCodes[el] < Date.now() - config.keyDuration)
|
|
delete adminCodes[el]
|
|
})
|
|
}, 1000 * 60); |