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.log(
      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.log(e);
    const response = {
      body: 'Unauthorized',
      status: 401,
    };
    return response;
  }
};