123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- 'use strict'
- const errors = require('./errors.js')
- const { Response } = require('minipass-fetch')
- const defaultOpts = require('./default-opts.js')
- const checkResponse =
- async ({ method, uri, res, registry, startTime, auth, opts }) => {
- opts = { ...defaultOpts, ...opts }
- if (res.headers.has('npm-notice') && !res.headers.has('x-local-cache'))
- opts.log.notice('', res.headers.get('npm-notice'))
- if (res.status >= 400) {
- logRequest(method, res, startTime, opts)
- if (auth && auth.scopeAuthKey && !auth.token && !auth.auth) {
- // we didn't have auth for THIS request, but we do have auth for
- // requests to the registry indicated by the spec's scope value.
- // Warn the user.
- opts.log.warn('registry', `No auth for URI, but auth present for scoped registry.
- URI: ${uri}
- Scoped Registry Key: ${auth.scopeAuthKey}
- More info here: https://github.com/npm/cli/wiki/No-auth-for-URI,-but-auth-present-for-scoped-registry`)
- }
- return checkErrors(method, res, startTime, opts)
- } else {
- res.body.on('end', () => logRequest(method, res, startTime, opts))
- if (opts.ignoreBody) {
- res.body.resume()
- return new Response(null, res)
- }
- return res
- }
- }
- module.exports = checkResponse
- function logRequest (method, res, startTime, opts) {
- const elapsedTime = Date.now() - startTime
- const attempt = res.headers.get('x-fetch-attempts')
- const attemptStr = attempt && attempt > 1 ? ` attempt #${attempt}` : ''
- const cacheStatus = res.headers.get('x-local-cache-status')
- const cacheStr = cacheStatus ? ` (cache ${cacheStatus})` : ''
- let urlStr
- try {
- const { URL } = require('url')
- const url = new URL(res.url)
- if (url.password)
- url.password = '***'
- urlStr = url.toString()
- } catch (er) {
- urlStr = res.url
- }
- opts.log.http(
- 'fetch',
- `${method.toUpperCase()} ${res.status} ${urlStr} ${elapsedTime}ms${attemptStr}${cacheStr}`
- )
- }
- function checkErrors (method, res, startTime, opts) {
- return res.buffer()
- .catch(() => null)
- .then(body => {
- let parsed = body
- try {
- parsed = JSON.parse(body.toString('utf8'))
- } catch (e) {}
- if (res.status === 401 && res.headers.get('www-authenticate')) {
- const auth = res.headers.get('www-authenticate')
- .split(/,\s*/)
- .map(s => s.toLowerCase())
- if (auth.indexOf('ipaddress') !== -1) {
- throw new errors.HttpErrorAuthIPAddress(
- method, res, parsed, opts.spec
- )
- } else if (auth.indexOf('otp') !== -1) {
- throw new errors.HttpErrorAuthOTP(
- method, res, parsed, opts.spec
- )
- } else {
- throw new errors.HttpErrorAuthUnknown(
- method, res, parsed, opts.spec
- )
- }
- } else if (res.status === 401 && body != null && /one-time pass/.test(body.toString('utf8'))) {
- // Heuristic for malformed OTP responses that don't include the
- // www-authenticate header.
- throw new errors.HttpErrorAuthOTP(
- method, res, parsed, opts.spec
- )
- } else {
- throw new errors.HttpErrorGeneral(
- method, res, parsed, opts.spec
- )
- }
- })
- }
|