patches pushed to nodejs-npm-registry-client (el6). "Merge branch 'master' into el6"

notifications at fedoraproject.org notifications at fedoraproject.org
Sat May 16 21:24:17 UTC 2015


From 857c90e16f7f9b9089a5266625a130d67cd99c74 Mon Sep 17 00:00:00 2001
From: Dennis Gilmore <dennis at ausil.us>
Date: Sat, 7 Jun 2014 09:11:03 -0500
Subject: - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild


diff --git a/nodejs-npm-registry-client.spec b/nodejs-npm-registry-client.spec
index 6d3ba92..4c6230b 100644
--- a/nodejs-npm-registry-client.spec
+++ b/nodejs-npm-registry-client.spec
@@ -2,7 +2,7 @@
 
 Name:           nodejs-npm-registry-client
 Version:        0.2.28
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Client for the npm registry
 
 Group:          System Environment/Libraries
@@ -45,6 +45,9 @@ rm -rf %buildroot
 %doc README.md LICENSE
 
 %changelog
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.2.28-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
 * Fri Sep 06 2013 Jamie Nguyen <jamielinux at fedoraproject.org> - 0.2.28-1
 - update to upstream release 0.2.28
 - add ExclusiveArch logic
-- 
cgit v0.10.2


From 7f827500bbdd347ce9dbab6ea30f42b4d07e7c62 Mon Sep 17 00:00:00 2001
From: "T.C. Hollingsworth" <tchollingsworth at gmail.com>
Date: Sat, 16 May 2015 14:23:01 -0700
Subject: backport fixes to publish and adduser functions (RHBZ#1220472)


diff --git a/nodejs-npm-registry-client-publish-fixes.patch b/nodejs-npm-registry-client-publish-fixes.patch
new file mode 100644
index 0000000..9c21f92
--- /dev/null
+++ b/nodejs-npm-registry-client-publish-fixes.patch
@@ -0,0 +1,989 @@
+diff --git a/README.md b/README.md
+index 534c407..4b3d4c3 100644
+--- a/README.md
++++ b/README.md
+@@ -34,6 +34,9 @@ also be accepted.
+ * `tag` {String} The default tag to use when publishing new packages.
+   Default = `"latest"`
+ * `ca` {String} Cerficate signing authority certificates to trust.
++* `cert` {String} Client certificate (PEM encoded). Enable access
++  to servers that require client certificates
++* `key` {String} Private key (PEM encoded) for client certificate 'cert'
+ * `strict-ssl` {Boolean} Whether or not to be strict with SSL
+   certificates.  Default = `true`
+ * `user-agent` {String} User agent header to send.  Default =
+@@ -82,6 +85,22 @@ around this. one.
+ 
+ Add a user account to the registry, or verify the credentials.
+ 
++# client.deprecate(name, version, message, cb)
++
++* `name` {String} The package name
++* `version` {String} Semver version range
++* `message` {String} The message to use as a deprecation warning
++* `cb` {Function}
++
++Deprecate a version of a package in the registry.
++
++# client.bugs(name, cb)
++
++* `name` {String} the name of the package
++* `cb` {Function}
++
++Get the url for bugs of a package
++
+ # client.get(url, [timeout], [nofollow], [staleOk], cb)
+ 
+ * `url` {String} The url path to fetch
+@@ -94,11 +113,10 @@ Add a user account to the registry, or verify the credentials.
+ Fetches data from the registry via a GET request, saving it in
+ the cache folder with the ETag.
+ 
+-# client.publish(data, tarball, [readme], cb)
++# client.publish(data, tarball, cb)
+ 
+ * `data` {Object} Package data
+ * `tarball` {String | Stream} Filename or stream of the package tarball
+-* `readme` {String} Contents of the README markdown file
+ * `cb` {Function}
+ 
+ Publish a package to the registry.
+diff --git a/index.js b/index.js
+index c2d50b6..24c33ae 100644
+--- a/index.js
++++ b/index.js
+@@ -1,4 +1,3 @@
+-
+ // utilities for working with the js-registry site.
+ 
+ module.exports = RegClient
+@@ -6,7 +5,6 @@ module.exports = RegClient
+ var fs = require('fs')
+ , url = require('url')
+ , path = require('path')
+-, CouchLogin = require('couch-login')
+ , npmlog
+ 
+ try {
+@@ -48,20 +46,6 @@ function RegClient (conf) {
+   }
+ 
+   if (!conf.get('cache')) throw new Error("Cache dir is required")
+-
+-  var auth = this.conf.get('_auth')
+-  var alwaysAuth = this.conf.get('always-auth')
+-  if (auth && !alwaysAuth && registry) {
+-    // if we're always authing, then we just send the
+-    // user/pass on every thing.  otherwise, create a
+-    // session, and use that.
+-    var token = this.conf.get('_token')
+-    this.couchLogin = new CouchLogin(registry, token)
+-    this.couchLogin.proxy = this.conf.get('proxy')
+-    this.couchLogin.strictSSL = this.conf.get('strict-ssl')
+-    this.couchLogin.ca = this.conf.get('ca')
+-  }
+-
+   this.log = conf.log || conf.get('log') || npmlog
+ }
+ 
+diff --git a/lib/adduser.js b/lib/adduser.js
+index 7106e44..5a76b02 100644
+--- a/lib/adduser.js
++++ b/lib/adduser.js
+@@ -1,11 +1,5 @@
+ module.exports = adduser
+ 
+-var crypto = require('crypto')
+-
+-function sha (s) {
+-  return crypto.createHash("sha1").update(s).digest("hex")
+-}
+-
+ function adduser (username, password, email, cb) {
+ 
+   password = ("" + (password || "")).trim()
+@@ -17,15 +11,9 @@ function adduser (username, password, email, cb) {
+     return cb(new Error("Please use a real email address."))
+   }
+ 
+-  if (password.indexOf(":") !== -1) return cb(new Error(
+-    "Sorry, ':' chars are not allowed in passwords.\n"+
+-    "See <https://issues.apache.org/jira/browse/COUCHDB-969> for why."))
+-
+-  var salt = crypto.randomBytes(30).toString('hex')
+-    , userobj =
++  var userobj =
+       { name : username
+-      , salt : salt
+-      , password_sha : sha(password + salt)
++      , password : password
+       , email : email
+       , _id : 'org.couchdb.user:'+username
+       , type : "user"
+@@ -51,7 +39,7 @@ function adduser (username, password, email, cb) {
+   cb = done.call(this, cb, pre)
+ 
+   var logObj = Object.keys(userobj).map(function (k) {
+-    if (k === 'salt' || k === 'password_sha') return [k, 'XXXXX']
++    if (k === 'password') return [k, 'XXXXX']
+     return [k, userobj[k]]
+   }).reduce(function (s, kv) {
+     s[kv[0]] = kv[1]
+@@ -81,13 +69,14 @@ function adduser (username, password, email, cb) {
+ 
+         this.log.verbose("adduser", "update existing user")
+         return this.request('GET'
+-          , '/-/user/org.couchdb.user:'+encodeURIComponent(username)
++          , '/-/user/org.couchdb.user:'+encodeURIComponent(username) +
++            '?write=true'
+           , function (er, data, json, response) {
+               if (er || data.error) {
+                 return cb(er, data, json, response)
+               }
+               Object.keys(data).forEach(function (k) {
+-                if (!userobj[k]) {
++                if (!userobj[k] || k === 'roles') {
+                   userobj[k] = data[k]
+                 }
+               })
+@@ -129,7 +118,7 @@ function done (cb, pre) {
+       this.log.warn("adduser", "Incorrect username or password\n"
+               +"You can reset your account by visiting:\n"
+               +"\n"
+-              +"    http://admin.npmjs.org/reset\n")
++              +"    https://npmjs.org/forgot\n")
+     }
+ 
+     return cb(error)
+diff --git a/lib/bugs.js b/lib/bugs.js
+new file mode 100644
+index 0000000..a047013
+--- /dev/null
++++ b/lib/bugs.js
+@@ -0,0 +1,9 @@
++
++module.exports = bugs
++
++function bugs (name, cb) {
++  this.get(name + "/latest", 3600, function (er, d) {
++    if (er) return cb(er)
++    cb(null, d.bugs)
++  })
++}
+diff --git a/lib/deprecate.js b/lib/deprecate.js
+new file mode 100644
+index 0000000..9cbc6d8
+--- /dev/null
++++ b/lib/deprecate.js
+@@ -0,0 +1,26 @@
++
++module.exports = deprecate
++
++var semver = require("semver")
++
++function deprecate (name, ver, message, cb) {
++  if (!this.conf.get('username')) {
++    return cb(new Error("Must be logged in to deprecate a package"))
++  }
++
++  if (semver.validRange(ver) === null) {
++    return cb(new Error("invalid version range: "+ver))
++  }
++
++  this.get(name + '?write=true', function (er, data) {
++    if (er) return cb(er)
++    // filter all the versions that match
++    Object.keys(data.versions).filter(function (v) {
++      return semver.satisfies(v, ver)
++    }).forEach(function (v) {
++      data.versions[v].deprecated = message
++    })
++    // now update the doc on the registry
++    this.request('PUT', data._id, data, cb)
++  }.bind(this))
++}
+diff --git a/lib/get.js b/lib/get.js
+index eeb716e..7722e91 100644
+--- a/lib/get.js
++++ b/lib/get.js
+@@ -10,7 +10,6 @@ function get (uri, timeout, nofollow, staleOk, cb) {
+   if (typeof cb !== "function") cb = staleOk, staleOk = false
+   if (typeof cb !== "function") cb = nofollow, nofollow = false
+   if (typeof cb !== "function") cb = timeout, timeout = -1
+-  if (typeof cb !== "function") cb = version, version = null
+ 
+   timeout = Math.min(timeout, this.conf.get('cache-max') || 0)
+   timeout = Math.max(timeout, this.conf.get('cache-min') || -Infinity)
+@@ -31,9 +30,15 @@ function get (uri, timeout, nofollow, staleOk, cb) {
+ 
+   var cacheUri = uri
+   // on windows ":" is not an allowed character in a foldername
+-  cacheUri = cacheUri.replace(/:/g, '_')
++  cacheUri = cacheUri.replace(/:/g, '_').replace(/\?write=true$/, '')
+   var cache = path.join(this.conf.get('cache'), cacheUri, ".cache.json")
+ 
++  // If the GET is part of a write operation (PUT or DELETE), then
++  // skip past the cache entirely, but still save the results.
++  if (uri.match(/\?write=true$/))
++    return get_.call(this, uri, timeout, cache, null, null, nofollow, staleOk, cb)
++
++
+   fs.stat(cache, function (er, stat) {
+     if (!er) fs.readFile(cache, function (er, data) {
+       try { data = JSON.parse(data) }
+@@ -48,6 +53,7 @@ function requestAll (cb) {
+   var cache = path.join(this.conf.get('cache'), "/-/all", ".cache.json")
+ 
+   mkdir(path.join(this.conf.get('cache'), "-", "all"), function (er) {
++    if (er) return cb(er)
+     fs.readFile(cache, function (er, data) {
+       if (er) return requestAll_.call(this, 0, {}, cb)
+       try {
+diff --git a/lib/publish.js b/lib/publish.js
+index d6a7496..2a50380 100644
+--- a/lib/publish.js
++++ b/lib/publish.js
+@@ -1,11 +1,12 @@
+ 
+ module.exports = publish
+ 
+-var path = require("path")
+-  , url = require("url")
++var url = require("url")
++  , semver = require("semver")
++  , crypto = require("crypto")
++  , fs = require("fs")
+ 
+ function publish (data, tarball, cb) {
+-
+   var email = this.conf.get('email')
+   var auth = this.conf.get('_auth')
+   var username = this.conf.get('username')
+@@ -16,14 +17,30 @@ function publish (data, tarball, cb) {
+     return cb(er)
+   }
+ 
+-  // add the dist-url to the data, pointing at the tarball.
+-  // if the {name} isn't there, then create it.
+-  // if the {version} is already there, then fail.
+-  // then:
+-  // PUT the data to {config.registry}/{data.name}/{data.version}
+-  var registry = this.conf.get('registry')
++  if (data.name !== encodeURIComponent(data.name))
++    return cb(new Error('invalid name: must be url-safe'))
++
++  var ver = semver.clean(data.version)
++  if (!ver)
++    return cb(new Error('invalid semver: ' + data.version))
++  data.version = ver
++
++  var self = this
++  fs.stat(tarball, function(er, s) {
++    if (er) return cb(er)
++    fs.readFile(tarball, function(er, tarbuffer) {
++      if (er) return cb(er)
++      putFirst.call(self, data, tarbuffer, s, username, email, cb)
++    })
++  })
++}
+ 
+-  var fullData =
++function putFirst (data, tarbuffer, stat, username, email, cb) {
++  // optimistically try to PUT all in one single atomic thing.
++  // If 409, then GET and merge, try again.
++  // If other error, then fail.
++
++  var root =
+     { _id : data.name
+     , name : data.name
+     , description : data.description
+@@ -37,76 +54,102 @@ function publish (data, tarball, cb) {
+       ]
+     }
+ 
++  root.versions[ data.version ] = data
++  data.maintainers = JSON.parse(JSON.stringify(root.maintainers))
++  var tag = data.tag || this.conf.get('tag') || "latest"
++  root["dist-tags"][tag] = data.version
++
++  var registry = this.conf.get('registry')
+   var tbName = data.name + "-" + data.version + ".tgz"
+     , tbURI = data.name + "/-/" + tbName
+ 
+   data._id = data.name+"@"+data.version
+   data.dist = data.dist || {}
++  data.dist.shasum = crypto.createHash("sha1").update(tarbuffer).digest("hex")
+   data.dist.tarball = url.resolve(registry, tbURI)
+                          .replace(/^https:\/\//, "http://")
+ 
+-
+-  // first try to just PUT the whole fullData, and this will fail if it's
+-  // already there, because it'll be lacking a _rev, so couch'll bounce it.
+-  this.request("PUT", encodeURIComponent(data.name), fullData,
+-      function (er, parsed, json, response) {
+-    // get the rev and then upload the attachment
+-    // a 409 is expected here, if this is a new version of an existing package.
+-    if (er
+-        && !(response && response.statusCode === 409)
+-        && !( parsed
+-            && parsed.reason ===
+-              "must supply latest _rev to update existing package" )) {
+-      this.log.error("publish", "Failed PUT response "
+-                    +(response && response.statusCode))
++  root._attachments = {}
++  root._attachments[ tbName ] = {
++    content_type: 'application/octet-stream',
++    data: tarbuffer.toString('base64'),
++    length: stat.size
++  };
++
++  this.request("PUT", data.name, root, function (er, parsed, json, res) {
++    var r409 = "must supply latest _rev to update existing package"
++    var r409b = "Document update conflict."
++    var conflict = res && res.statusCode === 409
++    if (parsed && (parsed.reason === r409 || parsed.reason === r409b))
++      conflict = true
++
++    // a 409 is typical here.  GET the data and merge in.
++    if (er && !conflict) {
++      this.log.error("publish", "Failed PUT "
++                    +(res && res.statusCode))
+       return cb(er)
+     }
+-    var dataURI = encodeURIComponent(data.name)
+-                + "/" + encodeURIComponent(data.version)
+ 
+-    var tag = data.tag || this.conf.get('tag') || "latest"
+-    dataURI += "/-tag/" + tag
++    if (!er && !conflict)
++      return cb(er, parsed, json, res)
+ 
+     // let's see what versions are already published.
+-    // could be that we just need to update the bin dist values.
+-    this.request("GET", data.name, function (er, fullData) {
+-      if (er) return cb(er)
+-
+-      function handle(er) {
+-        if (er.message.indexOf("conflict Document update conflict.") === 0) {
+-          return cb(conflictError.call(this, data._id));
+-        }
+-        this.log.error("publish", "Error uploading package");
++    var getUrl = data.name + "?write=true"
++    this.request("GET", getUrl, function (er, current) {
++      if (er)
+         return cb(er)
+-      }
+-
+-      var exists = fullData.versions && fullData.versions[data.version]
+-      if (exists) return cb(conflictError.call(this, data._id))
+-
+-      var rev = fullData._rev;
+-      attach.call(this, data.name, tarball, tbName, rev, function (er) {
+-        if (er) return handle.call(this, er)
+-        this.log.verbose("publish", "attached", [data.name, tarball, tbName])
+-        this.request("PUT", dataURI, data, function (er) {
+-          if (er) return handle.call(this, er)
+-          return cb(er)
+-        }.bind(this))
+-      }.bind(this))
++      putNext.call(this, data.version, root, current, cb)
+     }.bind(this))
+-  }.bind(this)) // pining for fat arrows.
++  }.bind(this))
+ }
+ 
+-function conflictError (pkgid) {
+-  var e = new Error("publish fail")
++function putNext(newVersion, root, current, cb) {
++  // already have the tardata on the root object
++  // just merge in existing stuff
++  var curVers = Object.keys(current.versions || {}).map(function (v) {
++    return semver.clean(v, true)
++  }).concat(Object.keys(current.time || {}).map(function(v) {
++    if (semver.valid(v, true))
++      return semver.clean(v, true)
++  }).filter(function(v) {
++    return v
++  }))
++
++  if (curVers.indexOf(newVersion) !== -1) {
++    return cb(conflictError(root.name, newVersion))
++  }
++
++  current.versions[newVersion] = root.versions[newVersion]
++  current._attachments = current._attachments || {}
++  for (var i in root) {
++    switch (i) {
++      // objects that copy over the new stuffs
++      case 'dist-tags':
++      case 'versions':
++      case '_attachments':
++        for (var j in root[i])
++          current[i][j] = root[i][j]
++        break
++
++      // ignore these
++      case 'maintainers':
++        break;
++
++      // copy
++      default:
++        current[i] = root[i]
++    }
++  }
++  var maint = JSON.parse(JSON.stringify(root.maintainers))
++  root.versions[newVersion].maintainers = maint
++
++  this.request("PUT", root.name, current, cb)
++}
++
++function conflictError (pkgid, version) {
++  var e = new Error("cannot modify pre-existing version")
+   e.code = "EPUBLISHCONFLICT"
+   e.pkgid = pkgid
++  e.version = version
+   return e
+ }
+-
+-function attach (doc, file, filename, rev, cb) {
+-  doc = encodeURIComponent(doc)
+-  var revu = "-rev/"+rev
+-    , attURI = doc + "/-/" + encodeURIComponent(filename) + "/" + revu
+-  this.log.verbose("uploading", [attURI, file])
+-  this.upload(attURI, file, cb)
+-}
+diff --git a/lib/request.js b/lib/request.js
+index ff45e0e..7f60666 100644
+--- a/lib/request.js
++++ b/lib/request.js
+@@ -1,19 +1,24 @@
+ module.exports = regRequest
+ 
+ var url = require("url")
+-  , fs = require("graceful-fs")
++  , zlib = require("zlib")
+   , rm = require("rimraf")
+   , asyncMap = require("slide").asyncMap
+   , Stream = require("stream").Stream
+   , request = require("request")
+   , retry = require("retry")
++  , crypto = require("crypto")
++  , pkg = require("../package.json")
+ 
+-function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
+-  if (typeof cb_ !== "function") cb_ = reauthed, reauthed = false
++function regRequest (method, where, what, etag, nofollow, cb_) {
+   if (typeof cb_ !== "function") cb_ = nofollow, nofollow = false
+   if (typeof cb_ !== "function") cb_ = etag, etag = null
+   if (typeof cb_ !== "function") cb_ = what, what = null
+ 
++  if (!this.sessionToken) {
++    this.sessionToken = crypto.randomBytes(8).toString("hex")
++  }
++
+   var registry = this.conf.get('registry')
+   if (!registry) return cb(new Error(
+     "No registry url provided: " + method + " " + where))
+@@ -35,9 +40,10 @@ function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
+   , adduserNew = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)/
+   , nu = where.match(adduserNew)
+   , uc = where.match(adduserChange)
+-  , isUpload = what || this.conf.get('always-auth')
++  , alwaysAuth = this.conf.get('always-auth')
+   , isDel = method === "DELETE"
+-  , authRequired = isUpload && !nu || uc || isDel
++  , isWrite = what || isDel
++  , authRequired = (alwaysAuth || isWrite) && !nu || uc || isDel
+ 
+   // resolve to a full url on the registry
+   if (!where.match(/^https?:\/\//)) {
+@@ -64,40 +70,19 @@ function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
+   var remote = url.parse(where)
+   , auth = this.conf.get('_auth')
+ 
+-  if (authRequired && !this.conf.get('always-auth')) {
+-    var couch = this.couchLogin
+-    , token = couch && (this.conf.get('_token') || couch.token)
+-    , validToken = token && couch.valid(token)
+-
+-    if (!validToken) token = null
+-    else this.conf.set('_token', token)
+-
+-    if (couch && !token) {
+-      // login to get a valid token
+-      var a = { name: this.conf.get('username'),
+-                password: this.conf.get('_password') }
+-      var args = arguments
+-      return this.couchLogin.login(a, function (er, cr, data) {
+-        if (er || !couch.valid(couch.token)) {
+-          er = er || new Error('login error')
+-          return cb(er, cr, data)
+-        }
+-        this.conf.set('_token', this.couchLogin.token)
+-        return regRequest.call(this,
+-                               method, where, what,
+-                               etag, nofollow, reauthed, cb_)
+-      }.bind(this))
+-    }
++  if (authRequired && !auth) {
++    var un = this.conf.get('username')
++    var pw = this.conf.get('_password')
++    if (un && pw)
++      auth = new Buffer(un + ':' + pw).toString('base64')
+   }
+ 
+-  // now we either have a valid token, or an auth.
+-
+-  if (authRequired && !auth && !token) {
++  if (authRequired && !auth) {
+     return cb(new Error(
+-      "Cannot insert data into the registry without auth"))
++      "This request requires auth credentials. Run `npm login` and repeat the request."))
+   }
+ 
+-  if (auth && !token) {
++  if (auth && authRequired) {
+     remote.auth = new Buffer(auth, "base64").toString("utf8")
+   }
+ 
+@@ -114,9 +99,9 @@ function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
+   operation.attempt(function (currentAttempt) {
+     self.log.info("trying", "registry request attempt " + currentAttempt
+         + " at " + (new Date()).toLocaleTimeString())
+-    makeRequest.call(self, method, remote, where, what, etag, nofollow, token
++    makeRequest.call(self, method, remote, where, what, etag, nofollow
+                      , function (er, parsed, raw, response) {
+-      if (!er || er.message.match(/^SSL Error/)) {
++      if (!er || (er.message && er.message.match(/^SSL Error/))) {
+         if (er)
+           er.code = 'ESSL'
+         return cb(er, parsed, raw, response)
+@@ -125,32 +110,21 @@ function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
+       // Only retry on 408, 5xx or no `response`.
+       var statusCode = response && response.statusCode
+ 
+-      var reauth = !reauthed &&
+-                   ( statusCode === 401 ||
+-                     statusCode === 400 ||
+-                     statusCode === 403 )
+-      if (reauth)
+-        reauthed = true
+-
+       var timeout = statusCode === 408
+       var serverError = statusCode >= 500
+       var statusRetry = !statusCode || timeout || serverError
+-      if (reauth && this.conf.get('_auth') && this.conf.get('_token')) {
+-        this.conf.del('_token')
+-        this.couchLogin.token = null
+-        return regRequest.call(this, method, where, what,
+-                               etag, nofollow, reauthed, cb_)
+-      }
+       if (er && statusRetry && operation.retry(er)) {
+         self.log.info("retry", "will retry, error on last attempt: " + er)
+         return
+       }
++      if (response)
++        this.log.verbose("headers", response.headers)
+       cb.apply(null, arguments)
+     }.bind(this))
+   }.bind(this))
+ }
+ 
+-function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
++function makeRequest (method, remote, where, what, etag, nofollow, cb_) {
+   var cbCalled = false
+   function cb () {
+     if (cbCalled) return
+@@ -162,7 +136,11 @@ function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
+   if (strict === undefined) strict = true
+   var opts = { url: remote
+              , method: method
++             , encoding: null // tell request let body be Buffer instance
+              , ca: this.conf.get('ca')
++             , localAddress: this.conf.get('local-address')
++             , cert: this.conf.get('cert')
++             , key: this.conf.get('key')
+              , strictSSL: strict }
+     , headers = opts.headers = {}
+   if (etag) {
+@@ -170,11 +148,15 @@ function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
+     headers[method === "GET" ? "if-none-match" : "if-match"] = etag
+   }
+ 
+-  if (tok) {
+-    headers.cookie = 'AuthSession=' + tok.AuthSession
++  headers['npm-session'] = this.sessionToken
++  headers.version = this.version || pkg.version
++
++  if (this.refer) {
++    headers.referer = this.refer
+   }
+ 
+   headers.accept = "application/json"
++  headers['accept-encoding'] = 'gzip'
+ 
+   headers["user-agent"] = this.conf.get('user-agent') ||
+                           'node/' + process.version
+@@ -205,7 +187,7 @@ function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
+   this.log.http(method, remote.href || "/")
+ 
+   var done = requestDone.call(this, method, where, cb)
+-  var req = request(opts, done)
++  var req = request(opts, decodeResponseBody(done))
+ 
+   req.on("error", cb)
+   req.on("socket", function (s) {
+@@ -217,6 +199,26 @@ function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
+   }
+ }
+ 
++function decodeResponseBody(cb) {
++  return function (er, response, data) {
++    if (er) return cb(er, response, data)
++
++    // don't ever re-use connections that had server errors.
++    // those sockets connect to the Bad Place!
++    if (response.socket && response.statusCode > 500) {
++      response.socket.destroy()
++    }
++
++    if (response.headers['content-encoding'] !== 'gzip') return cb(er, response, data)
++
++    zlib.gunzip(data, function (er, buf) {
++      if (er) return cb(er, response, data)
++
++      cb(null, response, buf)
++    })
++  }
++}
++
+ // cb(er, parsed, raw, response)
+ function requestDone (method, where, cb) {
+   return function (er, response, data) {
+@@ -254,7 +256,7 @@ function requestDone (method, where, cb) {
+                , null, data, response )
+     }
+ 
+-    var er = null
++    er = null
+     if (parsed && response.headers.etag) {
+       parsed._etag = response.headers.etag
+     }
+diff --git a/lib/star.js b/lib/star.js
+index 5b7ab4a..23fbd91 100644
+--- a/lib/star.js
++++ b/lib/star.js
+@@ -5,9 +5,7 @@ function star (package, starred, cb) {
+   if (!this.conf.get('username')) return cb(new Error(
+     "Must be logged in to star/unstar packages"))
+ 
+-  var users = {}
+-
+-  this.request("GET", package, function (er, fullData) {
++  this.request("GET", package + '?write=true', function (er, fullData) {
+     if (er) return cb(er)
+ 
+     fullData = { _id: fullData._id
+diff --git a/lib/stars.js b/lib/stars.js
+index 93f0d70..4ef57e2 100644
+--- a/lib/stars.js
++++ b/lib/stars.js
+@@ -1,5 +1,3 @@
+-var qs = require('querystring')
+-
+ module.exports = stars
+ 
+ function stars (name, cb) {
+diff --git a/lib/tag.js b/lib/tag.js
+index 96136b7..d7ebf08 100644
+--- a/lib/tag.js
++++ b/lib/tag.js
+@@ -1,6 +1,6 @@
+ 
+ module.exports = tag
+ 
+-function tag (project, version, tag, cb) {
+-  this.request("PUT", project+"/"+tag, JSON.stringify(version), cb)
++function tag (project, version, tagName, cb) {
++  this.request("PUT", project+"/"+tagName, JSON.stringify(version), cb)
+ }
+diff --git a/lib/unpublish.js b/lib/unpublish.js
+index 9aaac1b..1887a99 100644
+--- a/lib/unpublish.js
++++ b/lib/unpublish.js
+@@ -14,7 +14,8 @@ var semver = require("semver")
+ function unpublish (name, ver, cb) {
+   if (typeof cb !== "function") cb = ver, ver = null
+ 
+-  this.get(name, null, -1, true, function (er, data) {
++  var u = name + '?write=true'
++  this.get(u, null, -1, true, function (er, data) {
+     if (er) {
+       this.log.info("unpublish", name+" not published")
+       return cb()
+@@ -28,10 +29,11 @@ function unpublish (name, ver, cb) {
+     var versions = data.versions || {}
+       , versionPublic = versions.hasOwnProperty(ver)
+ 
++    var dist
+     if (!versionPublic) {
+       this.log.info("unpublish", name+"@"+ver+" not published")
+     } else {
+-      var dist = versions[ver].dist
++      dist = versions[ver].dist
+       this.log.verbose("unpublish", "removing attachments", dist)
+     }
+ 
+diff --git a/test/adduser-new.js b/test/adduser-new.js
+index a0fee04..96dfc26 100644
+--- a/test/adduser-new.js
++++ b/test/adduser-new.js
+@@ -32,9 +32,7 @@ tap.test("create new user account", function (t) {
+ 
+     req.on("end", function () {
+       var o = JSON.parse(b)
+-      var salt = o.salt
+-      userdata.salt = salt
+-      userdata.password_sha = sha(password + salt)
++      userdata.password = password
+       userdata.date = o.date
+       t.deepEqual(o, userdata)
+ 
+diff --git a/test/adduser-update.js b/test/adduser-update.js
+index 03a1edb..3704571 100644
+--- a/test/adduser-update.js
++++ b/test/adduser-update.js
+@@ -32,7 +32,7 @@ tap.test("update a user acct", function (t) {
+     res.json({error: "conflict"})
+   })
+ 
+-  server.expect("GET", "/-/user/org.couchdb.user:username", function (req, res) {
++  server.expect("GET", "/-/user/org.couchdb.user:username?write=true", function (req, res) {
+     t.equal(req.method, "GET")
+     res.json(userdata)
+   })
+@@ -47,9 +47,7 @@ tap.test("update a user acct", function (t) {
+ 
+     req.on("end", function () {
+       var o = JSON.parse(b)
+-      var salt = o.salt
+-      userdata.salt = salt
+-      userdata.password_sha = sha(password + salt)
++      userdata.password = password
+       userdata.date = o.date
+       t.deepEqual(o, userdata)
+ 
+diff --git a/test/fixtures/server.js b/test/fixtures/server.js
+index 468a89e..80bbf48 100644
+--- a/test/fixtures/server.js
++++ b/test/fixtures/server.js
+@@ -17,10 +17,10 @@ function handler (req, res) {
+   , mu = req.method + ' ' + req.url
+ 
+   var k = server._expect[mu] ? mu : server._expect[u] ? u : null
+-  if (!k) throw Error('unexpected request', req.method, req.url)
++  if (!k) throw Error('unexpected request: ' + req.method + ' ' + req.url)
+ 
+   var fn = server._expect[k].shift()
+-  if (!fn) throw Error('unexpected request', req.method, req.url)
++  if (!fn) throw Error('unexpected request' + req.method + ' ' + req.url)
+ 
+ 
+   var remain = (Object.keys(server._expect).reduce(function (s, k) {
+diff --git a/test/publish-again.js b/test/publish-again.js
+new file mode 100644
+index 0000000..011fbaf
+--- /dev/null
++++ b/test/publish-again.js
+@@ -0,0 +1,81 @@
++var tap = require('tap')
++var server = require('./fixtures/server.js')
++var RC = require('../')
++var client = new RC(
++  { cache: __dirname + '/fixtures/cache'
++  , registry: 'http://localhost:' + server.port
++  , username: "username"
++  , password: "password"
++  , email: "i at izs.me"
++  , _auth: new Buffer("username:password").toString('base64')
++  , "always-auth": true
++  })
++
++var fs = require("fs")
++
++tap.test("publish again", function (t) {
++  var lastTime = null
++  server.expect("/npm-registry-client", function (req, res) {
++    t.equal(req.method, "PUT")
++    var b = ""
++    req.setEncoding('utf8')
++    req.on("data", function (d) {
++      b += d
++    })
++
++    req.on("end", function () {
++      var o = lastTime = JSON.parse(b)
++      t.equal(o._id, "npm-registry-client")
++      t.equal(o["dist-tags"].latest, pkg.version)
++      t.has(o.versions[pkg.version], pkg)
++      t.same(o.maintainers, [ { name: 'username', email: 'i at izs.me' } ])
++      var att = o._attachments[ pkg.name + '-' + pkg.version + '.tgz' ]
++      t.same(att.data, pd)
++      res.statusCode = 409
++      res.json({reason: "must supply latest _rev to update existing package"})
++    })
++  })
++
++  server.expect("/npm-registry-client?write=true", function (req, res) {
++    t.equal(req.method, "GET")
++    t.ok(lastTime)
++    for (var i in lastTime.versions) {
++      var v = lastTime.versions[i]
++      delete lastTime.versions[i]
++      lastTime.versions["0.0.2"] = v
++      lastTime["dist-tags"] = { latest: "0.0.2" }
++    }
++    lastTime._rev = "asdf"
++    res.json(lastTime)
++  })
++
++  server.expect("/npm-registry-client", function (req, res) {
++    t.equal(req.method, "PUT")
++    t.ok(lastTime)
++
++    var b = ""
++    req.setEncoding('utf8')
++    req.on("data", function (d) {
++      b += d
++    })
++
++    req.on("end", function() {
++      var o = JSON.parse(b)
++      t.equal(o._rev, "asdf")
++      t.deepEqual(o.versions["0.0.2"], o.versions[pkg.version])
++      res.statusCode = 201
++      res.json({created: true})
++    })
++  })
++
++
++  // not really a tarball, but doesn't matter
++  var tarball = require.resolve('../package.json')
++  var pd = fs.readFileSync(tarball, 'base64')
++  var pkg = require('../package.json')
++  client.publish(pkg, tarball, function (er, data, raw, res) {
++    if (er) throw er
++    t.deepEqual(data, { created: true })
++    t.end()
++  })
++})
+diff --git a/test/publish.js b/test/publish.js
+new file mode 100644
+index 0000000..9dcfc33
+--- /dev/null
++++ b/test/publish.js
+@@ -0,0 +1,51 @@
++var tap = require('tap')
++var crypto = require('crypto')
++var server = require('./fixtures/server.js')
++var RC = require('../')
++var client = new RC(
++  { cache: __dirname + '/fixtures/cache'
++  , registry: 'http://localhost:' + server.port
++  , username: "username"
++  , password: "password"
++  , email: "i at izs.me"
++  , _auth: new Buffer("username:password").toString('base64')
++  , "always-auth": true
++  })
++
++var fs = require("fs")
++
++tap.test("publish", function (t) {
++  server.expect("/npm-registry-client", function (req, res) {
++    t.equal(req.method, "PUT")
++    var b = ""
++    req.setEncoding('utf8')
++    req.on("data", function (d) {
++      b += d
++    })
++
++    req.on("end", function () {
++      var o = JSON.parse(b)
++      t.equal(o._id, "npm-registry-client")
++      t.equal(o["dist-tags"].latest, pkg.version)
++      t.has(o.versions[pkg.version], pkg)
++      t.same(o.maintainers, [ { name: 'username', email: 'i at izs.me' } ])
++      t.same(o.maintainers, o.versions[pkg.version].maintainers)
++      var att = o._attachments[ pkg.name + '-' + pkg.version + '.tgz' ]
++      t.same(att.data, pd)
++      var hash = crypto.createHash('sha1').update(pd, 'base64').digest('hex')
++      t.equal(o.versions[pkg.version].dist.shasum, hash)
++      res.statusCode = 201
++      res.json({created:true})
++    })
++  })
++
++  // not really a tarball, but doesn't matter
++  var tarball = require.resolve('../package.json')
++  var pd = fs.readFileSync(tarball, 'base64')
++  var pkg = require('../package.json')
++  client.publish(pkg, tarball, function (er, data, raw, res) {
++    if (er) throw er
++    t.deepEqual(data, { created: true })
++    t.end()
++  })
++})
+diff --git a/test/request-gzip-content.js b/test/request-gzip-content.js
+new file mode 100644
+index 0000000..2c7dcae
+--- /dev/null
++++ b/test/request-gzip-content.js
+@@ -0,0 +1,47 @@
++var zlib = require('zlib')
++var tap = require('tap')
++var server = require('./fixtures/server.js')
++var RC = require('../')
++var pkg = {
++  _id: 'some-package-gzip at 1.2.3',
++  name: 'some-package-gzip',
++  version: '1.2.3'
++}
++
++zlib.gzip(JSON.stringify(pkg), function (err, pkgGzip) {
++  var client = new RC({
++      cache: __dirname + '/fixtures/cache'
++    , 'fetch-retries': 1
++    , 'fetch-retry-mintimeout': 10
++    , 'fetch-retry-maxtimeout': 100
++    , registry: 'http://localhost:' + server.port })
++
++  tap.test('request gzip package content', function (t) {
++    server.expect('GET', '/some-package-gzip/1.2.3', function (req, res) {
++      res.statusCode = 200
++      res.setHeader('Content-Encoding', 'gzip');
++      res.setHeader('Content-Type', 'application/json');
++      res.end(pkgGzip)
++    })
++
++    client.get('/some-package-gzip/1.2.3', function (er, data, raw, res) {
++      if (er) throw er
++      t.deepEqual(data, pkg)
++      t.end()
++    })
++  })
++
++  tap.test('request wrong gzip package content', function (t) {
++    server.expect('GET', '/some-package-gzip-error/1.2.3', function (req, res) {
++      res.statusCode = 200
++      res.setHeader('Content-Encoding', 'gzip')
++      res.setHeader('Content-Type', 'application/json')
++      res.end(new Buffer('wrong gzip content'))
++    })
++
++    client.get('/some-package-gzip-error/1.2.3', function (er, data, raw, res) {
++      t.ok(er)
++      t.end()
++    })
++  })
++});
diff --git a/nodejs-npm-registry-client.spec b/nodejs-npm-registry-client.spec
index 4c6230b..bac6725 100644
--- a/nodejs-npm-registry-client.spec
+++ b/nodejs-npm-registry-client.spec
@@ -2,7 +2,7 @@
 
 Name:           nodejs-npm-registry-client
 Version:        0.2.28
-Release:        2%{?dist}
+Release:        3%{?dist}
 Summary:        Client for the npm registry
 
 Group:          System Environment/Libraries
@@ -11,6 +11,11 @@ URL:            https://github.com/isaacs/npm-registry-client
 Source0:        http://registry.npmjs.org/npm-registry-client/-/npm-registry-client-%{version}.tgz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
+# this patch fixes `npm adduser` and `npm publish`
+# it effectively updates this package to v0.4.12; however we can't bump the
+# version of this package without breaking the world
+Patch1:         %{name}-publish-fixes.patch
+
 BuildArch:  noarch
 %if 0%{?fedora} >= 19
 ExclusiveArch: %{nodejs_arches} noarch
@@ -25,6 +30,8 @@ Client for the npm registry, or private servers using the npm registry software.
 
 %prep
 %setup -q -n package
+%patch1 -p1
+%nodejs_fixdep -r couch-login
 
 %build
 #nothing to do
@@ -45,6 +52,9 @@ rm -rf %buildroot
 %doc README.md LICENSE
 
 %changelog
+* Sat May 16 2015 T.C. Hollingsworth <tchollingsworth at gmail.com> - 0.2.28-3
+- backport fixes to publish and adduser functions (RHBZ#1220472)
+
 * Sat Jun 07 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.2.28-2
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
 
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/nodejs-npm-registry-client.git/commit/?h=el6&id=467e412aa6ef424eaa03c7dae6a12a062a558a86


More information about the scm-commits mailing list