vesper-memory 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/.env.example +28 -0
- package/CHANGELOG.md +137 -0
- package/LICENSE +21 -0
- package/README.md +665 -0
- package/config/sqlite-schema.sql +413 -0
- package/dist/benchmark/index.d.ts +18 -0
- package/dist/benchmark/index.d.ts.map +1 -0
- package/dist/benchmark/index.js +19 -0
- package/dist/benchmark/index.js.map +1 -0
- package/dist/benchmark/metrics-collector.d.ts +90 -0
- package/dist/benchmark/metrics-collector.d.ts.map +1 -0
- package/dist/benchmark/metrics-collector.js +196 -0
- package/dist/benchmark/metrics-collector.js.map +1 -0
- package/dist/benchmark/report-generator.d.ts +35 -0
- package/dist/benchmark/report-generator.d.ts.map +1 -0
- package/dist/benchmark/report-generator.js +221 -0
- package/dist/benchmark/report-generator.js.map +1 -0
- package/dist/benchmark/runner.d.ts +30 -0
- package/dist/benchmark/runner.d.ts.map +1 -0
- package/dist/benchmark/runner.js +308 -0
- package/dist/benchmark/runner.js.map +1 -0
- package/dist/benchmark/scenarios/context-recall.d.ts +65 -0
- package/dist/benchmark/scenarios/context-recall.d.ts.map +1 -0
- package/dist/benchmark/scenarios/context-recall.js +180 -0
- package/dist/benchmark/scenarios/context-recall.js.map +1 -0
- package/dist/benchmark/scenarios/index.d.ts +34 -0
- package/dist/benchmark/scenarios/index.d.ts.map +1 -0
- package/dist/benchmark/scenarios/index.js +230 -0
- package/dist/benchmark/scenarios/index.js.map +1 -0
- package/dist/benchmark/statistics.d.ts +125 -0
- package/dist/benchmark/statistics.d.ts.map +1 -0
- package/dist/benchmark/statistics.js +520 -0
- package/dist/benchmark/statistics.js.map +1 -0
- package/dist/benchmark/types.d.ts +458 -0
- package/dist/benchmark/types.d.ts.map +1 -0
- package/dist/benchmark/types.js +297 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/cli 2.js +583 -0
- package/dist/cli.d 2.ts +8 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts 2.map +1 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +583 -0
- package/dist/cli.js 2.map +1 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/rate-limits.d.ts +76 -0
- package/dist/config/rate-limits.d.ts.map +1 -0
- package/dist/config/rate-limits.js +161 -0
- package/dist/config/rate-limits.js.map +1 -0
- package/dist/config 2/rate-limits.d.ts +76 -0
- package/dist/config 2/rate-limits.d.ts.map +1 -0
- package/dist/config 2/rate-limits.js +161 -0
- package/dist/config 2/rate-limits.js.map +1 -0
- package/dist/consolidation/pipeline.d.ts +52 -0
- package/dist/consolidation/pipeline.d.ts.map +1 -0
- package/dist/consolidation/pipeline.js +193 -0
- package/dist/consolidation/pipeline.js.map +1 -0
- package/dist/consolidation 2/pipeline.d.ts +52 -0
- package/dist/consolidation 2/pipeline.d.ts.map +1 -0
- package/dist/consolidation 2/pipeline.js +193 -0
- package/dist/consolidation 2/pipeline.js.map +1 -0
- package/dist/embeddings/client.d.ts +95 -0
- package/dist/embeddings/client.d.ts.map +1 -0
- package/dist/embeddings/client.js +162 -0
- package/dist/embeddings/client.js.map +1 -0
- package/dist/embeddings 2/client.d.ts +94 -0
- package/dist/embeddings 2/client.d.ts.map +1 -0
- package/dist/embeddings 2/client.js +144 -0
- package/dist/embeddings 2/client.js.map +1 -0
- package/dist/memory-layers/semantic-memory.d.ts +76 -0
- package/dist/memory-layers/semantic-memory.d.ts.map +1 -0
- package/dist/memory-layers/semantic-memory.js +231 -0
- package/dist/memory-layers/semantic-memory.js.map +1 -0
- package/dist/memory-layers/skill-library.d.ts +25 -0
- package/dist/memory-layers/skill-library.d.ts.map +1 -0
- package/dist/memory-layers/skill-library.js +54 -0
- package/dist/memory-layers/skill-library.js.map +1 -0
- package/dist/memory-layers/working-memory.d.ts +57 -0
- package/dist/memory-layers/working-memory.d.ts.map +1 -0
- package/dist/memory-layers/working-memory.js +153 -0
- package/dist/memory-layers/working-memory.js.map +1 -0
- package/dist/memory-layers 2/semantic-memory.d.ts +33 -0
- package/dist/memory-layers 2/semantic-memory.d.ts.map +1 -0
- package/dist/memory-layers 2/semantic-memory.js +114 -0
- package/dist/memory-layers 2/semantic-memory.js.map +1 -0
- package/dist/memory-layers 2/skill-library.d.ts +25 -0
- package/dist/memory-layers 2/skill-library.d.ts.map +1 -0
- package/dist/memory-layers 2/skill-library.js +54 -0
- package/dist/memory-layers 2/skill-library.js.map +1 -0
- package/dist/memory-layers 2/working-memory.d.ts +57 -0
- package/dist/memory-layers 2/working-memory.d.ts.map +1 -0
- package/dist/memory-layers 2/working-memory.js +153 -0
- package/dist/memory-layers 2/working-memory.js.map +1 -0
- package/dist/middleware/auth.d.ts +287 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +610 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware 2/auth.d.ts +287 -0
- package/dist/middleware 2/auth.d.ts.map +1 -0
- package/dist/middleware 2/auth.js +610 -0
- package/dist/middleware 2/auth.js.map +1 -0
- package/dist/monitoring/health.d.ts +241 -0
- package/dist/monitoring/health.d.ts.map +1 -0
- package/dist/monitoring/health.js +649 -0
- package/dist/monitoring/health.js.map +1 -0
- package/dist/monitoring/metrics.d.ts +153 -0
- package/dist/monitoring/metrics.d.ts.map +1 -0
- package/dist/monitoring/metrics.js +349 -0
- package/dist/monitoring/metrics.js.map +1 -0
- package/dist/monitoring 2/health.d.ts +241 -0
- package/dist/monitoring 2/health.d.ts.map +1 -0
- package/dist/monitoring 2/health.js +649 -0
- package/dist/monitoring 2/health.js.map +1 -0
- package/dist/monitoring 2/metrics.d.ts +153 -0
- package/dist/monitoring 2/metrics.d.ts.map +1 -0
- package/dist/monitoring 2/metrics.js +349 -0
- package/dist/monitoring 2/metrics.js.map +1 -0
- package/dist/retrieval/hybrid-search.d.ts +186 -0
- package/dist/retrieval/hybrid-search.d.ts.map +1 -0
- package/dist/retrieval/hybrid-search.js +330 -0
- package/dist/retrieval/hybrid-search.js.map +1 -0
- package/dist/retrieval 2/hybrid-search.d.ts +186 -0
- package/dist/retrieval 2/hybrid-search.d.ts.map +1 -0
- package/dist/retrieval 2/hybrid-search.js +327 -0
- package/dist/retrieval 2/hybrid-search.js.map +1 -0
- package/dist/router/smart-router.d.ts +157 -0
- package/dist/router/smart-router.d.ts.map +1 -0
- package/dist/router/smart-router.js +524 -0
- package/dist/router/smart-router.js.map +1 -0
- package/dist/router 2/smart-router.d.ts +111 -0
- package/dist/router 2/smart-router.d.ts.map +1 -0
- package/dist/router 2/smart-router.js +383 -0
- package/dist/router 2/smart-router.js.map +1 -0
- package/dist/security/rate-limit-middleware.d.ts +119 -0
- package/dist/security/rate-limit-middleware.d.ts.map +1 -0
- package/dist/security/rate-limit-middleware.js +193 -0
- package/dist/security/rate-limit-middleware.js.map +1 -0
- package/dist/security 2/rate-limit-middleware.d.ts +119 -0
- package/dist/security 2/rate-limit-middleware.d.ts.map +1 -0
- package/dist/security 2/rate-limit-middleware.js +193 -0
- package/dist/security 2/rate-limit-middleware.js.map +1 -0
- package/dist/server 2.js +861 -0
- package/dist/server-wrapper 2.js +170 -0
- package/dist/server-wrapper.d 2.ts +12 -0
- package/dist/server-wrapper.d.ts +12 -0
- package/dist/server-wrapper.d.ts 2.map +1 -0
- package/dist/server-wrapper.d.ts.map +1 -0
- package/dist/server-wrapper.js +170 -0
- package/dist/server-wrapper.js 2.map +1 -0
- package/dist/server-wrapper.js.map +1 -0
- package/dist/server.d 2.ts +14 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts 2.map +1 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +656 -0
- package/dist/server.js 2.map +1 -0
- package/dist/server.js.map +1 -0
- package/dist/synthesis/conflict-detector.d.ts +43 -0
- package/dist/synthesis/conflict-detector.d.ts.map +1 -0
- package/dist/synthesis/conflict-detector.js +125 -0
- package/dist/synthesis/conflict-detector.js.map +1 -0
- package/dist/synthesis 2/conflict-detector.d.ts +43 -0
- package/dist/synthesis 2/conflict-detector.d.ts.map +1 -0
- package/dist/synthesis 2/conflict-detector.js +125 -0
- package/dist/synthesis 2/conflict-detector.js.map +1 -0
- package/dist/utils/monitoring.d.ts +25 -0
- package/dist/utils/monitoring.d.ts.map +1 -0
- package/dist/utils/monitoring.js +41 -0
- package/dist/utils/monitoring.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +97 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +166 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/validation.d.ts +139 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +195 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/utils 2/monitoring.d.ts +25 -0
- package/dist/utils 2/monitoring.d.ts.map +1 -0
- package/dist/utils 2/monitoring.js +41 -0
- package/dist/utils 2/monitoring.js.map +1 -0
- package/dist/utils 2/rate-limiter.d.ts +97 -0
- package/dist/utils 2/rate-limiter.d.ts.map +1 -0
- package/dist/utils 2/rate-limiter.js +166 -0
- package/dist/utils 2/rate-limiter.js.map +1 -0
- package/dist/utils 2/validation.d.ts +139 -0
- package/dist/utils 2/validation.d.ts.map +1 -0
- package/dist/utils 2/validation.js +195 -0
- package/dist/utils 2/validation.js.map +1 -0
- package/docker-compose.yml +65 -0
- package/embedding-service/Dockerfile +29 -0
- package/embedding-service/README.md +68 -0
- package/embedding-service/requirements.txt +6 -0
- package/embedding-service/server.py +110 -0
- package/package.json +92 -0
- package/scripts/FRESH_INSTALL.md +280 -0
- package/scripts/README.md +101 -0
- package/scripts/ensure-infrastructure.sh +38 -0
- package/scripts/fresh-install-auto.sh +96 -0
- package/scripts/fresh-install.sh +167 -0
- package/scripts/health-check.sh +72 -0
- package/scripts/init-qdrant.ts +201 -0
- package/scripts/postinstall.js +94 -0
- package/scripts/run-accuracy-benchmark.ts +1237 -0
- package/scripts/run-real-benchmark.ts +581 -0
- package/scripts/test-mcp-server.sh +38 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Authentication Middleware
|
|
3
|
+
*
|
|
4
|
+
* Implements API key authentication for MCP tools with:
|
|
5
|
+
* - Bearer token authentication
|
|
6
|
+
* - bcrypt password hashing
|
|
7
|
+
* - Key expiration
|
|
8
|
+
* - IP allowlisting
|
|
9
|
+
* - Scope-based authorization
|
|
10
|
+
* - Audit logging
|
|
11
|
+
*
|
|
12
|
+
* Security Features:
|
|
13
|
+
* - Constant-time comparison via bcrypt
|
|
14
|
+
* - No plaintext key storage
|
|
15
|
+
* - Gradual rollout support (AUTH_ENABLED env var)
|
|
16
|
+
* - Rate limit tier enforcement
|
|
17
|
+
*/
|
|
18
|
+
import { randomBytes, createHash } from "crypto";
|
|
19
|
+
import bcrypt from "bcrypt";
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Constants
|
|
22
|
+
// =============================================================================
|
|
23
|
+
/** API key format prefix */
|
|
24
|
+
export const API_KEY_PREFIX = "mem_v1_";
|
|
25
|
+
/** Number of random bytes for key generation (30 bytes = 40 chars base64url) */
|
|
26
|
+
export const API_KEY_BYTES = 30;
|
|
27
|
+
/** bcrypt work factor (12 = ~250ms on modern hardware) */
|
|
28
|
+
export const BCRYPT_ROUNDS = 12;
|
|
29
|
+
/** Default key expiration in days */
|
|
30
|
+
export const DEFAULT_KEY_EXPIRATION_DAYS = 90;
|
|
31
|
+
/** Maximum allowed key expiration in days */
|
|
32
|
+
export const MAX_KEY_EXPIRATION_DAYS = 365;
|
|
33
|
+
/** Maximum grace period for key rotation in hours */
|
|
34
|
+
export const MAX_GRACE_PERIOD_HOURS = 168; // 7 days
|
|
35
|
+
/** Valid scopes for API keys */
|
|
36
|
+
export const VALID_SCOPES = [
|
|
37
|
+
"store_memory",
|
|
38
|
+
"retrieve_memory",
|
|
39
|
+
"list_recent",
|
|
40
|
+
"get_stats",
|
|
41
|
+
"*", // Wildcard for all permissions
|
|
42
|
+
];
|
|
43
|
+
/** Audit log actions */
|
|
44
|
+
export var AuditAction;
|
|
45
|
+
(function (AuditAction) {
|
|
46
|
+
AuditAction["AUTHENTICATE"] = "authenticate";
|
|
47
|
+
AuditAction["RATE_LIMITED"] = "rate_limited";
|
|
48
|
+
AuditAction["REVOKED"] = "revoked";
|
|
49
|
+
AuditAction["ROTATED"] = "rotated";
|
|
50
|
+
AuditAction["CREATED"] = "created";
|
|
51
|
+
AuditAction["SCOPE_DENIED"] = "scope_denied";
|
|
52
|
+
AuditAction["IP_DENIED"] = "ip_denied";
|
|
53
|
+
AuditAction["EXPIRED"] = "expired";
|
|
54
|
+
})(AuditAction || (AuditAction = {}));
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// API Key Generation
|
|
57
|
+
// =============================================================================
|
|
58
|
+
/**
|
|
59
|
+
* Generate a new API key with cryptographically secure random bytes
|
|
60
|
+
*
|
|
61
|
+
* @returns Generated key with full key, prefix, and hash
|
|
62
|
+
*/
|
|
63
|
+
export async function generateApiKey() {
|
|
64
|
+
// Generate cryptographically secure random bytes
|
|
65
|
+
const randomPart = randomBytes(API_KEY_BYTES).toString("base64url").slice(0, 40);
|
|
66
|
+
const fullKey = `${API_KEY_PREFIX}${randomPart}`;
|
|
67
|
+
// Extract prefix for database lookup (first 8 chars after prefix)
|
|
68
|
+
const keyPrefix = randomPart.slice(0, 8);
|
|
69
|
+
// Hash with bcrypt for secure storage
|
|
70
|
+
const keyHash = await bcrypt.hash(fullKey, BCRYPT_ROUNDS);
|
|
71
|
+
return {
|
|
72
|
+
fullKey,
|
|
73
|
+
keyPrefix,
|
|
74
|
+
keyHash,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// =============================================================================
|
|
78
|
+
// API Key Verification
|
|
79
|
+
// =============================================================================
|
|
80
|
+
/**
|
|
81
|
+
* Verify an API key against its stored hash
|
|
82
|
+
*
|
|
83
|
+
* Uses bcrypt.compare for constant-time comparison
|
|
84
|
+
*
|
|
85
|
+
* @param providedKey - The API key provided by the client
|
|
86
|
+
* @param storedHash - The bcrypt hash stored in the database
|
|
87
|
+
* @returns true if key is valid
|
|
88
|
+
*/
|
|
89
|
+
export async function verifyApiKey(providedKey, storedHash) {
|
|
90
|
+
if (!providedKey || !storedHash) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// bcrypt.compare provides constant-time comparison
|
|
94
|
+
return bcrypt.compare(providedKey, storedHash);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate API key format without database lookup
|
|
98
|
+
*
|
|
99
|
+
* @param key - API key to validate
|
|
100
|
+
* @returns true if format is valid
|
|
101
|
+
*/
|
|
102
|
+
export function validateApiKeyFormat(key) {
|
|
103
|
+
if (!key || typeof key !== "string") {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
// Must start with correct prefix
|
|
107
|
+
if (!key.startsWith(API_KEY_PREFIX)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
// Must have exactly 40 characters after prefix
|
|
111
|
+
const keyPart = key.slice(API_KEY_PREFIX.length);
|
|
112
|
+
if (keyPart.length !== 40) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// Must be valid base64url characters
|
|
116
|
+
return /^[A-Za-z0-9_-]+$/.test(keyPart);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Extract the prefix from an API key for database lookup
|
|
120
|
+
*
|
|
121
|
+
* @param key - Full API key
|
|
122
|
+
* @returns 8-character prefix or null if invalid
|
|
123
|
+
*/
|
|
124
|
+
export function extractKeyPrefix(key) {
|
|
125
|
+
if (!validateApiKeyFormat(key)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return key.slice(API_KEY_PREFIX.length, API_KEY_PREFIX.length + 8);
|
|
129
|
+
}
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// Expiration Handling
|
|
132
|
+
// =============================================================================
|
|
133
|
+
/**
|
|
134
|
+
* Check if an API key is expired
|
|
135
|
+
*
|
|
136
|
+
* @param expiresAt - Expiration date (null means never expires)
|
|
137
|
+
* @returns true if key is expired
|
|
138
|
+
*/
|
|
139
|
+
export function isKeyExpired(expiresAt) {
|
|
140
|
+
if (expiresAt === null) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return new Date() > expiresAt;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Calculate default expiration date (90 days from now)
|
|
147
|
+
*
|
|
148
|
+
* @returns Expiration date
|
|
149
|
+
*/
|
|
150
|
+
export function calculateDefaultExpiration() {
|
|
151
|
+
const expiration = new Date();
|
|
152
|
+
expiration.setDate(expiration.getDate() + DEFAULT_KEY_EXPIRATION_DAYS);
|
|
153
|
+
return expiration;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Calculate expiration date with custom days (capped at max)
|
|
157
|
+
*
|
|
158
|
+
* @param days - Number of days until expiration
|
|
159
|
+
* @returns Expiration date
|
|
160
|
+
*/
|
|
161
|
+
export function calculateExpiration(days) {
|
|
162
|
+
const cappedDays = Math.min(days, MAX_KEY_EXPIRATION_DAYS);
|
|
163
|
+
const expiration = new Date();
|
|
164
|
+
expiration.setDate(expiration.getDate() + cappedDays);
|
|
165
|
+
return expiration;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get expiration days from environment or default
|
|
169
|
+
*
|
|
170
|
+
* @returns Number of days for key expiration
|
|
171
|
+
*/
|
|
172
|
+
export function getExpirationDays() {
|
|
173
|
+
const envDays = process.env.API_KEY_EXPIRATION_DAYS;
|
|
174
|
+
if (envDays) {
|
|
175
|
+
const parsed = parseInt(envDays, 10);
|
|
176
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
177
|
+
return Math.min(parsed, MAX_KEY_EXPIRATION_DAYS);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return DEFAULT_KEY_EXPIRATION_DAYS;
|
|
181
|
+
}
|
|
182
|
+
// =============================================================================
|
|
183
|
+
// IP Allowlisting
|
|
184
|
+
// =============================================================================
|
|
185
|
+
/**
|
|
186
|
+
* Check if an IP address is in the allowlist
|
|
187
|
+
*
|
|
188
|
+
* Supports both individual IPs and CIDR notation
|
|
189
|
+
*
|
|
190
|
+
* @param ip - Client IP address
|
|
191
|
+
* @param allowlist - Array of allowed IPs/CIDRs (empty or null allows all)
|
|
192
|
+
* @returns true if IP is allowed
|
|
193
|
+
*/
|
|
194
|
+
export function isIpAllowed(ip, allowlist) {
|
|
195
|
+
// Empty or null allowlist means all IPs are allowed
|
|
196
|
+
if (!allowlist || allowlist.length === 0) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
// Normalize IP for comparison
|
|
200
|
+
const normalizedIp = normalizeIp(ip);
|
|
201
|
+
for (const allowed of allowlist) {
|
|
202
|
+
if (matchIp(normalizedIp, allowed)) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Normalize an IP address for comparison
|
|
210
|
+
*/
|
|
211
|
+
function normalizeIp(ip) {
|
|
212
|
+
// Handle IPv4-mapped IPv6 addresses
|
|
213
|
+
if (ip.startsWith("::ffff:")) {
|
|
214
|
+
return ip.slice(7);
|
|
215
|
+
}
|
|
216
|
+
return ip;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if an IP matches an allowed pattern (IP or CIDR)
|
|
220
|
+
*/
|
|
221
|
+
function matchIp(ip, allowed) {
|
|
222
|
+
// Check for CIDR notation
|
|
223
|
+
if (allowed.includes("/")) {
|
|
224
|
+
return matchCidr(ip, allowed);
|
|
225
|
+
}
|
|
226
|
+
// Exact match
|
|
227
|
+
return normalizeIp(ip) === normalizeIp(allowed);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if an IP matches a CIDR range
|
|
231
|
+
*/
|
|
232
|
+
function matchCidr(ip, cidr) {
|
|
233
|
+
const [range, bits] = cidr.split("/");
|
|
234
|
+
const mask = parseInt(bits, 10);
|
|
235
|
+
// Handle IPv6
|
|
236
|
+
if (ip.includes(":") || range.includes(":")) {
|
|
237
|
+
return matchCidrIpv6(ip, range, mask);
|
|
238
|
+
}
|
|
239
|
+
// IPv4 CIDR matching
|
|
240
|
+
const ipNum = ipv4ToNumber(ip);
|
|
241
|
+
const rangeNum = ipv4ToNumber(range);
|
|
242
|
+
const maskNum = ~((1 << (32 - mask)) - 1);
|
|
243
|
+
return (ipNum & maskNum) === (rangeNum & maskNum);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Convert IPv4 address to number for CIDR matching
|
|
247
|
+
*/
|
|
248
|
+
function ipv4ToNumber(ip) {
|
|
249
|
+
const parts = ip.split(".").map((p) => parseInt(p, 10));
|
|
250
|
+
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Match IPv6 CIDR (simplified implementation)
|
|
254
|
+
*/
|
|
255
|
+
function matchCidrIpv6(ip, range, mask) {
|
|
256
|
+
// Expand both addresses to full form
|
|
257
|
+
const ipFull = expandIpv6(ip);
|
|
258
|
+
const rangeFull = expandIpv6(range);
|
|
259
|
+
// Compare the required number of bits
|
|
260
|
+
const bitsToCompare = Math.ceil(mask / 4);
|
|
261
|
+
const ipHex = ipFull.replace(/:/g, "");
|
|
262
|
+
const rangeHex = rangeFull.replace(/:/g, "");
|
|
263
|
+
return ipHex.slice(0, bitsToCompare) === rangeHex.slice(0, bitsToCompare);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Expand IPv6 address to full form
|
|
267
|
+
*/
|
|
268
|
+
function expandIpv6(ip) {
|
|
269
|
+
// Handle :: expansion
|
|
270
|
+
if (ip.includes("::")) {
|
|
271
|
+
const [left, right] = ip.split("::");
|
|
272
|
+
const leftParts = left ? left.split(":") : [];
|
|
273
|
+
const rightParts = right ? right.split(":") : [];
|
|
274
|
+
const missing = 8 - leftParts.length - rightParts.length;
|
|
275
|
+
const middle = Array(missing).fill("0000");
|
|
276
|
+
const parts = [...leftParts, ...middle, ...rightParts];
|
|
277
|
+
return parts.map((p) => p.padStart(4, "0")).join(":");
|
|
278
|
+
}
|
|
279
|
+
return ip
|
|
280
|
+
.split(":")
|
|
281
|
+
.map((p) => p.padStart(4, "0"))
|
|
282
|
+
.join(":");
|
|
283
|
+
}
|
|
284
|
+
// =============================================================================
|
|
285
|
+
// Scope Enforcement
|
|
286
|
+
// =============================================================================
|
|
287
|
+
/**
|
|
288
|
+
* Check if user has required scope
|
|
289
|
+
*
|
|
290
|
+
* @param userScopes - Scopes granted to user
|
|
291
|
+
* @param requiredScope - Scope required for operation
|
|
292
|
+
* @returns true if user has scope
|
|
293
|
+
*/
|
|
294
|
+
export function hasScope(userScopes, requiredScope) {
|
|
295
|
+
if (!userScopes || userScopes.length === 0) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
// Wildcard grants all permissions
|
|
299
|
+
if (userScopes.includes("*")) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
return userScopes.includes(requiredScope);
|
|
303
|
+
}
|
|
304
|
+
// =============================================================================
|
|
305
|
+
// Key Rotation
|
|
306
|
+
// =============================================================================
|
|
307
|
+
/**
|
|
308
|
+
* Rotate an API key with optional grace period
|
|
309
|
+
*
|
|
310
|
+
* @param oldKeyHash - Hash of the old key (unused, for signature compatibility)
|
|
311
|
+
* @param gracePeriodHours - Hours to allow old key (0 = immediate revocation)
|
|
312
|
+
* @returns New key and grace period info
|
|
313
|
+
*/
|
|
314
|
+
export async function rotateApiKey(_oldKeyHash, gracePeriodHours) {
|
|
315
|
+
// Cap grace period
|
|
316
|
+
const cappedGracePeriod = Math.min(gracePeriodHours, MAX_GRACE_PERIOD_HOURS);
|
|
317
|
+
// Generate new key
|
|
318
|
+
const newKey = await generateApiKey();
|
|
319
|
+
// Calculate when old key becomes invalid
|
|
320
|
+
const oldKeyValidUntil = new Date();
|
|
321
|
+
oldKeyValidUntil.setTime(oldKeyValidUntil.getTime() + cappedGracePeriod * 60 * 60 * 1000);
|
|
322
|
+
return {
|
|
323
|
+
newKey,
|
|
324
|
+
gracePeriodHours: cappedGracePeriod,
|
|
325
|
+
oldKeyValidUntil,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// =============================================================================
|
|
329
|
+
// Audit Logging
|
|
330
|
+
// =============================================================================
|
|
331
|
+
/**
|
|
332
|
+
* Create an audit log entry
|
|
333
|
+
*
|
|
334
|
+
* @param params - Audit entry parameters
|
|
335
|
+
* @returns Audit entry object
|
|
336
|
+
*/
|
|
337
|
+
export function createAuditEntry(params) {
|
|
338
|
+
return {
|
|
339
|
+
...params,
|
|
340
|
+
createdAt: new Date(),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Hash an API key for audit logging (never log full key)
|
|
345
|
+
*
|
|
346
|
+
* @param key - Full API key
|
|
347
|
+
* @returns Truncated SHA-256 hash for identification
|
|
348
|
+
*/
|
|
349
|
+
export function hashForAudit(key) {
|
|
350
|
+
return createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
351
|
+
}
|
|
352
|
+
// =============================================================================
|
|
353
|
+
// Authentication Middleware
|
|
354
|
+
// =============================================================================
|
|
355
|
+
/**
|
|
356
|
+
* Authenticate an MCP request
|
|
357
|
+
*
|
|
358
|
+
* @param request - Request context
|
|
359
|
+
* @param db - Database interface
|
|
360
|
+
* @returns Authentication result
|
|
361
|
+
* @throws Error if authentication fails
|
|
362
|
+
*/
|
|
363
|
+
export async function authenticateRequest(request, db) {
|
|
364
|
+
const { apiKey, ip, toolName } = request;
|
|
365
|
+
// Check if API key is provided
|
|
366
|
+
if (!apiKey) {
|
|
367
|
+
throw new Error("API key required");
|
|
368
|
+
}
|
|
369
|
+
// Validate format
|
|
370
|
+
if (!validateApiKeyFormat(apiKey)) {
|
|
371
|
+
await db.createAuditEntry(createAuditEntry({
|
|
372
|
+
apiKeyId: null,
|
|
373
|
+
action: AuditAction.AUTHENTICATE,
|
|
374
|
+
success: false,
|
|
375
|
+
ipAddress: ip,
|
|
376
|
+
failureReason: "Invalid API key format",
|
|
377
|
+
}));
|
|
378
|
+
throw new Error("Invalid API key");
|
|
379
|
+
}
|
|
380
|
+
// Extract prefix for lookup
|
|
381
|
+
const prefix = extractKeyPrefix(apiKey);
|
|
382
|
+
if (!prefix) {
|
|
383
|
+
throw new Error("Invalid API key");
|
|
384
|
+
}
|
|
385
|
+
// Look up key in database
|
|
386
|
+
const keyRecord = await db.getApiKey(prefix);
|
|
387
|
+
if (!keyRecord) {
|
|
388
|
+
await db.createAuditEntry(createAuditEntry({
|
|
389
|
+
apiKeyId: null,
|
|
390
|
+
action: AuditAction.AUTHENTICATE,
|
|
391
|
+
success: false,
|
|
392
|
+
ipAddress: ip,
|
|
393
|
+
failureReason: "API key not found",
|
|
394
|
+
}));
|
|
395
|
+
throw new Error("Invalid API key");
|
|
396
|
+
}
|
|
397
|
+
// Check if key is revoked
|
|
398
|
+
if (keyRecord.revokedAt) {
|
|
399
|
+
await db.createAuditEntry(createAuditEntry({
|
|
400
|
+
apiKeyId: keyRecord.id,
|
|
401
|
+
action: AuditAction.AUTHENTICATE,
|
|
402
|
+
success: false,
|
|
403
|
+
ipAddress: ip,
|
|
404
|
+
failureReason: "API key revoked",
|
|
405
|
+
}));
|
|
406
|
+
throw new Error("API key has been revoked");
|
|
407
|
+
}
|
|
408
|
+
// Verify key hash
|
|
409
|
+
const isValid = await verifyApiKey(apiKey, keyRecord.keyHash);
|
|
410
|
+
if (!isValid) {
|
|
411
|
+
await db.createAuditEntry(createAuditEntry({
|
|
412
|
+
apiKeyId: keyRecord.id,
|
|
413
|
+
action: AuditAction.AUTHENTICATE,
|
|
414
|
+
success: false,
|
|
415
|
+
ipAddress: ip,
|
|
416
|
+
failureReason: "Invalid API key",
|
|
417
|
+
}));
|
|
418
|
+
throw new Error("Invalid API key");
|
|
419
|
+
}
|
|
420
|
+
// Check expiration
|
|
421
|
+
if (isKeyExpired(keyRecord.expiresAt)) {
|
|
422
|
+
await db.createAuditEntry(createAuditEntry({
|
|
423
|
+
apiKeyId: keyRecord.id,
|
|
424
|
+
action: AuditAction.EXPIRED,
|
|
425
|
+
success: false,
|
|
426
|
+
ipAddress: ip,
|
|
427
|
+
failureReason: "API key expired",
|
|
428
|
+
}));
|
|
429
|
+
throw new Error("API key expired");
|
|
430
|
+
}
|
|
431
|
+
// Check IP allowlist
|
|
432
|
+
if (!isIpAllowed(ip, keyRecord.ipAllowlist)) {
|
|
433
|
+
await db.createAuditEntry(createAuditEntry({
|
|
434
|
+
apiKeyId: keyRecord.id,
|
|
435
|
+
action: AuditAction.IP_DENIED,
|
|
436
|
+
success: false,
|
|
437
|
+
ipAddress: ip,
|
|
438
|
+
failureReason: `IP ${ip} not in allowlist`,
|
|
439
|
+
}));
|
|
440
|
+
throw new Error("IP address not allowed");
|
|
441
|
+
}
|
|
442
|
+
// Check scope
|
|
443
|
+
if (!hasScope(keyRecord.scopes, toolName)) {
|
|
444
|
+
await db.createAuditEntry(createAuditEntry({
|
|
445
|
+
apiKeyId: keyRecord.id,
|
|
446
|
+
action: AuditAction.SCOPE_DENIED,
|
|
447
|
+
success: false,
|
|
448
|
+
ipAddress: ip,
|
|
449
|
+
failureReason: `Missing scope: ${toolName}`,
|
|
450
|
+
}));
|
|
451
|
+
throw new Error("Insufficient permissions");
|
|
452
|
+
}
|
|
453
|
+
// Update last used timestamp
|
|
454
|
+
await db.updateLastUsed(keyRecord.id);
|
|
455
|
+
// Log successful authentication
|
|
456
|
+
await db.createAuditEntry(createAuditEntry({
|
|
457
|
+
apiKeyId: keyRecord.id,
|
|
458
|
+
action: AuditAction.AUTHENTICATE,
|
|
459
|
+
success: true,
|
|
460
|
+
ipAddress: ip,
|
|
461
|
+
requestPath: toolName,
|
|
462
|
+
userAgent: request.userAgent,
|
|
463
|
+
}));
|
|
464
|
+
return {
|
|
465
|
+
authenticated: true,
|
|
466
|
+
userId: keyRecord.userId,
|
|
467
|
+
keyId: keyRecord.id,
|
|
468
|
+
tier: keyRecord.tier,
|
|
469
|
+
scopes: keyRecord.scopes,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
// =============================================================================
|
|
473
|
+
// Environment Configuration
|
|
474
|
+
// =============================================================================
|
|
475
|
+
/**
|
|
476
|
+
* Check if authentication is enabled
|
|
477
|
+
*
|
|
478
|
+
* @returns true if AUTH_ENABLED=true
|
|
479
|
+
*/
|
|
480
|
+
export function isAuthEnabled() {
|
|
481
|
+
return process.env.AUTH_ENABLED === "true";
|
|
482
|
+
}
|
|
483
|
+
// =============================================================================
|
|
484
|
+
// Rate Limit Tiers
|
|
485
|
+
// =============================================================================
|
|
486
|
+
/** Default rate limits per tier */
|
|
487
|
+
const TIER_RATE_LIMITS = {
|
|
488
|
+
standard: {
|
|
489
|
+
store_memory: 100,
|
|
490
|
+
retrieve_memory: 300,
|
|
491
|
+
list_recent: 60,
|
|
492
|
+
get_stats: 30,
|
|
493
|
+
},
|
|
494
|
+
premium: {
|
|
495
|
+
store_memory: 500,
|
|
496
|
+
retrieve_memory: 1000,
|
|
497
|
+
list_recent: 200,
|
|
498
|
+
get_stats: 100,
|
|
499
|
+
},
|
|
500
|
+
unlimited: {
|
|
501
|
+
store_memory: 2000,
|
|
502
|
+
retrieve_memory: 5000,
|
|
503
|
+
list_recent: 500,
|
|
504
|
+
get_stats: 300,
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Get rate limits for a tier
|
|
509
|
+
*
|
|
510
|
+
* @param tier - Rate limit tier
|
|
511
|
+
* @returns Rate limits for the tier
|
|
512
|
+
*/
|
|
513
|
+
export function getRateLimitsForTier(tier) {
|
|
514
|
+
return TIER_RATE_LIMITS[tier] || TIER_RATE_LIMITS.standard;
|
|
515
|
+
}
|
|
516
|
+
// =============================================================================
|
|
517
|
+
// Auth Cache
|
|
518
|
+
// =============================================================================
|
|
519
|
+
/**
|
|
520
|
+
* Create an in-memory cache for auth results
|
|
521
|
+
*
|
|
522
|
+
* @param options - Cache configuration
|
|
523
|
+
* @returns Cache object with get/set methods
|
|
524
|
+
*/
|
|
525
|
+
export function createAuthCache(options) {
|
|
526
|
+
const cache = new Map();
|
|
527
|
+
const { maxSize, ttlSeconds } = options;
|
|
528
|
+
return {
|
|
529
|
+
get(keyId) {
|
|
530
|
+
const entry = cache.get(keyId);
|
|
531
|
+
if (!entry) {
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
// Check TTL
|
|
535
|
+
if (Date.now() > entry.expiresAt) {
|
|
536
|
+
cache.delete(keyId);
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
return { userId: entry.userId, tier: entry.tier };
|
|
540
|
+
},
|
|
541
|
+
set(keyId, value) {
|
|
542
|
+
// Evict oldest if at max size
|
|
543
|
+
if (cache.size >= maxSize) {
|
|
544
|
+
const firstKey = cache.keys().next().value;
|
|
545
|
+
if (firstKey) {
|
|
546
|
+
cache.delete(firstKey);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
cache.set(keyId, {
|
|
550
|
+
userId: value.userId,
|
|
551
|
+
tier: value.tier,
|
|
552
|
+
expiresAt: Date.now() + ttlSeconds * 1000,
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
/**
|
|
556
|
+
* Invalidate a specific key from the cache
|
|
557
|
+
* HIGH-002: Used to immediately invalidate revoked/rotated keys
|
|
558
|
+
*
|
|
559
|
+
* @param keyId - The key ID (prefix) to invalidate
|
|
560
|
+
* @returns true if key was in cache, false otherwise
|
|
561
|
+
*/
|
|
562
|
+
invalidate(keyId) {
|
|
563
|
+
return cache.delete(keyId);
|
|
564
|
+
},
|
|
565
|
+
clear() {
|
|
566
|
+
cache.clear();
|
|
567
|
+
},
|
|
568
|
+
size() {
|
|
569
|
+
return cache.size;
|
|
570
|
+
},
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Revoke an API key and invalidate it from cache
|
|
575
|
+
* HIGH-002: Ensures revoked keys cannot be used even if cached
|
|
576
|
+
*
|
|
577
|
+
* @param keyPrefix - The key prefix to revoke
|
|
578
|
+
* @param cache - The auth cache instance
|
|
579
|
+
* @param reason - Reason for revocation (for audit logging)
|
|
580
|
+
* @returns true if key was invalidated from cache
|
|
581
|
+
*/
|
|
582
|
+
export function revokeApiKey(keyPrefix, cache, reason = "manual_revocation") {
|
|
583
|
+
console.error(`[INFO] Revoking API key: ${keyPrefix.slice(0, 4)}... (reason: ${reason})`);
|
|
584
|
+
// Invalidate from cache immediately
|
|
585
|
+
const wasInCache = cache.invalidate(keyPrefix);
|
|
586
|
+
if (wasInCache) {
|
|
587
|
+
console.error(`[INFO] Key ${keyPrefix.slice(0, 4)}... invalidated from cache`);
|
|
588
|
+
}
|
|
589
|
+
// In production, this would also update the PostgreSQL revoked_at timestamp
|
|
590
|
+
// UPDATE api_keys SET revoked_at = NOW() WHERE key_prefix = $1
|
|
591
|
+
return wasInCache;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Invalidate a rotated API key from cache
|
|
595
|
+
* HIGH-002: Ensures old keys cannot be used during rotation
|
|
596
|
+
*
|
|
597
|
+
* @param oldKeyPrefix - The old key prefix being rotated
|
|
598
|
+
* @param cache - The auth cache instance
|
|
599
|
+
* @returns true if old key was invalidated from cache
|
|
600
|
+
*/
|
|
601
|
+
export function invalidateRotatedKey(oldKeyPrefix, cache) {
|
|
602
|
+
console.error(`[INFO] Invalidating rotated key: ${oldKeyPrefix.slice(0, 4)}...`);
|
|
603
|
+
// Invalidate old key from cache immediately
|
|
604
|
+
const wasInCache = cache.invalidate(oldKeyPrefix);
|
|
605
|
+
if (wasInCache) {
|
|
606
|
+
console.error(`[INFO] Old key ${oldKeyPrefix.slice(0, 4)}... invalidated from cache`);
|
|
607
|
+
}
|
|
608
|
+
return wasInCache;
|
|
609
|
+
}
|
|
610
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
|