Welcome to mirror list, hosted at ThFree Co, Russian Federation.

auth.js « lib « npm-registry-fetch « node_modules - github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 870ce0d923cd0f4e2b7a404cdca36fc63de84750 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
'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.
const regKeyFromURI = (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) {
    // got some auth for this URI
    if (hasAuth(regKey, opts)) {
      return regKey
    }

    // 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(/([^/]+|\/)$/, '')
  }
}

const hasAuth = (regKey, opts) => (
  opts[`${regKey}:_authToken`] ||
  opts[`${regKey}:_auth`] ||
  opts[`${regKey}:username`] && opts[`${regKey}:_password`] ||
  opts[`${regKey}:certfile`] && opts[`${regKey}:keyfile`]
)

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 = regKeyFromURI(uri, forceAuth || opts)

  // we are only allowed to use what's in forceAuth if specified
  if (forceAuth && !regKey) {
    return new Auth({
      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 scopeAuthKey = regKeyFromURI(registry, opts)
      return new Auth({ scopeAuthKey })
    }
  }

  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,
    token,
    auth,
    username,
    password,
    certfile,
    keyfile,
  })
}

class Auth {
  constructor ({ token, auth, username, password, scopeAuthKey, certfile, keyfile }) {
    this.scopeAuthKey = scopeAuthKey
    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