cryptoserve 0.1.1 → 0.1.3
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/lib/pqc-engine.mjs +9 -1
- package/lib/scanner.mjs +40 -6
- package/package.json +1 -1
package/lib/pqc-engine.mjs
CHANGED
|
@@ -487,7 +487,15 @@ function calculateQuantumScore(libraries, classifications) {
|
|
|
487
487
|
|
|
488
488
|
if (total === 0) return 100.0;
|
|
489
489
|
|
|
490
|
-
|
|
490
|
+
// Two scoring approaches:
|
|
491
|
+
// - Ratio: safe / total (good for large samples)
|
|
492
|
+
// - Penalty: 100 - 30 per vulnerable (good for small samples)
|
|
493
|
+
// Small samples (≤3 algorithms) produce extreme ratios (1/1 = 0% or 100%),
|
|
494
|
+
// so use whichever approach gives the more representative score.
|
|
495
|
+
const ratioScore = (safe / total) * 100;
|
|
496
|
+
const penaltyScore = Math.max(0, 100 - vulnerable * 30);
|
|
497
|
+
let score = total <= 3 ? Math.max(ratioScore, penaltyScore) : ratioScore;
|
|
498
|
+
|
|
491
499
|
if (classifications.some(c => c.category === 'pqc')) {
|
|
492
500
|
score = Math.min(100, score + 20);
|
|
493
501
|
}
|
package/lib/scanner.mjs
CHANGED
|
@@ -51,9 +51,15 @@ const IMPORT_PATTERNS = [
|
|
|
51
51
|
{ pattern: /createDecipheriv\s*\(/g, lib: 'node:crypto', detail: 'cipher' },
|
|
52
52
|
{ pattern: /createSign\s*\(/g, lib: 'node:crypto', detail: 'signature' },
|
|
53
53
|
{ pattern: /createVerify\s*\(/g, lib: 'node:crypto', detail: 'signature' },
|
|
54
|
+
{ pattern: /createHash\s*\(/g, lib: 'node:crypto', detail: 'hash' },
|
|
55
|
+
{ pattern: /createHmac\s*\(/g, lib: 'node:crypto', detail: 'hmac' },
|
|
54
56
|
{ pattern: /generateKeyPair(?:Sync)?\s*\(/g, lib: 'node:crypto', detail: 'keygen' },
|
|
57
|
+
{ pattern: /createDiffieHellman(?:Group)?\s*\(/g, lib: 'node:crypto', detail: 'keyagreement' },
|
|
58
|
+
{ pattern: /createECDH\s*\(/g, lib: 'node:crypto', detail: 'keyagreement' },
|
|
55
59
|
{ pattern: /scrypt(?:Sync)?\s*\(/g, lib: 'node:crypto', detail: 'kdf' },
|
|
56
60
|
{ pattern: /pbkdf2(?:Sync)?\s*\(/g, lib: 'node:crypto', detail: 'kdf' },
|
|
61
|
+
{ pattern: /randomBytes\s*\(/g, lib: 'node:crypto', detail: 'random' },
|
|
62
|
+
{ pattern: /randomUUID\s*\(/g, lib: 'node:crypto', detail: 'random' },
|
|
57
63
|
{ pattern: /createCipher\s*\(/g, lib: 'node:crypto', detail: 'DEPRECATED-no-iv' },
|
|
58
64
|
{ pattern: /CryptoJS\./g, lib: 'crypto-js' },
|
|
59
65
|
{ pattern: /forge\.\w+/g, lib: 'node-forge' },
|
|
@@ -69,6 +75,10 @@ const ALGO_LITERALS = [
|
|
|
69
75
|
{ pattern: /['"`]sha(?:256|384|512|1)['"`]/gi, algo: 'SHA-256' },
|
|
70
76
|
{ pattern: /['"`](?:HS|RS|ES|PS)(?:256|384|512)['"`]/gi, algo: 'RS256' },
|
|
71
77
|
{ pattern: /['"`]ed25519['"`]/gi, algo: 'Ed25519' },
|
|
78
|
+
{ pattern: /['"`]x25519['"`]/gi, algo: 'X25519' },
|
|
79
|
+
{ pattern: /['"`](?:ecdsa|ecdh|ec|secp256k1|secp384r1|prime256v1)['"`]/gi, algo: 'ECDSA' },
|
|
80
|
+
{ pattern: /['"`](?:rsa|rsa-pss)['"`]/gi, algo: 'RSA' },
|
|
81
|
+
{ pattern: /['"`](?:dsa)['"`]/gi, algo: 'DSA' },
|
|
72
82
|
{ pattern: /minVersion:\s*['"`]TLSv1\.[0-3]['"`]/g, algo: 'TLS' },
|
|
73
83
|
{ pattern: /['"`](?:md5|MD5)['"`]/g, algo: 'MD5' },
|
|
74
84
|
{ pattern: /['"`](?:des|DES|3des|3DES|des-ede3)['"`]/gi, algo: 'DES' },
|
|
@@ -169,9 +179,26 @@ export function scanProject(projectDir) {
|
|
|
169
179
|
filesScanned: 0,
|
|
170
180
|
};
|
|
171
181
|
|
|
172
|
-
// 1. Scan package.json for crypto dependencies
|
|
173
|
-
const
|
|
174
|
-
|
|
182
|
+
// 1. Scan package.json for crypto dependencies (root + monorepo workspaces)
|
|
183
|
+
const pkgPaths = [join(projectDir, 'package.json')];
|
|
184
|
+
// Check common monorepo locations for nested package.json files
|
|
185
|
+
const monorepoGlobs = ['apps', 'packages', 'libs', 'modules', 'services'];
|
|
186
|
+
for (const sub of monorepoGlobs) {
|
|
187
|
+
const subDir = join(projectDir, sub);
|
|
188
|
+
try {
|
|
189
|
+
const entries = readdirSync(subDir, { withFileTypes: true });
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (entry.isDirectory()) {
|
|
192
|
+
const nested = join(subDir, entry.name, 'package.json');
|
|
193
|
+
if (existsSync(nested)) pkgPaths.push(nested);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch { /* dir doesn't exist */ }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const seenPkgs = new Set();
|
|
200
|
+
for (const pkgPath of pkgPaths) {
|
|
201
|
+
if (!existsSync(pkgPath)) continue;
|
|
175
202
|
try {
|
|
176
203
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
177
204
|
const allDeps = {
|
|
@@ -180,7 +207,8 @@ export function scanProject(projectDir) {
|
|
|
180
207
|
};
|
|
181
208
|
|
|
182
209
|
for (const [name, version] of Object.entries(allDeps)) {
|
|
183
|
-
if (name in CRYPTO_PACKAGES) {
|
|
210
|
+
if (name in CRYPTO_PACKAGES && !seenPkgs.has(name)) {
|
|
211
|
+
seenPkgs.add(name);
|
|
184
212
|
const info = CRYPTO_PACKAGES[name];
|
|
185
213
|
results.libraries.push({
|
|
186
214
|
name,
|
|
@@ -188,7 +216,7 @@ export function scanProject(projectDir) {
|
|
|
188
216
|
algorithms: info.algorithms,
|
|
189
217
|
quantumRisk: info.quantumRisk,
|
|
190
218
|
category: info.category,
|
|
191
|
-
source:
|
|
219
|
+
source: pkgPath.replace(projectDir + '/', ''),
|
|
192
220
|
});
|
|
193
221
|
}
|
|
194
222
|
}
|
|
@@ -281,11 +309,17 @@ export function scanProject(projectDir) {
|
|
|
281
309
|
if (seenImports.has('node:crypto:') || seenImports.has('node:crypto:cipher')) {
|
|
282
310
|
if (!nodeCryptoAlgos.includes('AES')) nodeCryptoAlgos.push('AES');
|
|
283
311
|
}
|
|
312
|
+
if (seenImports.has('node:crypto:') || seenImports.has('node:crypto:hash') || seenImports.has('node:crypto:hmac')) {
|
|
313
|
+
if (!nodeCryptoAlgos.includes('SHA-256')) nodeCryptoAlgos.push('SHA-256');
|
|
314
|
+
}
|
|
284
315
|
if (seenImports.has('node:crypto:signature')) {
|
|
285
316
|
if (!nodeCryptoAlgos.includes('RSA')) nodeCryptoAlgos.push('RSA');
|
|
286
317
|
}
|
|
318
|
+
if (seenImports.has('node:crypto:keygen') || seenImports.has('node:crypto:keyagreement')) {
|
|
319
|
+
if (!nodeCryptoAlgos.includes('ECDSA')) nodeCryptoAlgos.push('ECDSA');
|
|
320
|
+
}
|
|
287
321
|
if (seenImports.has('node:crypto:kdf')) {
|
|
288
|
-
nodeCryptoAlgos.push('scrypt');
|
|
322
|
+
if (!nodeCryptoAlgos.includes('scrypt')) nodeCryptoAlgos.push('scrypt');
|
|
289
323
|
}
|
|
290
324
|
|
|
291
325
|
if (nodeCryptoAlgos.length > 0) {
|