static-cms/functions/publish.js
2022-09-28 22:04:00 -04:00

85 lines
2.5 KiB
JavaScript

const crypto = require('crypto');
const axios = require('axios');
const verifySignature = event => {
const timestamp = Number(event.headers['x-slack-request-timestamp']);
const time = Math.floor(Date.now() / 1000);
if (time - timestamp > 60 * 5) {
throw new Error(`Failed verifying signature. Timestamp too old '${timestamp}'`);
}
const body = event.body;
const sigString = `v0:${timestamp}:${body}`;
const actualSignature = event.headers['x-slack-signature'];
const secret = process.env.SLACK_SIGNING_SECRET;
const hash = crypto
.createHmac('sha256', secret)
.update(sigString, 'utf8')
.digest('hex');
const expectedSignature = `v0=${hash}`;
const signaturesMatch = crypto.timingSafeEqual(
Buffer.from(actualSignature, 'utf8'),
Buffer.from(expectedSignature, 'utf8'),
);
if (!signaturesMatch) {
throw new Error(
`Signatures don't match. Expected: '${expectedSignature}', actual: '${actualSignature}'`,
);
}
};
exports.handler = async function(event) {
try {
console.info(
JSON.stringify(
{
event,
env: {
PUBLISH_COMMAND: process.env.PUBLISH_COMMAND,
ALLOWED_USERS: process.env.ALLOWED_USERS,
GITHUB_REPO: process.env.GITHUB_REPO,
},
},
null,
2,
),
);
verifySignature(event);
const params = new URLSearchParams(event.body);
const command = params.get('command');
const userId = params.get('user_id');
const allowedUsers = (process.env.ALLOWED_USERS || '').split(',');
if (!allowedUsers.includes(userId)) {
throw new Error(`User '${params.get('user_name')}' is not allowed to run command`);
}
const expectedCommand = process.env.PUBLISH_COMMAND;
if (expectedCommand && expectedCommand == command) {
const githubToken = process.env.GITHUB_TOKEN;
const repo = process.env.GITHUB_REPO;
await axios({
headers: { Authorization: `token ${githubToken}` },
method: 'post',
url: `https://api.github.com/repos/${repo}/dispatches`,
data: { event_type: 'on-demand-github-action' },
});
const message = 'Dispatched event to GitHub';
return { status: 200, body: message };
} else {
throw new Error(`Command is not allowed. Expected: ${expectedCommand}. Actual: ${command}`);
}
} catch (e) {
console.info(e);
const response = {
body: 'Unauthorized',
status: 401,
};
return response;
}
};