cors-whitelist-ip 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +284 -0
- package/dist/cjs/adapters/cache/InMemoryCacheAdapter.d.ts +19 -0
- package/dist/cjs/adapters/cache/InMemoryCacheAdapter.d.ts.map +1 -0
- package/dist/cjs/adapters/cache/InMemoryCacheAdapter.js +69 -0
- package/dist/cjs/adapters/cache/InMemoryCacheAdapter.js.map +1 -0
- package/dist/cjs/adapters/cache/NoCacheAdapter.d.ts +14 -0
- package/dist/cjs/adapters/cache/NoCacheAdapter.d.ts.map +1 -0
- package/dist/cjs/adapters/cache/NoCacheAdapter.js +29 -0
- package/dist/cjs/adapters/cache/NoCacheAdapter.js.map +1 -0
- package/dist/cjs/adapters/cache/index.d.ts +3 -0
- package/dist/cjs/adapters/cache/index.d.ts.map +1 -0
- package/dist/cjs/adapters/cache/index.js +8 -0
- package/dist/cjs/adapters/cache/index.js.map +1 -0
- package/dist/cjs/adapters/storage/InMemoryStorageAdapter.d.ts +30 -0
- package/dist/cjs/adapters/storage/InMemoryStorageAdapter.d.ts.map +1 -0
- package/dist/cjs/adapters/storage/InMemoryStorageAdapter.js +70 -0
- package/dist/cjs/adapters/storage/InMemoryStorageAdapter.js.map +1 -0
- package/dist/cjs/adapters/storage/index.d.ts +3 -0
- package/dist/cjs/adapters/storage/index.d.ts.map +1 -0
- package/dist/cjs/adapters/storage/index.js +6 -0
- package/dist/cjs/adapters/storage/index.js.map +1 -0
- package/dist/cjs/core/CorsWhitelist.d.ts +60 -0
- package/dist/cjs/core/CorsWhitelist.d.ts.map +1 -0
- package/dist/cjs/core/CorsWhitelist.js +273 -0
- package/dist/cjs/core/CorsWhitelist.js.map +1 -0
- package/dist/cjs/core/index.d.ts +4 -0
- package/dist/cjs/core/index.d.ts.map +1 -0
- package/dist/cjs/core/index.js +22 -0
- package/dist/cjs/core/index.js.map +1 -0
- package/dist/cjs/core/types.d.ts +201 -0
- package/dist/cjs/core/types.d.ts.map +1 -0
- package/dist/cjs/core/types.js +3 -0
- package/dist/cjs/core/types.js.map +1 -0
- package/dist/cjs/core/utils.d.ts +31 -0
- package/dist/cjs/core/utils.d.ts.map +1 -0
- package/dist/cjs/core/utils.js +82 -0
- package/dist/cjs/core/utils.js.map +1 -0
- package/dist/cjs/frameworks/express.d.ts +15 -0
- package/dist/cjs/frameworks/express.d.ts.map +1 -0
- package/dist/cjs/frameworks/express.js +49 -0
- package/dist/cjs/frameworks/express.js.map +1 -0
- package/dist/cjs/frameworks/fastify.d.ts +18 -0
- package/dist/cjs/frameworks/fastify.d.ts.map +1 -0
- package/dist/cjs/frameworks/fastify.js +49 -0
- package/dist/cjs/frameworks/fastify.js.map +1 -0
- package/dist/cjs/frameworks/index.d.ts +5 -0
- package/dist/cjs/frameworks/index.d.ts.map +1 -0
- package/dist/cjs/frameworks/index.js +15 -0
- package/dist/cjs/frameworks/index.js.map +1 -0
- package/dist/cjs/frameworks/koa.d.ts +15 -0
- package/dist/cjs/frameworks/koa.d.ts.map +1 -0
- package/dist/cjs/frameworks/koa.js +48 -0
- package/dist/cjs/frameworks/koa.js.map +1 -0
- package/dist/cjs/frameworks/node-http.d.ts +16 -0
- package/dist/cjs/frameworks/node-http.d.ts.map +1 -0
- package/dist/cjs/frameworks/node-http.js +46 -0
- package/dist/cjs/frameworks/node-http.js.map +1 -0
- package/dist/cjs/index.d.ts +12 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +43 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/adapters/cache/InMemoryCacheAdapter.d.ts +19 -0
- package/dist/esm/adapters/cache/InMemoryCacheAdapter.d.ts.map +1 -0
- package/dist/esm/adapters/cache/InMemoryCacheAdapter.js +69 -0
- package/dist/esm/adapters/cache/InMemoryCacheAdapter.js.map +1 -0
- package/dist/esm/adapters/cache/NoCacheAdapter.d.ts +14 -0
- package/dist/esm/adapters/cache/NoCacheAdapter.d.ts.map +1 -0
- package/dist/esm/adapters/cache/NoCacheAdapter.js +29 -0
- package/dist/esm/adapters/cache/NoCacheAdapter.js.map +1 -0
- package/dist/esm/adapters/cache/index.d.ts +3 -0
- package/dist/esm/adapters/cache/index.d.ts.map +1 -0
- package/dist/esm/adapters/cache/index.js +8 -0
- package/dist/esm/adapters/cache/index.js.map +1 -0
- package/dist/esm/adapters/storage/InMemoryStorageAdapter.d.ts +30 -0
- package/dist/esm/adapters/storage/InMemoryStorageAdapter.d.ts.map +1 -0
- package/dist/esm/adapters/storage/InMemoryStorageAdapter.js +70 -0
- package/dist/esm/adapters/storage/InMemoryStorageAdapter.js.map +1 -0
- package/dist/esm/adapters/storage/index.d.ts +3 -0
- package/dist/esm/adapters/storage/index.d.ts.map +1 -0
- package/dist/esm/adapters/storage/index.js +6 -0
- package/dist/esm/adapters/storage/index.js.map +1 -0
- package/dist/esm/core/CorsWhitelist.d.ts +60 -0
- package/dist/esm/core/CorsWhitelist.d.ts.map +1 -0
- package/dist/esm/core/CorsWhitelist.js +273 -0
- package/dist/esm/core/CorsWhitelist.js.map +1 -0
- package/dist/esm/core/index.d.ts +4 -0
- package/dist/esm/core/index.d.ts.map +1 -0
- package/dist/esm/core/index.js +22 -0
- package/dist/esm/core/index.js.map +1 -0
- package/dist/esm/core/types.d.ts +201 -0
- package/dist/esm/core/types.d.ts.map +1 -0
- package/dist/esm/core/types.js +3 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/core/utils.d.ts +31 -0
- package/dist/esm/core/utils.d.ts.map +1 -0
- package/dist/esm/core/utils.js +82 -0
- package/dist/esm/core/utils.js.map +1 -0
- package/dist/esm/frameworks/express.d.ts +15 -0
- package/dist/esm/frameworks/express.d.ts.map +1 -0
- package/dist/esm/frameworks/express.js +49 -0
- package/dist/esm/frameworks/express.js.map +1 -0
- package/dist/esm/frameworks/fastify.d.ts +18 -0
- package/dist/esm/frameworks/fastify.d.ts.map +1 -0
- package/dist/esm/frameworks/fastify.js +49 -0
- package/dist/esm/frameworks/fastify.js.map +1 -0
- package/dist/esm/frameworks/index.d.ts +5 -0
- package/dist/esm/frameworks/index.d.ts.map +1 -0
- package/dist/esm/frameworks/index.js +15 -0
- package/dist/esm/frameworks/index.js.map +1 -0
- package/dist/esm/frameworks/koa.d.ts +15 -0
- package/dist/esm/frameworks/koa.d.ts.map +1 -0
- package/dist/esm/frameworks/koa.js +48 -0
- package/dist/esm/frameworks/koa.js.map +1 -0
- package/dist/esm/frameworks/node-http.d.ts +16 -0
- package/dist/esm/frameworks/node-http.d.ts.map +1 -0
- package/dist/esm/frameworks/node-http.js +46 -0
- package/dist/esm/frameworks/node-http.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +43 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +147 -0
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# cors-whitelist-ip
|
|
2
|
+
|
|
3
|
+
A framework-agnostic CORS whitelist middleware with IP and domain validation, supporting pluggable storage and caching.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Framework-agnostic**: Works with Express, Fastify, Koa, or plain Node.js HTTP
|
|
8
|
+
- **Pluggable storage**: Implement your own storage adapter for any database
|
|
9
|
+
- **Optional caching**: Built-in in-memory cache or bring your own (Redis, etc.)
|
|
10
|
+
- **IP validation**: Whitelist specific IPv4/IPv6 addresses
|
|
11
|
+
- **Domain patterns**: Support for wildcard domains (e.g., `*.example.com`)
|
|
12
|
+
- **API key association**: Link domains to organizations and API keys
|
|
13
|
+
- **Zero production dependencies**: Only peer dependencies for framework integrations
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install cors-whitelist-ip
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Express
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import express from 'express';
|
|
27
|
+
import { CorsWhitelist, InMemoryStorageAdapter } from 'cors-whitelist-ip';
|
|
28
|
+
import { createExpressMiddleware } from 'cors-whitelist-ip/express';
|
|
29
|
+
|
|
30
|
+
const app = express();
|
|
31
|
+
|
|
32
|
+
const storage = new InMemoryStorageAdapter({
|
|
33
|
+
globalWhitelist: ['https://trusted-app.com', '*'], // '*' allows all origins
|
|
34
|
+
whitelistEntries: [
|
|
35
|
+
{ id: 1, type: 'DOMAIN', value: '*.example.com', isActive: true },
|
|
36
|
+
{ id: 2, type: 'IP', value: '192.168.1.100', isActive: true },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const corsWhitelist = new CorsWhitelist({ storage, debug: true });
|
|
41
|
+
|
|
42
|
+
app.use(createExpressMiddleware(corsWhitelist));
|
|
43
|
+
|
|
44
|
+
app.get('/api/data', (req, res) => {
|
|
45
|
+
res.json({ message: 'Hello!' });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
app.listen(3000);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Fastify
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import Fastify from 'fastify';
|
|
55
|
+
import { fastifyCorsWhitelist } from 'cors-whitelist-ip/fastify';
|
|
56
|
+
import { InMemoryStorageAdapter } from 'cors-whitelist-ip/storage';
|
|
57
|
+
|
|
58
|
+
const fastify = Fastify();
|
|
59
|
+
|
|
60
|
+
const storage = new InMemoryStorageAdapter({
|
|
61
|
+
globalWhitelist: ['https://trusted-app.com'],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
fastify.register(fastifyCorsWhitelist, {
|
|
65
|
+
storage,
|
|
66
|
+
hook: 'onRequest',
|
|
67
|
+
debug: true,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
fastify.get('/api/data', async () => {
|
|
71
|
+
return { message: 'Hello!' };
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
fastify.listen({ port: 3000 });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Koa
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import Koa from 'koa';
|
|
81
|
+
import { CorsWhitelist, InMemoryStorageAdapter } from 'cors-whitelist-ip';
|
|
82
|
+
import { createKoaMiddleware } from 'cors-whitelist-ip/koa';
|
|
83
|
+
|
|
84
|
+
const app = new Koa();
|
|
85
|
+
|
|
86
|
+
const storage = new InMemoryStorageAdapter({
|
|
87
|
+
globalWhitelist: ['https://trusted-app.com'],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const corsWhitelist = new CorsWhitelist({ storage });
|
|
91
|
+
|
|
92
|
+
app.use(createKoaMiddleware(corsWhitelist));
|
|
93
|
+
|
|
94
|
+
app.use((ctx) => {
|
|
95
|
+
ctx.body = { message: 'Hello!' };
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
app.listen(3000);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
### CorsWhitelistOptions
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
interface CorsWhitelistOptions {
|
|
107
|
+
// Required: Storage adapter for fetching whitelist data
|
|
108
|
+
storage: StorageAdapter;
|
|
109
|
+
|
|
110
|
+
// Optional: Cache adapter for caching whitelist lookups
|
|
111
|
+
cache?: CacheAdapter;
|
|
112
|
+
|
|
113
|
+
// Cache TTL in seconds (default: 3600)
|
|
114
|
+
cacheTtl?: number;
|
|
115
|
+
|
|
116
|
+
// Custom logger (default: console)
|
|
117
|
+
logger?: Logger;
|
|
118
|
+
|
|
119
|
+
// CORS headers configuration
|
|
120
|
+
corsHeaders?: {
|
|
121
|
+
allowMethods?: string; // default: 'GET, POST, PUT, DELETE, PATCH, OPTIONS'
|
|
122
|
+
allowHeaders?: string; // default: 'Content-Type, Authorization, X-Requested-With'
|
|
123
|
+
allowCredentials?: boolean; // default: true
|
|
124
|
+
maxAge?: number; // default: 86400 (24 hours)
|
|
125
|
+
exposeHeaders?: string;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Allow requests with no origin header (default: true)
|
|
129
|
+
allowNoOrigin?: boolean;
|
|
130
|
+
|
|
131
|
+
// Custom function to extract client IP
|
|
132
|
+
getClientIp?: (req: GenericRequest) => string;
|
|
133
|
+
|
|
134
|
+
// Enable debug logging (default: false)
|
|
135
|
+
debug?: boolean;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Custom Storage Adapter
|
|
140
|
+
|
|
141
|
+
Implement the `StorageAdapter` interface to use your own database:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { StorageAdapter, WhitelistEntry } from 'cors-whitelist-ip';
|
|
145
|
+
|
|
146
|
+
class PostgresStorageAdapter implements StorageAdapter {
|
|
147
|
+
constructor(private db: Pool) {}
|
|
148
|
+
|
|
149
|
+
async getGlobalWhitelist(): Promise<string[]> {
|
|
150
|
+
const result = await this.db.query(
|
|
151
|
+
'SELECT domains FROM global_cors_whitelist WHERE is_active = true'
|
|
152
|
+
);
|
|
153
|
+
return result.rows[0]?.domains || [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getWhitelistEntries(): Promise<WhitelistEntry[]> {
|
|
157
|
+
const result = await this.db.query(
|
|
158
|
+
'SELECT * FROM organisation_whitelist WHERE is_active = true'
|
|
159
|
+
);
|
|
160
|
+
return result.rows;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async getOrganisationWhitelist(orgId: string | number): Promise<WhitelistEntry[]> {
|
|
164
|
+
const result = await this.db.query(
|
|
165
|
+
'SELECT * FROM organisation_whitelist WHERE organisation_id = $1 AND is_active = true',
|
|
166
|
+
[orgId]
|
|
167
|
+
);
|
|
168
|
+
return result.rows;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async findOrganisationByDomain(domain: string): Promise<string | number | null> {
|
|
172
|
+
const result = await this.db.query(
|
|
173
|
+
`SELECT organisation_id FROM organisation_whitelist
|
|
174
|
+
WHERE type = 'DOMAIN' AND is_active = true
|
|
175
|
+
AND (value = $1 OR ($1 LIKE '%' || SUBSTRING(value FROM 3)))`,
|
|
176
|
+
[domain]
|
|
177
|
+
);
|
|
178
|
+
return result.rows[0]?.organisation_id || null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async getApiKey(orgId: string | number): Promise<string | null> {
|
|
182
|
+
const result = await this.db.query(
|
|
183
|
+
'SELECT api_key FROM organisation_api_key WHERE organisation_id = $1',
|
|
184
|
+
[orgId]
|
|
185
|
+
);
|
|
186
|
+
return result.rows[0]?.api_key || null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async isIpWhitelisted(ip: string): Promise<boolean> {
|
|
190
|
+
const result = await this.db.query(
|
|
191
|
+
`SELECT 1 FROM organisation_whitelist
|
|
192
|
+
WHERE type = 'IP' AND value = $1 AND is_active = true LIMIT 1`,
|
|
193
|
+
[ip]
|
|
194
|
+
);
|
|
195
|
+
return result.rows.length > 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async isDomainWhitelisted(domain: string): Promise<boolean> {
|
|
199
|
+
const result = await this.db.query(
|
|
200
|
+
`SELECT 1 FROM organisation_whitelist
|
|
201
|
+
WHERE type = 'DOMAIN' AND is_active = true
|
|
202
|
+
AND (value = $1 OR $1 LIKE '%' || SUBSTRING(value FROM 3)) LIMIT 1`,
|
|
203
|
+
[domain]
|
|
204
|
+
);
|
|
205
|
+
return result.rows.length > 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Custom Cache Adapter
|
|
211
|
+
|
|
212
|
+
Implement the `CacheAdapter` interface for Redis or other caching solutions:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { CacheAdapter } from 'cors-whitelist-ip';
|
|
216
|
+
import Redis from 'ioredis';
|
|
217
|
+
|
|
218
|
+
class RedisCacheAdapter implements CacheAdapter {
|
|
219
|
+
constructor(private redis: Redis) {}
|
|
220
|
+
|
|
221
|
+
async get<T>(key: string): Promise<T | null> {
|
|
222
|
+
const value = await this.redis.get(key);
|
|
223
|
+
return value ? JSON.parse(value) : null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async set<T>(key: string, value: T, ttlSeconds: number): Promise<void> {
|
|
227
|
+
await this.redis.set(key, JSON.stringify(value), 'EX', ttlSeconds);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async delete(key: string): Promise<void> {
|
|
231
|
+
await this.redis.del(key);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async deletePattern(pattern: string): Promise<void> {
|
|
235
|
+
const keys = await this.redis.keys(pattern);
|
|
236
|
+
if (keys.length > 0) await this.redis.del(...keys);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async clear(): Promise<void> {
|
|
240
|
+
await this.redis.flushdb();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async has(key: string): Promise<boolean> {
|
|
244
|
+
return (await this.redis.exists(key)) === 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## API
|
|
250
|
+
|
|
251
|
+
### CorsWhitelist
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
const cors = new CorsWhitelist(options);
|
|
255
|
+
|
|
256
|
+
// Initialize (optional, for adapters that need setup)
|
|
257
|
+
await cors.initialize();
|
|
258
|
+
|
|
259
|
+
// Handle a request (used internally by framework adapters)
|
|
260
|
+
const shouldContinue = await cors.handleRequest(req, res);
|
|
261
|
+
|
|
262
|
+
// Validate an origin directly
|
|
263
|
+
const result = await cors.validateOrigin('https://example.com');
|
|
264
|
+
// Returns: { allowed: boolean, reason: string, organisationId?, apiKey? }
|
|
265
|
+
|
|
266
|
+
// Invalidate cache
|
|
267
|
+
await cors.invalidateCache(); // Clear all CORS cache
|
|
268
|
+
await cors.invalidateCache('example'); // Clear cache matching pattern
|
|
269
|
+
|
|
270
|
+
// Clean up
|
|
271
|
+
await cors.dispose();
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Validation Flow
|
|
275
|
+
|
|
276
|
+
1. **Global Whitelist**: Check if origin is in the global whitelist (supports `*` wildcard)
|
|
277
|
+
2. **Domain Lookup**: Find if domain is associated with an organization
|
|
278
|
+
3. **API Key Check**: Verify organization has a valid API key
|
|
279
|
+
4. **IP Whitelist**: Check if origin IP is whitelisted
|
|
280
|
+
5. **Domain Pattern**: Match against wildcard patterns (e.g., `*.example.com`)
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CacheAdapter } from '../../core/types';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory cache adapter using a simple Map.
|
|
4
|
+
* Suitable for single-instance applications and testing.
|
|
5
|
+
*/
|
|
6
|
+
export declare class InMemoryCacheAdapter implements CacheAdapter {
|
|
7
|
+
private cache;
|
|
8
|
+
private cleanupInterval;
|
|
9
|
+
constructor(cleanupIntervalMs?: number);
|
|
10
|
+
get<T = string>(key: string): Promise<T | null>;
|
|
11
|
+
set<T = string>(key: string, value: T, ttlSeconds: number): Promise<void>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
13
|
+
deletePattern(pattern: string): Promise<void>;
|
|
14
|
+
clear(): Promise<void>;
|
|
15
|
+
has(key: string): Promise<boolean>;
|
|
16
|
+
dispose(): Promise<void>;
|
|
17
|
+
private cleanup;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=InMemoryCacheAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryCacheAdapter.d.ts","sourceRoot":"","sources":["../../../../src/adapters/cache/InMemoryCacheAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,eAAe,CAA+C;gBAE1D,iBAAiB,GAAE,MAAc;IAQvC,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAe/C,GAAG,CAAC,CAAC,GAAG,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAOV,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,OAAO,CAAC,OAAO;CAQhB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryCacheAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* In-memory cache adapter using a simple Map.
|
|
6
|
+
* Suitable for single-instance applications and testing.
|
|
7
|
+
*/
|
|
8
|
+
class InMemoryCacheAdapter {
|
|
9
|
+
constructor(cleanupIntervalMs = 60000) {
|
|
10
|
+
this.cache = new Map();
|
|
11
|
+
this.cleanupInterval = null;
|
|
12
|
+
// Periodically clean up expired entries
|
|
13
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);
|
|
14
|
+
}
|
|
15
|
+
async get(key) {
|
|
16
|
+
const entry = this.cache.get(key);
|
|
17
|
+
if (!entry) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (Date.now() > entry.expiresAt) {
|
|
21
|
+
this.cache.delete(key);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return entry.value;
|
|
25
|
+
}
|
|
26
|
+
async set(key, value, ttlSeconds) {
|
|
27
|
+
this.cache.set(key, {
|
|
28
|
+
value,
|
|
29
|
+
expiresAt: Date.now() + ttlSeconds * 1000,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async delete(key) {
|
|
33
|
+
this.cache.delete(key);
|
|
34
|
+
}
|
|
35
|
+
async deletePattern(pattern) {
|
|
36
|
+
// Convert simple pattern to regex (supports * as wildcard)
|
|
37
|
+
const regexPattern = pattern.replace(/\*/g, '.*');
|
|
38
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
39
|
+
for (const key of this.cache.keys()) {
|
|
40
|
+
if (regex.test(key)) {
|
|
41
|
+
this.cache.delete(key);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async clear() {
|
|
46
|
+
this.cache.clear();
|
|
47
|
+
}
|
|
48
|
+
async has(key) {
|
|
49
|
+
const value = await this.get(key);
|
|
50
|
+
return value !== null;
|
|
51
|
+
}
|
|
52
|
+
async dispose() {
|
|
53
|
+
if (this.cleanupInterval) {
|
|
54
|
+
clearInterval(this.cleanupInterval);
|
|
55
|
+
this.cleanupInterval = null;
|
|
56
|
+
}
|
|
57
|
+
this.cache.clear();
|
|
58
|
+
}
|
|
59
|
+
cleanup() {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
62
|
+
if (now > entry.expiresAt) {
|
|
63
|
+
this.cache.delete(key);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.InMemoryCacheAdapter = InMemoryCacheAdapter;
|
|
69
|
+
//# sourceMappingURL=InMemoryCacheAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryCacheAdapter.js","sourceRoot":"","sources":["../../../../src/adapters/cache/InMemoryCacheAdapter.ts"],"names":[],"mappings":";;;AAOA;;;GAGG;AACH,MAAa,oBAAoB;IAI/B,YAAY,oBAA4B,KAAK;QAHrC,UAAK,GAAqC,IAAI,GAAG,EAAE,CAAC;QACpD,oBAAe,GAA0C,IAAI,CAAC;QAGpE,wCAAwC;QACxC,IAAI,CAAC,eAAe,GAAG,WAAW,CAChC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EACpB,iBAAiB,CAClB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CAAa,GAAW;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,KAAU,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAW,EACX,KAAQ,EACR,UAAkB;QAElB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAe;QACjC,2DAA2D;QAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC;QAE9C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,KAAK,KAAK,IAAI,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAEO,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA/ED,oDA+EC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CacheAdapter } from '../../core/types';
|
|
2
|
+
/**
|
|
3
|
+
* No-op cache adapter that doesn't cache anything.
|
|
4
|
+
* Used as the default when no cache is configured.
|
|
5
|
+
*/
|
|
6
|
+
export declare class NoCacheAdapter implements CacheAdapter {
|
|
7
|
+
get<T = string>(_key: string): Promise<T | null>;
|
|
8
|
+
set<T = string>(_key: string, _value: T, _ttlSeconds: number): Promise<void>;
|
|
9
|
+
delete(_key: string): Promise<void>;
|
|
10
|
+
deletePattern(_pattern: string): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
has(_key: string): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=NoCacheAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoCacheAdapter.d.ts","sourceRoot":"","sources":["../../../../src/adapters/cache/NoCacheAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;;GAGG;AACH,qBAAa,cAAe,YAAW,YAAY;IAC3C,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAIhD,GAAG,CAAC,CAAC,GAAG,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAIV,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAG1C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoCacheAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* No-op cache adapter that doesn't cache anything.
|
|
6
|
+
* Used as the default when no cache is configured.
|
|
7
|
+
*/
|
|
8
|
+
class NoCacheAdapter {
|
|
9
|
+
async get(_key) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
async set(_key, _value, _ttlSeconds) {
|
|
13
|
+
// No-op
|
|
14
|
+
}
|
|
15
|
+
async delete(_key) {
|
|
16
|
+
// No-op
|
|
17
|
+
}
|
|
18
|
+
async deletePattern(_pattern) {
|
|
19
|
+
// No-op
|
|
20
|
+
}
|
|
21
|
+
async clear() {
|
|
22
|
+
// No-op
|
|
23
|
+
}
|
|
24
|
+
async has(_key) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.NoCacheAdapter = NoCacheAdapter;
|
|
29
|
+
//# sourceMappingURL=NoCacheAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoCacheAdapter.js","sourceRoot":"","sources":["../../../../src/adapters/cache/NoCacheAdapter.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,MAAa,cAAc;IACzB,KAAK,CAAC,GAAG,CAAa,IAAY;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,GAAG,CACP,IAAY,EACZ,MAAS,EACT,WAAmB;QAEnB,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB;QAClC,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,KAAK;QACT,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAY;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA5BD,wCA4BC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryCacheAdapter = exports.NoCacheAdapter = void 0;
|
|
4
|
+
var NoCacheAdapter_1 = require("./NoCacheAdapter");
|
|
5
|
+
Object.defineProperty(exports, "NoCacheAdapter", { enumerable: true, get: function () { return NoCacheAdapter_1.NoCacheAdapter; } });
|
|
6
|
+
var InMemoryCacheAdapter_1 = require("./InMemoryCacheAdapter");
|
|
7
|
+
Object.defineProperty(exports, "InMemoryCacheAdapter", { enumerable: true, get: function () { return InMemoryCacheAdapter_1.InMemoryCacheAdapter; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/cache/index.ts"],"names":[],"mappings":";;;AAAA,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { StorageAdapter, WhitelistEntry } from '../../core/types';
|
|
2
|
+
export interface InMemoryStorageConfig {
|
|
3
|
+
globalWhitelist?: string[];
|
|
4
|
+
whitelistEntries?: WhitelistEntry[];
|
|
5
|
+
apiKeys?: Map<string | number, string>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* In-memory storage adapter for testing and simple use cases.
|
|
9
|
+
* Data is stored in memory and lost when the process exits.
|
|
10
|
+
*/
|
|
11
|
+
export declare class InMemoryStorageAdapter implements StorageAdapter {
|
|
12
|
+
private globalWhitelist;
|
|
13
|
+
private whitelistEntries;
|
|
14
|
+
private apiKeys;
|
|
15
|
+
constructor(config?: InMemoryStorageConfig);
|
|
16
|
+
getGlobalWhitelist(): Promise<string[]>;
|
|
17
|
+
getWhitelistEntries(): Promise<WhitelistEntry[]>;
|
|
18
|
+
getOrganisationWhitelist(organisationId: string | number): Promise<WhitelistEntry[]>;
|
|
19
|
+
findOrganisationByDomain(domain: string): Promise<string | number | null>;
|
|
20
|
+
getApiKey(organisationId: string | number, _type?: 'client' | 'server'): Promise<string | null>;
|
|
21
|
+
isIpWhitelisted(ip: string): Promise<boolean>;
|
|
22
|
+
isDomainWhitelisted(domain: string): Promise<boolean>;
|
|
23
|
+
addGlobalDomain(domain: string): void;
|
|
24
|
+
removeGlobalDomain(domain: string): void;
|
|
25
|
+
addWhitelistEntry(entry: WhitelistEntry): void;
|
|
26
|
+
removeWhitelistEntry(id: string | number): void;
|
|
27
|
+
setApiKey(organisationId: string | number, apiKey: string): void;
|
|
28
|
+
clear(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=InMemoryStorageAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryStorageAdapter.d.ts","sourceRoot":"","sources":["../../../../src/adapters/storage/InMemoryStorageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlE,MAAM,WAAW,qBAAqB;IACpC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,qBAAa,sBAAuB,YAAW,cAAc;IAC3D,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,OAAO,CAA+B;gBAElC,MAAM,GAAE,qBAA0B;IAMxC,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIvC,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIhD,wBAAwB,CAC5B,cAAc,EAAE,MAAM,GAAG,MAAM,GAC9B,OAAO,CAAC,cAAc,EAAE,CAAC;IAMtB,wBAAwB,CAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAQ5B,SAAS,CACb,cAAc,EAAE,MAAM,GAAG,MAAM,EAC/B,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAInB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM7C,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW3D,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMrC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAOxC,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAI9C,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO/C,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAIhE,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryStorageAdapter = void 0;
|
|
4
|
+
const utils_1 = require("../../core/utils");
|
|
5
|
+
/**
|
|
6
|
+
* In-memory storage adapter for testing and simple use cases.
|
|
7
|
+
* Data is stored in memory and lost when the process exits.
|
|
8
|
+
*/
|
|
9
|
+
class InMemoryStorageAdapter {
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.globalWhitelist = config.globalWhitelist ?? [];
|
|
12
|
+
this.whitelistEntries = config.whitelistEntries ?? [];
|
|
13
|
+
this.apiKeys = config.apiKeys ?? new Map();
|
|
14
|
+
}
|
|
15
|
+
async getGlobalWhitelist() {
|
|
16
|
+
return [...this.globalWhitelist];
|
|
17
|
+
}
|
|
18
|
+
async getWhitelistEntries() {
|
|
19
|
+
return this.whitelistEntries.filter((e) => e.isActive);
|
|
20
|
+
}
|
|
21
|
+
async getOrganisationWhitelist(organisationId) {
|
|
22
|
+
return this.whitelistEntries.filter((e) => e.organisationId === organisationId && e.isActive);
|
|
23
|
+
}
|
|
24
|
+
async findOrganisationByDomain(domain) {
|
|
25
|
+
const entry = this.whitelistEntries.find((e) => e.type === 'DOMAIN' && e.isActive && (0, utils_1.matchesWildcard)(domain, e.value));
|
|
26
|
+
return entry?.organisationId ?? null;
|
|
27
|
+
}
|
|
28
|
+
async getApiKey(organisationId, _type) {
|
|
29
|
+
return this.apiKeys.get(organisationId) ?? null;
|
|
30
|
+
}
|
|
31
|
+
async isIpWhitelisted(ip) {
|
|
32
|
+
return this.whitelistEntries.some((e) => e.type === 'IP' && e.value === ip && e.isActive);
|
|
33
|
+
}
|
|
34
|
+
async isDomainWhitelisted(domain) {
|
|
35
|
+
return this.whitelistEntries.some((e) => e.type === 'DOMAIN' && e.isActive && (0, utils_1.matchesWildcard)(domain, e.value));
|
|
36
|
+
}
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────
|
|
38
|
+
// Additional methods for testing and management
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────
|
|
40
|
+
addGlobalDomain(domain) {
|
|
41
|
+
if (!this.globalWhitelist.includes(domain)) {
|
|
42
|
+
this.globalWhitelist.push(domain);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
removeGlobalDomain(domain) {
|
|
46
|
+
const index = this.globalWhitelist.indexOf(domain);
|
|
47
|
+
if (index > -1) {
|
|
48
|
+
this.globalWhitelist.splice(index, 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
addWhitelistEntry(entry) {
|
|
52
|
+
this.whitelistEntries.push(entry);
|
|
53
|
+
}
|
|
54
|
+
removeWhitelistEntry(id) {
|
|
55
|
+
const index = this.whitelistEntries.findIndex((e) => e.id === id);
|
|
56
|
+
if (index > -1) {
|
|
57
|
+
this.whitelistEntries.splice(index, 1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
setApiKey(organisationId, apiKey) {
|
|
61
|
+
this.apiKeys.set(organisationId, apiKey);
|
|
62
|
+
}
|
|
63
|
+
clear() {
|
|
64
|
+
this.globalWhitelist = [];
|
|
65
|
+
this.whitelistEntries = [];
|
|
66
|
+
this.apiKeys.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.InMemoryStorageAdapter = InMemoryStorageAdapter;
|
|
70
|
+
//# sourceMappingURL=InMemoryStorageAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryStorageAdapter.js","sourceRoot":"","sources":["../../../../src/adapters/storage/InMemoryStorageAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryStorageAdapter = void 0;
|
|
4
|
+
var InMemoryStorageAdapter_1 = require("./InMemoryStorageAdapter");
|
|
5
|
+
Object.defineProperty(exports, "InMemoryStorageAdapter", { enumerable: true, get: function () { return InMemoryStorageAdapter_1.InMemoryStorageAdapter; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/storage/index.ts"],"names":[],"mappings":";;;AAAA,mEAAkE;AAAzD,gIAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { CorsWhitelistOptions, ValidationResult, GenericRequest, GenericResponse, StorageAdapter, CacheAdapter } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Main CORS Whitelist class that handles origin validation
|
|
4
|
+
* and CORS header management in a framework-agnostic way.
|
|
5
|
+
*/
|
|
6
|
+
export declare class CorsWhitelist {
|
|
7
|
+
private storage;
|
|
8
|
+
private cache;
|
|
9
|
+
private cacheTtl;
|
|
10
|
+
private logger;
|
|
11
|
+
private corsHeaders;
|
|
12
|
+
private allowNoOrigin;
|
|
13
|
+
private customGetClientIp?;
|
|
14
|
+
private debug;
|
|
15
|
+
constructor(options: CorsWhitelistOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the CORS middleware (call before handling requests)
|
|
18
|
+
*/
|
|
19
|
+
initialize(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Clean up resources
|
|
22
|
+
*/
|
|
23
|
+
dispose(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Main handler for CORS requests. Returns whether to continue processing.
|
|
26
|
+
* @param req - Generic request object
|
|
27
|
+
* @param res - Generic response object
|
|
28
|
+
* @returns true if request should continue, false if handled (blocked or preflight)
|
|
29
|
+
*/
|
|
30
|
+
handleRequest(req: GenericRequest, res: GenericResponse): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* Validate if an origin is allowed
|
|
33
|
+
* @param origin - The origin to validate
|
|
34
|
+
* @returns Validation result with details
|
|
35
|
+
*/
|
|
36
|
+
validateOrigin(origin: string): Promise<ValidationResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Invalidate cache for a specific domain or pattern
|
|
39
|
+
*/
|
|
40
|
+
invalidateCache(pattern?: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the storage adapter instance
|
|
43
|
+
*/
|
|
44
|
+
getStorage(): StorageAdapter;
|
|
45
|
+
/**
|
|
46
|
+
* Get the cache adapter instance
|
|
47
|
+
*/
|
|
48
|
+
getCache(): CacheAdapter;
|
|
49
|
+
private handlePreflight;
|
|
50
|
+
private handleRegularRequest;
|
|
51
|
+
private performValidation;
|
|
52
|
+
private getGlobalWhitelist;
|
|
53
|
+
private setPreflightHeaders;
|
|
54
|
+
private setCorsHeaders;
|
|
55
|
+
private getOrigin;
|
|
56
|
+
private getClientIp;
|
|
57
|
+
private defaultGetClientIp;
|
|
58
|
+
private log;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=CorsWhitelist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CorsWhitelist.d.ts","sourceRoot":"","sources":["../../../src/core/CorsWhitelist.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAEhB,cAAc,EACd,eAAe,EAEf,cAAc,EACd,YAAY,EACb,MAAM,SAAS,CAAC;AAcjB;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,iBAAiB,CAAC,CAAkC;IAC5D,OAAO,CAAC,KAAK,CAAU;gBAEX,OAAO,EAAE,oBAAoB;IAWzC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;;;;OAKG;IACG,aAAa,CACjB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,GACnB,OAAO,CAAC,OAAO,CAAC;IA4BnB;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAkB/D;;OAEG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD;;OAEG;IACH,UAAU,IAAI,cAAc;IAI5B;;OAEG;IACH,QAAQ,IAAI,YAAY;YAQV,eAAe;YA4Bf,oBAAoB;YA8BpB,iBAAiB;YAuDjB,kBAAkB;IAchC,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,GAAG;CASZ"}
|