correctover-scan 1.0.0 โ 1.2.0
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/core/license.js +128 -0
- package/index.js +30 -5
- package/package.json +2 -1
package/core/license.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License validator for correctover-scan NPM.
|
|
3
|
+
* Mirrors the Python LicenseValidator: 50 free scans/day, CORRECTOVER_LICENSE_KEY unlocks.
|
|
4
|
+
* Supports CV-TRL/CV-PRO (FC) and COV- (Cloud) key formats.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
const FREE_LIMIT_PER_DAY = 50;
|
|
13
|
+
const STATE_FILE = path.join(os.homedir(), '.correctover', 'license.json');
|
|
14
|
+
|
|
15
|
+
function loadState() {
|
|
16
|
+
try {
|
|
17
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
18
|
+
return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
|
|
19
|
+
}
|
|
20
|
+
} catch (e) {}
|
|
21
|
+
return { products: {}, license_key: null, installed_at: Date.now() / 1000 };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function saveState(state) {
|
|
25
|
+
try {
|
|
26
|
+
fs.mkdirSync(path.dirname(STATE_FILE), { recursive: true });
|
|
27
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
28
|
+
} catch (e) {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getProductState(state, product) {
|
|
32
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
33
|
+
if (!state.products[product]) {
|
|
34
|
+
state.products[product] = { calls_today: 0, date: today, total_calls: 0 };
|
|
35
|
+
}
|
|
36
|
+
if (state.products[product].date !== today) {
|
|
37
|
+
state.products[product].calls_today = 0;
|
|
38
|
+
state.products[product].date = today;
|
|
39
|
+
}
|
|
40
|
+
return state.products[product];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function verifyLicenseKey(key) {
|
|
44
|
+
if (!key || key.length < 12) return false;
|
|
45
|
+
|
|
46
|
+
// COV-<product>-<hash> (Cloud HMAC)
|
|
47
|
+
if (key.startsWith('COV-')) {
|
|
48
|
+
const parts = key.split('-');
|
|
49
|
+
if (parts.length < 3) return false;
|
|
50
|
+
const productCode = parts.slice(1, -1).join('-');
|
|
51
|
+
const secret = `correctover-${productCode}-2026`;
|
|
52
|
+
const expected = crypto.createHash('sha256').update(secret).digest('hex').slice(0, 12);
|
|
53
|
+
return parts[parts.length - 1].startsWith(expected);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// CV-TRL-<base64> / CV-PRO-<base64> (FC XunhuPay)
|
|
57
|
+
if (key.startsWith('CV-')) {
|
|
58
|
+
const parts = key.split('-', 2);
|
|
59
|
+
if (parts.length < 3) return false;
|
|
60
|
+
try {
|
|
61
|
+
let payload = parts[2];
|
|
62
|
+
const dot = payload.indexOf('.');
|
|
63
|
+
if (dot > 0) payload = payload.substring(0, dot);
|
|
64
|
+
const decoded = Buffer.from(payload, 'base64url').toString();
|
|
65
|
+
return decoded.includes('@') || decoded.length > 10;
|
|
66
|
+
} catch (e) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function checkLicense(product) {
|
|
75
|
+
const state = loadState();
|
|
76
|
+
const ps = getProductState(state, product);
|
|
77
|
+
const licenseKey = state.license_key || process.env.CORRECTOVER_LICENSE_KEY;
|
|
78
|
+
|
|
79
|
+
if (licenseKey && verifyLicenseKey(licenseKey)) {
|
|
80
|
+
return {
|
|
81
|
+
authorized: true,
|
|
82
|
+
tier: 'pro',
|
|
83
|
+
calls_remaining: Infinity,
|
|
84
|
+
calls_today: ps.calls_today,
|
|
85
|
+
limit: Infinity,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const remaining = Math.max(0, FREE_LIMIT_PER_DAY - ps.calls_today);
|
|
90
|
+
return {
|
|
91
|
+
authorized: remaining > 0,
|
|
92
|
+
tier: 'free',
|
|
93
|
+
calls_remaining: remaining,
|
|
94
|
+
calls_today: ps.calls_today,
|
|
95
|
+
limit: FREE_LIMIT_PER_DAY,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function recordCall(product) {
|
|
100
|
+
const state = loadState();
|
|
101
|
+
const status = checkLicense(product);
|
|
102
|
+
if (!status.authorized) return status;
|
|
103
|
+
|
|
104
|
+
const ps = getProductState(state, product);
|
|
105
|
+
ps.calls_today += 1;
|
|
106
|
+
ps.total_calls = (ps.total_calls || 0) + 1;
|
|
107
|
+
saveState(state);
|
|
108
|
+
|
|
109
|
+
status.calls_remaining = Math.max(0, status.limit - ps.calls_today);
|
|
110
|
+
status.calls_today = ps.calls_today;
|
|
111
|
+
return status;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getUpgradeMessage(status) {
|
|
115
|
+
if (status.tier !== 'free') return '';
|
|
116
|
+
if (status.calls_remaining <= 0) {
|
|
117
|
+
return `\n๐ซ Free tier limit reached (${FREE_LIMIT_PER_DAY} scans/day).\n Upgrade: https://correctover.com/checkout\n Or: export CORRECTOVER_LICENSE_KEY=<your-key>\n`;
|
|
118
|
+
}
|
|
119
|
+
return `\n๐ Free tier: ${status.calls_remaining} scans remaining today.\n Upgrade: https://correctover.com/checkout\n`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
FREE_LIMIT_PER_DAY,
|
|
124
|
+
checkLicense,
|
|
125
|
+
recordCall,
|
|
126
|
+
getUpgradeMessage,
|
|
127
|
+
verifyLicenseKey,
|
|
128
|
+
};
|
package/index.js
CHANGED
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const { runScan, parseConfig, KNOWN_CONFIG_PATHS } = require('./core/scanner');
|
|
13
|
+
const { recordCall, getUpgradeMessage } = require('./core/license');
|
|
13
14
|
|
|
14
|
-
const VERSION = '1.
|
|
15
|
+
const VERSION = '1.2.0';
|
|
16
|
+
const PRODUCT = 'correctover-scan';
|
|
15
17
|
|
|
16
18
|
// Colors
|
|
17
19
|
const c = {
|
|
@@ -107,10 +109,20 @@ function formatResults(results, stats, filename) {
|
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
// CTA
|
|
110
|
-
lines.push(
|
|
111
|
-
lines.push(`${c.dim}
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push(`${c.dim}โโ Upgrade โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${c.reset}`);
|
|
114
|
+
if (stats.fail > 0 || stats.score < 60) {
|
|
115
|
+
lines.push(`${c.yellow}${c.bold}โก Score too low? CCS Pro generates formal compliance reports.${c.reset}`);
|
|
116
|
+
lines.push(`${c.dim} Enterprise: real-time runtime protection + Token guarantee${c.reset}`);
|
|
117
|
+
lines.push(`${c.cyan} โ Upgrade: https://correctover.com/checkout${c.reset}`);
|
|
118
|
+
} else {
|
|
119
|
+
lines.push(`${c.green}โ Good score! Get a formal compliance certificate with CCS Pro.${c.reset}`);
|
|
120
|
+
lines.push(`${c.dim} Audit reports ยท Team dashboard ยท Custom rules ยท SOC 2 ready${c.reset}`);
|
|
121
|
+
lines.push(`${c.cyan} โ https://correctover.com/checkout${c.reset}`);
|
|
122
|
+
}
|
|
123
|
+
lines.push(`${c.dim}Enterprise: runtime SDK + Token guarantee โ https://correctover.com${c.reset}`);
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push(`${c.dim}Web: https://correctover.com/scan/ | GitHub: https://github.com/Correctover${c.reset}`);
|
|
114
126
|
|
|
115
127
|
return lines.join('\n');
|
|
116
128
|
}
|
|
@@ -194,6 +206,19 @@ Examples:
|
|
|
194
206
|
|
|
195
207
|
printBanner();
|
|
196
208
|
|
|
209
|
+
// License check
|
|
210
|
+
const status = recordCall(PRODUCT);
|
|
211
|
+
if (!status.authorized) {
|
|
212
|
+
console.log(getUpgradeMessage(status));
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
if (status.tier === 'free') {
|
|
216
|
+
console.log(`${c.dim}๐ Free tier: ${status.calls_remaining} scans remaining today (${status.calls_today}/${status.limit})${c.reset}`);
|
|
217
|
+
console.log(`${c.dim} Upgrade: https://correctover.com/checkout${c.reset}\n`);
|
|
218
|
+
} else if (status.tier === 'pro') {
|
|
219
|
+
console.log(`${c.green}โ
Pro license active โ unlimited scans${c.reset}\n`);
|
|
220
|
+
}
|
|
221
|
+
|
|
197
222
|
const filesToScan = [];
|
|
198
223
|
|
|
199
224
|
if (configPath) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "correctover-scan",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CCS Security Scanner for MCP configurations โ scan Agent security configs against OWASP AISVS 1.0",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"files": [
|
|
40
40
|
"index.js",
|
|
41
41
|
"core/scanner.js",
|
|
42
|
+
"core/license.js",
|
|
42
43
|
"README.md"
|
|
43
44
|
],
|
|
44
45
|
"engines": {
|