Skip to content
This repository has been archived by the owner on Jun 2, 2024. It is now read-only.

Commit

Permalink
feat: support package version block list (#1683)
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 authored Nov 23, 2021
1 parent 59a8476 commit 3c5bc9d
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 43 deletions.
5 changes: 5 additions & 0 deletions config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ var config = {
// if enable this option, must create module_abbreviated and package_readme table in database
enableAbbreviatedMetadata: false,

// enable package or package version block list, must create package_version_blocklist table in database
enableBlockPackageVersion: false,

// global hook function: function* (envelope) {}
// envelope format please see https://github.com/npm/registry/blob/master/docs/hooks/hooks-payload.md#payload
globalHook: null,
Expand Down Expand Up @@ -334,6 +337,8 @@ if (process.env.NODE_ENV === 'test') {
yield next;
};
});

config.enableBlockPackageVersion = true;
}

if (process.env.NODE_ENV !== 'test') {
Expand Down
25 changes: 24 additions & 1 deletion controllers/registry/package/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var debug = require('debug')('cnpmjs.org:controllers:registry:package:list');
var utility = require('utility');
var packageService = require('../../../services/package');
var blocklistService = require('../../../services/blocklist');
var common = require('../../../lib/common');
var SyncModuleWorker = require('../../sync_module_worker');
var config = require('../../../config');
Expand All @@ -15,6 +16,13 @@ function etag(objs) {
return 'W/"' + utility.md5(JSON.stringify(objs)) + '"';
}

function filterBlockVerions(rows, blocks) {
if (!blocks) {
return rows;
}
return rows.filter(row => !blocks[row.version]);
}

/**
* list all version of a module
* GET /:name
Expand Down Expand Up @@ -63,9 +71,22 @@ module.exports = function* list() {
var rs = yield [
packageService.getModuleLastModified(name),
packageService.listModuleTags(name),
blocklistService.findBlockPackageVersions(name),
];
var modifiedTime = rs[0];
var tags = rs[1];
var blocks = rs[2];

if (blocks && blocks['*']) {
this.status = 451;
const error = `[block] package was blocked, reason: ${blocks['*'].reason}`;
this.jsonp = {
name,
error,
reason: error,
};
return;
}

debug('show %s, last modified: %s, tags: %j', name, modifiedTime, tags);
if (modifiedTime) {
Expand All @@ -89,11 +110,13 @@ module.exports = function* list() {

if (needAbbreviatedMeta) {
var rows = yield packageService.listModuleAbbreviatedsByName(name);
rows = filterBlockVerions(rows, blocks);
if (rows.length > 0) {
yield handleAbbreviatedMetaRequest(this, name, modifiedTime, tags, rows, cacheKey);
return;
}
var fullRows = yield packageService.listModulesByName(name);
fullRows = filterBlockVerions(fullRows, blocks);
if (fullRows.length > 0) {
// no abbreviated meta rows, use the full meta convert to abbreviated meta
yield handleAbbreviatedMetaRequestWithFullMeta(this, name, modifiedTime, tags, fullRows);
Expand All @@ -106,7 +129,7 @@ module.exports = function* list() {
packageService.listStarUserNames(name),
packageService.listMaintainers(name),
];
var rows = r[0];
var rows = filterBlockVerions(r[0], blocks);
var starUsers = r[1];
var maintainers = r[2];

Expand Down
11 changes: 11 additions & 0 deletions controllers/web/package/show.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var utils = require('../../utils');
var setDownloadURL = require('../../../lib/common').setDownloadURL;
var renderMarkdown = require('../../../common/markdown').render;
var packageService = require('../../../services/package');
var blocklistService = require('../../../services/blocklist');
var downloadTotalService = require('../../../services/download_total');

module.exports = function* show(next) {
Expand Down Expand Up @@ -71,6 +72,16 @@ module.exports = function* show(next) {
return yield next;
}

var blocks = yield blocklistService.findBlockPackageVersions(name);
if (blocks) {
var block = blocks['*'] || blocks[pkg.version];
if (block) {
this.status = 451;
this.body = `[block] package@${pkg.version} was blocked, reason: ${block.reason}`;
return;
}
}

var r = yield [
utils.getDownloadTotal(name),
packageService.listDependents(name),
Expand Down
11 changes: 11 additions & 0 deletions docs/db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,14 @@ CREATE TABLE IF NOT EXISTS `token` (
UNIQUE KEY `uk_token` (`token`),
KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='token info';

CREATE TABLE IF NOT EXISTS `package_version_blocklist` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`gmt_create` datetime(3) NOT NULL COMMENT 'create time',
`gmt_modified` datetime(3) NOT NULL COMMENT 'modified time',
`name` varchar(214) NOT NULL COMMENT 'package name',
`version` varchar(30) NOT NULL COMMENT 'package version, "*" meaning all versions',
`reason` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT 'block reason',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_name_version` (`name`, `version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='package version block list';
29 changes: 29 additions & 0 deletions models/block_package_version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

module.exports = function (sequelize, DataTypes) {
return sequelize.define('BlockPackageVersion', {
name: {
type: DataTypes.STRING(214),
allowNull: false,
comment: 'package name'
},
version: {
type: DataTypes.STRING(30),
allowNull: false,
comment: 'package version'
},
reason: {
type: DataTypes.LONGTEXT,
comment: 'block reason',
},
}, {
tableName: 'package_version_blocklist',
comment: 'package version block list',
indexes: [
{
unique: true,
fields: ['name', 'version'],
},
],
});
};
14 changes: 0 additions & 14 deletions models/download_total.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
/**!
* cnpmjs.org - models/download_total.js
*
* Copyright(c) fengmk2 and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <[email protected]> (http://fengmk2.github.com)
*/

'use strict';

/**
* Module dependencies.
*/

// CREATE TABLE IF NOT EXISTS `downloads` (
// `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
// `gmt_create` datetime NOT NULL COMMENT 'create time',
Expand Down
11 changes: 11 additions & 0 deletions models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function load(name) {

var _ModuleAbbreviated = config.enableAbbreviatedMetadata ? load('module_abbreviated') : null;
var _PackageReadme = config.enableAbbreviatedMetadata ? load('package_readme') : null;
var _BlockPackageVersion = config.enableBlockPackageVersion ? load('block_package_version') : null;

module.exports = {
sequelize: sequelize,
Expand Down Expand Up @@ -60,4 +61,14 @@ module.exports = {
}
return _PackageReadme;
},

get BlockPackageVersion() {
if (!config.enableBlockPackageVersion) {
return null;
}
if (!_BlockPackageVersion) {
_BlockPackageVersion = load('block_package_version');
}
return _BlockPackageVersion;
}
};
14 changes: 0 additions & 14 deletions models/total.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
/**!
* cnpmjs.org - models/total.js
*
* Copyright(c) fengmk2 and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <[email protected]> (http://fengmk2.github.com)
*/

'use strict';

/**
* Module dependencies.
*/

// CREATE TABLE IF NOT EXISTS `total` (
// `name` varchar(214) NOT NULL COMMENT 'total name',
// `gmt_modified` datetime NOT NULL COMMENT 'modified time',
Expand Down
28 changes: 28 additions & 0 deletions services/blocklist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

const BlockPackageVersion = require('../models').BlockPackageVersion;

exports.blockPackageVersion = function* (name, version, reason) {
const row = yield BlockPackageVersion.findOne({ where: { name, version } });
if (row) {
row.reason = reason;
yield row.save();
} else {
yield BlockPackageVersion.create({ name, version, reason });
}
};

exports.findBlockPackageVersions = function* (name) {
if (!BlockPackageVersion) {
return null;
}
const rows = yield BlockPackageVersion.findAll({ where: { name } });
if (rows.length === 0) {
return null;
}
const blocks = {};
for (const row of rows) {
blocks[row.version] = row;
}
return blocks;
};
58 changes: 58 additions & 0 deletions test/controllers/registry/package/list.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var request = require('supertest');
var mm = require('mm');
var pedding = require('pedding');
var packageService = require('../../../../services/package');
var blocklistService = require('../../../../services/blocklist');
var app = require('../../../../servers/registry');
var utils = require('../../../utils');
var config = require('../../../../config');
Expand Down Expand Up @@ -44,6 +45,63 @@ describe('test/controllers/registry/package/list.test.js', () => {
});
});

describe('block versions', () => {
before(function* () {
var pkg = utils.getPackage('@cnpmtest/testmodule-list-block', '0.0.1', utils.otherUser);
pkg.versions['0.0.1'].dependencies = {
bytetest: '~0.0.1',
mocha: '~1.0.0',
};
pkg.versions['0.0.1'].scripts = {
install: 'node -v',
};
yield request(app)
.put('/' + pkg.name)
.set('authorization', utils.otherUserAuth)
.send(pkg)
.expect(201);

pkg = utils.getPackage('@cnpmtest/testmodule-list-block', '1.0.0', utils.otherUser);
pkg.versions['1.0.0'].dependencies = {
bytetest: '~0.0.1',
mocha: '~1.0.0'
};
yield request(app)
.put('/' + pkg.name)
.set('authorization', utils.otherUserAuth)
.send(pkg)
.expect(201);
});

it('should block one version and all versions', function* () {
yield blocklistService.blockPackageVersion('@cnpmtest/testmodule-list-block', '0.0.1', 'unittest');
let res = yield request(app)
.get('/@cnpmtest/testmodule-list-block')
.expect(200);
let data = res.body;
assert(Object.keys(data.versions).length === 1);
assert(data.versions['1.0.0']);
assert(!data.versions['0.0.1']);

res = yield request(app)
.get('/@cnpmtest/testmodule-list-block')
.set('Accept', 'application/vnd.npm.install-v1+json')
.expect(200);
data = res.body;
assert(Object.keys(data.versions).length === 1);
assert(data.versions['1.0.0']);
assert(!data.versions['0.0.1']);

yield blocklistService.blockPackageVersion('@cnpmtest/testmodule-list-block', '*', 'unittest');
res = yield request(app)
.get('/@cnpmtest/testmodule-list-block')
.expect(451);
data = res.body;
console.log(data);
assert(data.error === '[block] package was blocked, reason: unittest');
});
});

it('should use costomized registry middleware', done => {
request(app)
.get('/@cnpmtest/testmodule-list-1')
Expand Down
37 changes: 37 additions & 0 deletions test/controllers/web/package/show.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

var should = require('should');
var assert = require('assert');
var request = require('supertest');
var mm = require('mm');
var config = require('../../../../config');
var app = require('../../../../servers/web');
var registry = require('../../../../servers/registry');
var blocklistService = require('../../../../services/blocklist');
var utils = require('../../../utils');

describe('test/controllers/web/package/show.test.js', () => {
Expand Down Expand Up @@ -55,6 +57,41 @@ describe('test/controllers/web/package/show.test.js', () => {
});
});

it('should get block package', function* () {
var pkg = utils.getPackage('@cnpmtest/testmodule-web-show-block', '0.0.1', utils.admin);
pkg.versions['0.0.1'].dependencies = {
bytetest: '~0.0.1',
mocha: '~1.0.0',
'testmodule-web-show': '0.0.1'
};
yield request(registry)
.put('/' + pkg.name)
.set('authorization', utils.adminAuth)
.send(pkg)
.expect(201);

yield blocklistService.blockPackageVersion('@cnpmtest/testmodule-web-show-block', '0.0.1', 'unittest');
let res = yield request(app)
.get('/package/@cnpmtest/testmodule-web-show-block')
.expect(451)
.expect('content-type', 'text/plain; charset=utf-8');
assert(res.text === '[block] [email protected] was blocked, reason: unittest');

yield blocklistService.blockPackageVersion('@cnpmtest/testmodule-web-show-block', '0.0.1', 'unittest');
res = yield request(app)
.get('/package/@cnpmtest/testmodule-web-show-block/0.0.1')
.expect(451)
.expect('content-type', 'text/plain; charset=utf-8');
assert(res.text === '[block] [email protected] was blocked, reason: unittest');

yield blocklistService.blockPackageVersion('@cnpmtest/testmodule-web-show-block', '*', 'block all');
res = yield request(app)
.get('/package/@cnpmtest/testmodule-web-show-block')
.expect(451)
.expect('content-type', 'text/plain; charset=utf-8');
assert(res.text === '[block] [email protected] was blocked, reason: block all');
});

it('should get scoped package', function (done) {
request(app)
.get('/package/@cnpmtest/testmodule-web-show')
Expand Down
Loading

0 comments on commit 3c5bc9d

Please sign in to comment.