Showing 2 of 7 files from the diff.
controllers/sync_module_worker.js
changed.
Other files ignored by Codecov
package.json
has changed.
test/controllers/registry/package/list.test.js
has changed.
test/controllers/registry/package/save.test.js
has changed.
test/controllers/sync_module_worker.test.js
has changed.
.github/workflows/nodejs.yml
has changed.
@@ -1717,11 +1717,13 @@
Loading
1717 | 1717 | mod.package._publish_on_cnpm = true; |
|
1718 | 1718 | } |
|
1719 | 1719 | ||
1720 | - | var dist = { |
|
1720 | + | // keep orgin dist fields, like `integrity` and so on |
|
1721 | + | var dist = Object.assign({}, sourcePackage.dist, { |
|
1722 | + | tarball: '', |
|
1721 | 1723 | shasum: shasum, |
|
1722 | 1724 | size: dataSize, |
|
1723 | 1725 | noattachment: dataSize === 0, |
|
1724 | - | }; |
|
1726 | + | }); |
|
1725 | 1727 | ||
1726 | 1728 | if (result.url) { |
|
1727 | 1729 | dist.tarball = result.url; |
@@ -1,9 +1,10 @@
Loading
1 | 1 | 'use strict'; |
|
2 | 2 | ||
3 | 3 | var debug = require('debug')('cnpmjs.org:controllers:registry:package:save'); |
|
4 | - | var crypto = require('crypto'); |
|
4 | + | var ssri = require('ssri'); |
|
5 | 5 | var deprecateVersions = require('./deprecate'); |
|
6 | 6 | var packageService = require('../../../services/package'); |
|
7 | + | var logger = require('../../../common/logger'); |
|
7 | 8 | var common = require('../../../lib/common'); |
|
8 | 9 | var nfs = require('../../../common/nfs'); |
|
9 | 10 | var config = require('../../../config'); |
@@ -16,14 +17,42 @@
Loading
16 | 17 | // |
|
17 | 18 | // new flows: only one request |
|
18 | 19 | // PUT /:name |
|
19 | - | // https://github.com/npm/npm-registry-client/blob/master/lib/publish.js#L84 |
|
20 | + | // old publish: https://github.com/npm/npm-registry-client/blob/master/lib/publish.js#L84 |
|
21 | + | // new publish: https://github.com/npm/libnpmpublish/blob/main/publish.js#L91 |
|
20 | 22 | module.exports = function* save(next) { |
|
21 | - | // 'dist-tags': { latest: '0.0.2' }, |
|
22 | - | // _attachments: |
|
23 | - | // { 'nae-sandbox-0.0.2.tgz': |
|
24 | - | // { content_type: 'application/octet-stream', |
|
25 | - | // data: 'H4sIAAAAA |
|
26 | - | // length: 9883 |
|
23 | + | // { |
|
24 | + | // "_id": "@cnpm/foo", |
|
25 | + | // "name": "@cnpm/foo", |
|
26 | + | // "dist-tags": { |
|
27 | + | // "latest": "1.0.0" |
|
28 | + | // }, |
|
29 | + | // "versions": { |
|
30 | + | // "1.0.0": { |
|
31 | + | // "name": "@cnpm/foo", |
|
32 | + | // "version": "1.0.0", |
|
33 | + | // "dependencies": { |
|
34 | + | // "xprofiler": "^1.2.6" |
|
35 | + | // }, |
|
36 | + | // "readme": "ERROR: No README data found!", |
|
37 | + | // "_id": "@cnpm/foo@1.0.0", |
|
38 | + | // "_nodeVersion": "16.13.0", |
|
39 | + | // "_npmVersion": "8.1.0", |
|
40 | + | // "dist": { |
|
41 | + | // "integrity": "sha512-7nm0vpDEWs7y+tTwlxd7YnGaBc+9Gk5KaPsx2cqQz6H84ndBXlw5nMxGtL4Uy0bCQIknPAZAVe+KNheInmmJrQ==", |
|
42 | + | // "shasum": "afd05dcfb8759b9b1c7151492a04f2254365c602", |
|
43 | + | // "tarball": "http://127.0.0.1:7001/@cnpm/foo/-/@cnpm/foo-1.0.0.tgz" |
|
44 | + | // } |
|
45 | + | // } |
|
46 | + | // }, |
|
47 | + | // "access": null, |
|
48 | + | // "_attachments": { |
|
49 | + | // "@cnpm/foo-1.0.0.tgz": { |
|
50 | + | // "content_type": "application/octet-stream", |
|
51 | + | // "data": "H4sIAAAAAA...", |
|
52 | + | // "length": 208 |
|
53 | + | // } |
|
54 | + | // } |
|
55 | + | // } |
|
27 | 56 | var pkg = this.request.body; |
|
28 | 57 | var username = this.user.name; |
|
29 | 58 | var name = this.params.name || this.params[0]; |
@@ -150,7 +179,6 @@
Loading
150 | 179 | username, name, version, attachment.length, versionPackage.maintainers, distTags); |
|
151 | 180 | ||
152 | 181 | var exists = yield packageService.getModule(name, version); |
|
153 | - | var shasum; |
|
154 | 182 | if (exists) { |
|
155 | 183 | this.status = 403; |
|
156 | 184 | const error = '[forbidden] cannot modify pre-existing version: ' + version; |
@@ -186,21 +214,60 @@
Loading
186 | 214 | } |
|
187 | 215 | } |
|
188 | 216 | ||
189 | - | shasum = crypto.createHash('sha1'); |
|
190 | - | shasum.update(tarballBuffer); |
|
191 | - | shasum = shasum.digest('hex'); |
|
217 | + | var originDist = versionPackage.dist || {}; |
|
218 | + | var shasum; |
|
219 | + | var integrity = originDist.integrity; |
|
220 | + | // for content security reason |
|
221 | + | // check integrity |
|
222 | + | if (integrity) { |
|
223 | + | var algorithm = ssri.checkData(tarballBuffer, integrity); |
|
224 | + | if (!algorithm) { |
|
225 | + | logger.error('[registry:save:integrity:invalid] %s@%s, dist:%j', name, version, originDist); |
|
226 | + | this.status = 400; |
|
227 | + | const error = '[invalid] dist.integrity invalid'; |
|
228 | + | this.body = { |
|
229 | + | error, |
|
230 | + | reason: error, |
|
231 | + | }; |
|
232 | + | return; |
|
233 | + | } |
|
234 | + | var integrityObj = ssri.fromData(tarballBuffer, { |
|
235 | + | algorithms: ['sha1'], |
|
236 | + | }); |
|
237 | + | shasum = integrityObj.sha1[0].hexDigest(); |
|
238 | + | } else { |
|
239 | + | var integrityObj = ssri.fromData(tarballBuffer, { |
|
240 | + | algorithms: ['sha512', 'sha1'], |
|
241 | + | }); |
|
242 | + | integrity = integrityObj.sha512[0].toString(); |
|
243 | + | shasum = integrityObj.sha1[0].hexDigest(); |
|
244 | + | if (originDist.shasum && originDist.shasum !== shasum) { |
|
245 | + | // if integrity not exists, check shasum |
|
246 | + | logger.error('[registry:save:shasum:invalid] %s@%s, dist:%j', name, version, originDist); |
|
247 | + | this.status = 400; |
|
248 | + | const error = '[invalid] dist.shasum invalid'; |
|
249 | + | this.body = { |
|
250 | + | error, |
|
251 | + | reason: error, |
|
252 | + | }; |
|
253 | + | return; |
|
254 | + | } |
|
255 | + | } |
|
192 | 256 | ||
193 | 257 | var options = { |
|
194 | 258 | key: common.getCDNKey(name, filename), |
|
195 | - | shasum: shasum |
|
259 | + | shasum: shasum, |
|
260 | + | integrity: integrity, |
|
196 | 261 | }; |
|
197 | 262 | var uploadResult = yield nfs.uploadBuffer(tarballBuffer, options); |
|
198 | - | debug('upload %j', uploadResult); |
|
263 | + | debug('upload %j, options: %j', uploadResult, options); |
|
199 | 264 | ||
200 | - | var dist = { |
|
265 | + | var dist = Object.assign({}, originDist, { |
|
266 | + | tarball: '', |
|
267 | + | integrity: integrity, |
|
201 | 268 | shasum: shasum, |
|
202 | - | size: attachment.length |
|
203 | - | }; |
|
269 | + | size: attachment.length, |
|
270 | + | }); |
|
204 | 271 | ||
205 | 272 | // if nfs upload return a key, record it |
|
206 | 273 | if (uploadResult.url) { |
Files | Coverage |
---|---|
common | 67.39% |
controllers | 86.46% |
middleware | 94.34% |
models | 90.42% |
routes | 100.00% |
servers | 90.91% |
services | 90.86% |
sync | 89.61% |
config/index.js | 75.51% |
lib/common.js | 89.19% |
Project Totals (97 files) | 87.90% |
1438273009
1438273009
1438273009
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.