99 lines
3.1 KiB
JavaScript
99 lines
3.1 KiB
JavaScript
|
/* jshint esversion: 8 */
|
||
|
import { promisify } from 'util'
|
||
|
import child_process from 'child_process'
|
||
|
const exec = promisify(child_process.exec) // run child_process.exec as a Promise/async
|
||
|
import { createHmac } from 'crypto'
|
||
|
import express from 'express'
|
||
|
const port = process.env.PORT
|
||
|
import { SMTPClient } from 'emailjs';
|
||
|
|
||
|
// express
|
||
|
const app = express()
|
||
|
app.use(express.json())
|
||
|
|
||
|
|
||
|
function sendEmail(msg, trigger) {
|
||
|
const client = new SMTPClient({
|
||
|
user: process.env.EMAIL_USER,
|
||
|
password: process.env.EMAIL_PASSWORD,
|
||
|
host: process.env.SMTP_DOMAIN,
|
||
|
ssl: true,
|
||
|
});
|
||
|
|
||
|
// send the message and get a callback with an error or details of the message that was sent
|
||
|
client.send(
|
||
|
{
|
||
|
text: `Git webhook for ${trigger} has triggered a "git pull" event with the following result:\n\n${msg}`,
|
||
|
from: `Webhook Alerts<${process.env.EMAIL_SEND_ADDRESS}>`,
|
||
|
to: process.env.EMAIL_RECEIVE_ADDRESS,
|
||
|
subject: `Git service triggered a pull for ${trigger}`,
|
||
|
},
|
||
|
(err, message) => {
|
||
|
console.log(err || message);
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// function to run git pull
|
||
|
async function gitPull(local_repo, res) {
|
||
|
try {
|
||
|
const { stdout, stderr } = await exec(`cd ${local_repo} && git pull`);
|
||
|
let msg = stderr ? stderr : stdout // message is the error message if there is one, else the stdout
|
||
|
sendEmail(msg, process.env.APP_PATH)
|
||
|
res.status(200).send('Ok')
|
||
|
} catch (err) {
|
||
|
console.error(err)
|
||
|
res.status(500).send('server error - sorry about that')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// we are *recieving* POST requests here
|
||
|
app.post(`/${process.env.APP_PATH}`, (req, res) => {
|
||
|
const hmac = createHmac('sha256', process.env.SECRET)
|
||
|
const local_repo = process.env.LOCAL_REPO
|
||
|
hmac.update(JSON.stringify(req.body))
|
||
|
|
||
|
// check has signature header and the decrypted signature matches
|
||
|
if (req.get('X-Hub-Signature-256')) {
|
||
|
if ( `sha256=${hmac.digest('hex').toString()}` === req.get('X-Hub-Signature-256') ){
|
||
|
if (req.body.ref === 'refs/heads/main') {
|
||
|
gitPull(local_repo, res)
|
||
|
} else {
|
||
|
console.log('Ignoring push to non-default branch')
|
||
|
res.status(200).send('Ignoring push to non-default branch')
|
||
|
}
|
||
|
} else {
|
||
|
console.error('signature header received but hash did not match')
|
||
|
res.status(403).send('Signature is missing or does not match')
|
||
|
}
|
||
|
} else {
|
||
|
console.error('Signature missing')
|
||
|
res.status(403).send('Signature is missing or does not match')
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// everything else should 404
|
||
|
app.use(function (req, res) {
|
||
|
res.status(404).send('Nothing here')
|
||
|
})
|
||
|
|
||
|
app.listen(port, () => {
|
||
|
const secrets = {
|
||
|
"PORT": process.env.PORT,
|
||
|
"SECRET": process.env.SECRET,
|
||
|
"EMAIL_USER": process.env.EMAIL_USER,
|
||
|
"EMAIL_PASSWORD": process.env.EMAIL_PASSWORD,
|
||
|
"SMTP_DOMAIN": process.env.SMTP_DOMAIN,
|
||
|
"EMAIL_SEND_ADDRESS": process.env.EMAIL_SEND_ADDRESS,
|
||
|
"EMAIL_RECEIVE_ADDRESS": process.env.EMAIL_RECEIVE_ADDRESS,
|
||
|
"APP_PATH": process.env.APP_PATH,
|
||
|
"LOCAL_REPO": process.env.LOCAL_REPO
|
||
|
}
|
||
|
for (let key in secrets) {
|
||
|
if (secrets[key] === undefined || null) {
|
||
|
throw Error(`Missing ${key} from environment values`)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
console.log(`Webhooks app listening on port ${port}`)
|
||
|
})
|