Source: server/authorization/authorization.middleware.js

import { messageUser } from '../../slack/messaging';
import { NextFunction, Request, Response } from 'express';
import Winston from '../../logging/app.logger';
import { prettyJson } from '../../logging/format';
import { SlackClient } from '../../slack';
import { userIsRegistered } from './authorization.service';
import * as crypto from 'crypto';
import * as qs from 'qs';

export async function validateUser(req: Request, res: Response, next: NextFunction) {
    const client = new SlackClient();
    try {
        //res.status(200).send('Got it!'); // basic receipt: https://api.slack.com/slash-commands?#responding_basic_receipt
        req.body |> prettyJson |> Winston.info;
        
        const slackId = req.body.user_id;

        if (await userIsRegistered(slackId)) {
            next();
        } else {
            next(Error('User not authenticated.'));
            messageUser(client, slackId, 'Oops! Seems like you are not logged in yet. Try using /login first!');
        }


    }
    catch (exception) {
        Winston.error('Exception in validateUser');
        exception |> prettyJson |> Winston.error;
        next(exception);
    }
}

/**
 * Validate that requests are coming from Slack using the Slack Signing Secret.
 */
export async function validateSlack(req: Request, res: Response, next: NextFunction) {
    // Code Credits: https://medium.com/@rajat_sriv/verifying-requests-from-slack-using-node-js-69a8b771b704   
    const timestamp = req.header('X-Slack-Request-Timestamp');
    const slackSignature = req.header('X-Slack-Signature');
    const body = qs.stringify(req.body, { format: 'RFC1738' });

    if (!timestamp) {
        Winston.error('Received a request without the X-Slack-Request-Timestamp header.');
        throw Error('Received Slack request without a timestamp.');
    }

    // convert current time from milliseconds to seconds
    const time = Math.floor(new Date().getTime() / 1000);
    if (Math.abs(time - timestamp) > 300) {
        Winston.error('Received a request with a timestamp older than 300 seconds. Possible replay attack.');
        return res.status(400).send('Verification failed');
    }

    const sigBasestring = `v0:${timestamp}:${body}`;

    const mySignature = 'v0=' + crypto
        .createHmac('sha256', process.env.SIGNING_SECRET)
        .update(sigBasestring, 'utf8')
        .digest('hex');

    if (crypto.timingSafeEqual(
        Buffer.from(mySignature, 'utf8'),
        Buffer.from(slackSignature, 'utf8'))) {
        Winston.debug('Message confirmed as coming from Slack.');
        next();
    } else {
        Winston.error('Received a request with an invalid signature.');
        return res.status(400).send('Verification failed');
    }
}