import debug from "debug" ; import express = require ( "express" ) ; import helmet = require ( "helmet" ) ; import * as http from "http" ; import * as https from "https" ; import * as tls from "tls" ; import { SERVER_HTTP_PORT , SERVER_HTTPS_PORT } from "./constants" ; import { createSignedCertificate } from "./forge" ; import { ISerializedRequest , ISerializedResponse , transform , } from "unmock-core" ; import { createUnmockAlgo } from "./unmock" ; const httpPort = SERVER_HTTP_PORT ; const httpsPort = SERVER_HTTPS_PORT ; const log = ( ... args ) => console . log ( ... args ) ; const debugLog = debug ( "unmock-server:express" ) ; export interface IServerOptions { servicesDirectory ? : string ; } export const serialize = async ( req ) : Promise < ISerializedRequest > => { const serializedRequest = { method : req . method . toLowerCase ( ) as any , headers : { } , host : req . get ( "x-forwarded-host" ) || req . hostname , path : `${ req . originalUrl }` , pathname : req . path , query : req . query , protocol : req . protocol as any , } ; return serializedRequest ; } ; export const requestResponseHandler = ( opts ) => { const { unmock , algo } = createUnmockAlgo ( opts ) ; const handler = async ( req , res ) => { const serializedRequest = await serialize ( req ) ; const sendResponse = ( serializedResponse ) => { res . set ( serializedResponse . headers ) ; res . status ( serializedResponse . statusCode ) . send ( serializedResponse . body ) ; } ; const emitError = ( e ) => { debugLog ( `Error: ${ e . message }, ${ e . stack }` ) ; res . status ( 500 ) . send ( e . message ) ; } ; if ( ! algo . onSerializedRequest ) { throw Error ( "No serialized request" ) ; } algo . onSerializedRequest ( serializedRequest , sendResponse , emitError ) ; } ; return { unmock , handler } ; } ; export const buildApp = ( opts ? ) => { const app = express ( ) ; app . use ( helmet ( ) ) ; const { unmock , handler } = requestResponseHandler ( opts || { } ) ; app . post ( "/api" , ( req , res , next ) => { if ( typeof req . get ( "x-forwarded-host" ) !== "undefined" ) { return next ( ) ; } try { if ( req . query && req . query . code ) { debugLog ( `Setting response code to ${ req . query . code }` ) ; const asNumber = parseInt ( req . query . code , 10 ) ; Object . values ( unmock . services ) . forEach ( service => service . state ( transform . withCodes ( asNumber ) ) ) ; res . json ( { code : req . query . code } ) ; return ; } return res . sendStatus ( 400 ) ; } catch ( err ) { next ( err ) ; } } ) ; app . all ( "*" , handler ) ; return { unmock , app } ; } ; export const generateContext = ( servername ) => { debugLog ( `Generating context for ${ servername }` ) ; const { privateKey , signedCrt } = createSignedCertificate ( servername ) ; return tls . createSecureContext ( { key : privateKey , cert : signedCrt , } ) ; } ; export const startServer = ( app ) => { const { privateKey , signedCrt } = createSignedCertificate ( "localhost" ) ; const options = { SNICallback : ( servername , cb ) => { debugLog ( `SNICallback to ${ servername }` ) ; const context = generateContext ( servername ) ; debugLog ( `Found certificate for ${ servername }` ) ; if ( cb ) { return cb ( null , context ) ; } return context ; } , key : privateKey , cert : signedCrt , } ; const httpServer = http . createServer ( app ) ; const httpsServer = https . createServer ( options , app ) ; httpServer . listen ( httpPort , ( ) => { log ( "HTTP server starting on port: " + httpPort ) ; } ) ; httpsServer . listen ( httpsPort , ( ) => { log ( "HTTPS server starting on port: " + httpsPort ) ; } ) ; return [ httpServer , httpsServer ] ; } ;