File Explorer

/var/lang/lib/node_modules/npm/node_modules/npm-registry-fetch/lib

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

auth.js5.2 KB · 182 lines
'use strict'const fs = require('fs')const npa = require('npm-package-arg')const { URL } = require('url') // Find the longest registry key that is used for some kind of auth// in the options.  Returns the registry key and the auth config.const regFromURI = (uri, opts) => {  const parsed = new URL(uri)  // try to find a config key indicating we have auth for this registry  // can be one of :_authToken, :_auth, :_password and :username, or  // :certfile and :keyfile  // We walk up the "path" until we're left with just //<host>[:<port>],  // stopping when we reach '//'.  let regKey = `//${parsed.host}${parsed.pathname}`  while (regKey.length > '//'.length) {    const authKey = hasAuth(regKey, opts)    // got some auth for this URI    if (authKey) {      return { regKey, authKey }    }     // can be either //host/some/path/:_auth or //host/some/path:_auth    // walk up by removing EITHER what's after the slash OR the slash itself    regKey = regKey.replace(/([^/]+|\/)$/, '')  }  return { regKey: false, authKey: null }} // Not only do we want to know if there is auth, but if we are calling `npm// logout` we want to know what config value specifically provided it.  This is// so we can look up where the config came from to delete it (i.e. user vs// project)const hasAuth = (regKey, opts) => {  if (opts[`${regKey}:_authToken`]) {    return '_authToken'  }  if (opts[`${regKey}:_auth`]) {    return '_auth'  }  if (opts[`${regKey}:username`] && opts[`${regKey}:_password`]) {    // 'password' can be inferred to also be present    return 'username'  }  if (opts[`${regKey}:certfile`] && opts[`${regKey}:keyfile`]) {    // 'keyfile' can be inferred to also be present    return 'certfile'  }  return false} const sameHost = (a, b) => {  const parsedA = new URL(a)  const parsedB = new URL(b)  return parsedA.host === parsedB.host} const getRegistry = opts => {  const { spec } = opts  const { scope: specScope, subSpec } = spec ? npa(spec) : {}  const subSpecScope = subSpec && subSpec.scope  const scope = subSpec ? subSpecScope : specScope  const scopeReg = scope && opts[`${scope}:registry`]  return scopeReg || opts.registry} const maybeReadFile = file => {  try {    return fs.readFileSync(file, 'utf8')  } catch (er) {    if (er.code !== 'ENOENT') {      throw er    }    return null  }} const getAuth = (uri, opts = {}) => {  const { forceAuth } = opts  if (!uri) {    throw new Error('URI is required')  }  const { regKey, authKey } = regFromURI(uri, forceAuth || opts)   // we are only allowed to use what's in forceAuth if specified  if (forceAuth && !regKey) {    return new Auth({      // if we force auth we don't want to refer back to anything in config      regKey: false,      authKey: null,      scopeAuthKey: null,      token: forceAuth._authToken || forceAuth.token,      username: forceAuth.username,      password: forceAuth._password || forceAuth.password,      auth: forceAuth._auth || forceAuth.auth,      certfile: forceAuth.certfile,      keyfile: forceAuth.keyfile,    })  }   // no auth for this URI, but might have it for the registry  if (!regKey) {    const registry = getRegistry(opts)    if (registry && uri !== registry && sameHost(uri, registry)) {      return getAuth(registry, opts)    } else if (registry !== opts.registry) {      // If making a tarball request to a different base URI than the      // registry where we logged in, but the same auth SHOULD be sent      // to that artifact host, then we track where it was coming in from,      // and warn the user if we get a 4xx error on it.      const { regKey: scopeAuthKey, authKey: _authKey } = regFromURI(registry, opts)      return new Auth({ scopeAuthKey, regKey: scopeAuthKey, authKey: _authKey })    }  }   const {    [`${regKey}:_authToken`]: token,    [`${regKey}:username`]: username,    [`${regKey}:_password`]: password,    [`${regKey}:_auth`]: auth,    [`${regKey}:certfile`]: certfile,    [`${regKey}:keyfile`]: keyfile,  } = opts   return new Auth({    scopeAuthKey: null,    regKey,    authKey,    token,    auth,    username,    password,    certfile,    keyfile,  })} class Auth {  constructor ({    token,    auth,    username,    password,    scopeAuthKey,    certfile,    keyfile,    regKey,    authKey,  }) {    // same as regKey but only present for scoped auth. Should have been named scopeRegKey    this.scopeAuthKey = scopeAuthKey    // `${regKey}:${authKey}` will get you back to the auth config that gave us auth    this.regKey = regKey    this.authKey = authKey    this.token = null    this.auth = null    this.isBasicAuth = false    this.cert = null    this.key = null    if (token) {      this.token = token    } else if (auth) {      this.auth = auth    } else if (username && password) {      const p = Buffer.from(password, 'base64').toString('utf8')      this.auth = Buffer.from(`${username}:${p}`, 'utf8').toString('base64')      this.isBasicAuth = true    }    // mTLS may be used in conjunction with another auth method above    if (certfile && keyfile) {      const cert = maybeReadFile(certfile, 'utf-8')      const key = maybeReadFile(keyfile, 'utf-8')      if (cert && key) {        this.cert = cert        this.key = key      }    }  }} module.exports = getAuth