nextjs-secure 0.7.0 → 0.8.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 +228 -1
- package/dist/api.cjs +1707 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +708 -0
- package/dist/api.d.ts +708 -0
- package/dist/api.js +1650 -0
- package/dist/api.js.map +1 -0
- package/dist/index.cjs +1674 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1631 -2
- package/dist/index.js.map +1 -1
- package/package.json +11 -1
package/dist/api.d.cts
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* API Security Types
|
|
5
|
+
* @module nextjs-secure/api
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Supported signing algorithms
|
|
9
|
+
*/
|
|
10
|
+
type SigningAlgorithm = 'sha256' | 'sha512' | 'sha384' | 'sha1';
|
|
11
|
+
/**
|
|
12
|
+
* Signature encoding format
|
|
13
|
+
*/
|
|
14
|
+
type SignatureEncoding = 'hex' | 'base64' | 'base64url';
|
|
15
|
+
/**
|
|
16
|
+
* Components to include in signature
|
|
17
|
+
*/
|
|
18
|
+
interface SignatureComponents {
|
|
19
|
+
/** Include HTTP method */
|
|
20
|
+
method?: boolean;
|
|
21
|
+
/** Include request path */
|
|
22
|
+
path?: boolean;
|
|
23
|
+
/** Include query string */
|
|
24
|
+
query?: boolean;
|
|
25
|
+
/** Include request body */
|
|
26
|
+
body?: boolean;
|
|
27
|
+
/** Include specific headers */
|
|
28
|
+
headers?: string[];
|
|
29
|
+
/** Include timestamp */
|
|
30
|
+
timestamp?: boolean;
|
|
31
|
+
/** Include nonce */
|
|
32
|
+
nonce?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Request signing options
|
|
36
|
+
*/
|
|
37
|
+
interface SigningOptions {
|
|
38
|
+
/** Secret key for HMAC signing */
|
|
39
|
+
secret: string;
|
|
40
|
+
/** Signing algorithm (default: sha256) */
|
|
41
|
+
algorithm?: SigningAlgorithm;
|
|
42
|
+
/** Signature encoding (default: hex) */
|
|
43
|
+
encoding?: SignatureEncoding;
|
|
44
|
+
/** Header name for signature (default: x-signature) */
|
|
45
|
+
signatureHeader?: string;
|
|
46
|
+
/** Header name for timestamp (default: x-timestamp) */
|
|
47
|
+
timestampHeader?: string;
|
|
48
|
+
/** Header name for nonce (default: x-nonce) */
|
|
49
|
+
nonceHeader?: string;
|
|
50
|
+
/** Components to include in signature */
|
|
51
|
+
components?: SignatureComponents;
|
|
52
|
+
/** Timestamp tolerance in seconds (default: 300) */
|
|
53
|
+
timestampTolerance?: number;
|
|
54
|
+
/** Custom canonical string builder */
|
|
55
|
+
canonicalBuilder?: (req: Request, components: SignatureComponents) => Promise<string>;
|
|
56
|
+
/** Custom error response */
|
|
57
|
+
onInvalid?: (reason: string) => Response | Promise<Response>;
|
|
58
|
+
/** Skip signing for certain requests */
|
|
59
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Signature verification result
|
|
63
|
+
*/
|
|
64
|
+
interface SignatureResult {
|
|
65
|
+
/** Whether signature is valid */
|
|
66
|
+
valid: boolean;
|
|
67
|
+
/** Reason for failure (if invalid) */
|
|
68
|
+
reason?: string;
|
|
69
|
+
/** Computed signature (for debugging) */
|
|
70
|
+
computed?: string;
|
|
71
|
+
/** Provided signature */
|
|
72
|
+
provided?: string;
|
|
73
|
+
/** Canonical string used */
|
|
74
|
+
canonical?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Nonce store interface for replay prevention
|
|
78
|
+
*/
|
|
79
|
+
interface NonceStore {
|
|
80
|
+
/** Check if nonce exists (has been used) */
|
|
81
|
+
exists(nonce: string): Promise<boolean>;
|
|
82
|
+
/** Store a nonce with TTL */
|
|
83
|
+
set(nonce: string, ttl: number): Promise<void>;
|
|
84
|
+
/** Remove expired nonces (optional cleanup) */
|
|
85
|
+
cleanup?(): Promise<void>;
|
|
86
|
+
/** Get store statistics */
|
|
87
|
+
getStats?(): {
|
|
88
|
+
size: number;
|
|
89
|
+
oldestTimestamp?: number;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Replay prevention options
|
|
94
|
+
*/
|
|
95
|
+
interface ReplayPreventionOptions {
|
|
96
|
+
/** Nonce store instance */
|
|
97
|
+
store?: NonceStore;
|
|
98
|
+
/** Header name for nonce (default: x-nonce) */
|
|
99
|
+
nonceHeader?: string;
|
|
100
|
+
/** Query param name for nonce (optional) */
|
|
101
|
+
nonceQuery?: string;
|
|
102
|
+
/** TTL for nonces in milliseconds (default: 300000 = 5 minutes) */
|
|
103
|
+
ttl?: number;
|
|
104
|
+
/** Require nonce on all requests (default: true) */
|
|
105
|
+
required?: boolean;
|
|
106
|
+
/** Minimum nonce length (default: 16) */
|
|
107
|
+
minLength?: number;
|
|
108
|
+
/** Maximum nonce length (default: 128) */
|
|
109
|
+
maxLength?: number;
|
|
110
|
+
/** Custom nonce validator */
|
|
111
|
+
validate?: (nonce: string) => boolean | Promise<boolean>;
|
|
112
|
+
/** Custom error response */
|
|
113
|
+
onReplay?: (nonce: string) => Response | Promise<Response>;
|
|
114
|
+
/** Skip replay check for certain requests */
|
|
115
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Replay check result
|
|
119
|
+
*/
|
|
120
|
+
interface ReplayCheckResult {
|
|
121
|
+
/** Whether request is a replay */
|
|
122
|
+
isReplay: boolean;
|
|
123
|
+
/** Nonce value */
|
|
124
|
+
nonce?: string;
|
|
125
|
+
/** Reason for failure */
|
|
126
|
+
reason?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Timestamp format
|
|
130
|
+
*/
|
|
131
|
+
type TimestampFormat = 'unix' | 'unix-ms' | 'iso8601';
|
|
132
|
+
/**
|
|
133
|
+
* Timestamp validation options
|
|
134
|
+
*/
|
|
135
|
+
interface TimestampOptions {
|
|
136
|
+
/** Header name for timestamp (default: x-timestamp) */
|
|
137
|
+
timestampHeader?: string;
|
|
138
|
+
/** Query param name for timestamp (optional) */
|
|
139
|
+
timestampQuery?: string;
|
|
140
|
+
/** Expected timestamp format (default: unix) */
|
|
141
|
+
format?: TimestampFormat;
|
|
142
|
+
/** Maximum age in seconds (default: 300 = 5 minutes) */
|
|
143
|
+
maxAge?: number;
|
|
144
|
+
/** Allow future timestamps (default: false) */
|
|
145
|
+
allowFuture?: boolean;
|
|
146
|
+
/** Maximum future time in seconds (default: 60) */
|
|
147
|
+
maxFuture?: number;
|
|
148
|
+
/** Require timestamp on all requests (default: true) */
|
|
149
|
+
required?: boolean;
|
|
150
|
+
/** Custom error response */
|
|
151
|
+
onInvalid?: (reason: string) => Response | Promise<Response>;
|
|
152
|
+
/** Skip timestamp check for certain requests */
|
|
153
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Timestamp validation result
|
|
157
|
+
*/
|
|
158
|
+
interface TimestampResult {
|
|
159
|
+
/** Whether timestamp is valid */
|
|
160
|
+
valid: boolean;
|
|
161
|
+
/** Parsed timestamp value */
|
|
162
|
+
timestamp?: number;
|
|
163
|
+
/** Age of request in seconds */
|
|
164
|
+
age?: number;
|
|
165
|
+
/** Reason for failure */
|
|
166
|
+
reason?: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Version extraction source
|
|
170
|
+
*/
|
|
171
|
+
type VersionSource = 'header' | 'path' | 'query' | 'accept';
|
|
172
|
+
/**
|
|
173
|
+
* Version status
|
|
174
|
+
*/
|
|
175
|
+
type VersionStatus = 'current' | 'supported' | 'deprecated' | 'sunset';
|
|
176
|
+
/**
|
|
177
|
+
* Version information
|
|
178
|
+
*/
|
|
179
|
+
interface VersionInfo {
|
|
180
|
+
/** Version string */
|
|
181
|
+
version: string;
|
|
182
|
+
/** Version status */
|
|
183
|
+
status: VersionStatus;
|
|
184
|
+
/** Sunset date (for deprecated versions) */
|
|
185
|
+
sunsetDate?: Date;
|
|
186
|
+
/** Deprecation message */
|
|
187
|
+
deprecationMessage?: string;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* API versioning options
|
|
191
|
+
*/
|
|
192
|
+
interface VersioningOptions {
|
|
193
|
+
/** Version extraction source (default: header) */
|
|
194
|
+
source?: VersionSource;
|
|
195
|
+
/** Header name for version (default: x-api-version) */
|
|
196
|
+
versionHeader?: string;
|
|
197
|
+
/** Query param name for version */
|
|
198
|
+
versionQuery?: string;
|
|
199
|
+
/** Path prefix pattern (e.g., /v{version}/) */
|
|
200
|
+
pathPattern?: RegExp;
|
|
201
|
+
/** Accept header media type pattern */
|
|
202
|
+
acceptPattern?: RegExp;
|
|
203
|
+
/** Current/default version */
|
|
204
|
+
current: string;
|
|
205
|
+
/** All supported versions */
|
|
206
|
+
supported: string[];
|
|
207
|
+
/** Deprecated versions (still work but show warning) */
|
|
208
|
+
deprecated?: string[];
|
|
209
|
+
/** Sunset versions (no longer work) */
|
|
210
|
+
sunset?: string[];
|
|
211
|
+
/** Sunset dates for deprecated versions */
|
|
212
|
+
sunsetDates?: Record<string, Date>;
|
|
213
|
+
/** Add deprecation headers to response */
|
|
214
|
+
addDeprecationHeaders?: boolean;
|
|
215
|
+
/** Custom version parser */
|
|
216
|
+
parseVersion?: (value: string) => string | null;
|
|
217
|
+
/** Custom error response for unsupported version */
|
|
218
|
+
onUnsupported?: (version: string) => Response | Promise<Response>;
|
|
219
|
+
/** Custom warning response for deprecated version */
|
|
220
|
+
onDeprecated?: (version: string, sunsetDate?: Date) => void;
|
|
221
|
+
/** Skip version check for certain requests */
|
|
222
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Version extraction result
|
|
226
|
+
*/
|
|
227
|
+
interface VersionResult {
|
|
228
|
+
/** Extracted version */
|
|
229
|
+
version: string | null;
|
|
230
|
+
/** Version source */
|
|
231
|
+
source: VersionSource | null;
|
|
232
|
+
/** Version status */
|
|
233
|
+
status: VersionStatus | null;
|
|
234
|
+
/** Whether version is valid */
|
|
235
|
+
valid: boolean;
|
|
236
|
+
/** Reason for failure */
|
|
237
|
+
reason?: string;
|
|
238
|
+
/** Sunset date (if deprecated) */
|
|
239
|
+
sunsetDate?: Date;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Cached response for idempotency
|
|
243
|
+
*/
|
|
244
|
+
interface CachedResponse {
|
|
245
|
+
/** Response status code */
|
|
246
|
+
status: number;
|
|
247
|
+
/** Response headers */
|
|
248
|
+
headers: Record<string, string>;
|
|
249
|
+
/** Response body */
|
|
250
|
+
body: string;
|
|
251
|
+
/** Timestamp when cached */
|
|
252
|
+
cachedAt: number;
|
|
253
|
+
/** Request hash for validation */
|
|
254
|
+
requestHash?: string;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Idempotency store interface
|
|
258
|
+
*/
|
|
259
|
+
interface IdempotencyStore {
|
|
260
|
+
/** Get cached response for key */
|
|
261
|
+
get(key: string): Promise<CachedResponse | null>;
|
|
262
|
+
/** Store response with TTL */
|
|
263
|
+
set(key: string, response: CachedResponse, ttl: number): Promise<void>;
|
|
264
|
+
/** Check if key is currently being processed (for concurrent requests) */
|
|
265
|
+
isProcessing(key: string): Promise<boolean>;
|
|
266
|
+
/** Mark key as being processed */
|
|
267
|
+
startProcessing(key: string, timeout: number): Promise<boolean>;
|
|
268
|
+
/** Mark key as done processing */
|
|
269
|
+
endProcessing(key: string): Promise<void>;
|
|
270
|
+
/** Remove a key */
|
|
271
|
+
delete(key: string): Promise<void>;
|
|
272
|
+
/** Cleanup expired entries */
|
|
273
|
+
cleanup?(): Promise<void>;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Idempotency options
|
|
277
|
+
*/
|
|
278
|
+
interface IdempotencyOptions {
|
|
279
|
+
/** Idempotency store instance */
|
|
280
|
+
store?: IdempotencyStore;
|
|
281
|
+
/** Header name for idempotency key (default: idempotency-key) */
|
|
282
|
+
keyHeader?: string;
|
|
283
|
+
/** TTL for cached responses in milliseconds (default: 86400000 = 24 hours) */
|
|
284
|
+
ttl?: number;
|
|
285
|
+
/** Require idempotency key for mutating requests (default: false) */
|
|
286
|
+
required?: boolean;
|
|
287
|
+
/** HTTP methods that require idempotency (default: POST, PUT, PATCH) */
|
|
288
|
+
methods?: string[];
|
|
289
|
+
/** Minimum key length (default: 16) */
|
|
290
|
+
minKeyLength?: number;
|
|
291
|
+
/** Maximum key length (default: 256) */
|
|
292
|
+
maxKeyLength?: number;
|
|
293
|
+
/** Include request body hash in cache key (default: true) */
|
|
294
|
+
hashRequestBody?: boolean;
|
|
295
|
+
/** Lock timeout for concurrent requests in ms (default: 30000) */
|
|
296
|
+
lockTimeout?: number;
|
|
297
|
+
/** Wait for lock instead of failing (default: true) */
|
|
298
|
+
waitForLock?: boolean;
|
|
299
|
+
/** Max wait time for lock in ms (default: 10000) */
|
|
300
|
+
maxWaitTime?: number;
|
|
301
|
+
/** Custom key validator */
|
|
302
|
+
validateKey?: (key: string) => boolean | Promise<boolean>;
|
|
303
|
+
/** Custom error response */
|
|
304
|
+
onError?: (reason: string) => Response | Promise<Response>;
|
|
305
|
+
/** Skip idempotency for certain requests */
|
|
306
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
307
|
+
/** Called when returning cached response */
|
|
308
|
+
onCacheHit?: (key: string, response: CachedResponse) => void;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Idempotency check result
|
|
312
|
+
*/
|
|
313
|
+
interface IdempotencyResult {
|
|
314
|
+
/** Idempotency key */
|
|
315
|
+
key: string | null;
|
|
316
|
+
/** Whether response was from cache */
|
|
317
|
+
fromCache: boolean;
|
|
318
|
+
/** Cached response (if from cache) */
|
|
319
|
+
cachedResponse?: CachedResponse;
|
|
320
|
+
/** Whether request is currently being processed */
|
|
321
|
+
isProcessing: boolean;
|
|
322
|
+
/** Reason for any errors */
|
|
323
|
+
reason?: string;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* API protection preset names
|
|
327
|
+
*/
|
|
328
|
+
type APIProtectionPreset = 'basic' | 'standard' | 'strict' | 'financial';
|
|
329
|
+
/**
|
|
330
|
+
* Combined API protection options
|
|
331
|
+
*/
|
|
332
|
+
interface APIProtectionOptions {
|
|
333
|
+
/** Request signing options (false to disable) */
|
|
334
|
+
signing?: SigningOptions | false;
|
|
335
|
+
/** Replay prevention options (false to disable) */
|
|
336
|
+
replay?: ReplayPreventionOptions | false;
|
|
337
|
+
/** Timestamp validation options (false to disable) */
|
|
338
|
+
timestamp?: TimestampOptions | false;
|
|
339
|
+
/** API versioning options (false to disable) */
|
|
340
|
+
versioning?: VersioningOptions | false;
|
|
341
|
+
/** Idempotency options (false to disable) */
|
|
342
|
+
idempotency?: IdempotencyOptions | false;
|
|
343
|
+
/** Custom error handler */
|
|
344
|
+
onError?: (error: APISecurityError) => Response | Promise<Response>;
|
|
345
|
+
/** Skip all checks for certain requests */
|
|
346
|
+
skip?: (req: Request) => boolean | Promise<boolean>;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* API security error
|
|
350
|
+
*/
|
|
351
|
+
interface APISecurityError {
|
|
352
|
+
/** Error type */
|
|
353
|
+
type: 'signing' | 'replay' | 'timestamp' | 'versioning' | 'idempotency';
|
|
354
|
+
/** Error message */
|
|
355
|
+
message: string;
|
|
356
|
+
/** Additional details */
|
|
357
|
+
details?: Record<string, unknown>;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* API protection result
|
|
361
|
+
*/
|
|
362
|
+
interface APIProtectionResult {
|
|
363
|
+
/** Whether all checks passed */
|
|
364
|
+
passed: boolean;
|
|
365
|
+
/** Signing result */
|
|
366
|
+
signing?: SignatureResult;
|
|
367
|
+
/** Replay check result */
|
|
368
|
+
replay?: ReplayCheckResult;
|
|
369
|
+
/** Timestamp result */
|
|
370
|
+
timestamp?: TimestampResult;
|
|
371
|
+
/** Version result */
|
|
372
|
+
version?: VersionResult;
|
|
373
|
+
/** Idempotency result */
|
|
374
|
+
idempotency?: IdempotencyResult;
|
|
375
|
+
/** Error if any check failed */
|
|
376
|
+
error?: APISecurityError;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* API protection presets
|
|
380
|
+
*/
|
|
381
|
+
declare const API_PROTECTION_PRESETS: Record<APIProtectionPreset, Partial<APIProtectionOptions>>;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Request Signing for API Security
|
|
385
|
+
* @module nextjs-secure/api
|
|
386
|
+
*/
|
|
387
|
+
|
|
388
|
+
declare const DEFAULT_SIGNING_OPTIONS: Required<Omit<SigningOptions, 'secret' | 'canonicalBuilder' | 'onInvalid' | 'skip'>>;
|
|
389
|
+
/**
|
|
390
|
+
* Create HMAC signature using Web Crypto API
|
|
391
|
+
*/
|
|
392
|
+
declare function createHMAC(data: string, secret: string, algorithm?: SigningAlgorithm, encoding?: SignatureEncoding): Promise<string>;
|
|
393
|
+
/**
|
|
394
|
+
* Timing-safe string comparison
|
|
395
|
+
*/
|
|
396
|
+
declare function timingSafeEqual(a: string, b: string): boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Build canonical string for signing
|
|
399
|
+
*/
|
|
400
|
+
declare function buildCanonicalString(req: NextRequest, components: SignatureComponents, options?: {
|
|
401
|
+
timestampHeader?: string;
|
|
402
|
+
nonceHeader?: string;
|
|
403
|
+
}): Promise<string>;
|
|
404
|
+
/**
|
|
405
|
+
* Generate signature for a request
|
|
406
|
+
*/
|
|
407
|
+
declare function generateSignature(req: NextRequest, options: SigningOptions): Promise<string>;
|
|
408
|
+
/**
|
|
409
|
+
* Generate signature headers for outgoing requests
|
|
410
|
+
*/
|
|
411
|
+
declare function generateSignatureHeaders(method: string, url: string, body: string | null, options: SigningOptions & {
|
|
412
|
+
includeTimestamp?: boolean;
|
|
413
|
+
includeNonce?: boolean;
|
|
414
|
+
}): Promise<Record<string, string>>;
|
|
415
|
+
/**
|
|
416
|
+
* Generate a random nonce
|
|
417
|
+
*/
|
|
418
|
+
declare function generateNonce$1(length?: number): string;
|
|
419
|
+
/**
|
|
420
|
+
* Verify request signature
|
|
421
|
+
*/
|
|
422
|
+
declare function verifySignature(req: NextRequest, options: SigningOptions): Promise<SignatureResult>;
|
|
423
|
+
/**
|
|
424
|
+
* Create request signing middleware
|
|
425
|
+
*/
|
|
426
|
+
declare function withRequestSigning<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options: SigningOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Replay Attack Prevention for API Security
|
|
430
|
+
* @module nextjs-secure/api
|
|
431
|
+
*/
|
|
432
|
+
|
|
433
|
+
declare const DEFAULT_REPLAY_OPTIONS: Required<Omit<ReplayPreventionOptions, 'store' | 'validate' | 'onReplay' | 'skip'>>;
|
|
434
|
+
/**
|
|
435
|
+
* In-memory nonce store with LRU eviction
|
|
436
|
+
*/
|
|
437
|
+
declare class MemoryNonceStore implements NonceStore {
|
|
438
|
+
private nonces;
|
|
439
|
+
private maxSize;
|
|
440
|
+
private cleanupInterval;
|
|
441
|
+
constructor(options?: {
|
|
442
|
+
maxSize?: number;
|
|
443
|
+
autoCleanup?: boolean;
|
|
444
|
+
cleanupIntervalMs?: number;
|
|
445
|
+
});
|
|
446
|
+
exists(nonce: string): Promise<boolean>;
|
|
447
|
+
set(nonce: string, ttl: number): Promise<void>;
|
|
448
|
+
cleanup(): Promise<void>;
|
|
449
|
+
getStats(): {
|
|
450
|
+
size: number;
|
|
451
|
+
oldestTimestamp?: number;
|
|
452
|
+
};
|
|
453
|
+
private evictOldest;
|
|
454
|
+
/**
|
|
455
|
+
* Clear all nonces
|
|
456
|
+
*/
|
|
457
|
+
clear(): void;
|
|
458
|
+
/**
|
|
459
|
+
* Stop auto cleanup
|
|
460
|
+
*/
|
|
461
|
+
destroy(): void;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get global nonce store (singleton)
|
|
465
|
+
*/
|
|
466
|
+
declare function getGlobalNonceStore(): MemoryNonceStore;
|
|
467
|
+
/**
|
|
468
|
+
* Generate a cryptographically secure nonce
|
|
469
|
+
*/
|
|
470
|
+
declare function generateNonce(length?: number): string;
|
|
471
|
+
/**
|
|
472
|
+
* Validate nonce format
|
|
473
|
+
*/
|
|
474
|
+
declare function isValidNonceFormat(nonce: string, minLength?: number, maxLength?: number): boolean;
|
|
475
|
+
/**
|
|
476
|
+
* Extract nonce from request
|
|
477
|
+
*/
|
|
478
|
+
declare function extractNonce(req: NextRequest, options?: ReplayPreventionOptions): string | null;
|
|
479
|
+
/**
|
|
480
|
+
* Check request for replay attack
|
|
481
|
+
*/
|
|
482
|
+
declare function checkReplay(req: NextRequest, options?: ReplayPreventionOptions): Promise<ReplayCheckResult>;
|
|
483
|
+
/**
|
|
484
|
+
* Create replay prevention middleware
|
|
485
|
+
*/
|
|
486
|
+
declare function withReplayPrevention<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options?: ReplayPreventionOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
487
|
+
/**
|
|
488
|
+
* Add nonce header to outgoing request headers
|
|
489
|
+
*/
|
|
490
|
+
declare function addNonceHeader(headers?: Record<string, string>, options?: {
|
|
491
|
+
headerName?: string;
|
|
492
|
+
length?: number;
|
|
493
|
+
}): Record<string, string>;
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Timestamp Validation for API Security
|
|
497
|
+
* @module nextjs-secure/api
|
|
498
|
+
*/
|
|
499
|
+
|
|
500
|
+
declare const DEFAULT_TIMESTAMP_OPTIONS: Required<Omit<TimestampOptions, 'timestampQuery' | 'onInvalid' | 'skip'>>;
|
|
501
|
+
/**
|
|
502
|
+
* Parse timestamp string to Unix timestamp (seconds)
|
|
503
|
+
*/
|
|
504
|
+
declare function parseTimestamp(value: string, format?: TimestampFormat): number | null;
|
|
505
|
+
/**
|
|
506
|
+
* Format current timestamp
|
|
507
|
+
*/
|
|
508
|
+
declare function formatTimestamp(format?: TimestampFormat): string;
|
|
509
|
+
/**
|
|
510
|
+
* Extract timestamp from request
|
|
511
|
+
*/
|
|
512
|
+
declare function extractTimestamp(req: NextRequest, options?: TimestampOptions): string | null;
|
|
513
|
+
/**
|
|
514
|
+
* Validate request timestamp
|
|
515
|
+
*/
|
|
516
|
+
declare function validateTimestamp(req: NextRequest, options?: TimestampOptions): TimestampResult;
|
|
517
|
+
/**
|
|
518
|
+
* Quick check if timestamp is valid
|
|
519
|
+
*/
|
|
520
|
+
declare function isTimestampValid(timestampStr: string, options?: {
|
|
521
|
+
format?: TimestampFormat;
|
|
522
|
+
maxAge?: number;
|
|
523
|
+
allowFuture?: boolean;
|
|
524
|
+
maxFuture?: number;
|
|
525
|
+
}): boolean;
|
|
526
|
+
/**
|
|
527
|
+
* Create timestamp validation middleware
|
|
528
|
+
*/
|
|
529
|
+
declare function withTimestamp<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options?: TimestampOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
530
|
+
/**
|
|
531
|
+
* Add timestamp header to outgoing request headers
|
|
532
|
+
*/
|
|
533
|
+
declare function addTimestampHeader(headers?: Record<string, string>, options?: {
|
|
534
|
+
headerName?: string;
|
|
535
|
+
format?: TimestampFormat;
|
|
536
|
+
}): Record<string, string>;
|
|
537
|
+
/**
|
|
538
|
+
* Get request age in seconds (for monitoring/logging)
|
|
539
|
+
*/
|
|
540
|
+
declare function getRequestAge(req: NextRequest, options?: TimestampOptions): number | null;
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* API Versioning for API Security
|
|
544
|
+
* @module nextjs-secure/api
|
|
545
|
+
*/
|
|
546
|
+
|
|
547
|
+
declare const DEFAULT_VERSIONING_OPTIONS: Required<Omit<VersioningOptions, 'current' | 'supported' | 'deprecated' | 'sunset' | 'sunsetDates' | 'pathPattern' | 'acceptPattern' | 'parseVersion' | 'onUnsupported' | 'onDeprecated' | 'skip'>>;
|
|
548
|
+
/**
|
|
549
|
+
* Extract version from request
|
|
550
|
+
*/
|
|
551
|
+
declare function extractVersion(req: NextRequest, options: VersioningOptions): {
|
|
552
|
+
version: string | null;
|
|
553
|
+
source: VersionSource | null;
|
|
554
|
+
};
|
|
555
|
+
/**
|
|
556
|
+
* Try to extract version from multiple sources
|
|
557
|
+
*/
|
|
558
|
+
declare function extractVersionMultiSource(req: NextRequest, options: VersioningOptions, sources?: VersionSource[]): {
|
|
559
|
+
version: string | null;
|
|
560
|
+
source: VersionSource | null;
|
|
561
|
+
};
|
|
562
|
+
/**
|
|
563
|
+
* Get version status
|
|
564
|
+
*/
|
|
565
|
+
declare function getVersionStatus(version: string, options: VersioningOptions): VersionStatus | null;
|
|
566
|
+
/**
|
|
567
|
+
* Check if version is supported
|
|
568
|
+
*/
|
|
569
|
+
declare function isVersionSupported(version: string, options: VersioningOptions): boolean;
|
|
570
|
+
/**
|
|
571
|
+
* Validate request version
|
|
572
|
+
*/
|
|
573
|
+
declare function validateVersion(req: NextRequest, options: VersioningOptions): VersionResult;
|
|
574
|
+
/**
|
|
575
|
+
* Add deprecation headers to response
|
|
576
|
+
*/
|
|
577
|
+
declare function addDeprecationHeaders(response: Response, version: string, sunsetDate?: Date): Response;
|
|
578
|
+
/**
|
|
579
|
+
* Create API versioning middleware
|
|
580
|
+
*/
|
|
581
|
+
declare function withAPIVersion<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options: VersioningOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
582
|
+
type VersionHandler<T> = (req: NextRequest, ctx: T) => Response | Promise<Response>;
|
|
583
|
+
/**
|
|
584
|
+
* Create version-based router
|
|
585
|
+
*/
|
|
586
|
+
declare function createVersionRouter<T = unknown>(handlers: Record<string, VersionHandler<T>>, options: Omit<VersioningOptions, 'current' | 'supported'> & {
|
|
587
|
+
default?: string;
|
|
588
|
+
}): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
589
|
+
/**
|
|
590
|
+
* Compare semantic versions
|
|
591
|
+
*/
|
|
592
|
+
declare function compareVersions(a: string, b: string): number;
|
|
593
|
+
/**
|
|
594
|
+
* Check if version is greater than or equal to minimum
|
|
595
|
+
*/
|
|
596
|
+
declare function isVersionAtLeast(version: string, minimum: string): boolean;
|
|
597
|
+
/**
|
|
598
|
+
* Normalize version string
|
|
599
|
+
*/
|
|
600
|
+
declare function normalizeVersion(version: string): string;
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Idempotency Support for API Security
|
|
604
|
+
* @module nextjs-secure/api
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
declare const DEFAULT_IDEMPOTENCY_OPTIONS: Required<Omit<IdempotencyOptions, 'store' | 'validateKey' | 'onError' | 'skip' | 'onCacheHit'>>;
|
|
608
|
+
/**
|
|
609
|
+
* In-memory idempotency store
|
|
610
|
+
*/
|
|
611
|
+
declare class MemoryIdempotencyStore implements IdempotencyStore {
|
|
612
|
+
private cache;
|
|
613
|
+
private processing;
|
|
614
|
+
private maxSize;
|
|
615
|
+
private cleanupInterval;
|
|
616
|
+
constructor(options?: {
|
|
617
|
+
maxSize?: number;
|
|
618
|
+
autoCleanup?: boolean;
|
|
619
|
+
cleanupIntervalMs?: number;
|
|
620
|
+
});
|
|
621
|
+
get(key: string): Promise<CachedResponse | null>;
|
|
622
|
+
set(key: string, response: CachedResponse, ttl: number): Promise<void>;
|
|
623
|
+
isProcessing(key: string): Promise<boolean>;
|
|
624
|
+
startProcessing(key: string, timeout: number): Promise<boolean>;
|
|
625
|
+
endProcessing(key: string): Promise<void>;
|
|
626
|
+
delete(key: string): Promise<void>;
|
|
627
|
+
cleanup(): Promise<void>;
|
|
628
|
+
getStats(): {
|
|
629
|
+
cacheSize: number;
|
|
630
|
+
processingSize: number;
|
|
631
|
+
};
|
|
632
|
+
private evictOldest;
|
|
633
|
+
/**
|
|
634
|
+
* Clear all entries
|
|
635
|
+
*/
|
|
636
|
+
clear(): void;
|
|
637
|
+
/**
|
|
638
|
+
* Stop auto cleanup
|
|
639
|
+
*/
|
|
640
|
+
destroy(): void;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Get global idempotency store (singleton)
|
|
644
|
+
*/
|
|
645
|
+
declare function getGlobalIdempotencyStore(): MemoryIdempotencyStore;
|
|
646
|
+
/**
|
|
647
|
+
* Generate a cryptographically secure idempotency key
|
|
648
|
+
*/
|
|
649
|
+
declare function generateIdempotencyKey(length?: number): string;
|
|
650
|
+
/**
|
|
651
|
+
* Hash request body using SHA-256
|
|
652
|
+
*/
|
|
653
|
+
declare function hashRequestBody(body: string): Promise<string>;
|
|
654
|
+
/**
|
|
655
|
+
* Validate idempotency key format
|
|
656
|
+
*/
|
|
657
|
+
declare function isValidIdempotencyKey(key: string, minLength?: number, maxLength?: number): boolean;
|
|
658
|
+
/**
|
|
659
|
+
* Create cache key from idempotency key and request hash
|
|
660
|
+
*/
|
|
661
|
+
declare function createCacheKey(idempotencyKey: string, req: NextRequest, hashBody?: boolean): Promise<string>;
|
|
662
|
+
/**
|
|
663
|
+
* Extract idempotency key from request
|
|
664
|
+
*/
|
|
665
|
+
declare function extractIdempotencyKey(req: NextRequest, options?: IdempotencyOptions): string | null;
|
|
666
|
+
/**
|
|
667
|
+
* Check idempotency for request
|
|
668
|
+
*/
|
|
669
|
+
declare function checkIdempotency(req: NextRequest, options?: IdempotencyOptions): Promise<IdempotencyResult>;
|
|
670
|
+
/**
|
|
671
|
+
* Cache response for idempotency key
|
|
672
|
+
*/
|
|
673
|
+
declare function cacheResponse(key: string, req: NextRequest, response: Response, options?: IdempotencyOptions): Promise<void>;
|
|
674
|
+
/**
|
|
675
|
+
* Create response from cached data
|
|
676
|
+
*/
|
|
677
|
+
declare function createResponseFromCache(cached: CachedResponse): Response;
|
|
678
|
+
/**
|
|
679
|
+
* Create idempotency middleware
|
|
680
|
+
*/
|
|
681
|
+
declare function withIdempotency<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options?: IdempotencyOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
682
|
+
/**
|
|
683
|
+
* Add idempotency key header to outgoing request headers
|
|
684
|
+
*/
|
|
685
|
+
declare function addIdempotencyHeader(headers?: Record<string, string>, options?: {
|
|
686
|
+
headerName?: string;
|
|
687
|
+
key?: string;
|
|
688
|
+
}): Record<string, string>;
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Combined API Security Middleware
|
|
692
|
+
* @module nextjs-secure/api
|
|
693
|
+
*/
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Check all API security measures
|
|
697
|
+
*/
|
|
698
|
+
declare function checkAPIProtection(req: NextRequest, options: APIProtectionOptions): Promise<APIProtectionResult>;
|
|
699
|
+
/**
|
|
700
|
+
* Create combined API protection middleware
|
|
701
|
+
*/
|
|
702
|
+
declare function withAPIProtection<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options: APIProtectionOptions): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
703
|
+
/**
|
|
704
|
+
* Create API protection middleware using preset
|
|
705
|
+
*/
|
|
706
|
+
declare function withAPIProtectionPreset<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, preset: APIProtectionPreset, overrides?: Partial<APIProtectionOptions>): (req: NextRequest, ctx: T) => Promise<Response>;
|
|
707
|
+
|
|
708
|
+
export { type APIProtectionOptions, type APIProtectionPreset, type APIProtectionResult, type APISecurityError, API_PROTECTION_PRESETS, type CachedResponse, DEFAULT_IDEMPOTENCY_OPTIONS, DEFAULT_REPLAY_OPTIONS, DEFAULT_SIGNING_OPTIONS, DEFAULT_TIMESTAMP_OPTIONS, DEFAULT_VERSIONING_OPTIONS, type IdempotencyOptions, type IdempotencyResult, type IdempotencyStore, MemoryIdempotencyStore, MemoryNonceStore, type NonceStore, type ReplayCheckResult, type ReplayPreventionOptions, type SignatureComponents, type SignatureEncoding, type SignatureResult, type SigningAlgorithm, type SigningOptions, type TimestampFormat, type TimestampOptions, type TimestampResult, type VersionInfo, type VersionResult, type VersionSource, type VersionStatus, type VersioningOptions, addDeprecationHeaders, addIdempotencyHeader, addNonceHeader, addTimestampHeader, buildCanonicalString, cacheResponse, checkAPIProtection, checkIdempotency, checkReplay, compareVersions, createCacheKey, createHMAC, generateNonce$1 as createNonce, createResponseFromCache, createVersionRouter, extractIdempotencyKey, extractNonce, extractTimestamp, extractVersion, extractVersionMultiSource, formatTimestamp, generateIdempotencyKey, generateNonce, generateSignature, generateSignatureHeaders, getGlobalIdempotencyStore, getGlobalNonceStore, getRequestAge, getVersionStatus, hashRequestBody, isTimestampValid, isValidIdempotencyKey, isValidNonceFormat, isVersionAtLeast, isVersionSupported, normalizeVersion, parseTimestamp, timingSafeEqual, validateTimestamp, validateVersion, verifySignature, withAPIProtection, withAPIProtectionPreset, withAPIVersion, withIdempotency, withReplayPrevention, withRequestSigning, withTimestamp };
|