Files
KVS-Key-Server/main.js
T

250 lines
8.1 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.ip] !== undefined){
if(ipLog[req.ip] > Date.now()){
ipLog[req.ip] = Date.now() + config.ratelimit
fs.writeFile("access.log", `${logTime} : ${req.ip} HIT RATE LIMIT\n`, { flag: "a" }, callback => {});
return
}
}
ipLog[req.ip] = 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(accounts[req.headers.username],req.headers.password))
passed = false
if(passed)
res.status(200).json(apikeys);
else
res.status(401).send("You are not authorised");
fs.writeFile("access.log", `${logTime} : ${req.ip} API KEY REQUEST ${passed?"SUCCESS":"FAILED"}\n`, { flag: "a" }, callback => {});
});
app.get("/admin", (req, res) => {
let logTime = getLogTime()
fs.writeFile("access.log", `${logTime} : ${req.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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.ip} 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);