Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe319b06ba | ||
|
|
d829600ed0 | ||
|
|
4dd59cb300 | ||
|
|
5ff25474c0 | ||
|
|
6d49a859c6 | ||
|
|
63a57b906e | ||
|
|
a09e6b142d | ||
|
|
bca9341e5d | ||
|
|
71b0662d49 | ||
|
|
b894c0fa2b | ||
|
|
4127fa1f07 | ||
|
|
5ee2a6e8fd | ||
|
|
8baa34145b | ||
|
|
4acb819356 | ||
|
|
2a84e39aee | ||
|
|
2019d72e36 | ||
|
|
b9fa7e7f98 |
@@ -1,3 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.11'
|
||||
script: "make test-travis"
|
||||
after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
|
||||
|
||||
29
History.md
29
History.md
@@ -1,4 +1,33 @@
|
||||
|
||||
1.0.2 / 2014-08-01
|
||||
==================
|
||||
|
||||
* ~_~ fix auth error response message
|
||||
|
||||
1.0.1 / 2014-08-01
|
||||
==================
|
||||
|
||||
* Merge pull request #398 from cnpm/fix-auth
|
||||
* hot fix auth error
|
||||
|
||||
1.0.0 / 2014-08-01
|
||||
==================
|
||||
|
||||
* add private package list
|
||||
|
||||
0.9.2 / 2014-07-30
|
||||
==================
|
||||
|
||||
* hotfix save custom user bug
|
||||
|
||||
0.9.1 / 2014-07-30
|
||||
==================
|
||||
|
||||
* Handle user service auth throw custom error message
|
||||
* add test for config private packages
|
||||
* add config.privatePackages
|
||||
* add more comments in config/index.js
|
||||
|
||||
0.9.0 / 2014-07-29
|
||||
==================
|
||||
|
||||
|
||||
15
Makefile
15
Makefile
@@ -44,6 +44,21 @@ test-cov cov: install pretest
|
||||
$(TESTS)
|
||||
@./node_modules/.bin/cov coverage
|
||||
|
||||
test-travis: install pretest
|
||||
@NODE_ENV=test node --harmony \
|
||||
node_modules/.bin/istanbul cover --preserve-comments \
|
||||
./node_modules/.bin/_mocha \
|
||||
--report lcovonly \
|
||||
-- \
|
||||
--reporter dot \
|
||||
--timeout $(TIMEOUT) \
|
||||
--require should \
|
||||
--require should-http \
|
||||
--require co-mocha \
|
||||
--require ./test/init.js \
|
||||
$(MOCHA_OPTS) \
|
||||
$(TESTS)
|
||||
|
||||
contributors: install
|
||||
@./node_modules/.bin/contributors -f plain -o AUTHORS
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -1,9 +1,22 @@
|
||||
cnpmjs.org
|
||||
=======
|
||||
|
||||
[](http://travis-ci.org/cnpm/cnpmjs.org) [](https://gemnasium.com/cnpm/cnpmjs.org)
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![build status][travis-image]][travis-url]
|
||||
[![Test coverage][coveralls-image]][coveralls-url]
|
||||
[![Gittip][gittip-image]][gittip-url]
|
||||
[![David deps][david-image]][david-url]
|
||||
|
||||
[](https://nodei.co/npm/cnpmjs.org/)
|
||||
[npm-image]: https://img.shields.io/npm/v/cnpmjs.org.svg?style=flat
|
||||
[npm-url]: https://npmjs.org/package/cnpmjs.org
|
||||
[travis-image]: https://img.shields.io/travis/cnpm/cnpmjs.org.svg?style=flat
|
||||
[travis-url]: https://travis-ci.org/cnpm/cnpmjs.org
|
||||
[coveralls-image]: https://img.shields.io/coveralls/cnpm/cnpmjs.org.svg?style=flat
|
||||
[coveralls-url]: https://coveralls.io/r/cnpm/cnpmjs.org?branch=master
|
||||
[gittip-image]: https://img.shields.io/gittip/fengmk2.svg?style=flat
|
||||
[gittip-url]: https://www.gittip.com/fengmk2/
|
||||
[david-image]: https://img.shields.io/david/cnpm/cnpmjs.org.svg?style=flat
|
||||
[david-url]: https://david-dm.org/cnpm/cnpmjs.org
|
||||
|
||||

|
||||
|
||||
|
||||
187
config/index.js
187
config/index.js
@@ -27,16 +27,88 @@ var version = require('../package.json').version;
|
||||
var root = path.dirname(__dirname);
|
||||
|
||||
var config = {
|
||||
|
||||
version: version,
|
||||
|
||||
/**
|
||||
* Cluster mode
|
||||
*/
|
||||
enableCluster: false,
|
||||
numCPUs: os.cpus().length,
|
||||
|
||||
/*
|
||||
* server configure
|
||||
*/
|
||||
registryPort: 7001,
|
||||
webPort: 7002,
|
||||
bindingHost: '127.0.0.1', // only binding on 127.0.0.1 for local access
|
||||
enableCluster: false,
|
||||
numCPUs: os.cpus().length,
|
||||
debug: true, // if debug
|
||||
|
||||
// debug mode
|
||||
// if in debug mode, some middleware like limit wont load
|
||||
// logger module will print to stdout
|
||||
debug: true,
|
||||
// session secret
|
||||
sessionSecret: 'cnpmjs.org test session secret',
|
||||
// max request json body size
|
||||
jsonLimit: '10mb',
|
||||
// log dir name
|
||||
logdir: path.join(root, '.tmp', 'logs'),
|
||||
// update file template dir
|
||||
uploadDir: path.join(root, '.dist'),
|
||||
// web page viewCache
|
||||
viewCache: false,
|
||||
// mysql config
|
||||
|
||||
// config for koa-limit middleware
|
||||
// for limit download rates
|
||||
limit: {
|
||||
enable: false,
|
||||
token: 'koa-limit:download',
|
||||
limit: 1000,
|
||||
interval: 1000 * 60 * 60 * 24,
|
||||
whiteList: [],
|
||||
blackList: [],
|
||||
message: 'request frequency limited, any question, please contact fengmk2@gmail.com',
|
||||
},
|
||||
|
||||
enableCompress: false, // enable gzip response or not
|
||||
|
||||
// default system admins
|
||||
admins: {
|
||||
// name: email
|
||||
fengmk2: 'fengmk2@gmail.com',
|
||||
admin: 'admin@cnpmjs.org',
|
||||
dead_horse: 'dead_horse@qq.com',
|
||||
cnpmjstest10: 'cnpmjstest10@cnpmjs.org',
|
||||
},
|
||||
|
||||
// email notification for errors
|
||||
mail: {
|
||||
appname: 'cnpmjs.org',
|
||||
sender: 'cnpmjs.org mail sender <adderss@gmail.com>',
|
||||
host: 'smtp.gmail.com',
|
||||
port: 465,
|
||||
user: 'address@gmail.com',
|
||||
pass: 'your password',
|
||||
ssl: true,
|
||||
debug: false
|
||||
},
|
||||
|
||||
|
||||
logoURL: '//ww4.sinaimg.cn/large/69c1d4acgw1ebfly5kjlij208202oglr.jpg', // cnpm logo image url
|
||||
customReadmeFile: '', // you can use your custom readme file instead the cnpm one
|
||||
customFooter: '', // you can add copyright and site total script html here
|
||||
npmClientName: 'cnpm', // use `${name} install package`
|
||||
packagePageContributorSearch: true, // package page contributor link to search, default is true
|
||||
|
||||
// max handle number of package.json `dependencies` property
|
||||
maxDependencies: 200,
|
||||
// backup filepath prefix
|
||||
backupFilePrefix: '/cnpm/backup/',
|
||||
|
||||
/**
|
||||
* mysql config
|
||||
*/
|
||||
|
||||
mysqlServers: [
|
||||
{
|
||||
host: '127.0.0.1',
|
||||
@@ -49,73 +121,32 @@ var config = {
|
||||
mysqlMaxConnections: 4,
|
||||
mysqlQueryTimeout: 5000,
|
||||
|
||||
sessionSecret: 'cnpmjs.org test session secret',
|
||||
redis: {
|
||||
// host: 'pub-redis-19533.us-east-1-4.3.ec2.garantiadata.com',
|
||||
// port: 19533,
|
||||
// pass: 'cnpmjs_dev'
|
||||
},
|
||||
jsonLimit: '10mb', // max request json body size
|
||||
uploadDir: path.join(root, '.dist'),
|
||||
|
||||
// redis config
|
||||
// use for koa-limit module as storage
|
||||
redis: null,
|
||||
|
||||
// package tarball store in qn by default
|
||||
// qiniu cdn: http://www.qiniu.com/, it free for dev.
|
||||
qn: {
|
||||
// accessKey: "iN7NgwM31j4-BZacMjPrOQBs34UG1maYCAQmhdCV",
|
||||
// secretKey: "6QTOr2Jg1gcZEWDQXKOGZh5PziC2MCV5KsntT70j",
|
||||
// bucket: "qtestbucket",
|
||||
// domain: "http://qtestbucket.qiniudn.com",
|
||||
accessKey: "5UyUq-l6jsWqZMU6tuQ85Msehrs3Dr58G-mCZ9rE",
|
||||
secretKey: "YaRsPKiYm4nGUt8mdz2QxeV5Q_yaUzVxagRuWTfM",
|
||||
bucket: "qiniu-sdk-test",
|
||||
domain: "http://qiniu-sdk-test.qiniudn.com",
|
||||
},
|
||||
|
||||
mail: {
|
||||
appname: 'cnpmjs.org',
|
||||
sender: 'cnpmjs.org mail sender <adderss@gmail.com>',
|
||||
host: 'smtp.gmail.com',
|
||||
port: 465,
|
||||
user: 'address@gmail.com',
|
||||
pass: 'your password',
|
||||
ssl: true,
|
||||
debug: false
|
||||
},
|
||||
|
||||
noticeSyncDistError: true,
|
||||
disturl: 'http://nodejs.org/dist',
|
||||
syncDist: false,
|
||||
logoURL: '//ww4.sinaimg.cn/large/69c1d4acgw1ebfly5kjlij208202oglr.jpg',
|
||||
// registry url name
|
||||
registryHost: 'r.cnpmjs.org',
|
||||
// customReadmeFile: __dirname + '/web_readme.md',
|
||||
customReadmeFile: '', // you can use your custom readme file instead the cnpm one
|
||||
customFooter: '', // you can add copyright and site total script html here
|
||||
npmClientName: 'cnpm', // use `${name} install package`
|
||||
packagePageContributorSearch: true, // package page contributor link to search, default is true
|
||||
sourceNpmRegistry: 'http://registry.npmjs.org',
|
||||
enablePrivate: true, // enable private mode, only admin can publish, other use just can sync package from source npm
|
||||
admins: {
|
||||
// name: email
|
||||
fengmk2: 'fengmk2@gmail.com',
|
||||
admin: 'admin@cnpmjs.org',
|
||||
dead_horse: 'dead_horse@qq.com',
|
||||
cnpmjstest10: 'cnpmjstest10@cnpmjs.org',
|
||||
},
|
||||
syncByInstall: true,
|
||||
backupFilePrefix: '/cnpm/backup/', // backup filepath prefix
|
||||
syncModel: 'none', // 'none', 'all', 'exist'
|
||||
syncConcurrency: 1,
|
||||
syncInterval: '10m', // sync interval, default is 10 minutes
|
||||
maxDependencies: 200, // max handle number of package.json `dependencies` property
|
||||
|
||||
limit: {
|
||||
enable: false,
|
||||
token: 'koa-limit:download',
|
||||
limit: 1000,
|
||||
interval: 1000 * 60 * 60 * 24,
|
||||
whiteList: [],
|
||||
blackList: [],
|
||||
message: 'request frequency limited, any question, please contact fengmk2@gmail.com',
|
||||
},
|
||||
enableCompress: false, // enable gzip response or not
|
||||
|
||||
/**
|
||||
* registry mode config
|
||||
*/
|
||||
|
||||
// enable private mode, only admin can publish, other use just can sync package from source npm
|
||||
enablePrivate: true,
|
||||
|
||||
// registry scopes, if don't set, means do not support scopes
|
||||
scopes: [
|
||||
'@cnpm',
|
||||
'@cnpmtest'
|
||||
@@ -125,8 +156,40 @@ var config = {
|
||||
// forward compatbility for update from lower version cnpmjs.org
|
||||
adaptScope: true,
|
||||
|
||||
// force publish with scope
|
||||
// force user publish with scope
|
||||
// but admins still can publish without scope
|
||||
forcePublishWithScope: true,
|
||||
|
||||
// some registry already have some private packages in global scope
|
||||
// but we want to treat them as scoped private packages,
|
||||
// so you can use this white list.
|
||||
privatePackages: ['private-package'],
|
||||
|
||||
/**
|
||||
* sync configs
|
||||
*/
|
||||
|
||||
// sync dist config
|
||||
// sync node.js dist from nodejs.org
|
||||
noticeSyncDistError: true,
|
||||
disturl: 'http://nodejs.org/dist',
|
||||
syncDist: false,
|
||||
|
||||
// sync source
|
||||
sourceNpmRegistry: 'http://registry.npmjs.org',
|
||||
|
||||
// if install return 404, try to sync from source registry
|
||||
syncByInstall: true,
|
||||
|
||||
// sync mode select
|
||||
// none: do not sync any module
|
||||
// exist: only sync exist modules
|
||||
// all: sync all modules
|
||||
syncModel: 'none', // 'none', 'all', 'exist'
|
||||
|
||||
syncConcurrency: 1,
|
||||
// sync interval, default is 10 minutes
|
||||
syncInterval: '10m',
|
||||
};
|
||||
|
||||
// load config/config.js, everything in config.js will cover the same key in index.js
|
||||
|
||||
@@ -154,7 +154,17 @@ exports.add = function* () {
|
||||
|
||||
debug('add user: %j', body);
|
||||
|
||||
var loginedUser = yield UserService.auth(body.name, body.password);
|
||||
var loginedUser;
|
||||
try {
|
||||
loginedUser = yield UserService.auth(body.name, body.password);
|
||||
} catch (err) {
|
||||
this.status = err.status || 500;
|
||||
this.body = {
|
||||
error: err.name,
|
||||
reason: err.message
|
||||
};
|
||||
return;
|
||||
}
|
||||
if (loginedUser) {
|
||||
var rev = Date.now() + '-' + loginedUser.login;
|
||||
if (config.customUserService) {
|
||||
|
||||
@@ -242,6 +242,14 @@ exports.displaySync = function* (next) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.listPrivates = function* () {
|
||||
var packages = yield Module.listPrivates();
|
||||
yield this.render('private', {
|
||||
title: 'private packages',
|
||||
packages: packages
|
||||
});
|
||||
};
|
||||
|
||||
function setLicense(pkg) {
|
||||
var license;
|
||||
license = pkg.license || pkg.licenses || pkg.licence || pkg.licences;
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
var debug = require('debug')('cnpmjs.org:middleware:auth');
|
||||
var UserService = require('../services/user');
|
||||
|
||||
/**
|
||||
* Parse the request authorization
|
||||
* get the real user
|
||||
*/
|
||||
|
||||
module.exports = function (options) {
|
||||
return function* auth(next) {
|
||||
this.user = {};
|
||||
@@ -36,7 +41,15 @@ module.exports = function (options) {
|
||||
var username = authorization[0];
|
||||
var password = authorization[1];
|
||||
|
||||
var row = yield* UserService.auth(username, password);
|
||||
var row;
|
||||
try {
|
||||
row = yield* UserService.auth(username, password);
|
||||
} catch (err) {
|
||||
// do not response error here
|
||||
// many request do not need login
|
||||
this.user.error = err;
|
||||
}
|
||||
|
||||
if (!row) {
|
||||
debug('auth fail user: %j, headers: %j', row, this.header);
|
||||
return yield* next;
|
||||
|
||||
@@ -15,7 +15,17 @@
|
||||
*/
|
||||
|
||||
module.exports = function *login(next) {
|
||||
if (this.user.error) {
|
||||
this.status = this.user.error.status || 500;
|
||||
this.body = {
|
||||
error: this.user.error.name,
|
||||
reason: this.user.error.message
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.user.name) {
|
||||
|
||||
this.status = 401;
|
||||
this.body = {
|
||||
error: 'unauthorized',
|
||||
|
||||
@@ -35,6 +35,12 @@ module.exports = function *publishable(next) {
|
||||
// if `config.forcePublishWithScope` set to true, only admins can publish without scope
|
||||
|
||||
var name = this.params.name || this.params[0];
|
||||
|
||||
// check if is private package list in config
|
||||
if (config.privatePackages && config.privatePackages.indexOf(name) !== -1) {
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
// scope
|
||||
if (name[0] === '@') {
|
||||
if (checkScope(name, this)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cnpmjs.org",
|
||||
"version": "0.9.0",
|
||||
"version": "1.0.2",
|
||||
"description": "Private npm registry and web for Enterprise, base on MySQL and Simple Store Service",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -704,3 +704,38 @@ exports.getAdaptName = function* (name) {
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
exports.listPrivates = function* () {
|
||||
var scopes = config.scopes;
|
||||
if (!scopes || !scopes.length) {
|
||||
return [];
|
||||
}
|
||||
var privatePackages = config.privatePackages || [];
|
||||
|
||||
var args = [];
|
||||
var sql = 'SELECT module_id AS id FROM tag WHERE tag="latest" AND (';
|
||||
var wheres = [];
|
||||
|
||||
scopes.forEach(function (scope) {
|
||||
wheres.push('name LIKE ?');
|
||||
args.push(scope + '%');
|
||||
});
|
||||
|
||||
if (privatePackages.length) {
|
||||
wheres.push('name in (?)');
|
||||
args.push(privatePackages);
|
||||
}
|
||||
|
||||
sql = sql + wheres.join(' OR ') + ')';
|
||||
|
||||
var ids = yield mysql.query(sql, args);
|
||||
ids = ids.map(function (row) {
|
||||
return row.id;
|
||||
});
|
||||
|
||||
if (!ids.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return yield mysql.query(QUERY_MODULES_BY_ID_SQL, [ids]);
|
||||
};
|
||||
|
||||
@@ -152,7 +152,7 @@ exports.saveNpmUser = function* (user) {
|
||||
|
||||
exports.saveCustomUser = function* (data) {
|
||||
var sql = 'SELECT id, json FROM user WHERE name=?;';
|
||||
var row = yield mysql.queryOne(sql, [data.user.name]);
|
||||
var row = yield mysql.queryOne(sql, [data.user.login]);
|
||||
var salt = data.salt || '0';
|
||||
var password_sha = data.password_sha || '0';
|
||||
var ip = data.ip || '0';
|
||||
|
||||
@@ -31,6 +31,8 @@ function routes(app) {
|
||||
app.get('/package/:name', pkg.display);
|
||||
app.get('/package/:name/:version', pkg.display);
|
||||
|
||||
app.get('/privates', pkg.listPrivates);
|
||||
|
||||
app.get(/\/browse\/keyword\/(@[\w\-\.]+\/[\w\-\.]+)$/, pkg.search);
|
||||
app.get('/browse/keyword/:word', pkg.search);
|
||||
|
||||
|
||||
105
test/controllers/registry/module/config_private_packages.test.js
Normal file
105
test/controllers/registry/module/config_private_packages.test.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* cnpmjs.org - test/controllers/registry/module/public_mode.test.js
|
||||
* Copyright(c) 2014 dead_horse <dead_horse@qq.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var should = require('should');
|
||||
var request = require('supertest');
|
||||
var mm = require('mm');
|
||||
var config = require('../../../../config');
|
||||
var app = require('../../../../servers/registry');
|
||||
var utils = require('../../../utils');
|
||||
|
||||
describe('controllers/registry/module/config_private_packages.test.js', function () {
|
||||
beforeEach(function () {
|
||||
mm(config, 'enablePrivate', false);
|
||||
mm(config, 'forcePublishWithScope', true);
|
||||
mm(config, 'privatePackages', ['private-package']);
|
||||
});
|
||||
|
||||
after(mm.restore);
|
||||
it('should publish with tgz base64, addPackageAndDist()', function (done) {
|
||||
var pkg = utils.getPackage('private-package', '0.0.1', utils.otherUser);
|
||||
request(app)
|
||||
.put('/' + pkg.name)
|
||||
.set('authorization', utils.otherUserAuth)
|
||||
.send(pkg)
|
||||
.expect(201, function (err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.should.have.keys('ok', 'rev');
|
||||
res.body.ok.should.equal(true);
|
||||
pkg = utils.getPackage('private-package', '0.0.1', utils.otherUser);
|
||||
// upload again should 403
|
||||
request(app)
|
||||
.put('/' + pkg.name)
|
||||
.set('authorization', utils.otherUserAuth)
|
||||
.send(pkg)
|
||||
.expect(403, function (err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.should.eql({
|
||||
error: 'forbidden',
|
||||
reason: 'cannot modify pre-existing version: 0.0.1'
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should other user publish 403', function (done) {
|
||||
var pkg = utils.getPackage('private-package', '0.0.2', utils.secondUser);
|
||||
request(app)
|
||||
.put('/' + pkg.name)
|
||||
.set('authorization', utils.secondUserAuth)
|
||||
.send(pkg)
|
||||
.expect(/forbidden user/)
|
||||
.expect(403, done);
|
||||
});
|
||||
|
||||
it('should admin publish 403', function (done) {
|
||||
var pkg = utils.getPackage('private-package', '0.0.2', utils.admin);
|
||||
request(app)
|
||||
.put('/' + pkg.name)
|
||||
.set('authorization', utils.adminAuth)
|
||||
.send(pkg)
|
||||
.expect(/forbidden user/)
|
||||
.expect(403, done);
|
||||
});
|
||||
|
||||
it('should add again new maintainers', function (done) {
|
||||
request(app)
|
||||
.put('/private-package/-rev/1')
|
||||
.send({
|
||||
maintainers: [{
|
||||
name: 'cnpmjstest101',
|
||||
email: 'cnpmjstest101@cnpmjs.org'
|
||||
}, {
|
||||
name: 'fengmk2',
|
||||
email: 'fengmk2@cnpmjs.org'
|
||||
}]
|
||||
})
|
||||
.set('authorization', utils.otherUserAuth)
|
||||
.expect(201)
|
||||
.expect('content-type', 'application/json; charset=utf-8', done);
|
||||
});
|
||||
|
||||
it('should remove maintainers', function (done) {
|
||||
request(app)
|
||||
.put('/private-package/-rev/1')
|
||||
.send({
|
||||
maintainers: [{
|
||||
name: 'cnpmjstest101',
|
||||
email: 'cnpmjstest101@cnpmjs.org'
|
||||
}]
|
||||
})
|
||||
.set('authorization', utils.otherUserAuth)
|
||||
.expect(201)
|
||||
.expect('content-type', 'application/json; charset=utf-8', done);
|
||||
});
|
||||
});
|
||||
@@ -342,5 +342,27 @@ describe('controllers/registry/user.test.js', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error json when userSerive.auth throw error', function (done) {
|
||||
mm(UserService, 'auth', function* () {
|
||||
var err = new Error('mock user service auth error, please visit http://ooxx.net/user to sigup first');
|
||||
err.name = 'UserSeriveAuthError';
|
||||
err.status = 401;
|
||||
throw err;
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:cnpmjstest10')
|
||||
.send({
|
||||
name: 'cnpmjstest10',
|
||||
password: 'cnpmjstest10',
|
||||
email: 'cnpmjstest10@cnpmjs.org'
|
||||
})
|
||||
.expect({
|
||||
error: 'UserSeriveAuthError',
|
||||
reason: 'mock user service auth error, please visit http://ooxx.net/user to sigup first'
|
||||
})
|
||||
.expect(401, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,6 +25,7 @@ var registry = require('../../../servers/registry');
|
||||
var pkg = require('../../../controllers/web/package');
|
||||
var SyncModuleWorker = require('../../../proxy/sync_module_worker');
|
||||
var utils = require('../../utils');
|
||||
var config = require('../../../config');
|
||||
|
||||
var fixtures = path.join(path.dirname(path.dirname(__dirname)), 'fixtures');
|
||||
|
||||
@@ -237,4 +238,21 @@ describe('controllers/web/package.test.js', function () {
|
||||
.expect(/This package has been unpublished\./, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /privates', function () {
|
||||
it('should response no private packages', function (done) {
|
||||
mm(config, 'scopes', []);
|
||||
request(app)
|
||||
.get('/privates')
|
||||
.expect(/Can not found private package/)
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
it('should response no private packages', function (done) {
|
||||
request(app)
|
||||
.get('/privates')
|
||||
.expect(/Private packages in this registry/)
|
||||
.expect(200, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,8 @@ var request = require('supertest');
|
||||
var app = require('../../servers/registry');
|
||||
var mm = require('mm');
|
||||
var mysql = require('../../common/mysql');
|
||||
var config = require('../../config');
|
||||
var UserService = require('../../services/user');
|
||||
|
||||
describe('middleware/auth.test.js', function () {
|
||||
before(function (done) {
|
||||
@@ -60,5 +62,29 @@ describe('middleware/auth.test.js', function () {
|
||||
.set('authorization', 'basic ' + new Buffer('cnpmjstest10:cnpmjstest10').toString('base64'))
|
||||
.expect(500, done);
|
||||
});
|
||||
|
||||
describe('config.customUserService = true', function () {
|
||||
beforeEach(function () {
|
||||
mm(config, 'customUserService', true);
|
||||
});
|
||||
|
||||
it('should 401 when user service auth throw error', function (done) {
|
||||
mm(UserService, 'auth', function* () {
|
||||
var err = new Error('mock user service auth error, please visit http://ooxx.net/user to sigup first');
|
||||
err.name = 'UserSeriveAuthError';
|
||||
err.status = 401;
|
||||
throw err;
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:cnpmjstest10/-rev/1')
|
||||
.set('authorization', 'basic ' + new Buffer('cnpmjstest10:cnpmjstest10').toString('base64'))
|
||||
.expect({
|
||||
error: 'UserSeriveAuthError',
|
||||
reason: 'mock user service auth error, please visit http://ooxx.net/user to sigup first'
|
||||
})
|
||||
.expect(401, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ var fs = require('fs');
|
||||
var path = require('path');
|
||||
var mysql = require('../../common/mysql');
|
||||
var Module = require('../../proxy/module');
|
||||
var config = require('../../config');
|
||||
|
||||
var fixtures = path.join(path.dirname(__dirname), 'fixtures');
|
||||
|
||||
@@ -173,4 +174,26 @@ describe('proxy/module.test.js', function () {
|
||||
yield* Module.removeTagsByNames('foo', ['latest', '1.0']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('listPrivates()', function () {
|
||||
it('should response [] if scopes not present', function* () {
|
||||
mm(config, 'scopes', []);
|
||||
var modules = yield Module.listPrivates();
|
||||
modules.should.eql([]);
|
||||
});
|
||||
|
||||
it('should response [] if private modules not present', function* () {
|
||||
mm(config, 'privatePackages', []);
|
||||
mm(config, 'scopes', ['@not-exist']);
|
||||
var modules = yield Module.listPrivates();
|
||||
modules.should.eql([]);
|
||||
});
|
||||
|
||||
it('should work', function* () {
|
||||
var modules = yield Module.listPrivates();
|
||||
modules.forEach(function (m) {
|
||||
m.should.have.keys(['name', 'description']);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
33
view/web/private.html
Normal file
33
view/web/private.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<style>
|
||||
#private .package {
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#private .alert a {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="private">
|
||||
<% if (!packages.length) { %>
|
||||
<div class="alert alert-warning">
|
||||
Can not found private package
|
||||
</div>
|
||||
<% } else {%>
|
||||
<h1>
|
||||
Private packages in this registry
|
||||
</h1>
|
||||
<hr />
|
||||
|
||||
<% for (var i = 0; i < packages.length; i++) {
|
||||
var item = packages[i];
|
||||
%>
|
||||
<div class="package">
|
||||
<a href="/package/<%= item.name %>" class="package-name"><%= item.name %></a>
|
||||
<span class="package-description"><%= item.description %></span>
|
||||
</div>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
Reference in New Issue
Block a user