@spektre/veil 0.1.0 → 0.1.2
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/hooks/index.d.ts +0 -3
- package/dist/index.d.ts +5 -6
- package/dist/index.esm.js +278 -107
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +276 -107
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +21 -24
- package/package.json +2 -1
- package/dist/components/VeilProvider.d.ts +0 -9
- package/dist/hooks/useVeil.d.ts +0 -2
package/dist/hooks/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export { default as VeilProvider } from './components/VeilProvider';
|
|
2
|
-
export { useVeil, useSpektre, useProtectedFetch } from './hooks';
|
|
3
|
-
export { SpektreContext } from './SpektreContext';
|
|
4
|
-
export { SpektreProvider } from './SpektreProvider';
|
|
5
1
|
export { SecurityGate } from './SecurityGate';
|
|
6
|
-
export
|
|
7
|
-
export
|
|
2
|
+
export { SpektreProvider } from './SpektreProvider';
|
|
3
|
+
export { SpektreContext } from './SpektreContext';
|
|
4
|
+
export { useSpektre } from './hooks/useSpektre';
|
|
5
|
+
export { useProtectedFetch } from './hooks/useProtectedFetch';
|
|
6
|
+
export type { SecurityGateProps, SpektreConfig, SpektreState, ProtectionState, MonitoringState, BlockedRequest, BlockedAttack, TamperingDetails, VeilConfig, VeilState, VeilProps, VeilContextType, } from './types';
|
package/dist/index.esm.js
CHANGED
|
@@ -1,81 +1,8 @@
|
|
|
1
|
-
import React, { createContext,
|
|
2
|
-
|
|
3
|
-
const VeilContext = createContext(undefined);
|
|
4
|
-
const VeilProvider = ({ config, children }) => {
|
|
5
|
-
const isMonitoring = useMemo(() => config.enableMonitoring ?? false, [config.enableMonitoring]);
|
|
6
|
-
const logEvent = useCallback((event, data) => {
|
|
7
|
-
if (isMonitoring) {
|
|
8
|
-
console.log('[Veil]', event, data);
|
|
9
|
-
}
|
|
10
|
-
}, [isMonitoring]);
|
|
11
|
-
const value = useMemo(() => ({
|
|
12
|
-
config,
|
|
13
|
-
isMonitoring,
|
|
14
|
-
logEvent,
|
|
15
|
-
}), [config, isMonitoring, logEvent]);
|
|
16
|
-
return React.createElement(VeilContext.Provider, { value: value }, children);
|
|
17
|
-
};
|
|
1
|
+
import React, { createContext, useState, useEffect, useContext } from 'react';
|
|
18
2
|
|
|
19
3
|
const SpektreContext = createContext(null);
|
|
20
4
|
SpektreContext.displayName = 'SpektreContext';
|
|
21
5
|
|
|
22
|
-
const useSpektre = () => {
|
|
23
|
-
const context = useContext(SpektreContext);
|
|
24
|
-
if (!context) {
|
|
25
|
-
throw new Error('useSpektre must be used within a SecurityGate component');
|
|
26
|
-
}
|
|
27
|
-
const runScan = async () => {
|
|
28
|
-
if (typeof window.securityScan === 'function') {
|
|
29
|
-
await window.securityScan();
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
const getTelemetry = () => {
|
|
33
|
-
if (typeof window.getSecurityTelemetry === 'function') {
|
|
34
|
-
return window.getSecurityTelemetry();
|
|
35
|
-
}
|
|
36
|
-
return context.monitoring;
|
|
37
|
-
};
|
|
38
|
-
const getProtectionStats = () => {
|
|
39
|
-
if (typeof window.getProtectionStats === 'function') {
|
|
40
|
-
return window.getProtectionStats();
|
|
41
|
-
}
|
|
42
|
-
return context.protection;
|
|
43
|
-
};
|
|
44
|
-
return {
|
|
45
|
-
isVerified: context.isVerified,
|
|
46
|
-
sessionId: context.sessionId,
|
|
47
|
-
protectionEnabled: context.protection?.enabled || false,
|
|
48
|
-
blockedRequests: context.protection?.blockedRequests || [],
|
|
49
|
-
totalBlocked: context.protection?.totalBlocked || 0,
|
|
50
|
-
secretExposures: context.monitoring?.secretExposures || 0,
|
|
51
|
-
scriptProfiles: context.monitoring?.scriptProfiles || 0,
|
|
52
|
-
supplyChainAlerts: context.monitoring?.supplyChainAlerts || 0,
|
|
53
|
-
sessionAnomalies: context.monitoring?.sessionAnomalies || 0,
|
|
54
|
-
runScan,
|
|
55
|
-
getTelemetry,
|
|
56
|
-
getProtectionStats,
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const useProtectedFetch = () => {
|
|
61
|
-
const { isVerified } = useSpektre();
|
|
62
|
-
const protectedFetch = async (url, options) => {
|
|
63
|
-
if (!isVerified) {
|
|
64
|
-
throw new Error('Security verification failed. Cannot make fetch requests until verification is complete.');
|
|
65
|
-
}
|
|
66
|
-
return fetch(url, options);
|
|
67
|
-
};
|
|
68
|
-
return protectedFetch;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const useVeil = () => {
|
|
72
|
-
const context = useContext(VeilContext);
|
|
73
|
-
if (context === undefined) {
|
|
74
|
-
throw new Error('useVeil must be used within a VeilProvider');
|
|
75
|
-
}
|
|
76
|
-
return context;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
6
|
const SpektreProvider = ({ value, children }) => {
|
|
80
7
|
return React.createElement(SpektreContext.Provider, { value: value }, children);
|
|
81
8
|
};
|
|
@@ -89,6 +16,9 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
89
16
|
sessionId: null,
|
|
90
17
|
});
|
|
91
18
|
useEffect(() => {
|
|
19
|
+
// Set tampering detection marker
|
|
20
|
+
sessionStorage.setItem('spektre_js_enabled', 'true');
|
|
21
|
+
sessionStorage.setItem('spektre_init_time', Date.now().toString());
|
|
92
22
|
const scriptUrl = `${SUPABASE_BASE_URL}/functions/v1/scanner_client`;
|
|
93
23
|
const script = document.createElement('script');
|
|
94
24
|
script.src = `${scriptUrl}?apiKey=${encodeURIComponent(apiKey)}`;
|
|
@@ -118,7 +48,7 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
118
48
|
script.setAttribute('data-session', String(config.modules.sessionProtection));
|
|
119
49
|
}
|
|
120
50
|
if (config.modules.activeProtection !== undefined) {
|
|
121
|
-
script.setAttribute('data-
|
|
51
|
+
script.setAttribute('data-protection', String(config.modules.activeProtection));
|
|
122
52
|
}
|
|
123
53
|
}
|
|
124
54
|
script.onload = () => {
|
|
@@ -141,6 +71,8 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
141
71
|
protection,
|
|
142
72
|
monitoring,
|
|
143
73
|
});
|
|
74
|
+
// Start tampering detection after successful load
|
|
75
|
+
startTamperingDetection(config);
|
|
144
76
|
}
|
|
145
77
|
catch (err) {
|
|
146
78
|
setState({
|
|
@@ -169,6 +101,7 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
169
101
|
if (script.parentNode) {
|
|
170
102
|
script.parentNode.removeChild(script);
|
|
171
103
|
}
|
|
104
|
+
stopTamperingDetection();
|
|
172
105
|
};
|
|
173
106
|
}, [apiKey, config]);
|
|
174
107
|
const handleRetry = () => {
|
|
@@ -185,10 +118,12 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
185
118
|
return React.createElement(React.Fragment, null, loadingComponent);
|
|
186
119
|
}
|
|
187
120
|
return (React.createElement("div", { style: styles.container },
|
|
121
|
+
React.createElement("div", { style: styles.backgroundGlow },
|
|
122
|
+
React.createElement("div", { style: styles.orangeGlowLeft }),
|
|
123
|
+
React.createElement("div", { style: styles.orangeGlowRight })),
|
|
188
124
|
React.createElement("div", { style: styles.content },
|
|
189
|
-
React.createElement("div", { style: styles.
|
|
190
|
-
React.createElement("
|
|
191
|
-
React.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }))),
|
|
125
|
+
React.createElement("div", { style: styles.logoContainer },
|
|
126
|
+
React.createElement("img", { src: "/image.png", alt: "Spektre", style: styles.logo })),
|
|
192
127
|
React.createElement("h2", { style: styles.title }, "Initializing Security"),
|
|
193
128
|
React.createElement("p", { style: styles.message }, "Please wait while we verify your application..."),
|
|
194
129
|
React.createElement("div", { style: styles.spinner }))));
|
|
@@ -198,69 +133,256 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
198
133
|
return React.createElement(React.Fragment, null, fallback);
|
|
199
134
|
}
|
|
200
135
|
return (React.createElement("div", { style: styles.container },
|
|
136
|
+
React.createElement("div", { style: styles.backgroundGlow },
|
|
137
|
+
React.createElement("div", { style: styles.orangeGlowLeft }),
|
|
138
|
+
React.createElement("div", { style: styles.orangeGlowRight })),
|
|
201
139
|
React.createElement("div", { style: styles.content },
|
|
202
|
-
React.createElement("div", { style:
|
|
203
|
-
React.createElement("
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
React.createElement("
|
|
208
|
-
React.createElement("p", { style: styles.message }, state.error || 'Unable to verify application security'),
|
|
209
|
-
React.createElement("button", { onClick: handleRetry, style: styles.button }, "Retry"))));
|
|
140
|
+
React.createElement("div", { style: styles.logoContainer },
|
|
141
|
+
React.createElement("img", { src: "/image.png", alt: "Spektre", style: styles.logo })),
|
|
142
|
+
React.createElement("h2", { style: styles.errorTitle }, "Security Protection Required"),
|
|
143
|
+
React.createElement("p", { style: styles.errorMessage }, "This application requires Spektre security protection to run safely."),
|
|
144
|
+
React.createElement("p", { style: styles.errorDetails }, state.error || 'Unable to verify application security'),
|
|
145
|
+
React.createElement("button", { onClick: handleRetry, style: styles.button }, "Retry Loading"))));
|
|
210
146
|
}
|
|
211
147
|
return React.createElement(SpektreProvider, { value: state }, children);
|
|
212
148
|
};
|
|
149
|
+
// Tampering detection
|
|
150
|
+
let tamperingInterval = null;
|
|
151
|
+
let fetchIntegrityHash = null;
|
|
152
|
+
function startTamperingDetection(config) {
|
|
153
|
+
// Calculate integrity hash of fetch function
|
|
154
|
+
if (typeof window.fetch === 'function') {
|
|
155
|
+
fetchIntegrityHash = hashCode(window.fetch.toString());
|
|
156
|
+
}
|
|
157
|
+
tamperingInterval = window.setInterval(() => {
|
|
158
|
+
// Check 1: Verify JavaScript marker is still present
|
|
159
|
+
const jsEnabled = sessionStorage.getItem('spektre_js_enabled');
|
|
160
|
+
if (!jsEnabled) {
|
|
161
|
+
handleTampering('JavaScript marker removed', config);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Check 2: Verify Spektre script is still in DOM
|
|
165
|
+
const scriptExists = document.querySelector('script[src*="scanner_client"]');
|
|
166
|
+
if (!scriptExists) {
|
|
167
|
+
handleTampering('Security script removed from page', config);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Check 3: Verify fetch function hasn't been tampered with
|
|
171
|
+
if (typeof window.fetch === 'function') {
|
|
172
|
+
const currentHash = hashCode(window.fetch.toString());
|
|
173
|
+
if (fetchIntegrityHash && currentHash !== fetchIntegrityHash) {
|
|
174
|
+
// Fetch function was modified
|
|
175
|
+
const fetchCode = window.fetch.toString();
|
|
176
|
+
// Check if it still has Spektre protection
|
|
177
|
+
if (!fetchCode.includes('Spektre') && !fetchCode.includes('PROTECTION')) {
|
|
178
|
+
handleTampering('Security protection has been disabled', config);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
handleTampering('Fetch function removed', config);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Check 4: Verify protection stats function exists
|
|
188
|
+
if (typeof window.getProtectionStats !== 'function') {
|
|
189
|
+
handleTampering('Security monitoring disabled', config);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}, 2000); // Check every 2 seconds
|
|
193
|
+
}
|
|
194
|
+
function stopTamperingDetection() {
|
|
195
|
+
if (tamperingInterval) {
|
|
196
|
+
clearInterval(tamperingInterval);
|
|
197
|
+
tamperingInterval = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function handleTampering(reason, config) {
|
|
201
|
+
console.error('[Spektre SecurityGate] TAMPERING DETECTED:', reason);
|
|
202
|
+
// Stop checking to prevent infinite loops
|
|
203
|
+
stopTamperingDetection();
|
|
204
|
+
// Call callback if provided
|
|
205
|
+
if (config?.onTamperingDetected) {
|
|
206
|
+
config.onTamperingDetected(reason);
|
|
207
|
+
}
|
|
208
|
+
// Lock down the application
|
|
209
|
+
const root = document.getElementById('root');
|
|
210
|
+
if (root) {
|
|
211
|
+
root.innerHTML = '';
|
|
212
|
+
}
|
|
213
|
+
document.body.innerHTML = `
|
|
214
|
+
<div style="
|
|
215
|
+
position: fixed;
|
|
216
|
+
top: 0;
|
|
217
|
+
left: 0;
|
|
218
|
+
width: 100%;
|
|
219
|
+
height: 100%;
|
|
220
|
+
background: linear-gradient(135deg, #dc2626 0%, #991b1b 100%);
|
|
221
|
+
color: white;
|
|
222
|
+
display: flex;
|
|
223
|
+
align-items: center;
|
|
224
|
+
justify-content: center;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
227
|
+
z-index: 999999;
|
|
228
|
+
">
|
|
229
|
+
<div style="max-width: 500px; text-align: center; padding: 40px;">
|
|
230
|
+
<div style="font-size: 72px; margin-bottom: 24px;">⛔</div>
|
|
231
|
+
<h1 style="font-size: 28px; font-weight: 600; margin-bottom: 16px;">
|
|
232
|
+
Security Violation Detected
|
|
233
|
+
</h1>
|
|
234
|
+
<p style="font-size: 16px; line-height: 1.6; opacity: 0.9; margin-bottom: 24px;">
|
|
235
|
+
This application has been locked due to security tampering.
|
|
236
|
+
</p>
|
|
237
|
+
<div style="
|
|
238
|
+
background: rgba(255, 255, 255, 0.1);
|
|
239
|
+
border-radius: 8px;
|
|
240
|
+
padding: 16px;
|
|
241
|
+
margin-bottom: 24px;
|
|
242
|
+
font-size: 14px;
|
|
243
|
+
font-family: monospace;
|
|
244
|
+
">
|
|
245
|
+
${reason}
|
|
246
|
+
</div>
|
|
247
|
+
<button onclick="location.reload()" style="
|
|
248
|
+
padding: 12px 32px;
|
|
249
|
+
font-size: 16px;
|
|
250
|
+
font-weight: 500;
|
|
251
|
+
background: white;
|
|
252
|
+
color: #dc2626;
|
|
253
|
+
border: none;
|
|
254
|
+
border-radius: 8px;
|
|
255
|
+
cursor: pointer;
|
|
256
|
+
transition: transform 0.2s;
|
|
257
|
+
" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
|
|
258
|
+
Reload Application
|
|
259
|
+
</button>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
// Simple hash function for integrity checking
|
|
265
|
+
function hashCode(str) {
|
|
266
|
+
let hash = 0;
|
|
267
|
+
for (let i = 0; i < str.length; i++) {
|
|
268
|
+
const char = str.charCodeAt(i);
|
|
269
|
+
hash = ((hash << 5) - hash) + char;
|
|
270
|
+
hash = hash & hash;
|
|
271
|
+
}
|
|
272
|
+
return hash.toString(36);
|
|
273
|
+
}
|
|
213
274
|
const styles = {
|
|
214
275
|
container: {
|
|
215
276
|
display: 'flex',
|
|
216
277
|
alignItems: 'center',
|
|
217
278
|
justifyContent: 'center',
|
|
218
279
|
minHeight: '100vh',
|
|
219
|
-
|
|
280
|
+
background: '#000000',
|
|
220
281
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
282
|
+
position: 'relative',
|
|
283
|
+
overflow: 'hidden',
|
|
284
|
+
},
|
|
285
|
+
backgroundGlow: {
|
|
286
|
+
position: 'absolute',
|
|
287
|
+
inset: 0,
|
|
288
|
+
pointerEvents: 'none',
|
|
289
|
+
},
|
|
290
|
+
orangeGlowLeft: {
|
|
291
|
+
position: 'absolute',
|
|
292
|
+
top: 0,
|
|
293
|
+
right: 0,
|
|
294
|
+
width: '384px',
|
|
295
|
+
height: '100%',
|
|
296
|
+
background: 'linear-gradient(to left, rgba(249, 115, 22, 0.4), rgba(239, 68, 68, 0.4), transparent)',
|
|
297
|
+
filter: 'blur(96px)',
|
|
298
|
+
transform: 'translateX(30%)',
|
|
299
|
+
},
|
|
300
|
+
orangeGlowRight: {
|
|
301
|
+
position: 'absolute',
|
|
302
|
+
top: '50%',
|
|
303
|
+
right: 0,
|
|
304
|
+
width: '384px',
|
|
305
|
+
height: '384px',
|
|
306
|
+
background: 'linear-gradient(to left, rgba(249, 115, 22, 0.3), transparent)',
|
|
307
|
+
filter: 'blur(96px)',
|
|
308
|
+
transform: 'translateY(-50%)',
|
|
221
309
|
},
|
|
222
310
|
content: {
|
|
223
311
|
textAlign: 'center',
|
|
224
312
|
padding: '2rem',
|
|
225
|
-
maxWidth: '
|
|
313
|
+
maxWidth: '500px',
|
|
314
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
315
|
+
border: '1px solid rgba(71, 85, 105, 0.5)',
|
|
316
|
+
borderRadius: '16px',
|
|
317
|
+
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.5)',
|
|
318
|
+
backdropFilter: 'blur(16px)',
|
|
319
|
+
position: 'relative',
|
|
320
|
+
zIndex: 10,
|
|
226
321
|
},
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
marginBottom: '1rem',
|
|
322
|
+
logoContainer: {
|
|
323
|
+
marginBottom: '2rem',
|
|
230
324
|
display: 'flex',
|
|
231
325
|
justifyContent: 'center',
|
|
232
326
|
},
|
|
327
|
+
logo: {
|
|
328
|
+
width: '56px',
|
|
329
|
+
height: '56px',
|
|
330
|
+
objectFit: 'contain',
|
|
331
|
+
},
|
|
233
332
|
title: {
|
|
234
|
-
fontSize: '1.
|
|
333
|
+
fontSize: '1.75rem',
|
|
235
334
|
fontWeight: '600',
|
|
236
|
-
color: '#
|
|
237
|
-
marginBottom: '0.
|
|
335
|
+
color: '#ffffff',
|
|
336
|
+
marginBottom: '0.75rem',
|
|
238
337
|
},
|
|
239
338
|
message: {
|
|
240
339
|
fontSize: '1rem',
|
|
241
|
-
color: '#
|
|
340
|
+
color: '#cbd5e1',
|
|
341
|
+
marginBottom: '1.5rem',
|
|
342
|
+
lineHeight: '1.6',
|
|
343
|
+
},
|
|
344
|
+
errorTitle: {
|
|
345
|
+
fontSize: '1.75rem',
|
|
346
|
+
fontWeight: '600',
|
|
347
|
+
color: '#ffffff',
|
|
348
|
+
marginBottom: '0.75rem',
|
|
349
|
+
},
|
|
350
|
+
errorMessage: {
|
|
351
|
+
fontSize: '1rem',
|
|
352
|
+
color: '#cbd5e1',
|
|
353
|
+
marginBottom: '1rem',
|
|
354
|
+
lineHeight: '1.6',
|
|
355
|
+
},
|
|
356
|
+
errorDetails: {
|
|
357
|
+
fontSize: '0.875rem',
|
|
358
|
+
color: '#fca5a5',
|
|
242
359
|
marginBottom: '1.5rem',
|
|
243
|
-
|
|
360
|
+
padding: '0.75rem',
|
|
361
|
+
background: 'rgba(239, 68, 68, 0.1)',
|
|
362
|
+
border: '1px solid rgba(239, 68, 68, 0.3)',
|
|
363
|
+
borderRadius: '8px',
|
|
364
|
+
fontFamily: 'monospace',
|
|
244
365
|
},
|
|
245
366
|
spinner: {
|
|
246
|
-
width: '
|
|
247
|
-
height: '
|
|
248
|
-
border: '
|
|
249
|
-
borderTopColor: '#
|
|
367
|
+
width: '40px',
|
|
368
|
+
height: '40px',
|
|
369
|
+
border: '4px solid rgba(71, 85, 105, 0.3)',
|
|
370
|
+
borderTopColor: '#f97316',
|
|
250
371
|
borderRadius: '50%',
|
|
251
372
|
margin: '0 auto',
|
|
252
373
|
animation: 'spin 1s linear infinite',
|
|
253
374
|
},
|
|
254
375
|
button: {
|
|
255
|
-
backgroundColor: '
|
|
376
|
+
backgroundColor: 'rgba(249, 115, 22, 0.6)',
|
|
256
377
|
color: 'white',
|
|
257
|
-
border: '
|
|
258
|
-
borderRadius: '
|
|
259
|
-
padding: '0.
|
|
378
|
+
border: '1px solid rgba(249, 115, 22, 0.6)',
|
|
379
|
+
borderRadius: '9999px',
|
|
380
|
+
padding: '0.875rem 2rem',
|
|
260
381
|
fontSize: '1rem',
|
|
261
|
-
fontWeight: '
|
|
382
|
+
fontWeight: '600',
|
|
262
383
|
cursor: 'pointer',
|
|
263
|
-
transition: '
|
|
384
|
+
transition: 'all 0.2s',
|
|
385
|
+
boxShadow: '0 4px 12px rgba(249, 115, 22, 0.3)',
|
|
264
386
|
},
|
|
265
387
|
};
|
|
266
388
|
const styleSheet = document.createElement('style');
|
|
@@ -273,5 +395,54 @@ styleSheet.textContent = `
|
|
|
273
395
|
`;
|
|
274
396
|
document.head.appendChild(styleSheet);
|
|
275
397
|
|
|
276
|
-
|
|
398
|
+
const useSpektre = () => {
|
|
399
|
+
const context = useContext(SpektreContext);
|
|
400
|
+
if (!context) {
|
|
401
|
+
throw new Error('useSpektre must be used within a SecurityGate component');
|
|
402
|
+
}
|
|
403
|
+
const runScan = async () => {
|
|
404
|
+
if (typeof window.securityScan === 'function') {
|
|
405
|
+
await window.securityScan();
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const getTelemetry = () => {
|
|
409
|
+
if (typeof window.getSecurityTelemetry === 'function') {
|
|
410
|
+
return window.getSecurityTelemetry();
|
|
411
|
+
}
|
|
412
|
+
return context.monitoring;
|
|
413
|
+
};
|
|
414
|
+
const getProtectionStats = () => {
|
|
415
|
+
if (typeof window.getProtectionStats === 'function') {
|
|
416
|
+
return window.getProtectionStats();
|
|
417
|
+
}
|
|
418
|
+
return context.protection;
|
|
419
|
+
};
|
|
420
|
+
return {
|
|
421
|
+
isVerified: context.isVerified,
|
|
422
|
+
sessionId: context.sessionId,
|
|
423
|
+
protectionEnabled: context.protection?.enabled || false,
|
|
424
|
+
blockedRequests: context.protection?.blockedRequests || [],
|
|
425
|
+
totalBlocked: context.protection?.totalBlocked || 0,
|
|
426
|
+
secretExposures: context.monitoring?.secretExposures || 0,
|
|
427
|
+
scriptProfiles: context.monitoring?.scriptProfiles || 0,
|
|
428
|
+
supplyChainAlerts: context.monitoring?.supplyChainAlerts || 0,
|
|
429
|
+
sessionAnomalies: context.monitoring?.sessionAnomalies || 0,
|
|
430
|
+
runScan,
|
|
431
|
+
getTelemetry,
|
|
432
|
+
getProtectionStats,
|
|
433
|
+
};
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const useProtectedFetch = () => {
|
|
437
|
+
const { isVerified } = useSpektre();
|
|
438
|
+
const protectedFetch = async (url, options) => {
|
|
439
|
+
if (!isVerified) {
|
|
440
|
+
throw new Error('Security verification failed. Cannot make fetch requests until verification is complete.');
|
|
441
|
+
}
|
|
442
|
+
return fetch(url, options);
|
|
443
|
+
};
|
|
444
|
+
return protectedFetch;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
export { SecurityGate, SpektreContext, SpektreProvider, useProtectedFetch, useSpektre };
|
|
277
448
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.js
CHANGED
|
@@ -2,82 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
|
|
5
|
-
const VeilContext = React.createContext(undefined);
|
|
6
|
-
const VeilProvider = ({ config, children }) => {
|
|
7
|
-
const isMonitoring = React.useMemo(() => config.enableMonitoring ?? false, [config.enableMonitoring]);
|
|
8
|
-
const logEvent = React.useCallback((event, data) => {
|
|
9
|
-
if (isMonitoring) {
|
|
10
|
-
console.log('[Veil]', event, data);
|
|
11
|
-
}
|
|
12
|
-
}, [isMonitoring]);
|
|
13
|
-
const value = React.useMemo(() => ({
|
|
14
|
-
config,
|
|
15
|
-
isMonitoring,
|
|
16
|
-
logEvent,
|
|
17
|
-
}), [config, isMonitoring, logEvent]);
|
|
18
|
-
return React.createElement(VeilContext.Provider, { value: value }, children);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
5
|
const SpektreContext = React.createContext(null);
|
|
22
6
|
SpektreContext.displayName = 'SpektreContext';
|
|
23
7
|
|
|
24
|
-
const useSpektre = () => {
|
|
25
|
-
const context = React.useContext(SpektreContext);
|
|
26
|
-
if (!context) {
|
|
27
|
-
throw new Error('useSpektre must be used within a SecurityGate component');
|
|
28
|
-
}
|
|
29
|
-
const runScan = async () => {
|
|
30
|
-
if (typeof window.securityScan === 'function') {
|
|
31
|
-
await window.securityScan();
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
const getTelemetry = () => {
|
|
35
|
-
if (typeof window.getSecurityTelemetry === 'function') {
|
|
36
|
-
return window.getSecurityTelemetry();
|
|
37
|
-
}
|
|
38
|
-
return context.monitoring;
|
|
39
|
-
};
|
|
40
|
-
const getProtectionStats = () => {
|
|
41
|
-
if (typeof window.getProtectionStats === 'function') {
|
|
42
|
-
return window.getProtectionStats();
|
|
43
|
-
}
|
|
44
|
-
return context.protection;
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
isVerified: context.isVerified,
|
|
48
|
-
sessionId: context.sessionId,
|
|
49
|
-
protectionEnabled: context.protection?.enabled || false,
|
|
50
|
-
blockedRequests: context.protection?.blockedRequests || [],
|
|
51
|
-
totalBlocked: context.protection?.totalBlocked || 0,
|
|
52
|
-
secretExposures: context.monitoring?.secretExposures || 0,
|
|
53
|
-
scriptProfiles: context.monitoring?.scriptProfiles || 0,
|
|
54
|
-
supplyChainAlerts: context.monitoring?.supplyChainAlerts || 0,
|
|
55
|
-
sessionAnomalies: context.monitoring?.sessionAnomalies || 0,
|
|
56
|
-
runScan,
|
|
57
|
-
getTelemetry,
|
|
58
|
-
getProtectionStats,
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const useProtectedFetch = () => {
|
|
63
|
-
const { isVerified } = useSpektre();
|
|
64
|
-
const protectedFetch = async (url, options) => {
|
|
65
|
-
if (!isVerified) {
|
|
66
|
-
throw new Error('Security verification failed. Cannot make fetch requests until verification is complete.');
|
|
67
|
-
}
|
|
68
|
-
return fetch(url, options);
|
|
69
|
-
};
|
|
70
|
-
return protectedFetch;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const useVeil = () => {
|
|
74
|
-
const context = React.useContext(VeilContext);
|
|
75
|
-
if (context === undefined) {
|
|
76
|
-
throw new Error('useVeil must be used within a VeilProvider');
|
|
77
|
-
}
|
|
78
|
-
return context;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
8
|
const SpektreProvider = ({ value, children }) => {
|
|
82
9
|
return React.createElement(SpektreContext.Provider, { value: value }, children);
|
|
83
10
|
};
|
|
@@ -91,6 +18,9 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
91
18
|
sessionId: null,
|
|
92
19
|
});
|
|
93
20
|
React.useEffect(() => {
|
|
21
|
+
// Set tampering detection marker
|
|
22
|
+
sessionStorage.setItem('spektre_js_enabled', 'true');
|
|
23
|
+
sessionStorage.setItem('spektre_init_time', Date.now().toString());
|
|
94
24
|
const scriptUrl = `${SUPABASE_BASE_URL}/functions/v1/scanner_client`;
|
|
95
25
|
const script = document.createElement('script');
|
|
96
26
|
script.src = `${scriptUrl}?apiKey=${encodeURIComponent(apiKey)}`;
|
|
@@ -120,7 +50,7 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
120
50
|
script.setAttribute('data-session', String(config.modules.sessionProtection));
|
|
121
51
|
}
|
|
122
52
|
if (config.modules.activeProtection !== undefined) {
|
|
123
|
-
script.setAttribute('data-
|
|
53
|
+
script.setAttribute('data-protection', String(config.modules.activeProtection));
|
|
124
54
|
}
|
|
125
55
|
}
|
|
126
56
|
script.onload = () => {
|
|
@@ -143,6 +73,8 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
143
73
|
protection,
|
|
144
74
|
monitoring,
|
|
145
75
|
});
|
|
76
|
+
// Start tampering detection after successful load
|
|
77
|
+
startTamperingDetection(config);
|
|
146
78
|
}
|
|
147
79
|
catch (err) {
|
|
148
80
|
setState({
|
|
@@ -171,6 +103,7 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
171
103
|
if (script.parentNode) {
|
|
172
104
|
script.parentNode.removeChild(script);
|
|
173
105
|
}
|
|
106
|
+
stopTamperingDetection();
|
|
174
107
|
};
|
|
175
108
|
}, [apiKey, config]);
|
|
176
109
|
const handleRetry = () => {
|
|
@@ -187,10 +120,12 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
187
120
|
return React.createElement(React.Fragment, null, loadingComponent);
|
|
188
121
|
}
|
|
189
122
|
return (React.createElement("div", { style: styles.container },
|
|
123
|
+
React.createElement("div", { style: styles.backgroundGlow },
|
|
124
|
+
React.createElement("div", { style: styles.orangeGlowLeft }),
|
|
125
|
+
React.createElement("div", { style: styles.orangeGlowRight })),
|
|
190
126
|
React.createElement("div", { style: styles.content },
|
|
191
|
-
React.createElement("div", { style: styles.
|
|
192
|
-
React.createElement("
|
|
193
|
-
React.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }))),
|
|
127
|
+
React.createElement("div", { style: styles.logoContainer },
|
|
128
|
+
React.createElement("img", { src: "/image.png", alt: "Spektre", style: styles.logo })),
|
|
194
129
|
React.createElement("h2", { style: styles.title }, "Initializing Security"),
|
|
195
130
|
React.createElement("p", { style: styles.message }, "Please wait while we verify your application..."),
|
|
196
131
|
React.createElement("div", { style: styles.spinner }))));
|
|
@@ -200,69 +135,256 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
|
|
|
200
135
|
return React.createElement(React.Fragment, null, fallback);
|
|
201
136
|
}
|
|
202
137
|
return (React.createElement("div", { style: styles.container },
|
|
138
|
+
React.createElement("div", { style: styles.backgroundGlow },
|
|
139
|
+
React.createElement("div", { style: styles.orangeGlowLeft }),
|
|
140
|
+
React.createElement("div", { style: styles.orangeGlowRight })),
|
|
203
141
|
React.createElement("div", { style: styles.content },
|
|
204
|
-
React.createElement("div", { style:
|
|
205
|
-
React.createElement("
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
React.createElement("
|
|
210
|
-
React.createElement("p", { style: styles.message }, state.error || 'Unable to verify application security'),
|
|
211
|
-
React.createElement("button", { onClick: handleRetry, style: styles.button }, "Retry"))));
|
|
142
|
+
React.createElement("div", { style: styles.logoContainer },
|
|
143
|
+
React.createElement("img", { src: "/image.png", alt: "Spektre", style: styles.logo })),
|
|
144
|
+
React.createElement("h2", { style: styles.errorTitle }, "Security Protection Required"),
|
|
145
|
+
React.createElement("p", { style: styles.errorMessage }, "This application requires Spektre security protection to run safely."),
|
|
146
|
+
React.createElement("p", { style: styles.errorDetails }, state.error || 'Unable to verify application security'),
|
|
147
|
+
React.createElement("button", { onClick: handleRetry, style: styles.button }, "Retry Loading"))));
|
|
212
148
|
}
|
|
213
149
|
return React.createElement(SpektreProvider, { value: state }, children);
|
|
214
150
|
};
|
|
151
|
+
// Tampering detection
|
|
152
|
+
let tamperingInterval = null;
|
|
153
|
+
let fetchIntegrityHash = null;
|
|
154
|
+
function startTamperingDetection(config) {
|
|
155
|
+
// Calculate integrity hash of fetch function
|
|
156
|
+
if (typeof window.fetch === 'function') {
|
|
157
|
+
fetchIntegrityHash = hashCode(window.fetch.toString());
|
|
158
|
+
}
|
|
159
|
+
tamperingInterval = window.setInterval(() => {
|
|
160
|
+
// Check 1: Verify JavaScript marker is still present
|
|
161
|
+
const jsEnabled = sessionStorage.getItem('spektre_js_enabled');
|
|
162
|
+
if (!jsEnabled) {
|
|
163
|
+
handleTampering('JavaScript marker removed', config);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Check 2: Verify Spektre script is still in DOM
|
|
167
|
+
const scriptExists = document.querySelector('script[src*="scanner_client"]');
|
|
168
|
+
if (!scriptExists) {
|
|
169
|
+
handleTampering('Security script removed from page', config);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Check 3: Verify fetch function hasn't been tampered with
|
|
173
|
+
if (typeof window.fetch === 'function') {
|
|
174
|
+
const currentHash = hashCode(window.fetch.toString());
|
|
175
|
+
if (fetchIntegrityHash && currentHash !== fetchIntegrityHash) {
|
|
176
|
+
// Fetch function was modified
|
|
177
|
+
const fetchCode = window.fetch.toString();
|
|
178
|
+
// Check if it still has Spektre protection
|
|
179
|
+
if (!fetchCode.includes('Spektre') && !fetchCode.includes('PROTECTION')) {
|
|
180
|
+
handleTampering('Security protection has been disabled', config);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
handleTampering('Fetch function removed', config);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Check 4: Verify protection stats function exists
|
|
190
|
+
if (typeof window.getProtectionStats !== 'function') {
|
|
191
|
+
handleTampering('Security monitoring disabled', config);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}, 2000); // Check every 2 seconds
|
|
195
|
+
}
|
|
196
|
+
function stopTamperingDetection() {
|
|
197
|
+
if (tamperingInterval) {
|
|
198
|
+
clearInterval(tamperingInterval);
|
|
199
|
+
tamperingInterval = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function handleTampering(reason, config) {
|
|
203
|
+
console.error('[Spektre SecurityGate] TAMPERING DETECTED:', reason);
|
|
204
|
+
// Stop checking to prevent infinite loops
|
|
205
|
+
stopTamperingDetection();
|
|
206
|
+
// Call callback if provided
|
|
207
|
+
if (config?.onTamperingDetected) {
|
|
208
|
+
config.onTamperingDetected(reason);
|
|
209
|
+
}
|
|
210
|
+
// Lock down the application
|
|
211
|
+
const root = document.getElementById('root');
|
|
212
|
+
if (root) {
|
|
213
|
+
root.innerHTML = '';
|
|
214
|
+
}
|
|
215
|
+
document.body.innerHTML = `
|
|
216
|
+
<div style="
|
|
217
|
+
position: fixed;
|
|
218
|
+
top: 0;
|
|
219
|
+
left: 0;
|
|
220
|
+
width: 100%;
|
|
221
|
+
height: 100%;
|
|
222
|
+
background: linear-gradient(135deg, #dc2626 0%, #991b1b 100%);
|
|
223
|
+
color: white;
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
flex-direction: column;
|
|
228
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
229
|
+
z-index: 999999;
|
|
230
|
+
">
|
|
231
|
+
<div style="max-width: 500px; text-align: center; padding: 40px;">
|
|
232
|
+
<div style="font-size: 72px; margin-bottom: 24px;">⛔</div>
|
|
233
|
+
<h1 style="font-size: 28px; font-weight: 600; margin-bottom: 16px;">
|
|
234
|
+
Security Violation Detected
|
|
235
|
+
</h1>
|
|
236
|
+
<p style="font-size: 16px; line-height: 1.6; opacity: 0.9; margin-bottom: 24px;">
|
|
237
|
+
This application has been locked due to security tampering.
|
|
238
|
+
</p>
|
|
239
|
+
<div style="
|
|
240
|
+
background: rgba(255, 255, 255, 0.1);
|
|
241
|
+
border-radius: 8px;
|
|
242
|
+
padding: 16px;
|
|
243
|
+
margin-bottom: 24px;
|
|
244
|
+
font-size: 14px;
|
|
245
|
+
font-family: monospace;
|
|
246
|
+
">
|
|
247
|
+
${reason}
|
|
248
|
+
</div>
|
|
249
|
+
<button onclick="location.reload()" style="
|
|
250
|
+
padding: 12px 32px;
|
|
251
|
+
font-size: 16px;
|
|
252
|
+
font-weight: 500;
|
|
253
|
+
background: white;
|
|
254
|
+
color: #dc2626;
|
|
255
|
+
border: none;
|
|
256
|
+
border-radius: 8px;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
transition: transform 0.2s;
|
|
259
|
+
" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
|
|
260
|
+
Reload Application
|
|
261
|
+
</button>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
// Simple hash function for integrity checking
|
|
267
|
+
function hashCode(str) {
|
|
268
|
+
let hash = 0;
|
|
269
|
+
for (let i = 0; i < str.length; i++) {
|
|
270
|
+
const char = str.charCodeAt(i);
|
|
271
|
+
hash = ((hash << 5) - hash) + char;
|
|
272
|
+
hash = hash & hash;
|
|
273
|
+
}
|
|
274
|
+
return hash.toString(36);
|
|
275
|
+
}
|
|
215
276
|
const styles = {
|
|
216
277
|
container: {
|
|
217
278
|
display: 'flex',
|
|
218
279
|
alignItems: 'center',
|
|
219
280
|
justifyContent: 'center',
|
|
220
281
|
minHeight: '100vh',
|
|
221
|
-
|
|
282
|
+
background: '#000000',
|
|
222
283
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
284
|
+
position: 'relative',
|
|
285
|
+
overflow: 'hidden',
|
|
286
|
+
},
|
|
287
|
+
backgroundGlow: {
|
|
288
|
+
position: 'absolute',
|
|
289
|
+
inset: 0,
|
|
290
|
+
pointerEvents: 'none',
|
|
291
|
+
},
|
|
292
|
+
orangeGlowLeft: {
|
|
293
|
+
position: 'absolute',
|
|
294
|
+
top: 0,
|
|
295
|
+
right: 0,
|
|
296
|
+
width: '384px',
|
|
297
|
+
height: '100%',
|
|
298
|
+
background: 'linear-gradient(to left, rgba(249, 115, 22, 0.4), rgba(239, 68, 68, 0.4), transparent)',
|
|
299
|
+
filter: 'blur(96px)',
|
|
300
|
+
transform: 'translateX(30%)',
|
|
301
|
+
},
|
|
302
|
+
orangeGlowRight: {
|
|
303
|
+
position: 'absolute',
|
|
304
|
+
top: '50%',
|
|
305
|
+
right: 0,
|
|
306
|
+
width: '384px',
|
|
307
|
+
height: '384px',
|
|
308
|
+
background: 'linear-gradient(to left, rgba(249, 115, 22, 0.3), transparent)',
|
|
309
|
+
filter: 'blur(96px)',
|
|
310
|
+
transform: 'translateY(-50%)',
|
|
223
311
|
},
|
|
224
312
|
content: {
|
|
225
313
|
textAlign: 'center',
|
|
226
314
|
padding: '2rem',
|
|
227
|
-
maxWidth: '
|
|
315
|
+
maxWidth: '500px',
|
|
316
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
317
|
+
border: '1px solid rgba(71, 85, 105, 0.5)',
|
|
318
|
+
borderRadius: '16px',
|
|
319
|
+
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.5)',
|
|
320
|
+
backdropFilter: 'blur(16px)',
|
|
321
|
+
position: 'relative',
|
|
322
|
+
zIndex: 10,
|
|
228
323
|
},
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
marginBottom: '1rem',
|
|
324
|
+
logoContainer: {
|
|
325
|
+
marginBottom: '2rem',
|
|
232
326
|
display: 'flex',
|
|
233
327
|
justifyContent: 'center',
|
|
234
328
|
},
|
|
329
|
+
logo: {
|
|
330
|
+
width: '56px',
|
|
331
|
+
height: '56px',
|
|
332
|
+
objectFit: 'contain',
|
|
333
|
+
},
|
|
235
334
|
title: {
|
|
236
|
-
fontSize: '1.
|
|
335
|
+
fontSize: '1.75rem',
|
|
237
336
|
fontWeight: '600',
|
|
238
|
-
color: '#
|
|
239
|
-
marginBottom: '0.
|
|
337
|
+
color: '#ffffff',
|
|
338
|
+
marginBottom: '0.75rem',
|
|
240
339
|
},
|
|
241
340
|
message: {
|
|
242
341
|
fontSize: '1rem',
|
|
243
|
-
color: '#
|
|
342
|
+
color: '#cbd5e1',
|
|
343
|
+
marginBottom: '1.5rem',
|
|
344
|
+
lineHeight: '1.6',
|
|
345
|
+
},
|
|
346
|
+
errorTitle: {
|
|
347
|
+
fontSize: '1.75rem',
|
|
348
|
+
fontWeight: '600',
|
|
349
|
+
color: '#ffffff',
|
|
350
|
+
marginBottom: '0.75rem',
|
|
351
|
+
},
|
|
352
|
+
errorMessage: {
|
|
353
|
+
fontSize: '1rem',
|
|
354
|
+
color: '#cbd5e1',
|
|
355
|
+
marginBottom: '1rem',
|
|
356
|
+
lineHeight: '1.6',
|
|
357
|
+
},
|
|
358
|
+
errorDetails: {
|
|
359
|
+
fontSize: '0.875rem',
|
|
360
|
+
color: '#fca5a5',
|
|
244
361
|
marginBottom: '1.5rem',
|
|
245
|
-
|
|
362
|
+
padding: '0.75rem',
|
|
363
|
+
background: 'rgba(239, 68, 68, 0.1)',
|
|
364
|
+
border: '1px solid rgba(239, 68, 68, 0.3)',
|
|
365
|
+
borderRadius: '8px',
|
|
366
|
+
fontFamily: 'monospace',
|
|
246
367
|
},
|
|
247
368
|
spinner: {
|
|
248
|
-
width: '
|
|
249
|
-
height: '
|
|
250
|
-
border: '
|
|
251
|
-
borderTopColor: '#
|
|
369
|
+
width: '40px',
|
|
370
|
+
height: '40px',
|
|
371
|
+
border: '4px solid rgba(71, 85, 105, 0.3)',
|
|
372
|
+
borderTopColor: '#f97316',
|
|
252
373
|
borderRadius: '50%',
|
|
253
374
|
margin: '0 auto',
|
|
254
375
|
animation: 'spin 1s linear infinite',
|
|
255
376
|
},
|
|
256
377
|
button: {
|
|
257
|
-
backgroundColor: '
|
|
378
|
+
backgroundColor: 'rgba(249, 115, 22, 0.6)',
|
|
258
379
|
color: 'white',
|
|
259
|
-
border: '
|
|
260
|
-
borderRadius: '
|
|
261
|
-
padding: '0.
|
|
380
|
+
border: '1px solid rgba(249, 115, 22, 0.6)',
|
|
381
|
+
borderRadius: '9999px',
|
|
382
|
+
padding: '0.875rem 2rem',
|
|
262
383
|
fontSize: '1rem',
|
|
263
|
-
fontWeight: '
|
|
384
|
+
fontWeight: '600',
|
|
264
385
|
cursor: 'pointer',
|
|
265
|
-
transition: '
|
|
386
|
+
transition: 'all 0.2s',
|
|
387
|
+
boxShadow: '0 4px 12px rgba(249, 115, 22, 0.3)',
|
|
266
388
|
},
|
|
267
389
|
};
|
|
268
390
|
const styleSheet = document.createElement('style');
|
|
@@ -275,11 +397,58 @@ styleSheet.textContent = `
|
|
|
275
397
|
`;
|
|
276
398
|
document.head.appendChild(styleSheet);
|
|
277
399
|
|
|
400
|
+
const useSpektre = () => {
|
|
401
|
+
const context = React.useContext(SpektreContext);
|
|
402
|
+
if (!context) {
|
|
403
|
+
throw new Error('useSpektre must be used within a SecurityGate component');
|
|
404
|
+
}
|
|
405
|
+
const runScan = async () => {
|
|
406
|
+
if (typeof window.securityScan === 'function') {
|
|
407
|
+
await window.securityScan();
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
const getTelemetry = () => {
|
|
411
|
+
if (typeof window.getSecurityTelemetry === 'function') {
|
|
412
|
+
return window.getSecurityTelemetry();
|
|
413
|
+
}
|
|
414
|
+
return context.monitoring;
|
|
415
|
+
};
|
|
416
|
+
const getProtectionStats = () => {
|
|
417
|
+
if (typeof window.getProtectionStats === 'function') {
|
|
418
|
+
return window.getProtectionStats();
|
|
419
|
+
}
|
|
420
|
+
return context.protection;
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
isVerified: context.isVerified,
|
|
424
|
+
sessionId: context.sessionId,
|
|
425
|
+
protectionEnabled: context.protection?.enabled || false,
|
|
426
|
+
blockedRequests: context.protection?.blockedRequests || [],
|
|
427
|
+
totalBlocked: context.protection?.totalBlocked || 0,
|
|
428
|
+
secretExposures: context.monitoring?.secretExposures || 0,
|
|
429
|
+
scriptProfiles: context.monitoring?.scriptProfiles || 0,
|
|
430
|
+
supplyChainAlerts: context.monitoring?.supplyChainAlerts || 0,
|
|
431
|
+
sessionAnomalies: context.monitoring?.sessionAnomalies || 0,
|
|
432
|
+
runScan,
|
|
433
|
+
getTelemetry,
|
|
434
|
+
getProtectionStats,
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const useProtectedFetch = () => {
|
|
439
|
+
const { isVerified } = useSpektre();
|
|
440
|
+
const protectedFetch = async (url, options) => {
|
|
441
|
+
if (!isVerified) {
|
|
442
|
+
throw new Error('Security verification failed. Cannot make fetch requests until verification is complete.');
|
|
443
|
+
}
|
|
444
|
+
return fetch(url, options);
|
|
445
|
+
};
|
|
446
|
+
return protectedFetch;
|
|
447
|
+
};
|
|
448
|
+
|
|
278
449
|
exports.SecurityGate = SecurityGate;
|
|
279
450
|
exports.SpektreContext = SpektreContext;
|
|
280
451
|
exports.SpektreProvider = SpektreProvider;
|
|
281
|
-
exports.VeilProvider = VeilProvider;
|
|
282
452
|
exports.useProtectedFetch = useProtectedFetch;
|
|
283
453
|
exports.useSpektre = useSpektre;
|
|
284
|
-
exports.useVeil = useVeil;
|
|
285
454
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
1
|
export interface SpektreConfig {
|
|
3
|
-
apiKey: string;
|
|
4
2
|
endpoint?: string;
|
|
5
|
-
environment?:
|
|
3
|
+
environment?: string;
|
|
6
4
|
enabledEnvironments?: string[];
|
|
7
5
|
modules?: {
|
|
8
6
|
performanceMonitoring?: boolean;
|
|
@@ -12,7 +10,7 @@ export interface SpektreConfig {
|
|
|
12
10
|
sessionProtection?: boolean;
|
|
13
11
|
activeProtection?: boolean;
|
|
14
12
|
};
|
|
15
|
-
onTamperingDetected?: (
|
|
13
|
+
onTamperingDetected?: (reason: string) => void;
|
|
16
14
|
onSecurityFailed?: (error: string) => void;
|
|
17
15
|
onAttackBlocked?: (attack: BlockedAttack) => void;
|
|
18
16
|
}
|
|
@@ -24,11 +22,22 @@ export interface SpektreState {
|
|
|
24
22
|
protection?: ProtectionState;
|
|
25
23
|
monitoring?: MonitoringState;
|
|
26
24
|
}
|
|
25
|
+
export interface VeilContextType {
|
|
26
|
+
isVerified: boolean;
|
|
27
|
+
isLoading: boolean;
|
|
28
|
+
error: string | null;
|
|
29
|
+
sessionId: string | null;
|
|
30
|
+
protection?: ProtectionState;
|
|
31
|
+
monitoring?: MonitoringState;
|
|
32
|
+
}
|
|
27
33
|
export interface ProtectionState {
|
|
28
34
|
enabled: boolean;
|
|
29
35
|
blockedRequests: BlockedRequest[];
|
|
30
36
|
totalBlocked: number;
|
|
31
37
|
}
|
|
38
|
+
export type VeilConfig = SpektreConfig;
|
|
39
|
+
export type VeilState = SpektreState;
|
|
40
|
+
export type VeilProps = SecurityGateProps;
|
|
32
41
|
export interface MonitoringState {
|
|
33
42
|
secretExposures: number;
|
|
34
43
|
scriptProfiles: number;
|
|
@@ -39,15 +48,14 @@ export interface BlockedRequest {
|
|
|
39
48
|
url: string;
|
|
40
49
|
reason: string;
|
|
41
50
|
timestamp: number;
|
|
42
|
-
severity
|
|
51
|
+
severity?: 'low' | 'medium' | 'high' | 'critical';
|
|
43
52
|
}
|
|
44
53
|
export interface BlockedAttack {
|
|
45
|
-
url: string;
|
|
46
|
-
reason: string;
|
|
47
|
-
timestamp: number;
|
|
48
|
-
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
49
54
|
type: string;
|
|
55
|
+
severity: string;
|
|
50
56
|
details: string;
|
|
57
|
+
timestamp: number;
|
|
58
|
+
url?: string;
|
|
51
59
|
}
|
|
52
60
|
export interface TamperingDetails {
|
|
53
61
|
type: string;
|
|
@@ -56,19 +64,8 @@ export interface TamperingDetails {
|
|
|
56
64
|
}
|
|
57
65
|
export interface SecurityGateProps {
|
|
58
66
|
apiKey: string;
|
|
59
|
-
children: ReactNode;
|
|
60
|
-
config?:
|
|
61
|
-
fallback?: ReactNode;
|
|
62
|
-
loadingComponent?: ReactNode;
|
|
63
|
-
}
|
|
64
|
-
export interface VeilConfig {
|
|
65
|
-
enableMonitoring?: boolean;
|
|
66
|
-
enableSecurityChecks?: boolean;
|
|
67
|
-
apiKey?: string;
|
|
68
|
-
environment?: 'development' | 'production';
|
|
69
|
-
}
|
|
70
|
-
export interface VeilContextType {
|
|
71
|
-
config: VeilConfig;
|
|
72
|
-
isMonitoring: boolean;
|
|
73
|
-
logEvent: (event: string, data?: Record<string, unknown>) => void;
|
|
67
|
+
children: React.ReactNode;
|
|
68
|
+
config?: SpektreConfig;
|
|
69
|
+
fallback?: React.ReactNode;
|
|
70
|
+
loadingComponent?: React.ReactNode;
|
|
74
71
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { VeilConfig, VeilContextType } from '../types';
|
|
3
|
-
export declare const VeilContext: React.Context<VeilContextType | undefined>;
|
|
4
|
-
interface VeilProviderProps {
|
|
5
|
-
config: VeilConfig;
|
|
6
|
-
children: React.ReactNode;
|
|
7
|
-
}
|
|
8
|
-
declare const VeilProvider: React.FC<VeilProviderProps>;
|
|
9
|
-
export default VeilProvider;
|
package/dist/hooks/useVeil.d.ts
DELETED