import sslify from "express-sslify" ; import helmet from "helmet" ; import getFrontendApp from "./app" ; import { Application } from "probot" ; import { Express , NextFunction , Request , Response , Router } from "express" ; import crypto from "crypto" ; import Redis from "ioredis" ; import getRedisInfo from "../config/redis-info" ; import RateLimit from "express-rate-limit" ; import RedisStore from "rate-limit-redis" ; import statsd , { elapsedTimeMetrics } from "../config/statsd" ; import { metricError } from "../config/metric-names" ; function secureHeaders ( router , frontendApp ) { router . use ( ( _ , res , next ) : void => { res . locals . nonce = crypto . randomBytes ( 16 ) . toString ( "hex" ) ; next ( ) ; } ) ; router . use ( helmet . contentSecurityPolicy ( { useDefaults : true , directives : { defaultSrc : [ "'self'" ] , scriptSrc : [ "'self'" , process . env . APP_URL , "https://*.atlassian.net" , "https://*.jira.com" , "https://connect-cdn.atl-paas.net/" , "'unsafe-inline'" , "'strict-dynamic'" , ( _ , res ) : string => `'nonce-${ res . locals . nonce }'` ] , connectSrc : [ "'self'" , process . env . APP_URL ] , styleSrc : [ "'self'" , "'unsafe-inline'" ] , frameAncestors : [ "https://*.atlassian.net" , "https://*.jira-dev.com" , "https://*.jira.com" ] , baseUri : [ "'none'" ] , reportUri : "https://web-security-reports.services.atlassian.com/csp-report/github-for-jira" , imgSrc : [ "'self'" , "data:" , "https://*.githubusercontent.com" , "https://octodex.github.com" ] } } ) ) ; router . use ( helmet . hsts ( { maxAge : 15552000 } ) ) ; router . use ( helmet . ieNoOpen ( ) ) ; router . use ( helmet . noCache ( ) ) ; router . use ( helmet . noSniff ( ) ) ; router . use ( helmet . xssFilter ( ) ) ; frontendApp . disable ( "x-powered-by" ) ; router . use ( helmet . hidePoweredBy ( ) ) ; } export default ( app ) : void => { const router = app . route ( ) ; router . use ( elapsedTimeMetrics ) ; if ( process . env . USE_RATE_LIMITING === "true" ) { const client = new Redis ( getRedisInfo ( "rate-limiter" ) ) ; const limiter = RateLimit ( { store : new RedisStore ( { client } ) , skip ( _ ) { return false ; } , handler ( _ , res ) { statsd . increment ( metricError . expressRateLimited ) ; res . status ( 429 ) . send ( "Too many requests, please try again later." ) ; } , max : 100 } ) ; router . use ( limiter ) ; } if ( process . env . FORCE_HTTPS ) { router . use ( sslify . HTTPS ( { trustProtoHeader : true } ) ) ; } const frontendApp = getFrontendApp ( app . app ) ; secureHeaders ( router , frontendApp ) ; router . use ( frontendApp ) ; } ;