npm-registry-couchapp
Advanced tools
Comparing version 2.5.5 to 2.6.2
{ | ||
"name": "npm-registry-couchapp", | ||
"version": "2.5.5", | ||
"version": "2.6.2", | ||
"description": "The CouchApp implementation of an npm registry", | ||
"scripts": { | ||
"start": "./push.sh", | ||
"start": "bash ./push.sh", | ||
"load": "bash ./load-views.sh", | ||
@@ -13,9 +13,8 @@ "copy": "bash ./copy.sh", | ||
"couchapp": "~0.11.0", | ||
"request": "^2.42.0", | ||
"semver": "^2.3.1 || 3 || 4" | ||
"semver": "4" | ||
}, | ||
"devDependencies": { | ||
"jsontool": "~7.0.1", | ||
"request": "^2.42.0", | ||
"json": "^9.0.1", | ||
"parse-json-response": "^1.0.1", | ||
"request": "^2.36.0", | ||
"rimraf": "~2.2.6", | ||
@@ -22,0 +21,0 @@ "tap": "*", |
# npm-registry-couchapp | ||
[![Build Status](https://img.shields.io/travis/npm/npm-registry-couchapp/master.svg)](https://travis-ci.org/npm/npm-registry-couchapp) | ||
The design doc for The npm Registry CouchApp | ||
@@ -4,0 +6,0 @@ |
@@ -75,2 +75,20 @@ // Each of these is a string that will be require()'d in the couchapp | ||
exports.scope = | ||
[ 'exports.parse = parse' | ||
, 'exports.isScoped = isScoped' | ||
, 'exports.isGlobal = isGlobal' | ||
, function parse(name) { | ||
var m = name.match(/^(?:@([^\/]+)\/)?([^\/]+)$/) | ||
return m ? [m[1], m[2]] : [] | ||
} | ||
, function isScoped(name) { | ||
return !!(parse(name)[0]) | ||
} | ||
, function isGlobal(name) { | ||
return !isScoped(name) | ||
} | ||
].map(function (s) { return s.toString() }).join("\n") | ||
exports.valid = | ||
@@ -77,0 +95,0 @@ [ 'var semver = require("semver")' |
@@ -10,2 +10,5 @@ module.exports = | ||
, { from: "/-/ping", to: "/_show/ping", method: "GET" } | ||
, { from: "/-/ping/*", to: "/_show/ping", method: "GET" } | ||
, { from: "/-/all/since", to:"_list/index/modified", method: "GET" } | ||
@@ -12,0 +15,0 @@ |
@@ -90,3 +90,3 @@ | ||
var proto = req.headers['X-Forwarded-Proto'] || 'http'; | ||
var h = proto + "://" + req.headers.Host | ||
var h = proto + "://" + ( req.headers['X-Forwarded-Host'] || req.headers.Host ); | ||
@@ -180,1 +180,21 @@ doc.versions[v].dist.tarball = h + t | ||
} | ||
shows.ping = function (doc, req) { | ||
var code = 200 | ||
, headers = {"Content-Type":"application/json"} | ||
var body = { | ||
host: req.headers["Host"] | ||
, ok: true | ||
, username: req.userCtx.name | ||
, peer: req.peer | ||
} | ||
body = toJSON(body) | ||
return { | ||
code : code | ||
, body : body | ||
, headers : headers | ||
} | ||
} |
@@ -52,4 +52,6 @@ var updates = exports | ||
doc.users[username] = true; | ||
if (!doc.users) doc.users = {} | ||
doc.users[username] = true | ||
return [doc, JSON.stringify({ok: username + ' has starred ' + doc.name})] | ||
@@ -61,4 +63,6 @@ } | ||
delete doc.users[username]; | ||
if (!doc.users) return [doc, JSON.stringify({ok: doc.name + ' has no users'})] | ||
delete doc.users[username] | ||
return [doc, JSON.stringify({ok: username + ' has unstarred ' + doc.name})] | ||
@@ -90,3 +94,2 @@ } | ||
var semver = require("semver") | ||
var valid = require("valid") | ||
var README_MAXLEN = 64 * 1024 | ||
@@ -312,7 +315,2 @@ var body = JSON.parse(req.body) | ||
var p = doc.versions[v] | ||
if (p.version !== v) | ||
return error("Version mismatch: "+JSON.stringify(v)+ | ||
" !== "+JSON.stringify(p.version)) | ||
if (!valid.name(p.name)) | ||
return error("Invalid name: "+JSON.stringify(p.name)) | ||
latest = semver.clean(v, true) | ||
@@ -319,0 +317,0 @@ } |
@@ -33,2 +33,3 @@ module.exports = function (doc, oldDoc, user, dbCtx) { | ||
var deepEquals = deep.deepEquals | ||
var scope = require("scope") | ||
} catch (er) { | ||
@@ -226,8 +227,31 @@ assert(false, "failed loading modules") | ||
function validUser () { | ||
// Admins can edit any packages | ||
if (isAdmin()) return true | ||
// scoped packages require that the user have the entity name as a role | ||
// They must ALSO be in the "maintainers" list by role or name. | ||
var roles = user && user.roles || [] | ||
var s = scope.parse(doc.name) | ||
var entity = s[0] | ||
if (entity && roles.indexOf(entity) === -1) { | ||
return false | ||
} | ||
// At this point, they can publish if either the thing doesn't exist, | ||
// or they are one of the maintainers. | ||
// Unpublished packages don't have a "maintainers" property. | ||
if ( !oldDoc || !oldDoc.maintainers ) return true | ||
if (isAdmin()) return true | ||
if (typeof oldDoc.maintainers !== "object") return true | ||
for (var i = 0, l = oldDoc.maintainers.length; i < l; i ++) { | ||
// In the maintainer list by name. | ||
if (oldDoc.maintainers[i].name === user.name) return true | ||
// in the maintainer list by role. | ||
var role = oldDoc.maintainers[i].role | ||
if (role && roles && typeof role === "string") { | ||
if (roles.indexOf(role) !== -1) return true | ||
} | ||
} | ||
// Not an owner, cannot publish. | ||
return false | ||
@@ -260,3 +284,3 @@ } | ||
assert(vu, "user: " + user.name + " not authorized to modify " | ||
+ oldDoc.name + "\n" | ||
+ doc.name + "\n" | ||
+ diffObj(oldDoc, doc).join("\n")) | ||
@@ -285,2 +309,3 @@ } | ||
// Now we know that it is not an unpublish. | ||
@@ -306,3 +331,6 @@ assert(typeof doc['dist-tags'] === 'object', 'dist-tags must be object') | ||
// sanity checks. | ||
assert(valid.name(doc.name), "name invalid: "+doc.name) | ||
var s = scope.parse(doc.name) | ||
var entity = s[0] | ||
var name = s[1] | ||
assert(valid.name(name), "name invalid: "+name) | ||
@@ -333,8 +361,5 @@ // New documents may only be created with all lowercase names. | ||
if (version) { | ||
if (!version.dist) | ||
assert(false, "no dist object in " + latest + " version") | ||
if (!version.dist.tarball) | ||
assert(false, "no tarball in " + latest + " version") | ||
if (!version.dist.shasum) | ||
assert(false, "no shasum in " + latest + " version") | ||
assert(version.dist, "no dist object in " + latest + " version") | ||
assert(version.dist.tarball, "no tarball in " + latest + " version") | ||
assert(version.dist.shasum, "no shasum in " + latest + " version") | ||
} | ||
@@ -353,2 +378,10 @@ | ||
function checkDep(version, dep, t) { | ||
ridiculousDeps() | ||
if (!entity) { | ||
assert(scope.isGlobal(dep), | ||
"global packages may only depend on other global packages") | ||
} | ||
} | ||
function ridiculousDeps() { | ||
@@ -370,7 +403,14 @@ if (++depCount > maxDeps) | ||
assert(version.version === ver, | ||
"Version mismatch: "+JSON.stringify(ver)+ | ||
" !== "+JSON.stringify(version.version)) | ||
depCount = 0 | ||
for (var dep in version.dependencies || {}) ridiculousDeps() | ||
for (var dep in version.devDependencies || {}) ridiculousDeps() | ||
for (var dep in version.optionalDependencies || {}) ridiculousDeps() | ||
var types = | ||
["dependencies", "devDependencies", "optionalDependencies"] | ||
types.forEach(function(t) { | ||
for (var dep in version[t] || {}) { | ||
checkDep(version, dep, t) | ||
} | ||
}) | ||
@@ -478,5 +518,9 @@ // NEW versions must only have strings in the 'scripts' field, | ||
assert(doc.time[v] === oldTime[v], | ||
"Cannot replace previously published version: "+v) | ||
"Attempting to modify version " + v + ",\n" + | ||
"which was previously published on " + oldTime[v] + ".\n" + | ||
"This is forbidden, to maintain package integrity.\n" + | ||
"Please update the version number and try again.") | ||
} | ||
// Do not allow creating a NEW attachment for a version that | ||
@@ -483,0 +527,0 @@ // already had an attachment in its metadata. |
@@ -196,2 +196,26 @@ var common = require('./common.js') | ||
test('GET with x-forwarded-for', function (t) { | ||
var wanted = 'http://fooblz/registry/_design/scratch/_rewrite/package/-/package-0.0.2.tgz' | ||
var g = url.parse('http://localhost:15986/registry/_design/scratch/_rewrite/package') | ||
g.headers = { | ||
'x-forwarded-host': 'fooblz' | ||
} | ||
http.get(g, function(res) { | ||
t.equal(res.statusCode, 200) | ||
var c = '' | ||
res.setEncoding('utf8') | ||
res.on('data', function(d) { | ||
c += d | ||
}) | ||
res.on('end', function() { | ||
c = JSON.parse(c) | ||
var actual = c.versions[c['dist-tags'].latest].dist.tarball | ||
t.equal(actual, wanted) | ||
t.end() | ||
}) | ||
}) | ||
}) | ||
test('fail to clobber', function(t) { | ||
@@ -198,0 +222,0 @@ var c = common.npm([ |
@@ -31,6 +31,11 @@ var fs = require("fs") | ||
} catch (er) { | ||
if (er.stack) { | ||
// *probably* not what we wanted. | ||
console.error(er.stack) | ||
} | ||
if (c.throw) | ||
t.same(er, c.throw, "got expected error") | ||
else | ||
else { | ||
t.notOk(er, JSON.stringify(er)) | ||
} | ||
} finally { | ||
@@ -37,0 +42,0 @@ if (c.throw) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1195363
2
146
26182
107
20
- Removedrequest@^2.42.0
Updatedsemver@4