[6a3a178] | 1 | 'use strict'
|
---|
| 2 |
|
---|
| 3 | const errors = require('./errors.js')
|
---|
| 4 | const { Response } = require('minipass-fetch')
|
---|
| 5 | const defaultOpts = require('./default-opts.js')
|
---|
| 6 |
|
---|
| 7 | const checkResponse =
|
---|
| 8 | async ({ method, uri, res, registry, startTime, auth, opts }) => {
|
---|
| 9 | opts = { ...defaultOpts, ...opts }
|
---|
| 10 | if (res.headers.has('npm-notice') && !res.headers.has('x-local-cache'))
|
---|
| 11 | opts.log.notice('', res.headers.get('npm-notice'))
|
---|
| 12 |
|
---|
| 13 | if (res.status >= 400) {
|
---|
| 14 | logRequest(method, res, startTime, opts)
|
---|
| 15 | if (auth && auth.scopeAuthKey && !auth.token && !auth.auth) {
|
---|
| 16 | // we didn't have auth for THIS request, but we do have auth for
|
---|
| 17 | // requests to the registry indicated by the spec's scope value.
|
---|
| 18 | // Warn the user.
|
---|
| 19 | opts.log.warn('registry', `No auth for URI, but auth present for scoped registry.
|
---|
| 20 |
|
---|
| 21 | URI: ${uri}
|
---|
| 22 | Scoped Registry Key: ${auth.scopeAuthKey}
|
---|
| 23 |
|
---|
| 24 | More info here: https://github.com/npm/cli/wiki/No-auth-for-URI,-but-auth-present-for-scoped-registry`)
|
---|
| 25 | }
|
---|
| 26 | return checkErrors(method, res, startTime, opts)
|
---|
| 27 | } else {
|
---|
| 28 | res.body.on('end', () => logRequest(method, res, startTime, opts))
|
---|
| 29 | if (opts.ignoreBody) {
|
---|
| 30 | res.body.resume()
|
---|
| 31 | return new Response(null, res)
|
---|
| 32 | }
|
---|
| 33 | return res
|
---|
| 34 | }
|
---|
| 35 | }
|
---|
| 36 | module.exports = checkResponse
|
---|
| 37 |
|
---|
| 38 | function logRequest (method, res, startTime, opts) {
|
---|
| 39 | const elapsedTime = Date.now() - startTime
|
---|
| 40 | const attempt = res.headers.get('x-fetch-attempts')
|
---|
| 41 | const attemptStr = attempt && attempt > 1 ? ` attempt #${attempt}` : ''
|
---|
| 42 | const cacheStatus = res.headers.get('x-local-cache-status')
|
---|
| 43 | const cacheStr = cacheStatus ? ` (cache ${cacheStatus})` : ''
|
---|
| 44 |
|
---|
| 45 | let urlStr
|
---|
| 46 | try {
|
---|
| 47 | const { URL } = require('url')
|
---|
| 48 | const url = new URL(res.url)
|
---|
| 49 | if (url.password)
|
---|
| 50 | url.password = '***'
|
---|
| 51 |
|
---|
| 52 | urlStr = url.toString()
|
---|
| 53 | } catch (er) {
|
---|
| 54 | urlStr = res.url
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | opts.log.http(
|
---|
| 58 | 'fetch',
|
---|
| 59 | `${method.toUpperCase()} ${res.status} ${urlStr} ${elapsedTime}ms${attemptStr}${cacheStr}`
|
---|
| 60 | )
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | function checkErrors (method, res, startTime, opts) {
|
---|
| 64 | return res.buffer()
|
---|
| 65 | .catch(() => null)
|
---|
| 66 | .then(body => {
|
---|
| 67 | let parsed = body
|
---|
| 68 | try {
|
---|
| 69 | parsed = JSON.parse(body.toString('utf8'))
|
---|
| 70 | } catch (e) {}
|
---|
| 71 | if (res.status === 401 && res.headers.get('www-authenticate')) {
|
---|
| 72 | const auth = res.headers.get('www-authenticate')
|
---|
| 73 | .split(/,\s*/)
|
---|
| 74 | .map(s => s.toLowerCase())
|
---|
| 75 | if (auth.indexOf('ipaddress') !== -1) {
|
---|
| 76 | throw new errors.HttpErrorAuthIPAddress(
|
---|
| 77 | method, res, parsed, opts.spec
|
---|
| 78 | )
|
---|
| 79 | } else if (auth.indexOf('otp') !== -1) {
|
---|
| 80 | throw new errors.HttpErrorAuthOTP(
|
---|
| 81 | method, res, parsed, opts.spec
|
---|
| 82 | )
|
---|
| 83 | } else {
|
---|
| 84 | throw new errors.HttpErrorAuthUnknown(
|
---|
| 85 | method, res, parsed, opts.spec
|
---|
| 86 | )
|
---|
| 87 | }
|
---|
| 88 | } else if (res.status === 401 && body != null && /one-time pass/.test(body.toString('utf8'))) {
|
---|
| 89 | // Heuristic for malformed OTP responses that don't include the
|
---|
| 90 | // www-authenticate header.
|
---|
| 91 | throw new errors.HttpErrorAuthOTP(
|
---|
| 92 | method, res, parsed, opts.spec
|
---|
| 93 | )
|
---|
| 94 | } else {
|
---|
| 95 | throw new errors.HttpErrorGeneral(
|
---|
| 96 | method, res, parsed, opts.spec
|
---|
| 97 | )
|
---|
| 98 | }
|
---|
| 99 | })
|
---|
| 100 | }
|
---|