node.js 通过 `npm login` 设置 npm 凭据,而无需从 stdin 交互式读取输入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23460980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:16:23  来源:igfitidea点击:

Set up npm credentials over `npm login` without reading input from interactively from stdin

node.jsbashnpmdocker

提问by shawmzhu

I'm trying to automate npm publishinside a Docker container but I have trouble when the npm logincommand tries to read the username and email from prompts:

我正在尝试npm publish在 Docker 容器内进行自动化,但是当npm login命令尝试从提示中读取用户名和电子邮件时遇到了问题:

npm login << EOF
username
password
email
EOF

It works in a Bash terminal but not in a container without stdin open, and shows the following error message:

它适用于 Bash 终端,但不适用于没有打开 stdin 的容器,并显示以下错误消息:

Username: Password: npm ERR! cb() never called!
npm ERR! not ok code 0

According to npm-adduser:

根据npm-adduser

The username, password, and email are read in from prompts.

从提示中读取用户名、密码和电子邮件。

So how can I run npm loginwithout stdin open?

那么如何在npm login没有打开标准输入的情况下运行呢?

回答by danielepolencic

TL;DR:Make an HTTP request directly to the registry:

TL;DR:直接向注册中心发出 HTTP 请求:

TOKEN=$(curl -s \
  -H "Accept: application/json" \
  -H "Content-Type:application/json" \
  -X PUT --data '{"name": "username_here", "password": "password_here"}' \
  http://your_registry/-/user/org.couchdb.user:username_here 2>&1 | grep -Po \
  '(?<="token": ")[^"]*')

npm set registry "http://your_registry"
npm set //your_registry/:_authToken $TOKEN

Rationale

基本原理

Behind the scenes npm addusermakes an HTTP request to the registry. Instead of forcing adduserto behave the way you want, you could make the request directly to the registry without going through the cli and then set the auth token with npm set.

在幕后npm adduser向注册中心发出 HTTP 请求。adduser您可以不通过 cli 直接向注册表发出请求,而不是强制按照您想要的方式行事,然后使用npm set.

The source code suggeststhat you could make a PUT request to http://your_registry/-/user/org.couchdb.user:your-usernamewith the following payload

源代码建议您可以http://your_registry/-/user/org.couchdb.user:your-username使用以下有效负载发出 PUT 请求

{
  name: username,
  password: password
}

and that would create a new user in the registry.

这将在注册表中创建一个新用户。

Many thanks to @shawnzhu for having found a more cleaner approach to solve the problem.

非常感谢@shawnzhu 找到了更简洁的方法来解决问题。

回答by Ted Elliott

An expect script worked for me. You need to make sure expect is installed, this command should do it for ubuntu:

一个期望脚本对我有用。你需要确保安装了expect,这个命令应该为ubuntu做:

apt-get install expect-dev

Your script could look something like this (npm_login_expect):

您的脚本可能如下所示 (npm_login_expect):

#!/usr/bin/expect -f

# set our args into variables
set i 0; foreach n $argv {set "p[incr i]" $n}

set timeout 60
#npm login command, add whatever command-line args are necessary
spawn npm login
match_max 100000

expect "Username"    
send "$p1\r"

expect "Password"
send "$p2\r" 

expect "Email"
send "$p3\r"

expect {
   timeout      exit 1
   eof
}

And then call it like this:

然后像这样调用它:

expect -f npm_login_expect myuser mypassword "[email protected]"

回答by Arun Dhiman

npm-cli-loginallows you to log in to NPM without STDIN.

npm-cli-login允许您在没有 STDIN 的情况下登录 NPM。

In order to install run:

为了安装运行:

npm install -g npm-cli-login

npm install -g npm-cli-login

Example usage:

用法示例:

npm-cli-login -u Username -p Password -e [email protected] -r https://your-private-registry-link

回答by Bryson Reynolds

I took a slightly different approach that seems to work great still. To begin with, you will need an auth token. This is easily obtainable by locally running npm adduserand then grabbing the generated token from your ~/.npmrclocated in your user folder. In order to be authenticated on your ci server this auth token needs to be appended to the registry URL in the user's .npmrc(similar to how it was locally), not the .npmrclocated in the repo, so these worked great as script steps in my CI configuration

我采取了一种略有不同的方法,但似乎仍然有效。首先,您需要一个身份验证令牌。这可以通过本地运行轻松获得npm adduser,然后从您~/.npmrc位于用户文件夹中的生成令牌中获取。为了在您的 ci 服务器上进行身份验证,此身份验证令牌需要附加到用户的注册表 URL .npmrc(类似于它在本地的方式),而不是.npmrc位于 repo 中,因此这些在我的 CI 配置中作为脚本步骤非常有效

- echo "//<npm-registry>:8080/:_authToken=$AUTH_TOKEN" > ~/.npmrc
- npm publish

where AUTH_TOKEN is stored as a secret variable in your settings. A good way to test this is to replace npm publishwith npm whoamito test and make sure it successfully logged you in.

其中 AUTH_TOKEN 在您的设置中存储为秘密变量。一个很好的方法来测试,这是替换npm publishnpm whoami测试,并确保它成功登录你进来。

Here is my entire publish configuration

这是我的整个发布配置

publish:
  stage: deploy
  only:
    - tags
  script:
    - yarn run build
    - echo "//<npm-registry>:8080/:_authToken=$NPME_AUTH_TOKEN" > ~/.npmrc
    - npm publish
    - echo 'Congrats on your publication!'

I'm using gitlab-ci but I don't see why this wouldn't apply to any ci application.

我正在使用 gitlab-ci 但我不明白为什么这不适用于任何 ci 应用程序。

回答by ?eljko ?evi?

npm set //<registry>/:_authToken $TOKEN

Example for Github Package Registry:

Github 包注册表示例:

npm set //npm.pkg.github.com/:_authToken $GITHUB_TOKEN

This is the simplest solution that I have found.

这是我找到的最简单的解决方案。

回答by dres

One solution is to fetch the token and update the ~/.npmrc

一种解决方案是获取令牌并更新 ~/.npmrc

export ARTIFACTORY_TOKEN=`curl --silent --show-error --fail -u $ARTIFACTORY_USERNAME:$ARTIFACTORY_API_KEY https://artifactory.my.io/artifactory/api/npm/auth | \
grep -oP '_auth[\s?]=[\s?]\K(.*)$'`

echo "@my:registry=https://artifactory.my.io/artifactory/api/npm/npm-release-local/" > ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:_auth=${ARTIFACTORY_TOKEN}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:email=${ARTIFACTORY_USERNAME}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:always-auth=true" >> ~/.npmrc

This prevents issues with @scope package retrieval from npmjs

这可以防止从 npmjs 检索 @scope 包的问题

回答by Chris Troutner

This builds on top of Alexander F's answer. This is just a simplified version of the code he provided, mashed up with the example code provided by npm-registry-client.

这建立在 Alexander F 的回答之上。这只是他提供的代码的简化版本,与npm-registry-client提供的示例代码混合在一起。

"use strict";

var RegClient = require('npm-registry-client')
var client = new RegClient()
var uri = "https://registry.npmjs.org/npm"
var params = {timeout: 1000}

var username = 'my.npm.username'
var password = 'myPassword'
var email = '[email protected]'

var params = {
  auth: {
    username,
    password,
    email
  }
};

client.adduser(uri, params, function (error, data, raw, res) {
  if(error) {
    console.error(error);
    return;
  }
  console.log(`Login succeeded`);
  console.log(`data: ${JSON.stringify(data,null,2)}`);
  console.log(`NPM access token: ${data.token}`);
});

回答by Alexander F.

Hard to believe that after all this time there is still no solution for npm login. Sure you can grab a token once and use it for all your CI needs, but what about the security implications of a never expiring token? And what if one day admins decide that tokens should expire?

很难相信,经过这么长时间,仍然没有 npm login 的解决方案。当然,您可以一次性获取令牌并将其用于所有 CI 需求,但是永不过期的令牌的安全隐患呢?如果有一天管理员决定令牌应该过期怎么办?

Below is my hacky javascript solution using npm-registry-clientpackage. Just pass a json string argument and it will login and write an .npmrcfile into your current dir. To log out use npm logoutas usual.

下面是我使用npm-registry-client包的hacky javascript 解决方案。只需传递一个 json 字符串参数,它就会登录并将.npmrc文件写入您当前的目录。npm logout像往常一样注销使用。

var client = new (require('npm-registry-client'))({});
var std_in = JSON.parse(process.argv[2]);

if (std_in.uri === undefined) {
    console.error('Must input registry uri!');
    return;
}

// fix annoying trailing '/' thing in registry uri
if (std_in.uri[std_in.uri.length - 1] !== '/') {
    std_in.uri = std_in.uri + '/';
}

if (std_in.scope === undefined) {
    console.error('Must input scope!');
    return;
    //std_in.scope = '@my-scope'; // or add default scope of your own
}

if (std_in.scope[0] !== '@') {
    std_in.scope = '@' + std_in.scope;
}

client.adduser(std_in.uri, std_in.params, function(err, data, raw, res) {
    if (err) {
        console.error(err);
        return;
    } 
    require('fs').writeFileSync('.npmrc', `${std_in.scope}:registry=${std_in.uri}\n//${(std_in.uri.split('//'))[1]}:_authToken=${data.token}`);
});

Example input:

示例输入:

{ 
    "uri": "https://my-nmp.reg",
    "scope": "@my-scope",
    "params": {
        "auth": {
            "username": "secret-agent",
            "password": "12345",
            "email": "[email protected]"
        }
    }
}

回答by mscdex

You could use an expect script instead or write a node script that uses pty.js.

您可以改用 expect 脚本或编写使用pty.js的节点脚本。

回答by JRichardsz

This worked in one of my devops flows

这在我的 DevOps 流程之一中起作用

steps

脚步

  1. Generate _authfrom npm registry credentials with base 64 using shell for security:
  1. 使用 shell 从 npm 注册表凭据生成_auth,base 64 以确保安全:
    echo -n 'myuser:mypassword' | openssl base64
    Result will be something like : eWFob29vb2E=
  1. Set npm registry url and _auth before npm install ...
  1. npm install之前设置 npm registry url 和 _auth ...
    npm config set registry https://nexus-acme.com/repository/npm-group/
    npm config set _auth eWFob29vb2E=

That's all. You could run npm install, and your private modules will be downloaded.

就这样。您可以运行npm install,您的私有模块将被下载。