Skip to content

Commit

Permalink
Consistent JSON responses
Browse files Browse the repository at this point in the history
  • Loading branch information
DEVTomatoCake committed Nov 2, 2023
1 parent 81935e4 commit 132d54f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
3 changes: 2 additions & 1 deletion generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ const events = {
"projects_v2": ["closed", "created", "deleted", "edited", "reopened"],
"projects_v2_item": ["archived", "converted", "created", "deleted", "edited", "reordered", "restored"],
"public": [],
"pull_request": ["assigned", "auto_merge_disabled", "auto_merge_enabled", "closed", "converted_to_draft", "demilestoned", "dequeued", "edited", "enqueued", "labeled", "locked", "milestoned", "opened", "ready_for_review", "reopened", "review_request_removed", "review_requested", "synchronize", "unassigned", "unlabeled", "unlocked"],
"pull_request": ["assigned", "auto_merge_disabled", "auto_merge_enabled", "closed", "converted_to_draft", "demilestoned", "dequeued", "edited", "enqueued", "labeled", "locked",
"milestoned", "opened", "ready_for_review", "reopened", "review_request_removed", "review_requested", "synchronize", "unassigned", "unlabeled", "unlocked"],
"pull_request_review_comment": ["created", "deleted", "edited"],
"pull_request_review": ["dismissed", "edited", "submitted"],
"pull_request_review_thread": ["resolved", "unresolved"],
Expand Down
63 changes: 48 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const bot = require("./bot.js")

const { botId, botSecret, userAgent, domain, port, cookieSecret } = require("./config.json")

const encode = s => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;")

const oauth = require("./util/oauth.js")
const pool = require("./util/setupDB.js")

Expand All @@ -15,6 +17,39 @@ app.disable("x-powered-by")
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(cookieParser(cookieSecret))

const ratelimit30s = {}
const ratelimit5m = {}
let ratelimitGlobal5m = 0
app.use((req, res, next) => {
const ip = req.headers["cf-connecting-ip"]
if (!req.headers["cf-connecting-ip"]) return res.status(400).send("Direct access is not allowed")

if (req.path.startsWith("/hook/")) return next()

if (ratelimit30s[ip] && ratelimit30s[ip] >= 30) return res.status(429).send("Too many requests in the last 30 seconds")
if (ratelimit5m[ip] && ratelimit5m[ip] >= 130) return res.status(429).send("Too many requests in the last 5 minutes")
if (ratelimitGlobal5m >= 800) return res.status(429).send("Too many requests in the last 5 minutes")

if (ratelimit30s[ip]) ratelimit30s[ip]++
else ratelimit30s[ip] = 1

if (ratelimit5m[ip]) ratelimit5m[ip]++
else ratelimit5m[ip] = 1

ratelimitGlobal5m++

setTimeout(() => {
ratelimit30s[ip]--
}, 1000 * 30)
setTimeout(() => {
ratelimit5m[ip]--
ratelimitGlobal5m--
}, 1000 * 60 * 5)

next()
})

app.listen(port)

// - Dashboard -
Expand Down Expand Up @@ -59,7 +94,7 @@ app.get("/servers/:id/hooks", async (req, res) => {
})

app.post("/servers/:id/hooks", async (req, res) => {
if (!req.signedCookies.token) return res.status(401).send("Missing token cookie")
if (!req.signedCookies.token) return res.status(401).send({success: false, error: "Missing token cookie"})

const servers = await oauth.getUserServers(req.signedCookies.token, pool)
if (!servers) return res.status(401).send({success: false, error: "Invalid token cookie"})
Expand All @@ -81,7 +116,7 @@ app.post("/servers/:id/hooks", async (req, res) => {
})

app.post("/servers/:id/hooks/:hook", async (req, res) => {
if (!req.signedCookies.token) return res.status(401).send("Missing token cookie")
if (!req.signedCookies.token) return res.status(401).send({success: false, error: "Missing token cookie"})

const servers = await oauth.getUserServers(req.signedCookies.token, pool)
if (!servers) return res.status(401).send({success: false, error: "Invalid token cookie"})
Expand All @@ -101,7 +136,7 @@ app.post("/servers/:id/hooks/:hook", async (req, res) => {
})

app.delete("/servers/:id/hooks/:hook", async (req, res) => {
if (!req.signedCookies.token) return res.status(401).send("Missing token cookie")
if (!req.signedCookies.token) return res.status(401).send({success: false, error: "Missing token cookie"})

const [rows] = await pool.query("SELECT * FROM `user` WHERE `token` = ?", [req.signedCookies.token])
if (rows.length == 0) return res.status(401).send({success: false, error: "Invalid token cookie"})
Expand All @@ -120,7 +155,7 @@ app.delete("/servers/:id/hooks/:hook", async (req, res) => {
})

app.post("/servers/:id/hooks/:hook/regen", async (req, res) => {
if (!req.signedCookies.token) return res.status(401).send("Missing token cookie")
if (!req.signedCookies.token) return res.status(401).send({success: false, error: "Missing token cookie"})

const servers = await oauth.getUserServers(req.signedCookies.token, pool)
if (!servers) return res.status(401).send({success: false, error: "Invalid token cookie"})
Expand All @@ -138,7 +173,7 @@ app.post("/servers/:id/hooks/:hook/regen", async (req, res) => {
})

app.get("/login", async (req, res) => {
if (!req.query.code) return res.status(400).send("Missing code query parameter")
if (!req.query.code) return res.status(400).send({success: false, error: "Missing code query parameter"})

const body = {
client_id: botId,
Expand Down Expand Up @@ -199,19 +234,17 @@ const hookFunc = async (req, res) => {

if (req.params.secret.startsWith("sha256=")) {
const sha256 = crypto.createHmac("sha256", hook.secret)
if (!crypto.timingSafeEqual(Buffer.from("sha256=" + sha256.update(JSON.stringify(req.body)).digest("hex")), Buffer.from(req.params.secret))) return res.status(401).send("Invalid secret in header")
if (!crypto.timingSafeEqual(Buffer.from("sha256=" + sha256.update(JSON.stringify(req.body)).digest("hex")), Buffer.from(req.params.secret)))
return res.status(401).send({success: false, error: "Invalid secret in header"})
} else if (req.params.secret != hook.secret) return res.status(401).send("Invalid secret in URL")

const githubEvent = req.headers["x-github-event"]
if (githubEvent == "ping") {
console.log("Received ping event on hook " + hook.id)
return res.sendStatus(204)
}
if (hook.filterEvent && !hook.filterEvent.includes(githubEvent)) return res.status(202).send("Event " + githubEvent + " is disabled in settings for this hook")
if (githubEvent == "ping") return res.sendStatus(204)
if (hook.filterEvent && !hook.filterEvent.includes(githubEvent)) return res.status(202).send({success: true, info: "Event " + encode(githubEvent) + " is disabled in settings for this hook"})

const data = req.body
const action = data.action
if (hook.filterAction && !hook.filterAction.includes(action)) return res.status(202).send("Action " + action + " is disabled in settings for this hook")
if (hook.filterAction && !hook.filterAction.includes(action)) return res.status(202).send({success: true, info: "Action " + encode(action) + " is disabled in settings for this hook"})

let message = hook.message
const recursiveFunc = (obj, path = "") => {
Expand All @@ -227,11 +260,11 @@ const hookFunc = async (req, res) => {
try {
parsed = JSON.parse(message)
} catch (e) {
return res.status(500).send("Invalid JSON in message")
return res.status(500).send("Invalid JSON in message: " + encode(e.message))
}

if (Array.isArray(parsed)) parsed = parsed.find(msg => msg.event == githubEvent && msg.action == action) || parsed.find(msg => msg.event == githubEvent) || parsed[0]
if (!parsed || Object.keys(parsed).length == 0) return res.status(500).send("Empty JSON in message")
if (!parsed || Object.keys(parsed).length == 0) return res.status(500).send({success: false, error: "Empty JSON in message"})

if (hook.webhook) {
const webhookClient = new Discord.WebhookClient(hook.webhook)
Expand All @@ -242,7 +275,7 @@ const hookFunc = async (req, res) => {
if (channel) {
await channel.send(parsed)
res.sendStatus(204)
} else res.status(500).send("Unable to send message of hook " + hook.id + " because the channel " + hook.channel + " does not exist")
} else res.status(500).send({success: false, error: "Unable to send message of hook " + hook.id + " because the channel " + hook.channel + " does not exist"})
}
}

Expand Down

0 comments on commit 132d54f

Please sign in to comment.