verdaccio-security-filter 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +50 -16
- package/package.json +3 -2
package/build/index.js
CHANGED
|
@@ -193,7 +193,13 @@ class SecurityFilterPlugin {
|
|
|
193
193
|
this.logger.info(`[Middleware] Config mode: ${this.config.mode || 'NOT SET'}`);
|
|
194
194
|
app.use((req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
195
195
|
try {
|
|
196
|
-
|
|
196
|
+
let path = req.url.split('?')[0];
|
|
197
|
+
try {
|
|
198
|
+
path = decodeURIComponent(path);
|
|
199
|
+
}
|
|
200
|
+
catch (_a) {
|
|
201
|
+
}
|
|
202
|
+
const urlMatch = path.match(/^\/(@[^/]+\/)?([^/]+)(?:\/-\/([^/]+\.tgz))?/);
|
|
197
203
|
if (!urlMatch) {
|
|
198
204
|
this.logger.debug(`[Middleware] Non-package request: ${req.method} ${req.url}`);
|
|
199
205
|
return next();
|
|
@@ -269,14 +275,15 @@ class SecurityFilterPlugin {
|
|
|
269
275
|
filter_metadata(packageInfo) {
|
|
270
276
|
return __awaiter(this, void 0, void 0, function* () {
|
|
271
277
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
272
|
-
|
|
278
|
+
let pkg = packageInfo;
|
|
279
|
+
const packageName = pkg.name;
|
|
273
280
|
this.logger.info(`[filter_metadata] --> Processing: ${packageName}`);
|
|
274
281
|
try {
|
|
275
282
|
const blockResult = yield this._checkPackageBlock(packageName);
|
|
276
283
|
if (blockResult.blocked) {
|
|
277
284
|
this.logger.warn(`[filter_metadata] BLOCKED: ${packageName}@* - ${blockResult.reason}`);
|
|
278
285
|
this.metrics.recordBlock(packageName, '*', blockResult.reason);
|
|
279
|
-
return Object.assign(Object.assign({},
|
|
286
|
+
return Object.assign(Object.assign({}, pkg), { versions: {}, 'dist-tags': {}, security: {
|
|
280
287
|
blocked: true,
|
|
281
288
|
reason: blockResult.reason,
|
|
282
289
|
plugin: {
|
|
@@ -289,7 +296,7 @@ class SecurityFilterPlugin {
|
|
|
289
296
|
} });
|
|
290
297
|
}
|
|
291
298
|
if ((_a = this.config.cveCheck) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
292
|
-
const versions = Object.keys(
|
|
299
|
+
const versions = Object.keys(pkg.versions || {});
|
|
293
300
|
const vulnerableVersions = [];
|
|
294
301
|
const BATCH_SIZE = 10;
|
|
295
302
|
for (let i = 0; i < versions.length; i += BATCH_SIZE) {
|
|
@@ -310,7 +317,7 @@ class SecurityFilterPlugin {
|
|
|
310
317
|
const reason = `Package has ${vulnerableVersions.length} vulnerable version(s)`;
|
|
311
318
|
this.logger.warn(`[filter_metadata] CVE BLOCKED: ${packageName} - ${reason}`);
|
|
312
319
|
this.metrics.recordBlock(packageName, '*', reason);
|
|
313
|
-
return Object.assign(Object.assign({},
|
|
320
|
+
return Object.assign(Object.assign({}, pkg), { versions: {}, 'dist-tags': {}, security: {
|
|
314
321
|
blocked: true,
|
|
315
322
|
reason,
|
|
316
323
|
vulnerableVersions,
|
|
@@ -323,14 +330,14 @@ class SecurityFilterPlugin {
|
|
|
323
330
|
}
|
|
324
331
|
}
|
|
325
332
|
if (this.config.licenses && this.config.licenses.allowed && this.config.licenses.allowed.length > 0) {
|
|
326
|
-
const latestVersion = (_b =
|
|
327
|
-
if (latestVersion && ((_c =
|
|
328
|
-
const versionData =
|
|
333
|
+
const latestVersion = (_b = pkg['dist-tags']) === null || _b === void 0 ? void 0 : _b.latest;
|
|
334
|
+
if (latestVersion && ((_c = pkg.versions) === null || _c === void 0 ? void 0 : _c[latestVersion])) {
|
|
335
|
+
const versionData = pkg.versions[latestVersion];
|
|
329
336
|
const licenseResult = this.licenseChecker.checkLicense(versionData);
|
|
330
337
|
if (!licenseResult.allowed) {
|
|
331
338
|
this.logger.warn(`[filter_metadata] LICENSE BLOCKED: ${packageName} - ${licenseResult.reason}`);
|
|
332
339
|
this.metrics.recordBlock(packageName, '*', licenseResult.reason || 'License not allowed');
|
|
333
|
-
return Object.assign(Object.assign({},
|
|
340
|
+
return Object.assign(Object.assign({}, pkg), { versions: {}, 'dist-tags': {}, security: {
|
|
334
341
|
blocked: true,
|
|
335
342
|
reason: licenseResult.reason || 'License not allowed',
|
|
336
343
|
license: licenseResult.license,
|
|
@@ -344,11 +351,11 @@ class SecurityFilterPlugin {
|
|
|
344
351
|
}
|
|
345
352
|
}
|
|
346
353
|
if ((_d = this.config.packageAge) === null || _d === void 0 ? void 0 : _d.enabled) {
|
|
347
|
-
const ageResult = this.packageAgeChecker.checkPackageAge(
|
|
354
|
+
const ageResult = this.packageAgeChecker.checkPackageAge(pkg);
|
|
348
355
|
if (!ageResult.allowed && !ageResult.warnOnly) {
|
|
349
356
|
this.logger.warn(`[filter_metadata] AGE BLOCKED: ${packageName} - ${ageResult.reason}`);
|
|
350
357
|
this.metrics.recordBlock(packageName, '*', ageResult.reason || 'Package too new');
|
|
351
|
-
return Object.assign(Object.assign({},
|
|
358
|
+
return Object.assign(Object.assign({}, pkg), { versions: {}, 'dist-tags': {}, security: {
|
|
352
359
|
blocked: true,
|
|
353
360
|
reason: ageResult.reason || 'Package too new',
|
|
354
361
|
ageDays: ageResult.ageDays,
|
|
@@ -362,11 +369,38 @@ class SecurityFilterPlugin {
|
|
|
362
369
|
else if (!ageResult.allowed && ageResult.warnOnly) {
|
|
363
370
|
this.logger.warn(`[filter_metadata] AGE WARNING: ${packageName} - ${ageResult.reason} (warn-only mode)`);
|
|
364
371
|
}
|
|
372
|
+
if (this.config.packageAge.minVersionAgeDays) {
|
|
373
|
+
const filteredVersions = Object.assign({}, pkg.versions);
|
|
374
|
+
const removedVersions = [];
|
|
375
|
+
for (const version of Object.keys(filteredVersions)) {
|
|
376
|
+
const versionAgeResult = this.packageAgeChecker.checkVersionAge(pkg, version);
|
|
377
|
+
if (!versionAgeResult.allowed && !versionAgeResult.warnOnly) {
|
|
378
|
+
this.logger.warn(`[filter_metadata] VERSION AGE FILTERED: ${packageName}@${version} - ${versionAgeResult.reason}`);
|
|
379
|
+
this.metrics.recordBlock(packageName, version, versionAgeResult.reason || 'Version too new');
|
|
380
|
+
delete filteredVersions[version];
|
|
381
|
+
removedVersions.push(version);
|
|
382
|
+
}
|
|
383
|
+
else if (!versionAgeResult.allowed && versionAgeResult.warnOnly) {
|
|
384
|
+
this.logger.warn(`[filter_metadata] VERSION AGE WARNING: ${packageName}@${version} - ${versionAgeResult.reason} (warn-only mode)`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (removedVersions.length > 0) {
|
|
388
|
+
this.logger.info(`[filter_metadata] Removed ${removedVersions.length} too-new version(s) from ${packageName}: ${removedVersions.join(', ')}`);
|
|
389
|
+
const filteredDistTags = Object.assign({}, pkg['dist-tags']);
|
|
390
|
+
for (const [tag, tagVersion] of Object.entries(filteredDistTags)) {
|
|
391
|
+
if (removedVersions.includes(tagVersion)) {
|
|
392
|
+
delete filteredDistTags[tag];
|
|
393
|
+
this.logger.debug(`[filter_metadata] Removed dist-tag "${tag}" pointing to filtered version ${tagVersion}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
pkg = Object.assign(Object.assign({}, pkg), { versions: filteredVersions, 'dist-tags': filteredDistTags });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
365
399
|
}
|
|
366
400
|
if ((_e = this.config.authorFilter) === null || _e === void 0 ? void 0 : _e.enabled) {
|
|
367
|
-
const latestVersion = (_f =
|
|
368
|
-
if (latestVersion && ((_g =
|
|
369
|
-
const versionData =
|
|
401
|
+
const latestVersion = (_f = pkg['dist-tags']) === null || _f === void 0 ? void 0 : _f.latest;
|
|
402
|
+
if (latestVersion && ((_g = pkg.versions) === null || _g === void 0 ? void 0 : _g[latestVersion])) {
|
|
403
|
+
const versionData = pkg.versions[latestVersion];
|
|
370
404
|
const authorResult = this.authorChecker.checkAuthor(versionData);
|
|
371
405
|
if (!authorResult.allowed && !this.config.authorFilter.warnOnly) {
|
|
372
406
|
this.logger.warn(`[filter_metadata] AUTHOR BLOCKED: ${packageName} - ${authorResult.reason}`);
|
|
@@ -381,7 +415,7 @@ class SecurityFilterPlugin {
|
|
|
381
415
|
authorInfo: authorResult.authorInfo,
|
|
382
416
|
},
|
|
383
417
|
});
|
|
384
|
-
return Object.assign(Object.assign({},
|
|
418
|
+
return Object.assign(Object.assign({}, pkg), { versions: {}, 'dist-tags': {}, security: {
|
|
385
419
|
blocked: true,
|
|
386
420
|
reason: authorResult.reason || 'Author not allowed',
|
|
387
421
|
blockedBy: authorResult.blockedBy,
|
|
@@ -399,7 +433,7 @@ class SecurityFilterPlugin {
|
|
|
399
433
|
}
|
|
400
434
|
}
|
|
401
435
|
this.logger.info(`[filter_metadata] [OK] ALLOWED: ${packageName}`);
|
|
402
|
-
return
|
|
436
|
+
return pkg;
|
|
403
437
|
}
|
|
404
438
|
catch (error) {
|
|
405
439
|
this.logger.error(`[filter_metadata] Error processing ${packageName}: ${error.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verdaccio-security-filter",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Advanced security filter plugin for Verdaccio with version range blocking and fallback strategies",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"typescript-eslint": "^8.0.0"
|
|
55
55
|
},
|
|
56
56
|
"overrides": {
|
|
57
|
-
"qs": "6.14.2"
|
|
57
|
+
"qs": "6.14.2",
|
|
58
|
+
"@cypress/request": "latest"
|
|
58
59
|
},
|
|
59
60
|
"author": {
|
|
60
61
|
"name": "Vitaliy Ponomarenko",
|