@privacyscrubber/mcp-server 1.0.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/README.md +66 -0
- package/index.js +322 -0
- package/package.json +31 -0
- package/scrubber-core.cjs +1532 -0
- package/test-mcp.js +114 -0
package/test-mcp.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete Cryptographic Verification Test Suite for @privacyscrubber/mcp-server
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const scrubberCorePath = path.resolve(__dirname, '../chrome-extension/scrubber-core.js');
|
|
14
|
+
const mcpServerIndex = path.resolve(__dirname, 'index.js');
|
|
15
|
+
|
|
16
|
+
console.log("Loading modules for verification test...");
|
|
17
|
+
try {
|
|
18
|
+
const PrivacyScrubberCore = require(scrubberCorePath);
|
|
19
|
+
PrivacyScrubberCore.init();
|
|
20
|
+
|
|
21
|
+
// Load index.js to test its internal validate functions
|
|
22
|
+
// We can simulate its checkLicenseStatus by mocking environment variables
|
|
23
|
+
const indexModule = await import('./index.js?update=' + Date.now());
|
|
24
|
+
|
|
25
|
+
// Test Case 1: No license key
|
|
26
|
+
console.log("\n[Test 1] Testing with no license key (Free tier)...");
|
|
27
|
+
process.env.PRIVACYSCRUBBER_KEY = "";
|
|
28
|
+
const t1 = global.checkLicenseStatus ? global.checkLicenseStatus() : mockCheckLicenseStatus();
|
|
29
|
+
console.log("Status:", t1);
|
|
30
|
+
if (t1.isPro) {
|
|
31
|
+
console.error("❌ Test 1 failed: keyless state should not be PRO.");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
console.log("✅ Test 1 passed.");
|
|
35
|
+
|
|
36
|
+
// Test Case 2: Expired trial key
|
|
37
|
+
console.log("\n[Test 2] Testing with expired signed trial key...");
|
|
38
|
+
// Expired key generated by generate-license.js
|
|
39
|
+
const expiredKey = "eyJ0eXBlIjoidHJpYWwiLCJleHBpcmVzIjoxNzgzMjcwMTgzLCJpc3N1ZWRBdCI6MTc4MzcwMjE4Mywibm9uY2UiOiIzYzRkYzEwNmRkOGJiZjczIn0=.Wc1cPwvRpEQxG3BarmedBYm9sUsGdwznboh8Gx3a7qQZm2I+Dha8lk1CtzmaaBt5O8pQszGuTCHapASFwZX2Ku8uZxkGipPI+tbNI39KK7cM6wA+Txc0Ufec/lnDE/27WelBswStSIMgR5LPVScfamMO5BK6jvJ9RgOrEdJeqJPcpab0mwy4jzZwSATyZ1JOS61i8ZlJ+n99zppBrrMZQQo/FJ5t70RpqZiZoMuyNbeDJB9UWGDEAELiJLBkaGeYgBo65zp7fRcTuyjmoZjINnOhCcXmKsmeB1vkHdjPg8jXaGVWFN7bJryeV7j/OkpNqO2q74x3hXDvNwlGtg4PUg==";
|
|
40
|
+
process.env.PRIVACYSCRUBBER_KEY = expiredKey;
|
|
41
|
+
const t2 = mockCheckLicenseStatus();
|
|
42
|
+
console.log("Status:", t2);
|
|
43
|
+
if (t2.isPro || !t2.error.includes("expired")) {
|
|
44
|
+
console.error("❌ Test 2 failed: expired key should be blocked with expiration reason.");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
console.log("✅ Test 2 passed.");
|
|
48
|
+
|
|
49
|
+
// Test Case 3: Valid signed PRO key
|
|
50
|
+
console.log("\n[Test 3] Testing with valid signed PRO key...");
|
|
51
|
+
// Valid key generated in this session
|
|
52
|
+
const validKey = "eyJ0eXBlIjoicHJvIiwiZXhwaXJlcyI6MjA5OTA2MjE3NCwiaXNzdWVkQXQiOjE3ODM3MDIxNzQsIm5vbmNlIjoiMmI4MTllN2ZmM2ZmOTFmYiJ9.ZmhaKDGf9vG0nTH0nyOy3EInsuUmzjBOk9IOyiqzt6Y5s3UG+2yRExuKBoeXWymbpJt3NIJNM9sVxxl+lcop5wqbi2LNtPY4MuwBRA7pO4nn3Bes5R0lxLbEYVE8Iiw3zbfK4uVYQ53BJ7El6JCeFKPJ5WbKUsPLsjb1Lr2iQzW3ODOMaM5jKdgAGcNpuWQ373D7SW7I03Jec9kvP5hL7j3u4DV8ZzuQFzy2Nh+uMH54suydg2sNIpxrRQyxpGv7rZjTO1KT+xzzqnjqX4Pein0e6GrC5E4JUEggADtXPFMKW5SEiWzeeirB5RUPMO/F927S5fFuOYHAfuar2FqErA==";
|
|
53
|
+
process.env.PRIVACYSCRUBBER_KEY = validKey;
|
|
54
|
+
const t3 = mockCheckLicenseStatus();
|
|
55
|
+
console.log("Status:", t3);
|
|
56
|
+
if (!t3.isPro) {
|
|
57
|
+
console.error("❌ Test 3 failed: valid key was not accepted.");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
console.log("✅ Test 3 passed.");
|
|
61
|
+
|
|
62
|
+
console.log("\n🎉 All local cryptographic validation tests passed!");
|
|
63
|
+
process.exit(0);
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("❌ Test run crashed:", error);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Mock checker mapping index.js logic locally for direct assertion
|
|
71
|
+
function mockCheckLicenseStatus() {
|
|
72
|
+
const crypto = require('crypto');
|
|
73
|
+
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
74
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3f37srO402PU4++Baf8
|
|
75
|
+
FG8LY4l/IA3NKLlBnYmNHRTjfI/O/w5PDZn1xPcUQevojA1J+A5moKcjXsJ5b21X
|
|
76
|
+
hJoYSkE4vLpcVYOt1FhRwEHs1APDSyss0HixboLz2eW2XQf2NbwajWtNlyxvgczO
|
|
77
|
+
KE6ClnLomtsaKywwqB4alzdYnnnFJttFPjwmgPSO7D9AgN9sYaVkXOaOFrIZ90Ng
|
|
78
|
+
TRhSHUeL7ReltWlCHwz9xf5m2FrKtxr2VBlEoyPjsFzalHMey1EX+yXe81zM7IIi
|
|
79
|
+
t1Z8agLzo7WIfNBAIWmRlerTplaFFZrQgdF5g/Y0n8IIMZOtadgoY8E855psDNZV
|
|
80
|
+
7wIDAQAB
|
|
81
|
+
-----END PUBLIC KEY-----`;
|
|
82
|
+
|
|
83
|
+
const key = (process.env.PRIVACYSCRUBBER_KEY || "").trim();
|
|
84
|
+
if (!key) return { isPro: false, type: null, error: "No license key provided." };
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const [payloadBase64, signatureBase64] = key.split('.');
|
|
88
|
+
if (!payloadBase64 || !signatureBase64) {
|
|
89
|
+
return { isPro: false, type: null, error: "Invalid license key structure." };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const verifier = crypto.createVerify('SHA256');
|
|
93
|
+
verifier.update(payloadBase64);
|
|
94
|
+
const isVerified = verifier.verify(PUBLIC_KEY, signatureBase64, 'base64');
|
|
95
|
+
|
|
96
|
+
if (!isVerified) {
|
|
97
|
+
return { isPro: false, type: null, error: "Signature verification failed." };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const payload = JSON.parse(Buffer.from(payloadBase64, 'base64').toString('utf8'));
|
|
101
|
+
|
|
102
|
+
if (payload.expires && payload.expires < Math.floor(Date.now() / 1000)) {
|
|
103
|
+
return {
|
|
104
|
+
isPro: false,
|
|
105
|
+
type: payload.type,
|
|
106
|
+
error: `License expired on ${new Date(payload.expires * 1000).toLocaleDateString()}`
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { isPro: true, type: payload.type, error: null };
|
|
111
|
+
} catch (e) {
|
|
112
|
+
return { isPro: false, type: null, error: "Error parsing license: " + e.message };
|
|
113
|
+
}
|
|
114
|
+
}
|