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