11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst errors = require('./errors.js')
41cb0ef41Sopenharmony_ciconst { Response } = require('minipass-fetch')
51cb0ef41Sopenharmony_ciconst defaultOpts = require('./default-opts.js')
61cb0ef41Sopenharmony_ciconst log = require('proc-log')
71cb0ef41Sopenharmony_ciconst cleanUrl = require('./clean-url.js')
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci/* eslint-disable-next-line max-len */
101cb0ef41Sopenharmony_ciconst moreInfoUrl = 'https://github.com/npm/cli/wiki/No-auth-for-URI,-but-auth-present-for-scoped-registry'
111cb0ef41Sopenharmony_ciconst checkResponse =
121cb0ef41Sopenharmony_ci  async ({ method, uri, res, startTime, auth, opts }) => {
131cb0ef41Sopenharmony_ci    opts = { ...defaultOpts, ...opts }
141cb0ef41Sopenharmony_ci    if (res.headers.has('npm-notice') && !res.headers.has('x-local-cache')) {
151cb0ef41Sopenharmony_ci      log.notice('', res.headers.get('npm-notice'))
161cb0ef41Sopenharmony_ci    }
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci    if (res.status >= 400) {
191cb0ef41Sopenharmony_ci      logRequest(method, res, startTime)
201cb0ef41Sopenharmony_ci      if (auth && auth.scopeAuthKey && !auth.token && !auth.auth) {
211cb0ef41Sopenharmony_ci      // we didn't have auth for THIS request, but we do have auth for
221cb0ef41Sopenharmony_ci      // requests to the registry indicated by the spec's scope value.
231cb0ef41Sopenharmony_ci      // Warn the user.
241cb0ef41Sopenharmony_ci        log.warn('registry', `No auth for URI, but auth present for scoped registry.
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ciURI: ${uri}
271cb0ef41Sopenharmony_ciScoped Registry Key: ${auth.scopeAuthKey}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciMore info here: ${moreInfoUrl}`)
301cb0ef41Sopenharmony_ci      }
311cb0ef41Sopenharmony_ci      return checkErrors(method, res, startTime, opts)
321cb0ef41Sopenharmony_ci    } else {
331cb0ef41Sopenharmony_ci      res.body.on('end', () => logRequest(method, res, startTime, opts))
341cb0ef41Sopenharmony_ci      if (opts.ignoreBody) {
351cb0ef41Sopenharmony_ci        res.body.resume()
361cb0ef41Sopenharmony_ci        return new Response(null, res)
371cb0ef41Sopenharmony_ci      }
381cb0ef41Sopenharmony_ci      return res
391cb0ef41Sopenharmony_ci    }
401cb0ef41Sopenharmony_ci  }
411cb0ef41Sopenharmony_cimodule.exports = checkResponse
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_cifunction logRequest (method, res, startTime) {
441cb0ef41Sopenharmony_ci  const elapsedTime = Date.now() - startTime
451cb0ef41Sopenharmony_ci  const attempt = res.headers.get('x-fetch-attempts')
461cb0ef41Sopenharmony_ci  const attemptStr = attempt && attempt > 1 ? ` attempt #${attempt}` : ''
471cb0ef41Sopenharmony_ci  const cacheStatus = res.headers.get('x-local-cache-status')
481cb0ef41Sopenharmony_ci  const cacheStr = cacheStatus ? ` (cache ${cacheStatus})` : ''
491cb0ef41Sopenharmony_ci  const urlStr = cleanUrl(res.url)
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  log.http(
521cb0ef41Sopenharmony_ci    'fetch',
531cb0ef41Sopenharmony_ci    `${method.toUpperCase()} ${res.status} ${urlStr} ${elapsedTime}ms${attemptStr}${cacheStr}`
541cb0ef41Sopenharmony_ci  )
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_cifunction checkErrors (method, res, startTime, opts) {
581cb0ef41Sopenharmony_ci  return res.buffer()
591cb0ef41Sopenharmony_ci    .catch(() => null)
601cb0ef41Sopenharmony_ci    .then(body => {
611cb0ef41Sopenharmony_ci      let parsed = body
621cb0ef41Sopenharmony_ci      try {
631cb0ef41Sopenharmony_ci        parsed = JSON.parse(body.toString('utf8'))
641cb0ef41Sopenharmony_ci      } catch {
651cb0ef41Sopenharmony_ci        // ignore errors
661cb0ef41Sopenharmony_ci      }
671cb0ef41Sopenharmony_ci      if (res.status === 401 && res.headers.get('www-authenticate')) {
681cb0ef41Sopenharmony_ci        const auth = res.headers.get('www-authenticate')
691cb0ef41Sopenharmony_ci          .split(/,\s*/)
701cb0ef41Sopenharmony_ci          .map(s => s.toLowerCase())
711cb0ef41Sopenharmony_ci        if (auth.indexOf('ipaddress') !== -1) {
721cb0ef41Sopenharmony_ci          throw new errors.HttpErrorAuthIPAddress(
731cb0ef41Sopenharmony_ci            method, res, parsed, opts.spec
741cb0ef41Sopenharmony_ci          )
751cb0ef41Sopenharmony_ci        } else if (auth.indexOf('otp') !== -1) {
761cb0ef41Sopenharmony_ci          throw new errors.HttpErrorAuthOTP(
771cb0ef41Sopenharmony_ci            method, res, parsed, opts.spec
781cb0ef41Sopenharmony_ci          )
791cb0ef41Sopenharmony_ci        } else {
801cb0ef41Sopenharmony_ci          throw new errors.HttpErrorAuthUnknown(
811cb0ef41Sopenharmony_ci            method, res, parsed, opts.spec
821cb0ef41Sopenharmony_ci          )
831cb0ef41Sopenharmony_ci        }
841cb0ef41Sopenharmony_ci      } else if (
851cb0ef41Sopenharmony_ci        res.status === 401 &&
861cb0ef41Sopenharmony_ci        body != null &&
871cb0ef41Sopenharmony_ci        /one-time pass/.test(body.toString('utf8'))
881cb0ef41Sopenharmony_ci      ) {
891cb0ef41Sopenharmony_ci        // Heuristic for malformed OTP responses that don't include the
901cb0ef41Sopenharmony_ci        // www-authenticate header.
911cb0ef41Sopenharmony_ci        throw new errors.HttpErrorAuthOTP(
921cb0ef41Sopenharmony_ci          method, res, parsed, opts.spec
931cb0ef41Sopenharmony_ci        )
941cb0ef41Sopenharmony_ci      } else {
951cb0ef41Sopenharmony_ci        throw new errors.HttpErrorGeneral(
961cb0ef41Sopenharmony_ci          method, res, parsed, opts.spec
971cb0ef41Sopenharmony_ci        )
981cb0ef41Sopenharmony_ci      }
991cb0ef41Sopenharmony_ci    })
1001cb0ef41Sopenharmony_ci}
101