<commit_before>'use strict'

/**
 * Dependencies
 * @ignore
 */
const crypto = require('@trust/webcrypto')
const qs = require('qs')

const HandledError = require('../errors/HandledError')

/**
 * Request Parameter Mapping
 */
const PARAMS = { 'GET': 'query', 'POST': 'body' }

/**
 * Response Mode Mapping
 */
const MODES = { 'query': '?', 'fragment': '#' }

/**
 * BaseRequest
 *
 * @class
 * Abstract class for implementing OpenID Connect request handlers.
 */
class BaseRequest {

  /**
   * Request Handler
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  static handle (req, res, provider) {
    throw new Error('Handle must be implemented by BaseRequest subclass')
  }

  /**
   * Constructor
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  constructor (req, res, provider) {
    this.req = req
    this.res = res
    this.provider = provider
    this.host = provider.host
  }

  /**
   * Get Params
   *
   * @param {BaseRequest} request
   * @returns {Object}
   */
  static getParams (request) {
    let {req,res,provider} = request
    return req[PARAMS[req.method]] || {}
  }

  /**
   * Get Response Types
   *
   * @param {BaseRequest} request
   * @returns {Array}
   */
  static getResponseTypes (request) {
    let { params: { response_type: type } } = request
    return (typeof type === 'string') ? type.split(' ') : []
  }

  /**
   * Get Response Mode
   *
   * @param {BaseRequest} request
   * @returns {string}
   */
  static getResponseMode (request) {
    let mode
    let { params } = request || {}
    let { response_mode: responseMode, response_type: responseType } = params

    if (responseMode) {
      mode = MODES[responseMode]
    } else if (responseType === 'code' || responseType === 'none') {
      mode = '?'
    } else {
      mode = '#'
    }

    return mode
  }

  /**
   * 302 Redirect Response
   */
  redirect (data) {
    let { res, params: { redirect_uri: uri, state }, responseMode } = this

    if (state) {
      data.state = state
    }

    let response = qs.stringify(data)
    res.redirect(`${uri}${responseMode}${response}`)

    throw new HandledError('302 Redirect')
  }

  /**
   * 401 Unauthorized Response
   */
  unauthorized (err) {
    let { res } = this
    let { realm, error, error_description: description } = err

    res.set({
      'WWW-Authenticate':
      `Bearer realm=${realm}, error=${error}, error_description=${description}`
    })

    res.status(401).send('Unauthorized')

    throw new HandledError('401 Unauthorized')
  }

  /**
   * 403 Forbidden Response
   */
  forbidden () {
    let {res} = this
    res.status(403).send('Forbidden')

    throw new HandledError('403 Forbidden')
  }

  /**
   * 400 Bad Request Response
   */
  badRequest (error) {
    let {res} = this

    res.set({
      'Cache-Control': 'no-store',
      'Pragma': 'no-cache'
    })

    res.status(400).json(error)

    throw new HandledError('400 Bad Request')
  }

  /**
   * Serves as a general purpose error handler for `.catch()` clauses in
   * Promise chains. Example usage:
   *
   *   ```
   *   return Promise.resolve(request)
   *     .then(request.validate)
   *     .then(request.stepOne)
   *     .then(request.stepTwo)  // etc.
   *     .catch(request.error.bind(request))
   *   ```
   *
   * If at any point (say, in `validate()` or `stepOne()`) the code needs to<commit_msg>refactor(BaseRequest): Add error and error_description to badRequest() params<commit_after>'use strict'

/**
 * Dependencies
 * @ignore
 */
const crypto = require('@trust/webcrypto')
const qs = require('qs')

const HandledError = require('../errors/HandledError')

/**
 * Request Parameter Mapping
 */
const PARAMS = { 'GET': 'query', 'POST': 'body' }

/**
 * Response Mode Mapping
 */
const MODES = { 'query': '?', 'fragment': '#' }

/**
 * BaseRequest
 *
 * @class
 * Abstract class for implementing OpenID Connect request handlers.
 */
class BaseRequest {

  /**
   * Request Handler
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  static handle (req, res, provider) {
    throw new Error('Handle must be implemented by BaseRequest subclass')
  }

  /**
   * Constructor
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  constructor (req, res, provider) {
    this.req = req
    this.res = res
    this.provider = provider
    this.host = provider.host
  }

  /**
   * Get Params
   *
   * @param {BaseRequest} request
   * @returns {Object}
   */
  static getParams (request) {
    let {req,res,provider} = request
    return req[PARAMS[req.method]] || {}
  }

  /**
   * Get Response Types
   *
   * @param {BaseRequest} request
   * @returns {Array}
   */
  static getResponseTypes (request) {
    let { params: { response_type: type } } = request
    return (typeof type === 'string') ? type.split(' ') : []
  }

  /**
   * Get Response Mode
   *
   * @param {BaseRequest} request
   * @returns {string}
   */
  static getResponseMode (request) {
    let mode
    let { params } = request || {}
    let { response_mode: responseMode, response_type: responseType } = params

    if (responseMode) {
      mode = MODES[responseMode]
    } else if (responseType === 'code' || responseType === 'none') {
      mode = '?'
    } else {
      mode = '#'
    }

    return mode
  }

  /**
   * 302 Redirect Response
   */
  redirect (data) {
    let { res, params: { redirect_uri: uri, state }, responseMode } = this

    if (state) {
      data.state = state
    }

    let response = qs.stringify(data)
    res.redirect(`${uri}${responseMode}${response}`)

    throw new HandledError('302 Redirect')
  }

  /**
   * 401 Unauthorized Response
   */
  unauthorized (err) {
    let { res } = this
    let { realm, error, error_description: description } = err

    res.set({
      'WWW-Authenticate':
      `Bearer realm=${realm}, error=${error}, error_description=${description}`
    })

    res.status(401).send('Unauthorized')

    throw new HandledError('401 Unauthorized')
  }

  /**
   * 403 Forbidden Response
   */
  forbidden () {
    let {res} = this
    res.status(403).send('Forbidden')

    throw new HandledError('403 Forbidden')
  }

  /**
   * 400 Bad Request Response
   *
   * @param params {Object}
   * @param params.error {string}
   * @param params.error_description {string}
   */
  badRequest (params) {
    let {res} = this

    res.set({
      'Cache-Control': 'no-store',
      'Pragma': 'no-cache'
    })

    res.status(400).json(params)

    let error = new HandledError('400 Bad Request')

    error.error = params.error || 'invalid_request'
    error.error_description = params.error_description

    throw error
  }

  /**
   * Serves as a general purpose error handler for `.catch()` clauses in
   * Promise chains. Example usage:
   *
   *   ```
   *   return Promise.resolve(request)
   *     .then(request.validate)
   *     .then(request.stepOne)
   *     .then(request.stepTwo)  // etc.
   *     .catch(request.error.bind(request))
   *   ```
   *
   * If at any point (say, in `validate()` or `stepOne()`) the code needs to
{'fraction_non_alphanumeric': 0.149585635359116, 'fraction_numerical': 0.009116022099447514, 'mean_word_length': 2.6223111555777887, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7458317', 'n_tokens_mistral': 2405, 'n_tokens_neox': 2292, 'n_words': 579}