import crypto from 'crypto' ; import { Buffer } from 'buffer' ; import * as Sentry from '@sentry/node' ; import { NowRequest , NowResponse } from '@vercel/node' ; import config from '../_utils/config' ; import handleGithubFeed from '../_utils/github/feed' ; import handleBlogFeed from '../_utils/blog/feed' ; import getRawBody from '../_utils/http' ; const { SENTRY_DSN , NODE_ENV , SUPERFEEDR_SECRET } = process . env ; Sentry . init ( { dsn : SENTRY_DSN } ) ; interface Item { permalinkUrl : string ; } description see https const validateSignature = ( headers , body ) => { const signatureHeaderName = 'x-hub-signature' ; if ( typeof headers [ signatureHeaderName ] === 'undefined' ) { throw new TypeError ( `validateSignature: header ${ signatureHeaderName } not found` ) ; } const signature = `sha1=${ crypto . createHmac ( 'sha1' , SUPERFEEDR_SECRET ?? '' ) . update ( body ) . digest ( 'hex' ) }` ; return crypto . timingSafeEqual ( Buffer . from ( headers [ signatureHeaderName ] ) , Buffer . from ( signature ) ) ; } ; export default async ( request , response ) : Promise < void > => { try { if ( request . method === 'POST' ) { const rawBody = await getRawBody ( request ) ; if ( validateSignature ( request . headers , rawBody ) ) { const updatedFeed = request . body . status . feed ; if ( updatedFeed . startsWith ( 'https://github.com' ) ) { const repoConfig = config . githubFeeds . find ( ( { feed } ) => feed === updatedFeed ) ; const urls = request . body . items . map ( ( item ) => item . permalinkUrl ) ; if ( repoConfig ) { await handleGithubFeed ( repoConfig , urls ) ; } } else { const isBlogFeedListed = config . blogFeeds . find ( ( { feed } ) => feed === updatedFeed ) ; if ( isBlogFeedListed ) { await handleBlogFeed ( request . body . items ) ; } } response . status ( 200 ) . send ( 'ok' ) ; } else { response . status ( 400 ) . send ( 'signature is not valid' ) ; } } else { response . status ( 401 ) . send ( 'Unauthorized' ) ; } } catch ( error ) { if ( NODE_ENV === 'development' ) { console . error ( error ) ; } else { Sentry . captureException ( error ) ; } response . status ( 400 ) . send ( 'not ok' ) ; } } ;