verdaccio-security-filter 1.0.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/LICENSE +21 -0
- package/README.md +672 -0
- package/build/index.d.ts +86 -0
- package/build/index.js +559 -0
- package/build/lib/cve-checker.d.ts +43 -0
- package/build/lib/cve-checker.js +256 -0
- package/build/lib/license-checker.d.ts +37 -0
- package/build/lib/license-checker.js +124 -0
- package/build/lib/logger.d.ts +42 -0
- package/build/lib/logger.js +95 -0
- package/build/lib/metrics.d.ts +54 -0
- package/build/lib/metrics.js +202 -0
- package/build/lib/package-age-checker.d.ts +49 -0
- package/build/lib/package-age-checker.js +138 -0
- package/build/lib/whitelist-checker.d.ts +48 -0
- package/build/lib/whitelist-checker.js +168 -0
- package/build/types.d.ts +114 -0
- package/build/types.js +2 -0
- package/package.json +73 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CVECheckConfig, CVECheckResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* CVE Checker that integrates with vulnerability databases
|
|
4
|
+
*/
|
|
5
|
+
export declare class CVEChecker {
|
|
6
|
+
private config;
|
|
7
|
+
private cache;
|
|
8
|
+
private lastUpdate;
|
|
9
|
+
constructor(config?: CVECheckConfig);
|
|
10
|
+
/**
|
|
11
|
+
* Check if a package version has known vulnerabilities
|
|
12
|
+
*/
|
|
13
|
+
checkPackage(packageName: string, version: string): Promise<CVECheckResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Fetch vulnerabilities from configured databases
|
|
16
|
+
*/
|
|
17
|
+
private fetchVulnerabilities;
|
|
18
|
+
/**
|
|
19
|
+
* Fetch vulnerabilities from OSV (Open Source Vulnerabilities) database
|
|
20
|
+
* https://osv.dev/
|
|
21
|
+
*/
|
|
22
|
+
private fetchFromOSV;
|
|
23
|
+
/**
|
|
24
|
+
* Map OSV severity to our severity levels
|
|
25
|
+
*/
|
|
26
|
+
private mapOSVSeverity;
|
|
27
|
+
/**
|
|
28
|
+
* Check if cache is stale
|
|
29
|
+
*/
|
|
30
|
+
private isCacheStale;
|
|
31
|
+
/**
|
|
32
|
+
* Load cache from disk
|
|
33
|
+
*/
|
|
34
|
+
private loadCache;
|
|
35
|
+
/**
|
|
36
|
+
* Save cache to disk
|
|
37
|
+
*/
|
|
38
|
+
private saveCache;
|
|
39
|
+
/**
|
|
40
|
+
* Clear cache
|
|
41
|
+
*/
|
|
42
|
+
clearCache(): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.CVEChecker = void 0;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
/**
|
|
49
|
+
* CVE Checker that integrates with vulnerability databases
|
|
50
|
+
*/
|
|
51
|
+
class CVEChecker {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.cache = new Map();
|
|
54
|
+
this.lastUpdate = 0;
|
|
55
|
+
this.config = {
|
|
56
|
+
enabled: (config === null || config === void 0 ? void 0 : config.enabled) || false,
|
|
57
|
+
databases: (config === null || config === void 0 ? void 0 : config.databases) || ['osv'],
|
|
58
|
+
severity: (config === null || config === void 0 ? void 0 : config.severity) || ['high', 'critical'],
|
|
59
|
+
autoBlock: (config === null || config === void 0 ? void 0 : config.autoBlock) || false,
|
|
60
|
+
updateInterval: (config === null || config === void 0 ? void 0 : config.updateInterval) || 24,
|
|
61
|
+
cacheDir: (config === null || config === void 0 ? void 0 : config.cacheDir) || './.security-cache',
|
|
62
|
+
};
|
|
63
|
+
if (this.config.enabled) {
|
|
64
|
+
this.loadCache();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a package version has known vulnerabilities
|
|
69
|
+
*/
|
|
70
|
+
checkPackage(packageName, version) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
if (!this.config.enabled) {
|
|
73
|
+
return {
|
|
74
|
+
package: packageName,
|
|
75
|
+
version,
|
|
76
|
+
vulnerabilities: [],
|
|
77
|
+
isVulnerable: false,
|
|
78
|
+
checkedAt: new Date().toISOString(),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const cacheKey = `${packageName}@${version}`;
|
|
82
|
+
// Check cache first
|
|
83
|
+
if (this.cache.has(cacheKey) && !this.isCacheStale()) {
|
|
84
|
+
return this.cache.get(cacheKey);
|
|
85
|
+
}
|
|
86
|
+
// Fetch from databases
|
|
87
|
+
const vulnerabilities = yield this.fetchVulnerabilities(packageName, version);
|
|
88
|
+
// Filter by configured severity
|
|
89
|
+
const filteredVulnerabilities = vulnerabilities.filter(vuln => this.config.severity.includes(vuln.severity));
|
|
90
|
+
const result = {
|
|
91
|
+
package: packageName,
|
|
92
|
+
version,
|
|
93
|
+
vulnerabilities: filteredVulnerabilities,
|
|
94
|
+
isVulnerable: filteredVulnerabilities.length > 0,
|
|
95
|
+
checkedAt: new Date().toISOString(),
|
|
96
|
+
};
|
|
97
|
+
// Cache result
|
|
98
|
+
this.cache.set(cacheKey, result);
|
|
99
|
+
this.saveCache();
|
|
100
|
+
return result;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Fetch vulnerabilities from configured databases
|
|
105
|
+
*/
|
|
106
|
+
fetchVulnerabilities(packageName, version) {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
const vulnerabilities = [];
|
|
109
|
+
for (const database of this.config.databases) {
|
|
110
|
+
try {
|
|
111
|
+
switch (database) {
|
|
112
|
+
case 'osv':
|
|
113
|
+
vulnerabilities.push(...yield this.fetchFromOSV(packageName, version));
|
|
114
|
+
break;
|
|
115
|
+
case 'snyk':
|
|
116
|
+
// Snyk integration would go here (requires API key)
|
|
117
|
+
break;
|
|
118
|
+
case 'github':
|
|
119
|
+
// GitHub Advisory Database integration would go here
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
+
console.error(`[CVE Checker] Error fetching from ${database}:`, message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return vulnerabilities;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Fetch vulnerabilities from OSV (Open Source Vulnerabilities) database
|
|
133
|
+
* https://osv.dev/
|
|
134
|
+
*/
|
|
135
|
+
fetchFromOSV(packageName, version) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
try {
|
|
138
|
+
const response = yield fetch('https://api.osv.dev/v1/query', {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
},
|
|
143
|
+
body: JSON.stringify({
|
|
144
|
+
package: {
|
|
145
|
+
name: packageName,
|
|
146
|
+
ecosystem: 'npm',
|
|
147
|
+
},
|
|
148
|
+
version: version,
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
throw new Error(`OSV API returned ${response.status}`);
|
|
153
|
+
}
|
|
154
|
+
const data = yield response.json();
|
|
155
|
+
if (!data.vulns || data.vulns.length === 0) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
return data.vulns.map((vuln) => {
|
|
159
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
160
|
+
return ({
|
|
161
|
+
id: vuln.id,
|
|
162
|
+
severity: this.mapOSVSeverity(vuln.severity),
|
|
163
|
+
summary: vuln.summary || vuln.details || 'No description available',
|
|
164
|
+
affectedVersions: ((_a = vuln.affected) === null || _a === void 0 ? void 0 : _a.map((a) => { var _a; return (_a = a.ranges) === null || _a === void 0 ? void 0 : _a.map((r) => { var _a; return (_a = r.events) === null || _a === void 0 ? void 0 : _a.map((e) => e.introduced || e.fixed).filter(Boolean); }).flat(); }).flat()) || [],
|
|
165
|
+
fixedVersion: (_g = (_f = (_e = (_d = (_c = (_b = vuln.affected) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.ranges) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.events) === null || _f === void 0 ? void 0 : _f.find((e) => e.fixed)) === null || _g === void 0 ? void 0 : _g.fixed,
|
|
166
|
+
publishedDate: vuln.published || new Date().toISOString(),
|
|
167
|
+
source: 'osv',
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
173
|
+
console.error('[CVE Checker] OSV API error:', message);
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Map OSV severity to our severity levels
|
|
180
|
+
*/
|
|
181
|
+
mapOSVSeverity(osvSeverity) {
|
|
182
|
+
if (!osvSeverity || osvSeverity.length === 0) {
|
|
183
|
+
return 'medium';
|
|
184
|
+
}
|
|
185
|
+
// OSV uses CVSS scores
|
|
186
|
+
const severity = osvSeverity[0];
|
|
187
|
+
if (severity.type === 'CVSS_V3') {
|
|
188
|
+
const score = parseFloat(severity.score);
|
|
189
|
+
if (score >= 9.0)
|
|
190
|
+
return 'critical';
|
|
191
|
+
if (score >= 7.0)
|
|
192
|
+
return 'high';
|
|
193
|
+
if (score >= 4.0)
|
|
194
|
+
return 'medium';
|
|
195
|
+
return 'low';
|
|
196
|
+
}
|
|
197
|
+
return 'medium';
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Check if cache is stale
|
|
201
|
+
*/
|
|
202
|
+
isCacheStale() {
|
|
203
|
+
const now = Date.now();
|
|
204
|
+
const updateIntervalMs = this.config.updateInterval * 60 * 60 * 1000;
|
|
205
|
+
return now - this.lastUpdate > updateIntervalMs;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Load cache from disk
|
|
209
|
+
*/
|
|
210
|
+
loadCache() {
|
|
211
|
+
try {
|
|
212
|
+
const cacheFile = path.join(this.config.cacheDir, 'cve-cache.json');
|
|
213
|
+
if (fs.existsSync(cacheFile)) {
|
|
214
|
+
const data = fs.readFileSync(cacheFile, 'utf8');
|
|
215
|
+
const parsed = JSON.parse(data);
|
|
216
|
+
this.cache = new Map(Object.entries(parsed.cache));
|
|
217
|
+
this.lastUpdate = parsed.lastUpdate || 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
222
|
+
console.error('[CVE Checker] Failed to load cache:', message);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Save cache to disk
|
|
227
|
+
*/
|
|
228
|
+
saveCache() {
|
|
229
|
+
try {
|
|
230
|
+
const cacheFile = path.join(this.config.cacheDir, 'cve-cache.json');
|
|
231
|
+
const dir = path.dirname(cacheFile);
|
|
232
|
+
if (!fs.existsSync(dir)) {
|
|
233
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
const data = {
|
|
236
|
+
cache: Object.fromEntries(this.cache),
|
|
237
|
+
lastUpdate: Date.now(),
|
|
238
|
+
};
|
|
239
|
+
fs.writeFileSync(cacheFile, JSON.stringify(data, null, 2), 'utf8');
|
|
240
|
+
this.lastUpdate = Date.now();
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
244
|
+
console.error('[CVE Checker] Failed to save cache:', message);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Clear cache
|
|
249
|
+
*/
|
|
250
|
+
clearCache() {
|
|
251
|
+
this.cache.clear();
|
|
252
|
+
this.lastUpdate = 0;
|
|
253
|
+
this.saveCache();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
exports.CVEChecker = CVEChecker;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LicenseConfig } from '../types';
|
|
2
|
+
import { Version } from '@verdaccio/types';
|
|
3
|
+
/**
|
|
4
|
+
* License checker for validating package licenses
|
|
5
|
+
*/
|
|
6
|
+
export declare class LicenseChecker {
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config?: LicenseConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Check if a package version's license is allowed
|
|
11
|
+
*/
|
|
12
|
+
checkLicense(versionData: Version): {
|
|
13
|
+
allowed: boolean;
|
|
14
|
+
reason?: string;
|
|
15
|
+
license?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Extract license from version data
|
|
19
|
+
*/
|
|
20
|
+
private extractLicense;
|
|
21
|
+
/**
|
|
22
|
+
* Check if license is blocked
|
|
23
|
+
*/
|
|
24
|
+
private isLicenseBlocked;
|
|
25
|
+
/**
|
|
26
|
+
* Check if license is allowed
|
|
27
|
+
*/
|
|
28
|
+
private isLicenseAllowed;
|
|
29
|
+
/**
|
|
30
|
+
* Get common open source licenses
|
|
31
|
+
*/
|
|
32
|
+
static getCommonOpenSourceLicenses(): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Get common copyleft licenses
|
|
35
|
+
*/
|
|
36
|
+
static getCopyleftLicenses(): string[];
|
|
37
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LicenseChecker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* License checker for validating package licenses
|
|
6
|
+
*/
|
|
7
|
+
class LicenseChecker {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = {
|
|
10
|
+
allowed: (config === null || config === void 0 ? void 0 : config.allowed) || [],
|
|
11
|
+
blocked: (config === null || config === void 0 ? void 0 : config.blocked) || [],
|
|
12
|
+
requireLicense: (config === null || config === void 0 ? void 0 : config.requireLicense) !== false,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if a package version's license is allowed
|
|
17
|
+
*/
|
|
18
|
+
checkLicense(versionData) {
|
|
19
|
+
const license = this.extractLicense(versionData);
|
|
20
|
+
// Check if license is missing
|
|
21
|
+
if (!license || license === 'UNLICENSED' || license === '') {
|
|
22
|
+
if (this.config.requireLicense) {
|
|
23
|
+
return {
|
|
24
|
+
allowed: false,
|
|
25
|
+
reason: 'Package does not specify a license',
|
|
26
|
+
license: license || 'none',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { allowed: true };
|
|
30
|
+
}
|
|
31
|
+
// Check blocked list
|
|
32
|
+
if (this.isLicenseBlocked(license)) {
|
|
33
|
+
return {
|
|
34
|
+
allowed: false,
|
|
35
|
+
reason: `License '${license}' is in blocked list`,
|
|
36
|
+
license,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Check allowed list (if specified)
|
|
40
|
+
if (this.config.allowed.length > 0 && !this.isLicenseAllowed(license)) {
|
|
41
|
+
return {
|
|
42
|
+
allowed: false,
|
|
43
|
+
reason: `License '${license}' is not in allowed list`,
|
|
44
|
+
license,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { allowed: true, license };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extract license from version data
|
|
51
|
+
*/
|
|
52
|
+
extractLicense(versionData) {
|
|
53
|
+
if (!versionData.license) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
// Handle string license
|
|
57
|
+
if (typeof versionData.license === 'string') {
|
|
58
|
+
return versionData.license;
|
|
59
|
+
}
|
|
60
|
+
// Handle SPDX license object
|
|
61
|
+
if (typeof versionData.license === 'object' && 'type' in versionData.license) {
|
|
62
|
+
return versionData.license.type;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if license is blocked
|
|
68
|
+
*/
|
|
69
|
+
isLicenseBlocked(license) {
|
|
70
|
+
return this.config.blocked.some(blocked => {
|
|
71
|
+
// Exact match
|
|
72
|
+
if (blocked === license) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
// Handle SPDX expressions (e.g., "MIT OR Apache-2.0")
|
|
76
|
+
const licenseTokens = license.split(/\s+(?:OR|AND)\s+/i);
|
|
77
|
+
return licenseTokens.some(token => token.trim() === blocked);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if license is allowed
|
|
82
|
+
*/
|
|
83
|
+
isLicenseAllowed(license) {
|
|
84
|
+
return this.config.allowed.some(allowed => {
|
|
85
|
+
// Exact match
|
|
86
|
+
if (allowed === license) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
// Handle SPDX expressions (e.g., "MIT OR Apache-2.0")
|
|
90
|
+
const licenseTokens = license.split(/\s+(?:OR|AND)\s+/i);
|
|
91
|
+
return licenseTokens.some(token => token.trim() === allowed);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get common open source licenses
|
|
96
|
+
*/
|
|
97
|
+
static getCommonOpenSourceLicenses() {
|
|
98
|
+
return [
|
|
99
|
+
'MIT',
|
|
100
|
+
'Apache-2.0',
|
|
101
|
+
'BSD-2-Clause',
|
|
102
|
+
'BSD-3-Clause',
|
|
103
|
+
'ISC',
|
|
104
|
+
'0BSD',
|
|
105
|
+
'CC0-1.0',
|
|
106
|
+
'Unlicense',
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get common copyleft licenses
|
|
111
|
+
*/
|
|
112
|
+
static getCopyleftLicenses() {
|
|
113
|
+
return [
|
|
114
|
+
'GPL-2.0',
|
|
115
|
+
'GPL-3.0',
|
|
116
|
+
'AGPL-3.0',
|
|
117
|
+
'LGPL-2.1',
|
|
118
|
+
'LGPL-3.0',
|
|
119
|
+
'MPL-2.0',
|
|
120
|
+
'EPL-2.0',
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.LicenseChecker = LicenseChecker;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Logger } from '@verdaccio/types';
|
|
2
|
+
import { LoggerConfig } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Enhanced logger wrapper with configurable log levels and formatting
|
|
5
|
+
*/
|
|
6
|
+
export declare class SecurityLogger {
|
|
7
|
+
private verdaccioLogger;
|
|
8
|
+
private config;
|
|
9
|
+
private readonly prefix;
|
|
10
|
+
constructor(verdaccioLogger: Logger, config?: LoggerConfig);
|
|
11
|
+
private shouldLog;
|
|
12
|
+
private formatMessage;
|
|
13
|
+
trace(message: string, ...args: any[]): void;
|
|
14
|
+
debug(message: string, ...args: any[]): void;
|
|
15
|
+
info(message: string, ...args: any[]): void;
|
|
16
|
+
warn(message: string, ...args: any[]): void;
|
|
17
|
+
error(message: string, ...args: any[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Log package blocking event
|
|
20
|
+
*/
|
|
21
|
+
logBlock(packageName: string, version: string, reason: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Log fallback event
|
|
24
|
+
*/
|
|
25
|
+
logFallback(packageName: string, fromVersion: string, toVersion: string, reason?: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Log CVE detection
|
|
28
|
+
*/
|
|
29
|
+
logCVE(packageName: string, version: string, cveId: string, severity: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Log license violation
|
|
32
|
+
*/
|
|
33
|
+
logLicense(packageName: string, version: string, license: string, reason: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Log publish rejection
|
|
36
|
+
*/
|
|
37
|
+
logPublishRejected(packageName: string, version: string, reason: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Log initialization
|
|
40
|
+
*/
|
|
41
|
+
logInit(features: string[]): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurityLogger = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Enhanced logger wrapper with configurable log levels and formatting
|
|
6
|
+
*/
|
|
7
|
+
class SecurityLogger {
|
|
8
|
+
constructor(verdaccioLogger, config) {
|
|
9
|
+
this.prefix = '[Security Filter]';
|
|
10
|
+
this.verdaccioLogger = verdaccioLogger;
|
|
11
|
+
this.config = {
|
|
12
|
+
level: (config === null || config === void 0 ? void 0 : config.level) || 'info',
|
|
13
|
+
enabled: (config === null || config === void 0 ? void 0 : config.enabled) !== false,
|
|
14
|
+
includeTimestamp: (config === null || config === void 0 ? void 0 : config.includeTimestamp) !== false,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
shouldLog(level) {
|
|
18
|
+
if (!this.config.enabled) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const levels = ['trace', 'debug', 'info', 'warn', 'error'];
|
|
22
|
+
const configLevel = levels.indexOf(this.config.level);
|
|
23
|
+
const messageLevel = levels.indexOf(level);
|
|
24
|
+
return messageLevel >= configLevel;
|
|
25
|
+
}
|
|
26
|
+
formatMessage(message) {
|
|
27
|
+
const timestamp = this.config.includeTimestamp
|
|
28
|
+
? `[${new Date().toISOString()}] `
|
|
29
|
+
: '';
|
|
30
|
+
return `${timestamp}${this.prefix} ${message}`;
|
|
31
|
+
}
|
|
32
|
+
trace(message, ...args) {
|
|
33
|
+
if (this.shouldLog('trace')) {
|
|
34
|
+
this.verdaccioLogger.trace(this.formatMessage(message), ...args);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
debug(message, ...args) {
|
|
38
|
+
if (this.shouldLog('debug')) {
|
|
39
|
+
this.verdaccioLogger.debug(this.formatMessage(message), ...args);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
info(message, ...args) {
|
|
43
|
+
if (this.shouldLog('info')) {
|
|
44
|
+
this.verdaccioLogger.info(this.formatMessage(message), ...args);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
warn(message, ...args) {
|
|
48
|
+
if (this.shouldLog('warn')) {
|
|
49
|
+
this.verdaccioLogger.warn(this.formatMessage(message), ...args);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
error(message, ...args) {
|
|
53
|
+
if (this.shouldLog('error')) {
|
|
54
|
+
this.verdaccioLogger.error(this.formatMessage(message), ...args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Log package blocking event
|
|
59
|
+
*/
|
|
60
|
+
logBlock(packageName, version, reason) {
|
|
61
|
+
this.warn(`Blocked ${packageName}@${version} - ${reason}`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Log fallback event
|
|
65
|
+
*/
|
|
66
|
+
logFallback(packageName, fromVersion, toVersion, reason) {
|
|
67
|
+
const reasonText = reason ? ` (${reason})` : '';
|
|
68
|
+
this.info(`Fallback applied: ${packageName}@${fromVersion} -> ${toVersion}${reasonText}`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Log CVE detection
|
|
72
|
+
*/
|
|
73
|
+
logCVE(packageName, version, cveId, severity) {
|
|
74
|
+
this.warn(`CVE detected: ${cveId} [${severity}] in ${packageName}@${version}`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Log license violation
|
|
78
|
+
*/
|
|
79
|
+
logLicense(packageName, version, license, reason) {
|
|
80
|
+
this.warn(`License violation: ${packageName}@${version} has ${license} - ${reason}`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Log publish rejection
|
|
84
|
+
*/
|
|
85
|
+
logPublishRejected(packageName, version, reason) {
|
|
86
|
+
this.warn(`Publish rejected: ${packageName}@${version} - ${reason}`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log initialization
|
|
90
|
+
*/
|
|
91
|
+
logInit(features) {
|
|
92
|
+
this.info(`Plugin initialized with features: ${features.join(', ')}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.SecurityLogger = SecurityLogger;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { MetricsConfig, MetricsData } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Metrics collector for tracking security events
|
|
4
|
+
*/
|
|
5
|
+
export declare class MetricsCollector {
|
|
6
|
+
private config;
|
|
7
|
+
private metricsBuffer;
|
|
8
|
+
private readonly bufferSize;
|
|
9
|
+
constructor(config?: MetricsConfig);
|
|
10
|
+
/**
|
|
11
|
+
* Record a security event
|
|
12
|
+
*/
|
|
13
|
+
record(event: MetricsData): void;
|
|
14
|
+
/**
|
|
15
|
+
* Record a block event
|
|
16
|
+
*/
|
|
17
|
+
recordBlock(packageName: string, version: string, reason: string, metadata?: Record<string, any>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Record a fallback event
|
|
20
|
+
*/
|
|
21
|
+
recordFallback(packageName: string, fromVersion: string, toVersion: string, reason: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Record a publish rejection
|
|
24
|
+
*/
|
|
25
|
+
recordPublishRejected(packageName: string, version: string, reason: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Record a CVE detection
|
|
28
|
+
*/
|
|
29
|
+
recordCVE(packageName: string, version: string, cveId: string, severity: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Record a license block
|
|
32
|
+
*/
|
|
33
|
+
recordLicenseBlock(packageName: string, version: string, license: string, reason: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Record a package-too-new event
|
|
36
|
+
*/
|
|
37
|
+
recordPackageTooNew(packageName: string, version: string, reason: string, metadata?: Record<string, any>): void;
|
|
38
|
+
/**
|
|
39
|
+
* Flush metrics buffer to output
|
|
40
|
+
*/
|
|
41
|
+
flush(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Write metrics to file
|
|
44
|
+
*/
|
|
45
|
+
private writeToFile;
|
|
46
|
+
/**
|
|
47
|
+
* Get metrics summary
|
|
48
|
+
*/
|
|
49
|
+
getSummary(): Record<string, number>;
|
|
50
|
+
/**
|
|
51
|
+
* Cleanup - flush remaining metrics
|
|
52
|
+
*/
|
|
53
|
+
cleanup(): void;
|
|
54
|
+
}
|