import { raw } from "body-parser" ; import * as http from "http" ; import { JSONParseError , SignatureValidationFailed } from "./exceptions" ; import * as Types from "./types" ; import validateSignature from "./validate-signature" ; export type Request = http . IncomingMessage & { body : any ; } ; export type Response = http . ServerResponse ; export type NextCallback = ( err ? : Error ) => void ; export type Middleware = ( req : Request , res : Response , next : NextCallback ) => void | Promise < void > ; function isValidBody ( body ? ) { return ( body && typeof body === "string" ) || Buffer . isBuffer ( body ) ; } export default function middleware ( config ) { if ( ! config . channelSecret ) { throw new Error ( "no channel secret" ) ; } const secret = config . channelSecret ; const _middleware = async ( req , res , next ) => { const signature = req . headers [ Types . LINE_SIGNATURE_HTTP_HEADER_NAME ] as string ; if ( ! signature ) { next ( new SignatureValidationFailed ( "no signature" ) ) ; return ; } const body = await ( async ( ) : Promise < string | Buffer > => { if ( isValidBody ( ( req as any ) . rawBody ) ) { return ( req as any ) . rawBody ; } else if ( isValidBody ( req . body ) ) { return req . body ; } else { return new Promise < Buffer > ( ( resolve , reject ) => raw ( { type : "*/*" } ) ( req as any , res as any , ( error ) => error ? reject ( error ) : resolve ( req . body ) ) ) ; } } ) ( ) ; if ( ! validateSignature ( body , secret , signature ) ) { next ( new SignatureValidationFailed ( "signature validation failed" , signature ) ) ; return ; } const strBody = Buffer . isBuffer ( body ) ? body . toString ( ) : body ; try { req . body = JSON . parse ( strBody ) ; next ( ) ; } catch ( err ) { next ( new JSONParseError ( err . message , strBody ) ) ; } } ; return ( req , res , next ) : void => { ( < Promise < void > > _middleware ( req , res , next ) ) . catch ( next ) ; } ; }