From e6dfea6392b74eb516f9658321f5af4f0aa525ab Mon Sep 17 00:00:00 2001 From: Marrub Date: Sat, 29 Oct 2016 02:58:52 -0400 Subject: [PATCH] Initial commit. --- .gitignore | 3 + LICENSE | 22 +++ build/bundle.js | 451 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 44 +++++ rollup.config.js | 6 + src/events.js | 400 +++++++++++++++++++++++++++++++++++++++++ src/main.js | 49 +++++ 7 files changed, 975 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 build/bundle.js create mode 100644 package.json create mode 100644 rollup.config.js create mode 100644 src/events.js create mode 100644 src/main.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..636685a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +*.swp + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b2fd8fc --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Dylan Falconer and Project Golan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/build/bundle.js b/build/bundle.js new file mode 100644 index 0000000..dd8e33f --- /dev/null +++ b/build/bundle.js @@ -0,0 +1,451 @@ +'use strict'; + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var bodyParser = _interopDefault(require('body-parser')); +var request = _interopDefault(require('request')); +var URI = _interopDefault(require('urijs')); +var merge = _interopDefault(require('merge')); +var express = _interopDefault(require('express')); +var crypto = _interopDefault(require('crypto-js')); +var bufeq = _interopDefault(require('buffer-equal-constant-time')); + +const uri = process.env.WEBHOOK_URI; + +let color = 0x77CBD1; + +function esc(str) +{ + return str.replace(/([*#/()[\]_`\\])/g, "\\$&"); +} + +function sendMessage(content, embeds) +{ + request.post({ uri: uri, json: { content: content, embeds: embeds } }, + function(error, response, body) + { + if(error || response.statusCode < 200 || response.statusCode >= 300) + { + if(body != undefined) + console.log("ERROR: \n", body); + else + console.log(""); + } + }); +} + +function struri(str) +{ + return new URI(str).unicode().toString(); +} + +function uristr(name, uri) +{ + return "[" + esc(name) + "](" + struri(uri) + ")"; +} + +function clipstr(str, amt) +{ + if(str == null) return str; + if(str.length > amt) + str = str.substring(0, amt - 3) + "..."; + return str; +} + +function author(name, url, icon_url) +{ + return { + color: color, + author: { + name: name, + url: url, + icon_url: icon_url + } + }; +} + +function embed(title, description, url) +{ + return { + color: color, + title: title, + description: description, + url: url + }; +} + +function field(name, value) +{ + return { + color: color, + fields: [{ + name: name, + value: value, + inline: true + }] + }; +} + +function footer(text, icon_url) +{ + return { + color: color, + footer: { + text: text, + icon_url: icon_url + } + }; +} + +function prsCommInfo(info) +{ + return { + id: info.comment.commit_id.substring(0, 7), + idLong: info.comment.commit_id, + uri: info.comment.html_url, + body: esc(info.comment.body) + }; +} + +function prsTracInfo(info) +{ + return { + title: info.title, + body: info.body, + uristr: uristr("#" + info.number, info.html_url), + uri: info.html_url + }; +} + +function prsIssuInfo(info) +{ + return prsTracInfo(info.issue); +} + +function prsPullInfo(info) +{ + return prsTracInfo(info.pull_request); +} + +function prsRepoInfo(info) +{ + return { + shortname: info.repository.name, + name: info.repository.full_name, + avatar: info.repository.owner.avatar_url, + uri: info.repository.html_url, + uristr: uristr(info.repository.full_name, info.repository.html_url), + mai: "**" + + uristr(info.repository.full_name, info.repository.html_url) + + "**:" + }; +} + +function prsUserInfo(info) +{ + return { + user: info.login, + userUri: info.html_url, + avatar: info.avatar_url, + uristr: uristr(info.login, info.html_url) + }; +} + +function prsSendInfo(info) +{ + return prsUserInfo(info.sender); +} + +function issueInfo(info, issu) +{ + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + let outp = null; + + switch(info.action) + { + case "opened": + const body = clipstr(issu.body, 128); + outp = merge(true, + author(send.user, send.uri, send.avatar), + field(esc(issu.title), body ? body : "") + ); + break; + case "labeled": case "unlabeled": + const tmp = color; + const uri = struri(`${repo.uri}/labels/${info.label.name}`); + const tag = info.action[0].toUpperCase() + info.action.substring(1); + + color = parseInt(info.label.color, 16); + outp = embed(`${tag} **${info.label.name}**`, null, uri); + color = tmp; + break; + case "assigned": case "unassigned": + let user = prsUserInfo(info.assignee); + outp = + author(`${user.user} was ${info.action}`, user.uri, user.avatar); + break; + } + return outp; +} + +class Events +{ + static commit_comment(info) + { + const comm = prsCommInfo(info); + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const comment = uristr("comment", comm.uri); + const commit = uristr(comm.id, `${repo.uri}/commit/${comm.idLong}`); + + sendMessage(`${repo.mai} New ${comment} on commit **${commit}**`, + [merge(true, + author(send.user, send.uri, send.avatar), + footer(clipstr(comm.body, 80)) + )]); + } + + static create(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const type = info.ref_type; + const ref = info.ref; + const refmsg = (ref != null) ? (": **" + ref + "**") : ""; + + sendMessage( + `${send.uristr} created a new ${type} on ${repo.uristr}${refmsg}`); + } + + static delete(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const type = info.ref_type; + const ref = info.ref; + const refmsg = (ref != null) ? (": **" + ref + "**") : ""; + + sendMessage( + `${send.uristr} deleted a ${type} on ${repo.uristr}${refmsg}`); + } + + static fork(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const fork = uristr(info.forkee.full_name, info.forkee.html_url); + + sendMessage(`**${send.uristr}** forked ${repo.uristr} into **${fork}**`); + } + + static issue_comment(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const user = prsUserInfo(info.comment.user); + const issu = prsIssuInfo(info); + + let outp = null; + let msg = null; + + switch(info.action) + { + case "created": + { + const comment = uristr("comment", info.comment.html_url); + msg = `New ${comment} on issue **${issu.uristr}**`; + outp = merge(true, + author(user.user, user.uri, user.avatar), + footer(clipstr(info.comment.body, 80)) + ); + break; + } + case "edited": + { + const comm = uristr("Comment", info.comment.html_url); + msg = `${comm} on issue **${issu.uristr}** edited by ${send.uristr}`; + break; + } + case "deleted": + msg = `Comment on issue **${issu.uristr}** deleted by ${send.uristr}`; + break; + } + + sendMessage(`${repo.mai} ${msg}`, outp ? [outp] : null); + } + + static issues(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const issu = prsIssuInfo(info); + const outp = issueInfo(info, issu); + + sendMessage( + `${repo.mai} Issue **${issu.uristr}** ` + + `${info.action} by ${send.uristr}`, + outp ? [outp] : null); + } + + static member(info) + { + const repo = prsRepoInfo(info); + const user = prsUserInfo(info.member); + sendMessage(`${user.uristr} was added to ${repo.uristr}`); + } + + static milestone(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const mstone = uristr(info.milestone.title, info.milestone.html_url); + const action = info.action; + + sendMessage( + `${repo.mai} Milestone ${mstone} ${action} by ${send.uristr}`); + } + + static public(info) + { + sendMessage(`${prsRepoInfo(info).uristr} has been made public`); + } + + static pull_request_review(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const pull = prsPullInfo(info); + + let statename = info.review.state; + if(statename == "changes_requested") statename = "denied"; + + const state = uristr(statename, info.review.html_url); + const body = clipstr(info.review.body, 80); + + sendMessage( + `${repo.mai} Pull request **${pull.uristr}** ${state}`, + [merge(true, + author(send.user, send.uri, send.avatar), + footer(clipstr(body ? body : "", 80)) + )]); + } + + static pull_request(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const pull = prsPullInfo(info); + + let outp = null; + let msg = + `Pull request **${pull.uristr}** ${info.action} by ${send.uristr}`; + + if(info.pull_request.merged && info.action == "closed") + msg = `Pull request **${pull.uristr}** merged by ${send.uristr}`; + else + outp = issueInfo(info, pull); + + sendMessage(`${repo.mai} ${msg}`, outp ? [outp] : null); + } + + static push(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const name = `${repo.shortname}/${info.ref.split("/")[2]}`; + const s = info.commits.length != 1 ? "s" : ""; + + let commits = ""; + for (let commit of info.commits) { + if(commits.length > 1000) break; + const shorthash = commit.id.substring(0, 7); + const uri = struri(`${repo.uri}/commit/${commit.id}`); + const msg = esc(clipstr(commit.message.split(/\r?\n/)[0], 64)); + const name = esc(commit.author.name); + commits += `${uristr(`\`${shorthash}\``, uri)} ${msg} - *${name}*\n`; + } + + const uri = info.compare; + + sendMessage(null, [merge(true, + author(send.user, send.uri, send.avatar), + embed(`[${name}] ${info.commits.length} new commit${s}`, commits, uri) + )]); + } + + static release(info) + { + const repo = prsRepoInfo(info); + const tag = uristr(info.release.tag_name, info.release.html_url); + sendMessage(`${repo.mai} ${tag} released`); + } + + static watch(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + sendMessage(`${repo.uristr} was starred by ${send.uristr}`); + } + + static ping(info) {} + static gollum(info) {} + static status(info) {} + static team_add(info) {} + static repository(info) {} + static deployment(info) {} + static membership(info) {} + static page_build(info) {} + static deployment_status(info) {} + static pull_request_review_comment(info) {} +} + +const env = process.env; +const vhost = env.VHOST; + +function verifyRequest(req) +{ + const hmac = crypto.HmacSHA1(req.body, env.GITHUB_SECRET); + + const hash = new Buffer("sha1=" + crypto.enc.Hex.stringify(hmac)); + const reqhash = new Buffer(req.get("X-Hub-Signature")); + + return bufeq(hash, reqhash); +} + +function handleRequest(req, res) +{ + if(req.body == null || (vhost && req.hostname != vhost)) return; + + if(env.GITHUB_SECRET && !verifyRequest(req)) + res.sendStatus(500); + else + { + const event = req.get("X-GitHub-Event"); + + if(event) + { + Events[event](JSON.parse(req.body)); + res.sendStatus(200); + } + else + res.sendStaus(400); + } +} + +function main() +{ + express() + .use(bodyParser.text({type: "application/json"})) + .post("/", handleRequest) + .listen(2237); +} + +main(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..14dec3e --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "UNATCORelay", + "version": "1.0.0", + "description": "A Discord webhook generator for GitHub.", + "main": "build/bundle.js", + "scripts": { + "test": "echo \"No tests\"", + "build": "./node_modules/.bin/rollup -c", + "start": "npm run build && node build/bundle.js" + }, + "engines": { + "node": "6.5.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Project-Golan/UNATCORelay.git" + }, + "keywords": [ + "Discord", + "GitHub" + ], + "contributors": [ + "Dylan Falconer (http://falconerd.com)", + "Project Golan (http://greyserv.net)" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/Project-Golan/UNATCORelay/issues" + }, + "homepage": "https://github.com/Project-Golan/UNATCORelay#readme", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "body-parser": "^1.9.2", + "crypto-js": "^3.1.8", + "express": "^4.14.0", + "request": "^2.74.0", + "rollup": "^0.35.11", + "merge": "^1.2.0", + "urijs": "^1.18.2" + }, + "devDependencies": { + "rollup": "^0.35.11" + } +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..d9de4d4 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,6 @@ +export default +{ + entry: "src/main.js", + dest: "build/bundle.js", + format: "cjs" +} diff --git a/src/events.js b/src/events.js new file mode 100644 index 0000000..fb388a9 --- /dev/null +++ b/src/events.js @@ -0,0 +1,400 @@ +import request from "request"; +import URI from "urijs"; +import merge from "merge"; + +const uri = process.env.WEBHOOK_URI; + +let color = 0x77CBD1; + +function esc(str) +{ + return str.replace(/([*#/()[\]_`\\])/g, "\\$&"); +} + +function sendMessage(content, embeds) +{ + request.post({ uri: uri, json: { content: content, embeds: embeds } }, + function(error, response, body) + { + if(error || response.statusCode < 200 || response.statusCode >= 300) + { + if(body != undefined) + console.log("ERROR: \n", body); + else + console.log(""); + } + }); +} + +function struri(str) +{ + return new URI(str).unicode().toString(); +} + +function uristr(name, uri) +{ + return "[" + esc(name) + "](" + struri(uri) + ")"; +} + +function clipstr(str, amt) +{ + if(str == null) return str; + if(str.length > amt) + str = str.substring(0, amt - 3) + "..."; + return str; +} + +function author(name, url, icon_url) +{ + return { + color: color, + author: { + name: name, + url: url, + icon_url: icon_url + } + }; +} + +function embed(title, description, url) +{ + return { + color: color, + title: title, + description: description, + url: url + }; +} + +function field(name, value) +{ + return { + color: color, + fields: [{ + name: name, + value: value, + inline: true + }] + }; +} + +function footer(text, icon_url) +{ + return { + color: color, + footer: { + text: text, + icon_url: icon_url + } + }; +} + +function prsCommInfo(info) +{ + return { + id: info.comment.commit_id.substring(0, 7), + idLong: info.comment.commit_id, + uri: info.comment.html_url, + body: esc(info.comment.body) + }; +} + +function prsTracInfo(info) +{ + return { + title: info.title, + body: info.body, + uristr: uristr("#" + info.number, info.html_url), + uri: info.html_url + }; +} + +function prsIssuInfo(info) +{ + return prsTracInfo(info.issue); +} + +function prsPullInfo(info) +{ + return prsTracInfo(info.pull_request); +} + +function prsRepoInfo(info) +{ + return { + shortname: info.repository.name, + name: info.repository.full_name, + avatar: info.repository.owner.avatar_url, + uri: info.repository.html_url, + uristr: uristr(info.repository.full_name, info.repository.html_url), + mai: "**" + + uristr(info.repository.full_name, info.repository.html_url) + + "**:" + }; +} + +function prsUserInfo(info) +{ + return { + user: info.login, + userUri: info.html_url, + avatar: info.avatar_url, + uristr: uristr(info.login, info.html_url) + }; +} + +function prsSendInfo(info) +{ + return prsUserInfo(info.sender); +} + +function issueInfo(info, issu) +{ + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + let outp = null; + + switch(info.action) + { + case "opened": + const body = clipstr(issu.body, 128); + outp = merge(true, + author(send.user, send.uri, send.avatar), + field(esc(issu.title), body ? body : "") + ); + break; + case "labeled": case "unlabeled": + const tmp = color; + const uri = struri(`${repo.uri}/labels/${info.label.name}`); + const tag = info.action[0].toUpperCase() + info.action.substring(1); + + color = parseInt(info.label.color, 16); + outp = embed(`${tag} **${info.label.name}**`, null, uri); + color = tmp; + break; + case "assigned": case "unassigned": + let user = prsUserInfo(info.assignee); + outp = + author(`${user.user} was ${info.action}`, user.uri, user.avatar); + break; + } + return outp; +} + +export default class Events +{ + static commit_comment(info) + { + const comm = prsCommInfo(info); + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const comment = uristr("comment", comm.uri); + const commit = uristr(comm.id, `${repo.uri}/commit/${comm.idLong}`); + + sendMessage(`${repo.mai} New ${comment} on commit **${commit}**`, + [merge(true, + author(send.user, send.uri, send.avatar), + footer(clipstr(comm.body, 80)) + )]); + } + + static create(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const type = info.ref_type; + const ref = info.ref; + const refmsg = (ref != null) ? (": **" + ref + "**") : ""; + + sendMessage( + `${send.uristr} created a new ${type} on ${repo.uristr}${refmsg}`); + } + + static delete(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const type = info.ref_type; + const ref = info.ref; + const refmsg = (ref != null) ? (": **" + ref + "**") : ""; + + sendMessage( + `${send.uristr} deleted a ${type} on ${repo.uristr}${refmsg}`); + } + + static fork(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const fork = uristr(info.forkee.full_name, info.forkee.html_url); + + sendMessage(`**${send.uristr}** forked ${repo.uristr} into **${fork}**`); + } + + static issue_comment(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const user = prsUserInfo(info.comment.user); + const issu = prsIssuInfo(info); + + let outp = null; + let msg = null; + + switch(info.action) + { + case "created": + { + const comment = uristr("comment", info.comment.html_url); + msg = `New ${comment} on issue **${issu.uristr}**`; + outp = merge(true, + author(user.user, user.uri, user.avatar), + footer(clipstr(info.comment.body, 80)) + ); + break; + } + case "edited": + { + const comm = uristr("Comment", info.comment.html_url); + msg = `${comm} on issue **${issu.uristr}** edited by ${send.uristr}`; + break; + } + case "deleted": + msg = `Comment on issue **${issu.uristr}** deleted by ${send.uristr}`; + break; + } + + sendMessage(`${repo.mai} ${msg}`, outp ? [outp] : null); + } + + static issues(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const issu = prsIssuInfo(info); + const outp = issueInfo(info, issu); + + sendMessage( + `${repo.mai} Issue **${issu.uristr}** ` + + `${info.action} by ${send.uristr}`, + outp ? [outp] : null); + } + + static member(info) + { + const repo = prsRepoInfo(info); + const user = prsUserInfo(info.member); + sendMessage(`${user.uristr} was added to ${repo.uristr}`); + } + + static milestone(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + const mstone = uristr(info.milestone.title, info.milestone.html_url); + const action = info.action; + + sendMessage( + `${repo.mai} Milestone ${mstone} ${action} by ${send.uristr}`); + } + + static public(info) + { + sendMessage(`${prsRepoInfo(info).uristr} has been made public`); + } + + static pull_request_review(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const pull = prsPullInfo(info); + + let statename = info.review.state; + if(statename == "changes_requested") statename = "denied"; + + const state = uristr(statename, info.review.html_url); + const body = clipstr(info.review.body, 80); + + sendMessage( + `${repo.mai} Pull request **${pull.uristr}** ${state}`, + [merge(true, + author(send.user, send.uri, send.avatar), + footer(clipstr(body ? body : "", 80)) + )]); + } + + static pull_request(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const pull = prsPullInfo(info); + + let outp = null; + let msg = + `Pull request **${pull.uristr}** ${info.action} by ${send.uristr}`; + + if(info.pull_request.merged && info.action == "closed") + msg = `Pull request **${pull.uristr}** merged by ${send.uristr}`; + else + outp = issueInfo(info, pull); + + sendMessage(`${repo.mai} ${msg}`, outp ? [outp] : null); + } + + static push(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + const name = `${repo.shortname}/${info.ref.split("/")[2]}`; + const s = info.commits.length != 1 ? "s" : ""; + + let commits = ""; + for (let commit of info.commits) { + if(commits.length > 1000) break; + const shorthash = commit.id.substring(0, 7); + const uri = struri(`${repo.uri}/commit/${commit.id}`); + const msg = esc(clipstr(commit.message.split(/\r?\n/)[0], 64)); + const name = esc(commit.author.name); + commits += `${uristr(`\`${shorthash}\``, uri)} ${msg} - *${name}*\n`; + } + + const uri = info.compare; + + sendMessage(null, [merge(true, + author(send.user, send.uri, send.avatar), + embed(`[${name}] ${info.commits.length} new commit${s}`, commits, uri) + )]); + } + + static release(info) + { + const repo = prsRepoInfo(info); + const tag = uristr(info.release.tag_name, info.release.html_url); + sendMessage(`${repo.mai} ${tag} released`); + } + + static watch(info) + { + const repo = prsRepoInfo(info); + const send = prsSendInfo(info); + + sendMessage(`${repo.uristr} was starred by ${send.uristr}`); + } + + static ping(info) {} + static gollum(info) {} + static status(info) {} + static team_add(info) {} + static repository(info) {} + static deployment(info) {} + static membership(info) {} + static page_build(info) {} + static deployment_status(info) {} + static pull_request_review_comment(info) {} +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..c452a6c --- /dev/null +++ b/src/main.js @@ -0,0 +1,49 @@ +import bodyParser from "body-parser"; +import Events from "./events"; +import express from "express"; +import crypto from "crypto-js"; +import bufeq from "buffer-equal-constant-time"; + +const env = process.env; +const vhost = env.VHOST; +const port = parseInt(env.WEBHOOK_PORT); + +function verifyRequest(req) +{ + const hmac = crypto.HmacSHA1(req.body, env.GITHUB_SECRET); + + const hash = new Buffer("sha1=" + crypto.enc.Hex.stringify(hmac)); + const reqhash = new Buffer(req.get("X-Hub-Signature")); + + return bufeq(hash, reqhash); +} + +function handleRequest(req, res) +{ + if(req.body == null || (vhost && req.hostname != vhost)) return; + + if(env.GITHUB_SECRET && !verifyRequest(req)) + res.sendStatus(500); + else + { + const event = req.get("X-GitHub-Event"); + + if(event) + { + Events[event](JSON.parse(req.body)); + res.sendStatus(200); + } + else + res.sendStaus(400); + } +} + +function main() +{ + express() + .use(bodyParser.text({type: "application/json"})) + .post("/", handleRequest) + .listen(port); +} + +main();