在`npm login`上设置npm凭证而不从stdin读取输入

问题描述 投票:30回答:8

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

npm login << EOF
username
password
email
EOF

它在Bash终端中工作,但不在没有stdin打开的容器中工作,并显示以下错误消息:

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

npm-adduser说:

用户名,密码和电子邮件将从提示中读入。

那么如何在没有stdin打开的情况下运行npm login

node.js bash npm docker
8个回答
30
投票

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

在幕后,npm adduser向注册表发出HTTP请求。您可以直接向注册表发出请求,而无需通过cli,然后使用adduser设置身份验证令牌,而不是强制npm set按您希望的方式运行。

The source code suggests你可以用以下有效载荷向http://your_registry/-/user/org.couchdb.user:your-username发出PUT请求

{
  name: username,
  password: password
}

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

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


9
投票

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

apt-get install expect-dev

你的脚本看起来像这样(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
}

然后像这样调用它:

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

7
投票

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

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

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

这是我的整个发布配置

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!'

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


3
投票

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

为了安装运行

npm install -g npm-cli-login

示例用法: -

npm-cli-login -u用户名-p密码-e [email protected] -r https://your-private-registry-link


2
投票

难以置信,毕竟这段时间仍然没有针对npm登录的解决方案。当然,您可以获取一次令牌并将其用于满足您的所有CI需求,但是永不过期的令牌的安全含义又如何呢?如果有一天管理员决定令牌应该到期怎么办?

下面是我使用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}`);
});

输入示例:

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

2
投票

这是建立在亚历山大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}`);
});

2
投票

一种解决方案是获取令牌并更新〜/ .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

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


0
投票

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


-1
投票

对于ke_wa在这个duplicated post暴露的解决方案2已经奏效。

混搭:

export NPM_USERNAME=mUs34
export NPM_PASSWORD=mypassW0rD
export [email protected]
npm adduser<<!
$NPM_USERNAME
$NPM_PASSWORD
$NPM_EMAIL
!
© www.soinside.com 2019 - 2024. All rights reserved.