2017-06-10 20:37:15 +05:30
|
|
|
/*
|
2018-03-20 13:23:07 +02:00
|
|
|
* Bot that receives a POST request (from a GitHub issue comment webhook),
|
|
|
|
* finds the address of the bounty contract and funds it automatically
|
|
|
|
* with either ETH or any ERC20/223 token.
|
|
|
|
* REVIEW hardcoded string length.
|
|
|
|
* Depends on openbounty version as of 2018-03-20.
|
2018-01-22 12:24:19 +01:00
|
|
|
*/
|
2018-01-19 18:33:27 +01:00
|
|
|
|
2018-03-19 22:37:38 +01:00
|
|
|
const config = require('./config')
|
|
|
|
const bot = require('./bot')
|
|
|
|
const crypto = require('crypto')
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
const express = require('express')
|
|
|
|
const cors = require('cors')
|
|
|
|
const helmet = require('helmet')
|
|
|
|
const app = express()
|
|
|
|
const bodyParser = require('body-parser')
|
|
|
|
const jsonParser = bodyParser.json()
|
2017-03-07 12:24:01 +01:00
|
|
|
|
2018-03-19 22:37:38 +01:00
|
|
|
app.use(cors())
|
|
|
|
app.use(helmet())
|
2018-01-17 16:48:56 +00:00
|
|
|
|
2018-01-22 23:45:09 +01:00
|
|
|
// Receive a POST request at the url specified by an env. var.
|
2018-01-23 16:36:34 +01:00
|
|
|
app.post(`${config.urlEndpoint}`, jsonParser, function (req, res, next) {
|
2018-03-19 23:02:24 +01:00
|
|
|
if (!req.body || !req.body.action) {
|
|
|
|
return res.sendStatus(400)
|
|
|
|
} else if (!bot.needsFunding(req)) {
|
|
|
|
return res.sendStatus(204)
|
|
|
|
}
|
|
|
|
|
|
|
|
const validation = validateRequest(req)
|
|
|
|
|
|
|
|
if (validation.correct) {
|
|
|
|
setTimeout(async () => {
|
|
|
|
try {
|
|
|
|
await processRequest(req)
|
|
|
|
bot.info(`issue well funded: ${req.body.issue.url}`)
|
|
|
|
} catch (err) {
|
|
|
|
bot.error(`Error processing request: ${req.body.issue.url}`)
|
2018-03-20 11:00:38 +01:00
|
|
|
bot.error(err)
|
|
|
|
bot.error(`Dump: ${JSON.stringify(req.body)}`)
|
2018-03-19 23:02:24 +01:00
|
|
|
}
|
|
|
|
}, config.delayInMiliSeconds)
|
|
|
|
} else {
|
|
|
|
bot.error(`Error validating issue: ${req.body.issue.url}`)
|
|
|
|
bot.error(`Error: ${validation.error}`)
|
|
|
|
}
|
|
|
|
return res.sendStatus(200)
|
2018-03-19 22:37:38 +01:00
|
|
|
})
|
2018-01-22 23:45:09 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
function validateRequest (req) {
|
|
|
|
const validation = { correct: false, error: '' }
|
|
|
|
const webhookSecret = process.env.WEBHOOK_SECRET
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
if (!webhookSecret) {
|
|
|
|
validation.error = 'Github Webhook Secret key not found. ' +
|
|
|
|
'Please set env variable WEBHOOK_SECRET to github\'s webhook secret value'
|
|
|
|
} else {
|
|
|
|
const blob = JSON.stringify(req.body)
|
|
|
|
const hmac = crypto.createHmac('sha1', webhookSecret)
|
|
|
|
const ourSignature = `sha1=${hmac.update(blob).digest('hex')}`
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
const theirSignature = req.get('X-Hub-Signature')
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
const bufferA = Buffer.from(ourSignature, 'utf8')
|
|
|
|
const bufferB = Buffer.from(theirSignature, 'utf8')
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
const safe = crypto.timingSafeEqual(bufferA, bufferB)
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
if (safe) {
|
|
|
|
validation.correct = true
|
|
|
|
} else {
|
|
|
|
validation.error = 'Invalid signature. Check that WEBHOOK_SECRET ' +
|
|
|
|
'env variable matches github\'s webhook secret value'
|
2018-02-10 19:55:24 +01:00
|
|
|
}
|
2018-03-19 23:02:24 +01:00
|
|
|
}
|
2018-02-10 19:55:24 +01:00
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
return validation
|
2018-02-10 19:55:24 +01:00
|
|
|
}
|
|
|
|
|
2018-03-19 23:02:24 +01:00
|
|
|
async function processRequest (req) {
|
|
|
|
const to = bot.getAddress(req)
|
|
|
|
const amount = await bot.getAmount(req)
|
|
|
|
const gasPrice = await bot.getGasPrice()
|
|
|
|
const hash = await bot.sendTransaction(to, amount, gasPrice)
|
|
|
|
|
|
|
|
bot.logTransaction(hash)
|
2018-01-22 23:45:09 +01:00
|
|
|
}
|
2018-01-22 16:50:23 +01:00
|
|
|
|
2017-03-07 12:24:01 +01:00
|
|
|
const port = process.env.PORT || 8181
|
2018-01-23 16:36:34 +01:00
|
|
|
app.listen(port, function () {
|
2018-03-20 13:50:51 +01:00
|
|
|
bot.info(`Autobounty listening on port ${port}`)
|
2018-03-19 22:37:38 +01:00
|
|
|
})
|