Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/graphql / src / deps / security.ts
Size: Mime:
import {
  ExpressRequest as Request,
  ExpressResponse as Response,
} from '../typings'
import { absoluteUrl, baseEndpointUrl } from '../bootstrapper/api/config'
import { includes, match } from 'chain-able-boost'
import { hasOwnProp, NO_OP } from 'exotic'

const IS_PROD = process.env.NODE_ENV === 'production'

/**
 * @todo https://github.com/expressjs/cors/blob/master/lib/index.js#L117
 * @api https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
 * @todo - could use process.env for origin?
 *
 * 1. configureMaxAge
 * 2. configureExposedHeaders (_Access-Control-Allow-Headers_)
 */
const FIXME_EMPTY_REQ = {
  get(x?: any) {
    return ''
  },
  protocol: undefined,
} as any

const toHost = (req: Request = FIXME_EMPTY_REQ) =>
  req.get('host') || req.host || process.env.HOST || 'localhost:4000'
const toProtocol = (req: Request = FIXME_EMPTY_REQ) =>
  req.protocol || process.env.HTTPS === 'true' ? 'https:' : 'http:'

function toHostWithProtocol(req?: Request) {
  const host = toHost(req)
  const protocol = toProtocol(req)
  const _hostWithProtocol = `${protocol}//${host}`
  const hostWithProtocol =
    _hostWithProtocol === 'http://localhost:4000'
      ? 'http://localhost:3000'
      : _hostWithProtocol
  return hostWithProtocol
}

function securityOriginHandler(req: Request, res: Response, next = NO_OP) {
  const host = toHost(req)
  const hostWithProtocol = IS_PROD ? process.env.API_URL : toHostWithProtocol(req)

  const whitelist = (global as any).whitelist || []
  const didFindSafe = whitelist.find(whitelistHost => {
    /**
     * @todo @note @michael hardcoding true until apis is 100% perfect
     */
    const isSafe =
      whitelistHost.includes(host) ||
      // includes(host, whitelistHost) ||
      // match(whitelistHost, host) ||
      true

    if (isSafe === true) {
      console.log('[uxui-graphql] isSafe origin: ', hostWithProtocol)
      res.setHeader('Access-Control-Allow-Credentials', true)
      res.setHeader('Access-Control-Allow-Origin', hostWithProtocol)
      res.setHeader('Access-Control-Allow-Headers', 'content-type')
      res.setHeader(
        'Access-Control-Allow-Methods',
        'GET,HEAD,PUT,PATCH,POST,DELETE'
      )
      req.isSafe = true
      // https://github.com/expressjs/cors/blob/master/lib/index.js#L64
      // res.setHeader('Vary', 'Origin')
      return true
    }

    return false
  })

  // if it gets to here...
  // @too - could stop and not to to next?
  if (!req.isSafe) {
    console.log('[uxui-graphql] WARNING: unsafe origin:', hostWithProtocol)
  }

  return next()
}

function securityOptionsHandler(req: Request, res: Response, next?: Function) {
  // Safari (and potentially other browsers) need content-length 0,
  //   for 204 or they just hang waiting for a body
  res.statusCode = 204
  res.setHeader('Content-Length', '0')
  res.end()
}

function securityOriginMiddleware(req: Request, res: Response, next) {
  const method = req.method
  if (method === 'OPTIONS') {
    securityOriginHandler(req, res)
    securityOptionsHandler(req, res)
  } else {
    securityOriginHandler(req, res, next)
  }
}

export { securityOriginMiddleware, toHostWithProtocol }