@chdlabs/my-shield 0.1.3 → 0.3.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 +245 -113
- package/models/default-weights.json +682 -0
- package/package.json +19 -4
- package/src/admin/otpGate.js +370 -0
- package/src/biometrics/index.js +10 -0
- package/src/biometrics/minirocket.js +213 -0
- package/src/biometrics/ridge.js +144 -0
- package/src/client/collector.js +136 -0
- package/src/client/index.js +68 -0
- package/src/client/shieldClient.js +118 -0
- package/src/core/ipResolver.js +225 -0
- package/src/index.d.ts +181 -0
- package/src/index.js +138 -5
- package/src/middleware/behavioralGuard.js +304 -0
- package/src/middleware/honeypot.js +6 -4
- package/src/middleware/notFoundCollector.js +6 -4
- package/src/middleware/shieldGuard.js +3 -0
- package/src/storage/BaseAdapter.js +58 -0
- package/src/storage/CallbackStorageAdapter.js +69 -0
- package/src/storage/FileStorageAdapter.js +174 -0
- package/src/storage/MemoryAdapter.js +56 -0
- package/src/storage/index.js +53 -0
package/src/index.d.ts
CHANGED
|
@@ -47,12 +47,87 @@ export interface AdminOptions {
|
|
|
47
47
|
enabled?: boolean;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
export interface BehavioralVerdict {
|
|
51
|
+
isHuman: boolean;
|
|
52
|
+
probability: number;
|
|
53
|
+
score: number;
|
|
54
|
+
latencyMs: number;
|
|
55
|
+
ip?: string;
|
|
56
|
+
mode?: 'block' | 'audit' | 'header-only';
|
|
57
|
+
reason?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface BehavioralGuardOptions {
|
|
61
|
+
threshold?: number;
|
|
62
|
+
mode?: 'block' | 'audit' | 'header-only';
|
|
63
|
+
headerName?: string;
|
|
64
|
+
replayWindowMs?: number;
|
|
65
|
+
allowFallbackOnError?: boolean;
|
|
66
|
+
autoBlockIP?: boolean;
|
|
67
|
+
onBotDetected?: (req: any, res: any, meta: any) => void;
|
|
68
|
+
onVerdict?: (verdict: BehavioralVerdict, req: any, res: any) => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface BiometricsOptions {
|
|
72
|
+
modelWeights?: {
|
|
73
|
+
thresholds: number[];
|
|
74
|
+
weights: number[];
|
|
75
|
+
bias: number;
|
|
76
|
+
windowLength?: number;
|
|
77
|
+
numFeatures?: number;
|
|
78
|
+
} | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface BehavioralVerificationResult {
|
|
82
|
+
score: number;
|
|
83
|
+
probability: number;
|
|
84
|
+
isHuman: boolean;
|
|
85
|
+
latencyMs: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface FileStorageOptions {
|
|
89
|
+
type?: 'file';
|
|
90
|
+
directory?: string;
|
|
91
|
+
filename?: string;
|
|
92
|
+
debounceMs?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface CallbackStorageOptions {
|
|
96
|
+
onLoad?: () => Promise<Array<{ ip: string; reason: string; metadata?: any; expiresAt?: number | null }>>;
|
|
97
|
+
onBlock?: (ip: string, reason: string, metadata?: any, expiresAt?: number | null) => Promise<void>;
|
|
98
|
+
onUnblock?: (ip: string) => Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type StorageOption = 'memory' | 'file' | FileStorageOptions | CallbackStorageOptions | BaseStorageAdapter;
|
|
102
|
+
|
|
103
|
+
export interface IPResolverOptions {
|
|
104
|
+
trustProxy?: boolean | string | string[];
|
|
105
|
+
protectGateways?: boolean;
|
|
106
|
+
protectedSubnets?: string[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface OtpGateOptions {
|
|
110
|
+
adminEmail?: string;
|
|
111
|
+
jwtSecret?: string;
|
|
112
|
+
secret?: string;
|
|
113
|
+
cookieName?: string;
|
|
114
|
+
codeTtlMs?: number;
|
|
115
|
+
sessionTtlMs?: number;
|
|
116
|
+
maxAttempts?: number;
|
|
117
|
+
sendOtp?: (email: string, code: string) => Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
50
120
|
export interface ShieldOptions {
|
|
51
121
|
whitelist?: string[];
|
|
122
|
+
trustProxy?: boolean | string | string[];
|
|
123
|
+
protectGateways?: boolean;
|
|
124
|
+
protectedSubnets?: string[];
|
|
125
|
+
storage?: StorageOption;
|
|
52
126
|
bloom?: BloomOptions;
|
|
53
127
|
lru?: LRUOptions;
|
|
54
128
|
honeypot?: HoneypotOptions;
|
|
55
129
|
intelligence?: IntelligenceOptions;
|
|
130
|
+
biometrics?: BiometricsOptions;
|
|
56
131
|
admin?: AdminOptions;
|
|
57
132
|
blockStatusCode?: number;
|
|
58
133
|
logger?: {
|
|
@@ -73,15 +148,100 @@ export interface AdminRouterOptions {
|
|
|
73
148
|
authMiddleware?: RequestHandler | RequestHandler[];
|
|
74
149
|
}
|
|
75
150
|
|
|
151
|
+
export class BaseStorageAdapter {
|
|
152
|
+
shield: any;
|
|
153
|
+
init(shield: any): Promise<void>;
|
|
154
|
+
loadBlockedIPs(): Promise<Array<{ ip: string; reason: string; metadata?: any; expiresAt?: number | null }>>;
|
|
155
|
+
saveBlockedIP(ip: string, reason: string, metadata?: any, expiresAt?: number | null): Promise<void>;
|
|
156
|
+
removeBlockedIP(ip: string): Promise<void>;
|
|
157
|
+
close(): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class MemoryAdapter extends BaseStorageAdapter {}
|
|
161
|
+
export class FileStorageAdapter extends BaseStorageAdapter {
|
|
162
|
+
constructor(options?: FileStorageOptions & { logger?: any });
|
|
163
|
+
flushSync(): void;
|
|
164
|
+
}
|
|
165
|
+
export class CallbackStorageAdapter extends BaseStorageAdapter {
|
|
166
|
+
constructor(options?: CallbackStorageOptions & { logger?: any });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function createStorageAdapter(storageOption?: StorageOption, logger?: any): BaseStorageAdapter;
|
|
170
|
+
|
|
171
|
+
export class IPResolver {
|
|
172
|
+
constructor(options?: IPResolverOptions);
|
|
173
|
+
normalize(rawIp: string): string;
|
|
174
|
+
isValid(ip: string): boolean;
|
|
175
|
+
isPrivateOrLoopback(ip: string): boolean;
|
|
176
|
+
isProtectedGateway(ip: string): boolean;
|
|
177
|
+
resolve(req: any): string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export class OTPGate {
|
|
181
|
+
constructor(options?: OtpGateOptions & { logger?: any });
|
|
182
|
+
generateCode(): string;
|
|
183
|
+
createSessionToken(email: string): string;
|
|
184
|
+
verifySessionToken(token: string): { valid: boolean; email?: string };
|
|
185
|
+
middleware(): RequestHandler;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function createOtpGate(options?: OtpGateOptions & { logger?: any }): RequestHandler;
|
|
189
|
+
|
|
190
|
+
export interface MouseTelemetryCollectorOptions {
|
|
191
|
+
windowLength?: number;
|
|
192
|
+
sampleIntervalMs?: number;
|
|
193
|
+
maxBufferSize?: number;
|
|
194
|
+
maxIdleMs?: number;
|
|
195
|
+
minPoints?: number;
|
|
196
|
+
flushOnConsumption?: boolean;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface ShieldClientOptions extends MouseTelemetryCollectorOptions {
|
|
200
|
+
autoInjectTripwire?: boolean;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface InstrumentFetchOptions {
|
|
204
|
+
headerName?: string;
|
|
205
|
+
endpoints?: string[];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export class MouseTelemetryCollector {
|
|
209
|
+
windowLength: number;
|
|
210
|
+
sampleIntervalMs: number;
|
|
211
|
+
maxBufferSize: number;
|
|
212
|
+
constructor(options?: MouseTelemetryCollectorOptions);
|
|
213
|
+
start(): void;
|
|
214
|
+
stop(): void;
|
|
215
|
+
getPayload(): { velocity: number[]; isTrusted: boolean; timestamp: number } | null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export class ShieldClient {
|
|
219
|
+
collector: MouseTelemetryCollector;
|
|
220
|
+
constructor(options?: ShieldClientOptions);
|
|
221
|
+
start(): void;
|
|
222
|
+
stop(): void;
|
|
223
|
+
getPayload(): { velocity: number[]; isTrusted: boolean; timestamp: number } | null;
|
|
224
|
+
instrumentFetch(options?: InstrumentFetchOptions): void;
|
|
225
|
+
instrumentAxios(axiosInstance: any, options?: InstrumentFetchOptions): void;
|
|
226
|
+
}
|
|
227
|
+
|
|
76
228
|
export class Shield extends EventEmitter {
|
|
229
|
+
ipResolver: IPResolver;
|
|
230
|
+
storageAdapter: BaseStorageAdapter;
|
|
231
|
+
|
|
77
232
|
constructor(options?: ShieldOptions);
|
|
78
233
|
|
|
234
|
+
init(): Promise<this>;
|
|
79
235
|
middleware(): RequestHandler;
|
|
80
236
|
honeypot(): RequestHandler;
|
|
81
237
|
notFoundCollector(): RequestHandler;
|
|
82
238
|
adminRouter(options?: AdminRouterOptions): Router;
|
|
83
239
|
costThrottle(options?: CostThrottleOptions): RequestHandler;
|
|
84
240
|
keyLeakDetector(): RequestHandler;
|
|
241
|
+
behavioralGuard(options?: BehavioralGuardOptions): RequestHandler;
|
|
242
|
+
strictBotGuard(options?: BehavioralGuardOptions): RequestHandler;
|
|
243
|
+
otpGate(options?: OtpGateOptions): RequestHandler;
|
|
244
|
+
verifyBiometrics(velocity: number[] | Float64Array): BehavioralVerificationResult;
|
|
85
245
|
|
|
86
246
|
blockIP(ip: string, reason?: string, metadata?: Record<string, any>, customTtlMs?: number | null): void;
|
|
87
247
|
unblockIP(ip: string): void;
|
|
@@ -99,5 +259,26 @@ export class Shield extends EventEmitter {
|
|
|
99
259
|
shutdown(): Promise<void>;
|
|
100
260
|
}
|
|
101
261
|
|
|
262
|
+
export class MiniRocket {
|
|
263
|
+
windowLength: number;
|
|
264
|
+
targetFeatures: number;
|
|
265
|
+
thresholds: Float32Array | null;
|
|
266
|
+
constructor(windowLength?: number, numFeatures?: number);
|
|
267
|
+
loadThresholds(thresholdsArray: number[] | Float32Array): void;
|
|
268
|
+
fit(trainingWindows: Array<number[] | Float64Array>): void;
|
|
269
|
+
transform(series: number[] | Float64Array): Float32Array;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export class DualRidgeClassifier {
|
|
273
|
+
alpha: number;
|
|
274
|
+
weights: Float32Array | null;
|
|
275
|
+
bias: number;
|
|
276
|
+
constructor(alpha?: number);
|
|
277
|
+
loadWeights(weightsArray: number[] | Float32Array, bias?: number): void;
|
|
278
|
+
fit(X: Array<Float32Array | number[]>, y: number[]): void;
|
|
279
|
+
predict(features: Float32Array | number[]): { score: number; probability: number; isHuman: boolean };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function injectTripwire(): void;
|
|
102
283
|
export function createShield(options?: ShieldOptions): Shield;
|
|
103
284
|
export default createShield;
|
package/src/index.js
CHANGED
|
@@ -17,7 +17,13 @@ import { NotFoundCollector } from './middleware/notFoundCollector.js';
|
|
|
17
17
|
import { ShieldGuard } from './middleware/shieldGuard.js';
|
|
18
18
|
import { CostThrottle } from './middleware/costThrottle.js';
|
|
19
19
|
import { KeyLeakDetector } from './middleware/keyLeakDetector.js';
|
|
20
|
+
import { BehavioralShieldService } from './middleware/behavioralGuard.js';
|
|
21
|
+
import { MiniRocket } from './biometrics/minirocket.js';
|
|
22
|
+
import { DualRidgeClassifier } from './biometrics/ridge.js';
|
|
20
23
|
import { createAdminRouter } from './admin/adminRouter.js';
|
|
24
|
+
import { IPResolver } from './core/ipResolver.js';
|
|
25
|
+
import { createStorageAdapter } from './storage/index.js';
|
|
26
|
+
import { createOtpGate, OTPGate } from './admin/otpGate.js';
|
|
21
27
|
|
|
22
28
|
export class Shield extends EventEmitter {
|
|
23
29
|
/**
|
|
@@ -122,9 +128,58 @@ export class Shield extends EventEmitter {
|
|
|
122
128
|
logger: this.logger
|
|
123
129
|
});
|
|
124
130
|
|
|
125
|
-
// 8.
|
|
131
|
+
// 8. Behavioral Biometrics Subsystem (MiniRocket + Dual Ridge)
|
|
132
|
+
const biometricsOpts = options.biometrics || {};
|
|
133
|
+
this.behavioralShieldService = new BehavioralShieldService({
|
|
134
|
+
modelWeights: biometricsOpts.modelWeights || null,
|
|
135
|
+
shield: this,
|
|
136
|
+
logger: this.logger
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// 9. Admin Dashboard Configuration (Default: false)
|
|
126
140
|
const adminOpts = options.admin || {};
|
|
127
141
|
this.adminEnabled = Boolean(adminOpts.enabled);
|
|
142
|
+
|
|
143
|
+
// 10. Enterprise Client IP Resolution & Gateway Protection
|
|
144
|
+
this.ipResolver = new IPResolver({
|
|
145
|
+
trustProxy: options.trustProxy,
|
|
146
|
+
protectGateways: options.protectGateways !== false,
|
|
147
|
+
protectedSubnets: options.protectedSubnets || []
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// 11. Pluggable Storage Adapter (Memory, File, or Database Callbacks)
|
|
151
|
+
this.storageAdapter = createStorageAdapter(options.storage, this.logger);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Asynchronous initialization: hydrates unexpired threats from persistent storage
|
|
156
|
+
* into Bloom filter and LRU cache.
|
|
157
|
+
* @returns {Promise<this>}
|
|
158
|
+
*/
|
|
159
|
+
async init() {
|
|
160
|
+
await this.storageAdapter.init(this);
|
|
161
|
+
try {
|
|
162
|
+
const blockedList = await this.storageAdapter.loadBlockedIPs();
|
|
163
|
+
if (Array.isArray(blockedList)) {
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
for (const item of blockedList) {
|
|
166
|
+
if (item && item.ip) {
|
|
167
|
+
const cleanIp = this.ipResolver ? this.ipResolver.normalize(item.ip) : item.ip.trim();
|
|
168
|
+
if (!this.whitelist.has(cleanIp) && !this.ipResolver.isProtectedGateway(cleanIp)) {
|
|
169
|
+
this.bloom.add(cleanIp);
|
|
170
|
+
const ttl = item.expiresAt ? Math.max(1, item.expiresAt - now) : null;
|
|
171
|
+
this.lru.set(cleanIp, { reason: item.reason || 'restored_threat', metadata: item.metadata || {} }, ttl);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (blockedList.length > 0) {
|
|
176
|
+
this.logger.info?.(`[SHIELD] Hydrated ${blockedList.length} persistent threats into Bloom & LRU.`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch (err) {
|
|
180
|
+
this.logger.error?.('[SHIELD:STORAGE] Error during startup threat hydration:', err.message);
|
|
181
|
+
}
|
|
182
|
+
return this;
|
|
128
183
|
}
|
|
129
184
|
|
|
130
185
|
/**
|
|
@@ -171,6 +226,49 @@ export class Shield extends EventEmitter {
|
|
|
171
226
|
return this.keyLeakDetectorInstance.middleware();
|
|
172
227
|
}
|
|
173
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Route-level Behavioral Biometrics Express Middleware
|
|
231
|
+
* Validates mouse kinematics against MiniRocket model
|
|
232
|
+
* @param {Object} [opts]
|
|
233
|
+
*/
|
|
234
|
+
behavioralGuard(opts) {
|
|
235
|
+
return this.behavioralShieldService.middleware(opts);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Route-level strict behavioral bot defense decorator
|
|
240
|
+
* Designed specifically for mission-critical routes like /login, /checkout, /register
|
|
241
|
+
* Automatically rejects bots with 403 and blacklists their IP in Shield L1.
|
|
242
|
+
* @param {Object} [opts]
|
|
243
|
+
*/
|
|
244
|
+
strictBotGuard(opts = {}) {
|
|
245
|
+
return this.behavioralGuard({
|
|
246
|
+
mode: 'block',
|
|
247
|
+
autoBlockIP: true,
|
|
248
|
+
threshold: 0.50,
|
|
249
|
+
...opts
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Shield Standalone OTP Authentication Gate Middleware
|
|
255
|
+
* @param {Object} [options]
|
|
256
|
+
*/
|
|
257
|
+
otpGate(options = {}) {
|
|
258
|
+
return createOtpGate({
|
|
259
|
+
logger: this.logger,
|
|
260
|
+
...options
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Verify kinematics velocity series against MiniRocket model
|
|
266
|
+
* @param {number[]|Float64Array} velocityArray
|
|
267
|
+
*/
|
|
268
|
+
verifyBiometrics(velocityArray) {
|
|
269
|
+
return this.behavioralShieldService.verify(velocityArray);
|
|
270
|
+
}
|
|
271
|
+
|
|
174
272
|
/**
|
|
175
273
|
* Block an IP address immediately
|
|
176
274
|
* @param {string} ip
|
|
@@ -180,16 +278,28 @@ export class Shield extends EventEmitter {
|
|
|
180
278
|
*/
|
|
181
279
|
blockIP(ip, reason = 'manual_block', metadata = {}, customTtlMs = null) {
|
|
182
280
|
if (!ip || typeof ip !== 'string') return;
|
|
183
|
-
const cleanIp = ip.trim();
|
|
281
|
+
const cleanIp = this.ipResolver ? this.ipResolver.normalize(ip) : ip.trim();
|
|
184
282
|
|
|
185
|
-
// Whitelisted IPs can never be blocked
|
|
283
|
+
// Whitelisted IPs and protected gateways can never be blocked
|
|
186
284
|
if (this.whitelist.has(cleanIp)) return;
|
|
285
|
+
if (this.ipResolver && this.ipResolver.isProtectedGateway(cleanIp)) {
|
|
286
|
+
this.logger.warn?.(`[SHIELD] Block attempted on protected gateway/loopback (${cleanIp}). Block prevented.`);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
187
289
|
|
|
188
290
|
// 1. Add to Bloom filter (for sub-0.1ms pass-through check)
|
|
189
291
|
this.bloom.add(cleanIp);
|
|
190
292
|
|
|
191
293
|
// 2. Add to LRU confirmed threat cache (with TTL)
|
|
192
294
|
this.lru.set(cleanIp, { reason, metadata }, customTtlMs);
|
|
295
|
+
|
|
296
|
+
// 3. Persist to storage adapter
|
|
297
|
+
const expiresAt = customTtlMs ? Date.now() + customTtlMs : (this.lru.ttlMs ? Date.now() + this.lru.ttlMs : null);
|
|
298
|
+
try {
|
|
299
|
+
this.storageAdapter?.saveBlockedIP(cleanIp, reason, metadata, expiresAt);
|
|
300
|
+
} catch (err) {
|
|
301
|
+
this.logger.error?.('[SHIELD:STORAGE] Error saving blocked IP to storage:', err.message);
|
|
302
|
+
}
|
|
193
303
|
}
|
|
194
304
|
|
|
195
305
|
/**
|
|
@@ -199,8 +309,14 @@ export class Shield extends EventEmitter {
|
|
|
199
309
|
*/
|
|
200
310
|
unblockIP(ip) {
|
|
201
311
|
if (!ip || typeof ip !== 'string') return;
|
|
202
|
-
const cleanIp = ip.trim();
|
|
312
|
+
const cleanIp = this.ipResolver ? this.ipResolver.normalize(ip) : ip.trim();
|
|
203
313
|
this.lru.delete(cleanIp);
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
this.storageAdapter?.removeBlockedIP(cleanIp);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
this.logger.error?.('[SHIELD:STORAGE] Error removing blocked IP from storage:', err.message);
|
|
319
|
+
}
|
|
204
320
|
}
|
|
205
321
|
|
|
206
322
|
/**
|
|
@@ -300,8 +416,9 @@ export class Shield extends EventEmitter {
|
|
|
300
416
|
* Graceful shutdown: flush in-memory state to 404_intelligence.json
|
|
301
417
|
*/
|
|
302
418
|
async shutdown() {
|
|
303
|
-
this.logger.info?.('[SHIELD] Graceful shutdown initiated. Flushing
|
|
419
|
+
this.logger.info?.('[SHIELD] Graceful shutdown initiated. Flushing state to disk...');
|
|
304
420
|
await this.filePersistence.stop();
|
|
421
|
+
await this.storageAdapter?.close?.();
|
|
305
422
|
this.notFoundHandler.destroy();
|
|
306
423
|
this.costThrottleInstance.destroy();
|
|
307
424
|
this.keyLeakDetectorInstance.destroy();
|
|
@@ -318,4 +435,20 @@ export function createShield(options = {}) {
|
|
|
318
435
|
return new Shield(options);
|
|
319
436
|
}
|
|
320
437
|
|
|
438
|
+
export { MiniRocket } from './biometrics/minirocket.js';
|
|
439
|
+
export { DualRidgeClassifier } from './biometrics/ridge.js';
|
|
440
|
+
export { BehavioralShieldService } from './middleware/behavioralGuard.js';
|
|
441
|
+
export { IPResolver } from './core/ipResolver.js';
|
|
442
|
+
export { OTPGate, createOtpGate } from './admin/otpGate.js';
|
|
443
|
+
export {
|
|
444
|
+
BaseStorageAdapter,
|
|
445
|
+
MemoryAdapter,
|
|
446
|
+
FileStorageAdapter,
|
|
447
|
+
CallbackStorageAdapter,
|
|
448
|
+
createStorageAdapter
|
|
449
|
+
} from './storage/index.js';
|
|
450
|
+
export { ShieldClient } from './client/shieldClient.js';
|
|
451
|
+
export { MouseTelemetryCollector } from './client/collector.js';
|
|
452
|
+
export { injectTripwire } from './client/index.js';
|
|
453
|
+
|
|
321
454
|
export default createShield;
|