All files / proxy/handlers handleResult.ts

76.19% Statements 32/42
100% Branches 5/5
76.92% Functions 10/13
77.5% Lines 31/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110    2x 2x   2x   2x 18x 18x   18x   18x 18x   49x   45x 45x 3x   45x   18x   18x   18x             5x   5x 5x   5x         5x                     18x   15x 13x 13x                 15x         13x                 13x                                             18x 18x    
import { ResultOptions } from '../model'
import { CloudFrontResultResponse } from 'aws-lambda'
import https from 'https'
import { Region } from '../model'
 
import { updateResponseHeaders, addTrafficMonitoringSearchParamsForVisitorIdRequest } from '../utils'
 
export function handleResult(options: ResultOptions): Promise<CloudFrontResultResponse> {
  return new Promise((resolve) => {
    console.debug('Handling result:', { options })
 
    const data: any[] = []
 
    const url = new URL(getIngressAPIHost(options.region, options.fpIngressBaseHost) + options.suffix)
    decodeURIComponent(options.querystring)
      .split('&')
      .filter((it) => it.includes('='))
      .forEach((it) => {
        const kv = it.split('=')
        if (kv[0] === 'region') {
          kv[1] = options.region
        }
        url.searchParams.append(kv[0], kv[1])
      })
    addTrafficMonitoringSearchParamsForVisitorIdRequest(url)
 
    console.debug(`Performing request: ${url.toString()}`)
 
    const request = https.request(
      url,
      {
        method: options.method,
        headers: options.headers,
      },
      (response) => {
        response.on('data', (chunk) => data.push(chunk))
 
        response.on('end', () => {
          const payload = Buffer.concat(data)
 
          console.debug('Response from Ingress API', {
            statusCode: response.statusCode,
            payload: payload.toString('utf-8'),
          })
 
          resolve({
            status: response.statusCode ? response.statusCode.toString() : '500',
            statusDescription: response.statusMessage,
            headers: updateResponseHeaders(response.headers),
            bodyEncoding: 'base64',
            body: payload.toString('base64'),
          })
        })
      }
    )
 
    request.write(Buffer.from(options.body, 'base64'))
 
    request.on('error', (error) => {
      console.error('unable to handle result', { error })
      resolve({
        status: '500',
        statusDescription: 'Bad request',
        headers: {},
        bodyEncoding: 'text',
        body: generateErrorResponse(error),
      })
    })
 
    request.end()
  })
}
 
function generateErrorResponse(err: Error): string {
  const body = {
    v: '2',
    error: {
      code: 'Failed',
      message: `An error occurred with Fingerprint Pro Lambda function. Reason ${err}`,
    },
    requestId: generateRequestId,
    products: {},
  }
  return JSON.stringify(body)
}
 
function generateRequestId(): string {
  const uniqueId = generateRequestUniqueId()
  const now = new Date().getTime()
  return `${now}.aws-${uniqueId}`
}
 
function generateRandomString(length: number): string {
  let result = ''
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * characters.length))
  }
  return result
}
 
function generateRequestUniqueId(): string {
  return generateRandomString(2)
}
 
function getIngressAPIHost(region: Region, baseHost: string): string {
  const prefix = region === Region.us ? '' : `${region}.`
  return `https://${prefix}${baseHost}`
}