xploitscan 1.0.1 → 1.0.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/dist/{api-Z7VNGPT2.js → api-HTHCG6QE.js} +8 -2
- package/dist/chunk-RJUUWD2F.js +199 -0
- package/dist/chunk-RJUUWD2F.js.map +1 -0
- package/dist/index.js +460 -3291
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
- package/dist/chunk-CBDFSACC.js +0 -121
- package/dist/chunk-CBDFSACC.js.map +0 -1
- /package/dist/{api-Z7VNGPT2.js.map → api-HTHCG6QE.js.map} +0 -0
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
checkUsage,
|
|
4
|
+
clearProRulesCache,
|
|
4
5
|
clearToken,
|
|
6
|
+
downloadProRulesBundle,
|
|
5
7
|
getCheckoutUrl,
|
|
6
8
|
getStoredToken,
|
|
7
9
|
incrementUsage,
|
|
8
10
|
isAuthenticated,
|
|
11
|
+
loadCachedProRules,
|
|
9
12
|
storeToken,
|
|
10
13
|
syncUser,
|
|
11
14
|
uploadScanResults
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RJUUWD2F.js";
|
|
13
16
|
export {
|
|
14
17
|
checkUsage,
|
|
18
|
+
clearProRulesCache,
|
|
15
19
|
clearToken,
|
|
20
|
+
downloadProRulesBundle,
|
|
16
21
|
getCheckoutUrl,
|
|
17
22
|
getStoredToken,
|
|
18
23
|
incrementUsage,
|
|
19
24
|
isAuthenticated,
|
|
25
|
+
loadCachedProRules,
|
|
20
26
|
storeToken,
|
|
21
27
|
syncUser,
|
|
22
28
|
uploadScanResults
|
|
23
29
|
};
|
|
24
|
-
//# sourceMappingURL=api-
|
|
30
|
+
//# sourceMappingURL=api-HTHCG6QE.js.map
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/utils/api.ts
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { createHash } from "crypto";
|
|
14
|
+
var CONFIG_DIR = join(homedir(), ".xploitscan");
|
|
15
|
+
var TOKEN_FILE = join(CONFIG_DIR, "token.json");
|
|
16
|
+
var PRO_RULES_FILE = join(CONFIG_DIR, "pro-rules.cjs");
|
|
17
|
+
var PRO_RULES_META = join(CONFIG_DIR, "pro-rules-meta.json");
|
|
18
|
+
var API_BASE = process.env.XPLOITSCAN_API_URL ?? "https://api.xploitscan.com";
|
|
19
|
+
var WEB_BASE = process.env.XPLOITSCAN_WEB_URL ?? "https://xploitscan.com";
|
|
20
|
+
if (API_BASE.startsWith("http://") && !API_BASE.includes("localhost") && !API_BASE.includes("127.0.0.1")) {
|
|
21
|
+
throw new Error("API URL must use HTTPS for security. Set XPLOITSCAN_API_URL to an https:// URL.");
|
|
22
|
+
}
|
|
23
|
+
if (WEB_BASE.startsWith("http://") && !WEB_BASE.includes("localhost") && !WEB_BASE.includes("127.0.0.1")) {
|
|
24
|
+
throw new Error("Web URL must use HTTPS for security. Set XPLOITSCAN_WEB_URL to an https:// URL.");
|
|
25
|
+
}
|
|
26
|
+
function getStoredToken() {
|
|
27
|
+
try {
|
|
28
|
+
if (!existsSync(TOKEN_FILE)) return null;
|
|
29
|
+
const data = JSON.parse(readFileSync(TOKEN_FILE, "utf-8"));
|
|
30
|
+
if (data.expiresAt && Date.now() > data.expiresAt) {
|
|
31
|
+
unlinkSync(TOKEN_FILE);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function storeToken(data) {
|
|
40
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
41
|
+
writeFileSync(TOKEN_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
42
|
+
}
|
|
43
|
+
function clearToken() {
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(TOKEN_FILE)) {
|
|
46
|
+
unlinkSync(TOKEN_FILE);
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isAuthenticated() {
|
|
52
|
+
return getStoredToken() !== null;
|
|
53
|
+
}
|
|
54
|
+
async function apiRequest(path, options = {}) {
|
|
55
|
+
const token = getStoredToken();
|
|
56
|
+
const headers = {
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
...options.headers
|
|
59
|
+
};
|
|
60
|
+
if (token) {
|
|
61
|
+
headers.Authorization = `Bearer ${token.token}`;
|
|
62
|
+
}
|
|
63
|
+
return fetch(`${API_BASE}${path}`, {
|
|
64
|
+
...options,
|
|
65
|
+
headers
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function checkUsage() {
|
|
69
|
+
const token = getStoredToken();
|
|
70
|
+
if (!token) {
|
|
71
|
+
return { allowed: true, plan: "anonymous", remaining: -1, limit: -1 };
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch(`${WEB_BASE}/api/cli/usage`, {
|
|
75
|
+
headers: { Authorization: `Bearer ${token.token}` }
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
return { allowed: true, plan: "unknown", remaining: -1, limit: -1 };
|
|
79
|
+
}
|
|
80
|
+
return await res.json();
|
|
81
|
+
} catch {
|
|
82
|
+
return { allowed: true, plan: "offline", remaining: -1, limit: -1 };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function incrementUsage() {
|
|
86
|
+
const token = getStoredToken();
|
|
87
|
+
if (!token) return;
|
|
88
|
+
try {
|
|
89
|
+
await apiRequest("/api/usage/increment", { method: "POST" });
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function uploadScanResults(result) {
|
|
94
|
+
const token = getStoredToken();
|
|
95
|
+
if (!token) return;
|
|
96
|
+
try {
|
|
97
|
+
await apiRequest("/api/scans", {
|
|
98
|
+
method: "POST",
|
|
99
|
+
body: JSON.stringify(result)
|
|
100
|
+
});
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function syncUser() {
|
|
105
|
+
const token = getStoredToken();
|
|
106
|
+
if (!token) return null;
|
|
107
|
+
try {
|
|
108
|
+
const res = await fetch(`${WEB_BASE}/api/cli/usage`, {
|
|
109
|
+
headers: { Authorization: `Bearer ${token.token}` }
|
|
110
|
+
});
|
|
111
|
+
if (!res.ok) return null;
|
|
112
|
+
const data = await res.json();
|
|
113
|
+
return { plan: data.plan, email: token.email };
|
|
114
|
+
} catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function getCheckoutUrl() {
|
|
119
|
+
try {
|
|
120
|
+
const res = await apiRequest("/api/billing/checkout", { method: "POST" });
|
|
121
|
+
if (!res.ok) return null;
|
|
122
|
+
const data = await res.json();
|
|
123
|
+
return data.url;
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
var PRO_RULES_CACHE_HOURS = 24;
|
|
129
|
+
async function downloadProRulesBundle() {
|
|
130
|
+
const token = getStoredToken();
|
|
131
|
+
if (!token) return false;
|
|
132
|
+
try {
|
|
133
|
+
const res = await fetch(`${WEB_BASE}/api/cli/rules-bundle`, {
|
|
134
|
+
headers: { Authorization: `Bearer ${token.token}` }
|
|
135
|
+
});
|
|
136
|
+
if (!res.ok) return false;
|
|
137
|
+
const bundle = await res.text();
|
|
138
|
+
if (!bundle || bundle.length < 100) return false;
|
|
139
|
+
if (!bundle.includes("proOnlyRules") || !bundle.includes("exports")) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const hash = createHash("sha256").update(bundle).digest("hex");
|
|
143
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
144
|
+
writeFileSync(PRO_RULES_FILE, bundle, { mode: 384 });
|
|
145
|
+
writeFileSync(PRO_RULES_META, JSON.stringify({
|
|
146
|
+
cachedAt: Date.now(),
|
|
147
|
+
expiresAt: Date.now() + PRO_RULES_CACHE_HOURS * 60 * 60 * 1e3,
|
|
148
|
+
sha256: hash
|
|
149
|
+
}), { mode: 384 });
|
|
150
|
+
return true;
|
|
151
|
+
} catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function loadCachedProRules() {
|
|
156
|
+
try {
|
|
157
|
+
if (!existsSync(PRO_RULES_FILE) || !existsSync(PRO_RULES_META)) return null;
|
|
158
|
+
const meta = JSON.parse(readFileSync(PRO_RULES_META, "utf-8"));
|
|
159
|
+
if (Date.now() > meta.expiresAt) {
|
|
160
|
+
clearProRulesCache();
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
if (meta.sha256) {
|
|
164
|
+
const fileContent = readFileSync(PRO_RULES_FILE, "utf-8");
|
|
165
|
+
const currentHash = createHash("sha256").update(fileContent).digest("hex");
|
|
166
|
+
if (currentHash !== meta.sha256) {
|
|
167
|
+
clearProRulesCache();
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const mod = __require(PRO_RULES_FILE);
|
|
172
|
+
return mod.proOnlyRules || null;
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function clearProRulesCache() {
|
|
178
|
+
try {
|
|
179
|
+
if (existsSync(PRO_RULES_FILE)) unlinkSync(PRO_RULES_FILE);
|
|
180
|
+
if (existsSync(PRO_RULES_META)) unlinkSync(PRO_RULES_META);
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
getStoredToken,
|
|
187
|
+
storeToken,
|
|
188
|
+
clearToken,
|
|
189
|
+
isAuthenticated,
|
|
190
|
+
checkUsage,
|
|
191
|
+
incrementUsage,
|
|
192
|
+
uploadScanResults,
|
|
193
|
+
syncUser,
|
|
194
|
+
getCheckoutUrl,
|
|
195
|
+
downloadProRulesBundle,
|
|
196
|
+
loadCachedProRules,
|
|
197
|
+
clearProRulesCache
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=chunk-RJUUWD2F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/api.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHash } from \"node:crypto\";\n\nconst CONFIG_DIR = join(homedir(), \".xploitscan\");\nconst TOKEN_FILE = join(CONFIG_DIR, \"token.json\");\nconst PRO_RULES_FILE = join(CONFIG_DIR, \"pro-rules.cjs\");\nconst PRO_RULES_META = join(CONFIG_DIR, \"pro-rules-meta.json\");\n\nconst API_BASE = process.env.XPLOITSCAN_API_URL ?? \"https://api.xploitscan.com\";\nconst WEB_BASE = process.env.XPLOITSCAN_WEB_URL ?? \"https://xploitscan.com\";\n\nif (API_BASE.startsWith(\"http://\") && !API_BASE.includes(\"localhost\") && !API_BASE.includes(\"127.0.0.1\")) {\n throw new Error(\"API URL must use HTTPS for security. Set XPLOITSCAN_API_URL to an https:// URL.\");\n}\nif (WEB_BASE.startsWith(\"http://\") && !WEB_BASE.includes(\"localhost\") && !WEB_BASE.includes(\"127.0.0.1\")) {\n throw new Error(\"Web URL must use HTTPS for security. Set XPLOITSCAN_WEB_URL to an https:// URL.\");\n}\n\ninterface TokenData {\n token: string;\n userId: string;\n email: string;\n expiresAt?: number;\n}\n\nexport function getStoredToken(): TokenData | null {\n try {\n if (!existsSync(TOKEN_FILE)) return null;\n const data = JSON.parse(readFileSync(TOKEN_FILE, \"utf-8\"));\n if (data.expiresAt && Date.now() > data.expiresAt) {\n // Token expired\n unlinkSync(TOKEN_FILE);\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nexport function storeToken(data: TokenData): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(TOKEN_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });\n}\n\nexport function clearToken(): void {\n try {\n if (existsSync(TOKEN_FILE)) {\n unlinkSync(TOKEN_FILE);\n }\n } catch {\n // ignore\n }\n}\n\nexport function isAuthenticated(): boolean {\n return getStoredToken() !== null;\n}\n\nasync function apiRequest(\n path: string,\n options: RequestInit = {},\n): Promise<Response> {\n const token = getStoredToken();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token.token}`;\n }\n\n return fetch(`${API_BASE}${path}`, {\n ...options,\n headers,\n });\n}\n\nexport async function checkUsage(): Promise<{\n allowed: boolean;\n plan: string;\n remaining: number;\n limit: number;\n}> {\n const token = getStoredToken();\n if (!token) {\n // Unauthenticated users get limited local scans\n return { allowed: true, plan: \"anonymous\", remaining: -1, limit: -1 };\n }\n\n try {\n // Use web app API for real subscription lookup\n const res = await fetch(`${WEB_BASE}/api/cli/usage`, {\n headers: { Authorization: `Bearer ${token.token}` },\n });\n if (!res.ok) {\n return { allowed: true, plan: \"unknown\", remaining: -1, limit: -1 };\n }\n return await res.json();\n } catch {\n // Network error — allow local scan\n return { allowed: true, plan: \"offline\", remaining: -1, limit: -1 };\n }\n}\n\nexport async function incrementUsage(): Promise<void> {\n const token = getStoredToken();\n if (!token) return;\n\n try {\n await apiRequest(\"/api/usage/increment\", { method: \"POST\" });\n } catch {\n // Silent fail — don't block scan\n }\n}\n\nexport async function uploadScanResults(result: {\n directory: string;\n filesScanned: number;\n findings: unknown[];\n duration: number;\n}): Promise<void> {\n const token = getStoredToken();\n if (!token) return;\n\n try {\n await apiRequest(\"/api/scans\", {\n method: \"POST\",\n body: JSON.stringify(result),\n });\n } catch {\n // Silent fail\n }\n}\n\nexport async function syncUser(): Promise<{ plan: string; email: string } | null> {\n const token = getStoredToken();\n if (!token) return null;\n try {\n const res = await fetch(`${WEB_BASE}/api/cli/usage`, {\n headers: { Authorization: `Bearer ${token.token}` },\n });\n if (!res.ok) return null;\n const data = await res.json();\n return { plan: data.plan, email: token.email };\n } catch {\n return null;\n }\n}\n\nexport async function getCheckoutUrl(): Promise<string | null> {\n try {\n const res = await apiRequest(\"/api/billing/checkout\", { method: \"POST\" });\n if (!res.ok) return null;\n const data = await res.json();\n return data.url;\n } catch {\n return null;\n }\n}\n\n// ── Pro Rules Bundle (Server-Side Delivery) ──────────────────────────────\n\nconst PRO_RULES_CACHE_HOURS = 24;\n\nexport async function downloadProRulesBundle(): Promise<boolean> {\n const token = getStoredToken();\n if (!token) return false;\n\n try {\n const res = await fetch(`${WEB_BASE}/api/cli/rules-bundle`, {\n headers: { Authorization: `Bearer ${token.token}` },\n });\n if (!res.ok) return false;\n\n const bundle = await res.text();\n if (!bundle || bundle.length < 100) return false;\n\n // Basic integrity check: verify bundle contains expected exports\n if (!bundle.includes(\"proOnlyRules\") || !bundle.includes(\"exports\")) {\n return false;\n }\n\n const hash = createHash(\"sha256\").update(bundle).digest(\"hex\");\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(PRO_RULES_FILE, bundle, { mode: 0o600 });\n writeFileSync(PRO_RULES_META, JSON.stringify({\n cachedAt: Date.now(),\n expiresAt: Date.now() + PRO_RULES_CACHE_HOURS * 60 * 60 * 1000,\n sha256: hash,\n }), { mode: 0o600 });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function loadCachedProRules(): unknown[] | null {\n try {\n if (!existsSync(PRO_RULES_FILE) || !existsSync(PRO_RULES_META)) return null;\n\n const meta = JSON.parse(readFileSync(PRO_RULES_META, \"utf-8\"));\n if (Date.now() > meta.expiresAt) {\n clearProRulesCache();\n return null;\n }\n\n // Verify integrity before loading\n if (meta.sha256) {\n const fileContent = readFileSync(PRO_RULES_FILE, \"utf-8\");\n const currentHash = createHash(\"sha256\").update(fileContent).digest(\"hex\");\n if (currentHash !== meta.sha256) {\n clearProRulesCache();\n return null;\n }\n }\n\n // Dynamic require of the cached CJS bundle\n const mod = require(PRO_RULES_FILE);\n return mod.proOnlyRules || null;\n } catch {\n return null;\n }\n}\n\nexport function clearProRulesCache(): void {\n try {\n if (existsSync(PRO_RULES_FILE)) unlinkSync(PRO_RULES_FILE);\n if (existsSync(PRO_RULES_META)) unlinkSync(PRO_RULES_META);\n } catch { /* ignore */ }\n}\n"],"mappings":"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","names":[]}
|