File Explorer

/proc/self/root/proc/1/task/1/root/node24/lib/node_modules/npm/node_modules/npm-profile/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 /.

index.js6.7 KB · 279 lines
const { URL } = require('node:url')const timers = require('node:timers/promises')const fetch = require('npm-registry-fetch')const { HttpErrorBase } = require('npm-registry-fetch/lib/errors')const { log } = require('proc-log') // try loginWeb, catch the "not supported" message and fall back to couchconst login = async (opener, prompter, opts = {}) => {  try {    return await loginWeb(opener, opts)  } catch (er) {    if (er instanceof WebLoginNotSupported) {      log.verbose('web login', 'not supported, trying couch')      const { username, password } = await prompter(opts.creds)      return loginCouch(username, password, opts)    }    throw er  }} const adduser = async (opener, prompter, opts = {}) => {  try {    return await adduserWeb(opener, opts)  } catch (er) {    if (er instanceof WebLoginNotSupported) {      log.verbose('web adduser', 'not supported, trying couch')      const { username, email, password } = await prompter(opts.creds)      return adduserCouch(username, email, password, opts)    }    throw er  }} const adduserWeb = (opener, opts = {}) => {  log.verbose('web adduser', 'before first POST')  return webAuth(opener, opts, { create: true })} const loginWeb = (opener, opts = {}) => {  log.verbose('web login', 'before first POST')  return webAuth(opener, opts, {})} const isValidUrl = u => {  try {    return /^https?:$/.test(new URL(u).protocol)  } catch {    return false  }} const webAuth = async (opener, opts, body) => {  try {    const res = await fetch('/-/v1/login', {      ...opts,      method: 'POST',      body,    })     const content = await res.json()    log.verbose('web auth', 'got response', content)     const { doneUrl, loginUrl } = content    if (!isValidUrl(doneUrl) || !isValidUrl(loginUrl)) {      throw new WebLoginInvalidResponse('POST', res, content)    }     return await webAuthOpener(opener, loginUrl, doneUrl, opts)  } catch (er) {    if ((er.statusCode >= 400 && er.statusCode <= 499) || er.statusCode === 500) {      throw new WebLoginNotSupported('POST', {        status: er.statusCode,        headers: er.headers,      }, er.body)    }    throw er  }} const webAuthOpener = async (opener, loginUrl, doneUrl, opts) => {  const abortController = new AbortController()  const { signal } = abortController  try {    log.verbose('web auth', 'opening url pair')    const [, authResult] = await Promise.all([      opener(loginUrl, { signal }).catch((err) => {        if (err.name === 'AbortError') {          abortController.abort()          return        }        throw err      }),      webAuthCheckLogin(doneUrl, { ...opts, cache: false }, { signal }).then((r) => {        log.verbose('web auth', 'done-check finished')        abortController.abort()        return r      }),    ])    return authResult  } catch (er) {    abortController.abort()    throw er  }} const webAuthCheckLogin = async (doneUrl, opts, { signal } = {}) => {  signal?.throwIfAborted()   const res = await fetch(doneUrl, opts)  const content = await res.json()   if (res.status === 200) {    if (!content.token) {      throw new WebLoginInvalidResponse('GET', res, content)    }    return content  }   if (res.status === 202) {    const retry = +res.headers.get('retry-after') * 1000    if (retry > 0) {      await timers.setTimeout(retry, null, { signal })    }    return webAuthCheckLogin(doneUrl, opts, { signal })  }   throw new WebLoginInvalidResponse('GET', res, content)} const couchEndpoint = (username) => `/-/user/org.couchdb.user:${encodeURIComponent(username)}` const putCouch = async (path, username, body, opts) => {  const result = await fetch.json(`${couchEndpoint(username)}${path}`, {    ...opts,    method: 'PUT',    body,  })  result.username = username  return result} const adduserCouch = async (username, email, password, opts = {}) => {  const body = {    _id: `org.couchdb.user:${username}`,    name: username,    password: password,    email: email,    type: 'user',    roles: [],    date: new Date().toISOString(),  }   log.verbose('adduser', 'before first PUT', {    ...body,    password: 'XXXXX',  })   return putCouch('', username, body, opts)} const loginCouch = async (username, password, opts = {}) => {  const body = {    _id: `org.couchdb.user:${username}`,    name: username,    password: password,    type: 'user',    roles: [],    date: new Date().toISOString(),  }   log.verbose('login', 'before first PUT', {    ...body,    password: 'XXXXX',  })   try {    return await putCouch('', username, body, opts)  } catch (err) {    if (err.code === 'E400') {      err.message = `There is no user with the username "${username}".`      throw err    }     if (err.code !== 'E409') {      throw err    }  }   const result = await fetch.json(couchEndpoint(username), {    ...opts,    query: { write: true },  })   for (const k of Object.keys(result)) {    if (!body[k] || k === 'roles') {      body[k] = result[k]    }  }   return putCouch(`/-rev/${body._rev}`, username, body, {    ...opts,    forceAuth: {      username,      password: Buffer.from(password, 'utf8').toString('base64'),      otp: opts.otp,    },  })} const get = (opts = {}) => fetch.json('/-/npm/v1/user', opts) const set = (profile, opts = {}) => fetch.json('/-/npm/v1/user', {  ...opts,  method: 'POST',  // profile keys can't be empty strings, but they CAN be null  body: Object.fromEntries(Object.entries(profile).map(([k, v]) => [k, v === '' ? null : v])),}) const paginate = async (href, opts, items = []) => {  const result = await fetch.json(href, opts)  items = items.concat(result.objects)  if (result.urls.next) {    return paginate(result.urls.next, opts, items)  }  return items} const listTokens = (opts = {}) => paginate('/-/npm/v1/tokens', opts) const removeToken = async (tokenKey, opts = {}) => {  await fetch(`/-/npm/v1/tokens/token/${tokenKey}`, {    ...opts,    method: 'DELETE',    ignoreBody: true,  })  return null} const createToken = (password, readonly, cidrs, opts = {}) => fetch.json('/-/npm/v1/tokens', {  ...opts,  method: 'POST',  body: {    password: password,    readonly: readonly,    cidr_whitelist: cidrs,  },}) class WebLoginInvalidResponse extends HttpErrorBase {  constructor (method, res, body) {    super(method, res, body)    this.message = 'Invalid response from web login endpoint'  }} class WebLoginNotSupported extends HttpErrorBase {  constructor (method, res, body) {    super(method, res, body)    this.message = 'Web login not supported'    this.code = 'ENYI'  }} module.exports = {  adduserCouch,  loginCouch,  adduserWeb,  loginWeb,  login,  adduser,  get,  set,  listTokens,  removeToken,  createToken,  webAuthCheckLogin,  webAuthOpener,}