@gugananuvem/aws-local-simulator 1.0.35 → 1.0.39

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.
Files changed (149) hide show
  1. package/README.md +662 -658
  2. package/package.json +10 -3
  3. package/src/config/default-config.js +71 -0
  4. package/src/config/env-loader.js +4 -2
  5. package/src/middleware/authorization.js +271 -0
  6. package/src/middleware/cloudtrail-logger.js +333 -0
  7. package/src/middleware/error-handler.js +138 -0
  8. package/src/middleware/index.js +79 -0
  9. package/src/middleware/policy-enforcement.js +407 -0
  10. package/src/server.js +74 -4
  11. package/src/services/acm/index.js +66 -0
  12. package/src/services/acm/models/certificate.js +202 -0
  13. package/src/services/acm/server.js +224 -0
  14. package/src/services/acm/simulator.js +293 -0
  15. package/src/services/alb/index.js +104 -0
  16. package/src/services/alb/models/loadBalancer.js +88 -0
  17. package/src/services/alb/models/targetGroup.js +128 -0
  18. package/src/services/alb/server.js +160 -0
  19. package/src/services/alb/simulator.js +262 -0
  20. package/src/services/apigateway/index.js +22 -0
  21. package/src/services/apigateway/server.js +247 -35
  22. package/src/services/apigateway/simulator.js +780 -26
  23. package/src/services/asg/index.js +100 -0
  24. package/src/services/asg/models/autoScalingGroup.js +110 -0
  25. package/src/services/asg/models/launchTemplate.js +41 -0
  26. package/src/services/asg/models/scalingPolicy.js +51 -0
  27. package/src/services/asg/server.js +236 -0
  28. package/src/services/asg/simulator.js +410 -0
  29. package/src/services/aurora/cluster-manager.js +731 -0
  30. package/src/services/aurora/data-api.js +514 -0
  31. package/src/services/aurora/db-engine.js +270 -0
  32. package/src/services/aurora/index.js +159 -0
  33. package/src/services/aurora/rds-api.js +189 -0
  34. package/src/services/aurora/server.js +213 -0
  35. package/src/services/aurora/sql-translator.js +334 -0
  36. package/src/services/cloudformation/index.js +2 -2
  37. package/src/services/cloudformation/server.js +1 -0
  38. package/src/services/cloudfront/cache-engine.js +225 -0
  39. package/src/services/cloudfront/geo-restrictions.js +377 -0
  40. package/src/services/cloudfront/index.js +220 -0
  41. package/src/services/cloudfront/models/behavior.js +158 -0
  42. package/src/services/cloudfront/models/distribution.js +284 -0
  43. package/src/services/cloudfront/models/index.js +99 -0
  44. package/src/services/cloudfront/models/invalidation.js +109 -0
  45. package/src/services/cloudfront/models/origin.js +155 -0
  46. package/src/services/cloudfront/origin-router.js +552 -0
  47. package/src/services/cloudfront/origin-validator.js +398 -0
  48. package/src/services/cloudfront/server.js +512 -0
  49. package/src/services/cloudfront/signed-url-generator.js +377 -0
  50. package/src/services/cloudfront/simulator.js +425 -0
  51. package/src/services/cloudfront/store.js +326 -0
  52. package/src/services/cloudshell/env-builder.js +27 -0
  53. package/src/services/cloudshell/index.js +48 -0
  54. package/src/services/cloudshell/routes.js +60 -0
  55. package/src/services/cloudshell/session-manager.js +226 -0
  56. package/src/services/cloudshell/static/.gitkeep +0 -0
  57. package/src/services/cloudshell/static/index.html +406 -0
  58. package/src/services/cloudshell/websocket-handler.js +107 -0
  59. package/src/services/cloudtrail/index.js +2 -3
  60. package/src/services/cloudtrail/server.js +68 -0
  61. package/src/services/cognito/server.js +4 -1
  62. package/src/services/dynamodb/server.js +4 -1
  63. package/src/services/dynamodb/simulator.js +2 -1
  64. package/src/services/ec2/index.js +101 -0
  65. package/src/services/ec2/instanceServer.js +311 -0
  66. package/src/services/ec2/models/ami.js +39 -0
  67. package/src/services/ec2/models/instance.js +98 -0
  68. package/src/services/ec2/models/networkInterface.js +74 -0
  69. package/src/services/ec2/models/securityGroup.js +71 -0
  70. package/src/services/ec2/server.js +350 -0
  71. package/src/services/ec2/simulator.js +436 -0
  72. package/src/services/eventbridge/server.js +36 -0
  73. package/src/services/eventbridge/simulator.js +230 -45
  74. package/src/services/iam/index.js +65 -0
  75. package/src/services/iam/middleware.js +99 -0
  76. package/src/services/iam/server.js +331 -0
  77. package/src/services/iam/simulator.js +1432 -0
  78. package/src/services/index.js +28 -0
  79. package/src/services/kinesis-analytics/index.js +105 -0
  80. package/src/services/kinesis-analytics/models/application.js +325 -0
  81. package/src/services/kinesis-analytics/models/index.js +12 -0
  82. package/src/services/kinesis-analytics/server.js +250 -0
  83. package/src/services/kinesis-analytics/simulator.js +407 -0
  84. package/src/services/kinesis-analytics/store.js +176 -0
  85. package/src/services/kinesis-data-streams/index.js +106 -0
  86. package/src/services/kinesis-data-streams/models/index.js +12 -0
  87. package/src/services/kinesis-data-streams/models/record.js +70 -0
  88. package/src/services/kinesis-data-streams/models/stream.js +280 -0
  89. package/src/services/kinesis-data-streams/server.js +255 -0
  90. package/src/services/kinesis-data-streams/simulator.js +514 -0
  91. package/src/services/kinesis-data-streams/store.js +163 -0
  92. package/src/services/kinesis-firehose/index.js +106 -0
  93. package/src/services/kinesis-firehose/models/delivery-stream.js +265 -0
  94. package/src/services/kinesis-firehose/models/index.js +10 -0
  95. package/src/services/kinesis-firehose/server.js +215 -0
  96. package/src/services/kinesis-firehose/simulator.js +388 -0
  97. package/src/services/kinesis-firehose/store.js +163 -0
  98. package/src/services/kms/server.js +4 -1
  99. package/src/services/lambda/index.js +26 -0
  100. package/src/services/lambda/server.js +12 -1
  101. package/src/services/lambda/simulator.js +4 -0
  102. package/src/services/opensearch/index.js +105 -0
  103. package/src/services/opensearch/models/document.js +115 -0
  104. package/src/services/opensearch/models/index.js +73 -0
  105. package/src/services/opensearch/server.js +310 -0
  106. package/src/services/opensearch/simulator.js +605 -0
  107. package/src/services/opensearch/store.js +162 -0
  108. package/src/services/organizations/control-tower-simulator.js +321 -0
  109. package/src/services/organizations/control-tower-store.js +182 -0
  110. package/src/services/organizations/iam-integration.js +413 -0
  111. package/src/services/organizations/index.js +172 -0
  112. package/src/services/organizations/models/index.js +13 -0
  113. package/src/services/organizations/models/invitation.js +48 -0
  114. package/src/services/organizations/models/organization.js +566 -0
  115. package/src/services/organizations/models/role.js +244 -0
  116. package/src/services/organizations/models/scp.js +131 -0
  117. package/src/services/organizations/server.js +736 -0
  118. package/src/services/organizations/simulator.js +593 -0
  119. package/src/services/organizations/store.js +235 -0
  120. package/src/services/organizations/vpc-integration.js +453 -0
  121. package/src/services/route53/index.js +67 -0
  122. package/src/services/route53/models/healthCheck.js +101 -0
  123. package/src/services/route53/models/hostedZone.js +37 -0
  124. package/src/services/route53/models/resourceRecord.js +106 -0
  125. package/src/services/route53/server.js +841 -0
  126. package/src/services/route53/simulator.js +350 -0
  127. package/src/services/s3/index.js +62 -0
  128. package/src/services/s3/presigned-url-generator.js +337 -0
  129. package/src/services/s3/server.js +231 -0
  130. package/src/services/s3/simulator.js +551 -4
  131. package/src/services/sns/index.js +31 -0
  132. package/src/services/sns/server.js +9 -0
  133. package/src/services/sqs/index.js +38 -0
  134. package/src/services/sqs/server.js +57 -4
  135. package/src/services/sqs/simulator.js +423 -33
  136. package/src/services/sts/simulator.js +209 -17
  137. package/src/services/vpc/README.md +459 -0
  138. package/src/services/vpc/ec2ResponseFormatter.js +431 -0
  139. package/src/services/vpc/index.js +90 -0
  140. package/src/services/vpc/models/internetGateway.js +71 -0
  141. package/src/services/vpc/models/routeTable.js +160 -0
  142. package/src/services/vpc/models/subnet.js +48 -0
  143. package/src/services/vpc/models/vpc.js +37 -0
  144. package/src/services/vpc/models/vpcEndpoint.js +100 -0
  145. package/src/services/vpc/models/vpcGateway.js +134 -0
  146. package/src/services/vpc/server.js +836 -0
  147. package/src/services/vpc/simulator.js +613 -0
  148. package/src/utils/policy-cache.js +215 -0
  149. package/aws-config +0 -154
@@ -0,0 +1,398 @@
1
+ const crypto = require('crypto');
2
+
3
+ /**
4
+ * Origin Validator and Restriction Checker for CloudFront
5
+ * Validates origin accessibility, enforces origin restrictions, and manages Origin Custom Headers
6
+ */
7
+ class OriginValidator {
8
+ constructor() {
9
+ this.validationCache = new Map();
10
+ this.cacheExpiry = 5 * 60 * 1000; // 5 minutes
11
+ }
12
+
13
+ /**
14
+ * Validate that an origin is reachable and compatible
15
+ * @param {object} origin - Origin object from Distribution
16
+ * @returns {Promise<object>} Validation result
17
+ */
18
+ async validateOrigin(origin) {
19
+ const cacheKey = `${origin.domainName}-${origin.id}`;
20
+
21
+ // Check cache
22
+ const cached = this.validationCache.get(cacheKey);
23
+ if (cached && Date.now() - cached.timestamp < this.cacheExpiry) {
24
+ return cached.result;
25
+ }
26
+
27
+ try {
28
+ const result = await this._performValidation(origin);
29
+
30
+ // Cache result
31
+ this.validationCache.set(cacheKey, {
32
+ result,
33
+ timestamp: Date.now()
34
+ });
35
+
36
+ return result;
37
+ } catch (error) {
38
+ return {
39
+ isValid: false,
40
+ error: error.message,
41
+ originId: origin.id
42
+ };
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Check if a request should be allowed based on origin restrictions
48
+ * @param {object} origin - Origin object
49
+ * @param {object} request - Request object with headers, ip, etc.
50
+ * @returns {object} Restriction check result
51
+ */
52
+ checkOriginRestrictions(origin, request = {}) {
53
+ const violations = [];
54
+
55
+ // Check origin custom headers
56
+ if (origin.customHeaders && origin.customHeaders.length > 0) {
57
+ for (const header of origin.customHeaders) {
58
+ const requestValue = request.headers?.[header.headerName];
59
+ if (requestValue !== header.headerValue) {
60
+ violations.push({
61
+ type: 'CUSTOM_HEADER_MISMATCH',
62
+ header: header.headerName,
63
+ expected: header.headerValue,
64
+ received: requestValue
65
+ });
66
+ }
67
+ }
68
+ }
69
+
70
+ // Check origin SSL/TLS requirements
71
+ if (origin.originSslProtocols && request.protocol) {
72
+ const allowedProtocols = origin.originSslProtocols;
73
+ if (!allowedProtocols.includes(request.protocol)) {
74
+ violations.push({
75
+ type: 'SSL_PROTOCOL_NOT_ALLOWED',
76
+ allowed: allowedProtocols,
77
+ requested: request.protocol
78
+ });
79
+ }
80
+ }
81
+
82
+ // Check keep-alive timeout
83
+ if (origin.originKeepAliveTimeout !== undefined) {
84
+ // This is more of a configuration that affects how long connections stay open
85
+ // Not a restriction per se, but recorded for monitoring
86
+ }
87
+
88
+ return {
89
+ isAllowed: violations.length === 0,
90
+ violations: violations,
91
+ originId: origin.id
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Get origin-specific headers that should be forwarded to the origin
97
+ * @param {object} origin - Origin object
98
+ * @param {object} behavior - Behavior object (may have header policies)
99
+ * @returns {object} Headers to forward to origin
100
+ */
101
+ getOriginHeaders(origin, behavior = {}) {
102
+ const headers = {};
103
+
104
+ // Add custom headers from origin
105
+ if (origin.customHeaders && origin.customHeaders.length > 0) {
106
+ for (const header of origin.customHeaders) {
107
+ headers[header.headerName] = header.headerValue;
108
+ }
109
+ }
110
+
111
+ // Add origin path if specified
112
+ if (origin.originPath) {
113
+ // This is typically handled at request routing level, not as a header
114
+ // But we include it for reference
115
+ headers['X-Origin-Path'] = origin.originPath;
116
+ }
117
+
118
+ // Add Host header (for HTTP/S origins)
119
+ if (origin.domainName) {
120
+ headers['Host'] = origin.domainName;
121
+ }
122
+
123
+ return headers;
124
+ }
125
+
126
+ /**
127
+ * Validate origin group failover configuration
128
+ * @param {object} originGroup - OriginGroup object
129
+ * @param {object} distribution - Distribution object (contains origins)
130
+ * @returns {object} Validation result
131
+ */
132
+ validateOriginGroup(originGroup, distribution = {}) {
133
+ const errors = [];
134
+
135
+ // Check primary member
136
+ if (!originGroup.members || originGroup.members.length === 0) {
137
+ errors.push('OriginGroup must have at least one member');
138
+ }
139
+
140
+ // Validate all members exist in distribution
141
+ const originIds = distribution.origins?.map(o => o.id) || [];
142
+ for (const member of originGroup.members || []) {
143
+ if (!originIds.includes(member.originId)) {
144
+ errors.push(`Origin '${member.originId}' not found in distribution`);
145
+ }
146
+ }
147
+
148
+ // Check failover criteria
149
+ if (originGroup.failoverCriteria) {
150
+ const { statusCodes } = originGroup.failoverCriteria;
151
+ if (statusCodes && statusCodes.length === 0) {
152
+ errors.push('Failover status codes cannot be empty');
153
+ }
154
+
155
+ // Validate status codes
156
+ if (statusCodes) {
157
+ for (const code of statusCodes) {
158
+ if (!Number.isInteger(code) || code < 100 || code > 599) {
159
+ errors.push(`Invalid HTTP status code: ${code}`);
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
+ return {
166
+ isValid: errors.length === 0,
167
+ errors: errors,
168
+ originGroupId: originGroup.id
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Check if origin should be used based on failover criteria
174
+ * @param {object} originGroup - OriginGroup object
175
+ * @param {number} statusCode - HTTP status code from origin
176
+ * @param {number} [failureCount] - Number of consecutive failures
177
+ * @returns {boolean} True if should failover to next origin
178
+ */
179
+ shouldFailover(originGroup, statusCode, failureCount = 1) {
180
+ if (!originGroup.failoverCriteria) {
181
+ return false;
182
+ }
183
+
184
+ const { statusCodes, quantity } = originGroup.failoverCriteria;
185
+
186
+ // Check if status code matches failover criteria
187
+ if (statusCodes && statusCodes.includes(statusCode)) {
188
+ return true;
189
+ }
190
+
191
+ // Check if we've hit failure threshold
192
+ if (quantity && failureCount >= quantity) {
193
+ return true;
194
+ }
195
+
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * Get the next origin in failover sequence
201
+ * @param {object} originGroup - OriginGroup object
202
+ * @param {object} currentOrigin - Current origin being used
203
+ * @returns {object|null} Next origin member or null if no more failovers
204
+ */
205
+ getFailoverOrigin(originGroup, currentOrigin) {
206
+ if (!originGroup.members || originGroup.members.length === 0) {
207
+ return null;
208
+ }
209
+
210
+ const currentIndex = originGroup.members.findIndex(
211
+ m => m.originId === currentOrigin.id
212
+ );
213
+
214
+ if (currentIndex === -1 || currentIndex >= originGroup.members.length - 1) {
215
+ return null; // No more origins to failover to
216
+ }
217
+
218
+ return originGroup.members[currentIndex + 1];
219
+ }
220
+
221
+ /**
222
+ * Validate S3 origin specific requirements
223
+ * @param {object} origin - Origin object
224
+ * @returns {object} Validation result
225
+ */
226
+ validateS3Origin(origin) {
227
+ const errors = [];
228
+ const warnings = [];
229
+
230
+ // S3 domain should end with .s3.amazonaws.com or regional variant
231
+ const domainPattern = /\.s3[.-]([a-z0-9-]+)?\.amazonaws\.com$/i;
232
+ if (!domainPattern.test(origin.domainName)) {
233
+ errors.push(
234
+ `S3 origin domain '${origin.domainName}' does not match expected S3 format`
235
+ );
236
+ }
237
+
238
+ // Check for origin access identity configuration
239
+ if (!origin.s3OriginConfig?.originAccessIdentity) {
240
+ warnings.push(
241
+ 'S3 origin does not use Origin Access Identity (OAI); bucket must be public or have bucket policy'
242
+ );
243
+ }
244
+
245
+ // Warn if using website endpoint instead of REST endpoint
246
+ if (origin.domainName.includes('.s3-website-')) {
247
+ warnings.push(
248
+ 'S3 website endpoint detected; use REST endpoint for better CloudFront compatibility'
249
+ );
250
+ }
251
+
252
+ return {
253
+ isValid: errors.length === 0,
254
+ errors: errors,
255
+ warnings: warnings,
256
+ originType: 'S3'
257
+ };
258
+ }
259
+
260
+ /**
261
+ * Validate HTTP origin specific requirements
262
+ * @param {object} origin - Origin object
263
+ * @returns {object} Validation result
264
+ */
265
+ validateHttpOrigin(origin) {
266
+ const errors = [];
267
+ const warnings = [];
268
+
269
+ // Validate domain format
270
+ try {
271
+ new URL(`https://${origin.domainName}`);
272
+ } catch (e) {
273
+ errors.push(`Invalid domain name: ${origin.domainName}`);
274
+ }
275
+
276
+ // Check port
277
+ if (origin.customOriginConfig?.httpPort) {
278
+ const port = origin.customOriginConfig.httpPort;
279
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
280
+ errors.push(`Invalid HTTP port: ${port}`);
281
+ }
282
+ }
283
+
284
+ if (origin.customOriginConfig?.httpsPort) {
285
+ const port = origin.customOriginConfig.httpsPort;
286
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
287
+ errors.push(`Invalid HTTPS port: ${port}`);
288
+ }
289
+ }
290
+
291
+ // Validate origin protocol policy
292
+ const validPolicies = [
293
+ 'http-only',
294
+ 'https-only',
295
+ 'match-viewer'
296
+ ];
297
+ if (
298
+ origin.customOriginConfig?.originProtocolPolicy &&
299
+ !validPolicies.includes(origin.customOriginConfig.originProtocolPolicy)
300
+ ) {
301
+ errors.push(
302
+ `Invalid origin protocol policy: ${origin.customOriginConfig.originProtocolPolicy}`
303
+ );
304
+ }
305
+
306
+ return {
307
+ isValid: errors.length === 0,
308
+ errors: errors,
309
+ warnings: warnings,
310
+ originType: 'HTTP'
311
+ };
312
+ }
313
+
314
+ /**
315
+ * Validate Lambda@Edge origin
316
+ * @param {object} origin - Origin object
317
+ * @returns {object} Validation result
318
+ */
319
+ validateLambdaEdgeOrigin(origin) {
320
+ const errors = [];
321
+
322
+ // Lambda@Edge functions should have ARN format
323
+ const arnPattern = /^arn:aws:lambda:[a-z0-9-]+:\d{12}:function:[a-zA-Z0-9_-]+$/;
324
+ if (!arnPattern.test(origin.domainName)) {
325
+ errors.push(`Invalid Lambda@Edge ARN format: ${origin.domainName}`);
326
+ }
327
+
328
+ return {
329
+ isValid: errors.length === 0,
330
+ errors: errors,
331
+ originType: 'Lambda@Edge'
332
+ };
333
+ }
334
+
335
+ /**
336
+ * Clear validation cache
337
+ */
338
+ clearCache() {
339
+ this.validationCache.clear();
340
+ }
341
+
342
+ /**
343
+ * Get validation cache stats
344
+ */
345
+ getCacheStats() {
346
+ return {
347
+ entries: this.validationCache.size,
348
+ cacheExpiry: this.cacheExpiry
349
+ };
350
+ }
351
+
352
+ /**
353
+ * Private Methods
354
+ */
355
+
356
+ async _performValidation(origin) {
357
+ const validations = [];
358
+
359
+ // Basic structure validation
360
+ if (!origin.id || !origin.domainName) {
361
+ return {
362
+ isValid: false,
363
+ error: 'Origin must have id and domainName'
364
+ };
365
+ }
366
+
367
+ // Type-specific validation
368
+ if (origin.s3OriginConfig) {
369
+ validations.push(this.validateS3Origin(origin));
370
+ } else if (origin.customOriginConfig) {
371
+ validations.push(this.validateHttpOrigin(origin));
372
+ } else if (this._isLambdaEdgeOrigin(origin)) {
373
+ validations.push(this.validateLambdaEdgeOrigin(origin));
374
+ }
375
+
376
+ // Check if any validation failed
377
+ const failedValidation = validations.find(v => !v.isValid);
378
+ if (failedValidation) {
379
+ return {
380
+ isValid: false,
381
+ ...failedValidation
382
+ };
383
+ }
384
+
385
+ return {
386
+ isValid: true,
387
+ validations: validations,
388
+ originId: origin.id,
389
+ timestamp: new Date().toISOString()
390
+ };
391
+ }
392
+
393
+ _isLambdaEdgeOrigin(origin) {
394
+ return origin.domainName?.startsWith('arn:aws:lambda:');
395
+ }
396
+ }
397
+
398
+ module.exports = OriginValidator;