@gugananuvem/aws-local-simulator 1.0.34 → 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 (150) hide show
  1. package/README.md +662 -658
  2. package/package.json +11 -4
  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/handler-loader.js +50 -5
  100. package/src/services/lambda/index.js +26 -0
  101. package/src/services/lambda/server.js +18 -12
  102. package/src/services/lambda/simulator.js +73 -17
  103. package/src/services/opensearch/index.js +105 -0
  104. package/src/services/opensearch/models/document.js +115 -0
  105. package/src/services/opensearch/models/index.js +73 -0
  106. package/src/services/opensearch/server.js +310 -0
  107. package/src/services/opensearch/simulator.js +605 -0
  108. package/src/services/opensearch/store.js +162 -0
  109. package/src/services/organizations/control-tower-simulator.js +321 -0
  110. package/src/services/organizations/control-tower-store.js +182 -0
  111. package/src/services/organizations/iam-integration.js +413 -0
  112. package/src/services/organizations/index.js +172 -0
  113. package/src/services/organizations/models/index.js +13 -0
  114. package/src/services/organizations/models/invitation.js +48 -0
  115. package/src/services/organizations/models/organization.js +566 -0
  116. package/src/services/organizations/models/role.js +244 -0
  117. package/src/services/organizations/models/scp.js +131 -0
  118. package/src/services/organizations/server.js +736 -0
  119. package/src/services/organizations/simulator.js +593 -0
  120. package/src/services/organizations/store.js +235 -0
  121. package/src/services/organizations/vpc-integration.js +453 -0
  122. package/src/services/route53/index.js +67 -0
  123. package/src/services/route53/models/healthCheck.js +101 -0
  124. package/src/services/route53/models/hostedZone.js +37 -0
  125. package/src/services/route53/models/resourceRecord.js +106 -0
  126. package/src/services/route53/server.js +841 -0
  127. package/src/services/route53/simulator.js +350 -0
  128. package/src/services/s3/index.js +62 -0
  129. package/src/services/s3/presigned-url-generator.js +337 -0
  130. package/src/services/s3/server.js +231 -0
  131. package/src/services/s3/simulator.js +551 -4
  132. package/src/services/sns/index.js +31 -0
  133. package/src/services/sns/server.js +9 -0
  134. package/src/services/sqs/index.js +38 -0
  135. package/src/services/sqs/server.js +57 -4
  136. package/src/services/sqs/simulator.js +423 -33
  137. package/src/services/sts/simulator.js +209 -17
  138. package/src/services/vpc/README.md +459 -0
  139. package/src/services/vpc/ec2ResponseFormatter.js +431 -0
  140. package/src/services/vpc/index.js +90 -0
  141. package/src/services/vpc/models/internetGateway.js +71 -0
  142. package/src/services/vpc/models/routeTable.js +160 -0
  143. package/src/services/vpc/models/subnet.js +48 -0
  144. package/src/services/vpc/models/vpc.js +37 -0
  145. package/src/services/vpc/models/vpcEndpoint.js +100 -0
  146. package/src/services/vpc/models/vpcGateway.js +134 -0
  147. package/src/services/vpc/server.js +836 -0
  148. package/src/services/vpc/simulator.js +613 -0
  149. package/src/utils/policy-cache.js +215 -0
  150. package/aws-config +0 -154
@@ -0,0 +1,377 @@
1
+ const crypto = require('crypto');
2
+ const { DateTime } = require('luxon');
3
+
4
+ /**
5
+ * Signed URL/Cookie Generator for CloudFront
6
+ * Implements AWS CloudFront's signing mechanisms for URLs and cookies
7
+ * Supports both Canned Policies (simple TTL) and Custom Policies (advanced restrictions)
8
+ */
9
+ class SignedUrlGenerator {
10
+ constructor() {
11
+ this.algorithmIdentifier = 'AWS4-HMAC-SHA256';
12
+ }
13
+
14
+ /**
15
+ * Generate a canned signed URL (simple TTL-based)
16
+ * @param {string} distributionUrl - Base CloudFront distribution URL or CNAME
17
+ * @param {string} resourcePath - Path to the resource (e.g., /videos/movie.mp4)
18
+ * @param {string} privateKey - Private key in PEM format
19
+ * @param {string} keyPairId - CloudFront key pair ID
20
+ * @param {Date|number} expirationTime - When the URL expires (Date or Unix timestamp)
21
+ * @returns {string} Signed URL with Signature, Key-Pair-Id, and Policy query parameters
22
+ */
23
+ generateCannedUrl(
24
+ distributionUrl,
25
+ resourcePath,
26
+ privateKey,
27
+ keyPairId,
28
+ expirationTime
29
+ ) {
30
+ const expiration = this._normalizeExpiration(expirationTime);
31
+
32
+ // Build the resource URL
33
+ const baseUrl = this._normalizeUrl(distributionUrl);
34
+ const fullUrl = baseUrl + resourcePath;
35
+
36
+ // Create the policy string for canned policy
37
+ const policy = {
38
+ Statement: [
39
+ {
40
+ Resource: fullUrl,
41
+ Condition: {
42
+ DateLessThan: {
43
+ 'AWS:EpochTime': Math.floor(expiration / 1000)
44
+ }
45
+ }
46
+ }
47
+ ]
48
+ };
49
+
50
+ const policyString = JSON.stringify(policy);
51
+ const signature = this._signPolicy(policyString, privateKey);
52
+ const encodedPolicy = Buffer.from(policyString).toString('base64');
53
+ const encodedSignature = this._sanitizeBase64(signature);
54
+
55
+ // Build signed URL
56
+ const separator = fullUrl.includes('?') ? '&' : '?';
57
+ return `${fullUrl}${separator}Signature=${encodedSignature}&Key-Pair-Id=${keyPairId}`;
58
+ }
59
+
60
+ /**
61
+ * Generate a custom signed URL (advanced policy with multiple restrictions)
62
+ * @param {string} distributionUrl - Base CloudFront distribution URL or CNAME
63
+ * @param {string} resourcePath - Path to the resource (wildcard paths supported)
64
+ * @param {string} privateKey - Private key in PEM format
65
+ * @param {string} keyPairId - CloudFront key pair ID
66
+ * @param {object} options - Policy options
67
+ * @param {Date|number} options.expirationTime - URL expiration time
68
+ * @param {Date|number} [options.notBefore] - Time before which URL is not valid
69
+ * @param {string|string[]} [options.ipRange] - Allowed IP address(es) (CIDR format)
70
+ * @returns {object} Object with signed URL, policy, and signature
71
+ */
72
+ generateCustomUrl(
73
+ distributionUrl,
74
+ resourcePath,
75
+ privateKey,
76
+ keyPairId,
77
+ options = {}
78
+ ) {
79
+ const expiration = this._normalizeExpiration(options.expirationTime);
80
+ const baseUrl = this._normalizeUrl(distributionUrl);
81
+ const fullUrl = baseUrl + resourcePath;
82
+
83
+ // Build custom policy
84
+ const condition = {
85
+ DateLessThan: {
86
+ 'AWS:EpochTime': Math.floor(expiration / 1000)
87
+ }
88
+ };
89
+
90
+ if (options.notBefore) {
91
+ const notBefore = this._normalizeExpiration(options.notBefore);
92
+ condition.DateGreaterThan = {
93
+ 'AWS:EpochTime': Math.floor(notBefore / 1000)
94
+ };
95
+ }
96
+
97
+ if (options.ipRange) {
98
+ const ipAddresses = Array.isArray(options.ipRange)
99
+ ? options.ipRange
100
+ : [options.ipRange];
101
+ condition.IpAddress = {
102
+ 'AWS:SourceIp': ipAddresses
103
+ };
104
+ }
105
+
106
+ const policy = {
107
+ Statement: [
108
+ {
109
+ Resource: fullUrl,
110
+ Condition: condition
111
+ }
112
+ ]
113
+ };
114
+
115
+ const policyString = JSON.stringify(policy);
116
+ const signature = this._signPolicy(policyString, privateKey);
117
+ const encodedPolicy = this._sanitizeBase64(Buffer.from(policyString).toString('base64'));
118
+ const encodedSignature = this._sanitizeBase64(signature);
119
+
120
+ // Build signed URL with custom policy
121
+ const separator = fullUrl.includes('?') ? '&' : '?';
122
+ const signedUrl = `${fullUrl}${separator}Policy=${encodedPolicy}&Signature=${encodedSignature}&Key-Pair-Id=${keyPairId}`;
123
+
124
+ return {
125
+ url: signedUrl,
126
+ policy: policyString,
127
+ signature: encodedSignature,
128
+ keyPairId: keyPairId
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Generate signed cookies (for multiple files or alternative to URL signing)
134
+ * @param {string} privateKey - Private key in PEM format
135
+ * @param {string} keyPairId - CloudFront key pair ID
136
+ * @param {string} resourcePath - Path pattern (e.g., /private/*, /videos/*)
137
+ * @param {Date|number} expirationTime - When cookies expire
138
+ * @param {object} [options] - Additional options
139
+ * @param {Date|number} [options.notBefore] - Time before which cookies are not valid
140
+ * @param {string|string[]} [options.ipRange] - Allowed IP address(es)
141
+ * @returns {object} Object with CloudFront-Policy, CloudFront-Signature, and CloudFront-Key-Pair-Id cookies
142
+ */
143
+ generateCookies(
144
+ privateKey,
145
+ keyPairId,
146
+ resourcePath,
147
+ expirationTime,
148
+ options = {}
149
+ ) {
150
+ const expiration = this._normalizeExpiration(expirationTime);
151
+
152
+ // Build policy for cookies
153
+ const condition = {
154
+ DateLessThan: {
155
+ 'AWS:EpochTime': Math.floor(expiration / 1000)
156
+ }
157
+ };
158
+
159
+ if (options.notBefore) {
160
+ const notBefore = this._normalizeExpiration(options.notBefore);
161
+ condition.DateGreaterThan = {
162
+ 'AWS:EpochTime': Math.floor(notBefore / 1000)
163
+ };
164
+ }
165
+
166
+ if (options.ipRange) {
167
+ const ipAddresses = Array.isArray(options.ipRange)
168
+ ? options.ipRange
169
+ : [options.ipRange];
170
+ condition.IpAddress = {
171
+ 'AWS:SourceIp': ipAddresses
172
+ };
173
+ }
174
+
175
+ const policy = {
176
+ Statement: [
177
+ {
178
+ Resource: resourcePath,
179
+ Condition: condition
180
+ }
181
+ ]
182
+ };
183
+
184
+ const policyString = JSON.stringify(policy);
185
+ const signature = this._signPolicy(policyString, privateKey);
186
+ const encodedPolicy = this._sanitizeBase64(Buffer.from(policyString).toString('base64'));
187
+ const encodedSignature = this._sanitizeBase64(signature);
188
+
189
+ return {
190
+ 'CloudFront-Policy': encodedPolicy,
191
+ 'CloudFront-Signature': encodedSignature,
192
+ 'CloudFront-Key-Pair-Id': keyPairId,
193
+ policyObject: policy
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Verify a signed URL or validate its signature
199
+ * @param {string} signedUrl - The signed URL to verify
200
+ * @param {string} publicKey - Public key in PEM format
201
+ * @returns {object} Verification result with isValid, policy, and error details
202
+ */
203
+ verifySignedUrl(signedUrl, publicKey) {
204
+ try {
205
+ const url = new URL(signedUrl);
206
+ const params = new URLSearchParams(url.search);
207
+
208
+ // Extract signature components
209
+ const signature = params.get('Signature');
210
+ const policy = params.get('Policy');
211
+ const keyPairId = params.get('Key-Pair-Id');
212
+
213
+ if (!signature || !keyPairId) {
214
+ return {
215
+ isValid: false,
216
+ error: 'Missing required signature parameters'
217
+ };
218
+ }
219
+
220
+ if (!policy) {
221
+ return {
222
+ isValid: false,
223
+ error: 'Missing Policy parameter'
224
+ };
225
+ }
226
+
227
+ // Decode policy
228
+ const decodedPolicy = Buffer.from(policy, 'base64').toString('utf-8');
229
+ let policyObject;
230
+ try {
231
+ policyObject = JSON.parse(decodedPolicy);
232
+ } catch (e) {
233
+ return {
234
+ isValid: false,
235
+ error: 'Invalid policy JSON'
236
+ };
237
+ }
238
+
239
+ // Verify signature
240
+ const isValid = this._verifySignature(decodedPolicy, signature, publicKey);
241
+
242
+ if (!isValid) {
243
+ return {
244
+ isValid: false,
245
+ error: 'Invalid signature'
246
+ };
247
+ }
248
+
249
+ // Check expiration
250
+ const statement = policyObject.Statement[0];
251
+ if (statement && statement.Condition && statement.Condition.DateLessThan) {
252
+ const expirationTimestamp = statement.Condition.DateLessThan['AWS:EpochTime'];
253
+ const now = Math.floor(Date.now() / 1000);
254
+
255
+ if (now >= expirationTimestamp) {
256
+ return {
257
+ isValid: false,
258
+ error: 'URL has expired'
259
+ };
260
+ }
261
+ }
262
+
263
+ // Check not-before time
264
+ if (statement && statement.Condition && statement.Condition.DateGreaterThan) {
265
+ const notBeforeTimestamp = statement.Condition.DateGreaterThan['AWS:EpochTime'];
266
+ const now = Math.floor(Date.now() / 1000);
267
+
268
+ if (now < notBeforeTimestamp) {
269
+ return {
270
+ isValid: false,
271
+ error: 'URL is not yet valid'
272
+ };
273
+ }
274
+ }
275
+
276
+ return {
277
+ isValid: true,
278
+ policy: policyObject,
279
+ keyPairId: keyPairId,
280
+ resource: statement?.Resource
281
+ };
282
+ } catch (error) {
283
+ return {
284
+ isValid: false,
285
+ error: `Verification failed: ${error.message}`
286
+ };
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Validate an IP against CIDR notation
292
+ * @param {string} ip - IP address to check
293
+ * @param {string} cidr - CIDR notation (e.g., 192.0.2.0/24)
294
+ * @returns {boolean} True if IP is in CIDR range
295
+ */
296
+ isIpInCidr(ip, cidr) {
297
+ try {
298
+ const [network, bits] = cidr.split('/');
299
+ const networkBits = parseInt(bits, 10);
300
+
301
+ const ipParts = ip.split('.').map(Number);
302
+ const networkParts = network.split('.').map(Number);
303
+
304
+ for (let i = 0; i < 4; i++) {
305
+ const ipBits = ipParts[i] * Math.pow(2, 8 - (i + 1) * 8);
306
+ const networkBits_ = networkParts[i] * Math.pow(2, 8 - (i + 1) * 8);
307
+ const mask = (0xffffffff << (32 - networkBits)) >>> 0;
308
+
309
+ if ((ipBits & mask) !== (networkBits_ & mask)) {
310
+ return false;
311
+ }
312
+ }
313
+ return true;
314
+ } catch (e) {
315
+ return false;
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Private Methods
321
+ */
322
+
323
+ _normalizeUrl(url) {
324
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
325
+ url = 'https://' + url;
326
+ }
327
+ return url.endsWith('/') ? url.slice(0, -1) : url;
328
+ }
329
+
330
+ _normalizeExpiration(expirationTime) {
331
+ if (typeof expirationTime === 'number') {
332
+ // If it's less than 10^10, assume it's in seconds; otherwise milliseconds
333
+ return expirationTime < 10000000000 ? expirationTime * 1000 : expirationTime;
334
+ }
335
+ if (expirationTime instanceof Date) {
336
+ return expirationTime.getTime();
337
+ }
338
+ throw new Error('Expiration time must be a Date or Unix timestamp');
339
+ }
340
+
341
+ _signPolicy(policyString, privateKey) {
342
+ const signature = crypto
343
+ .createSign('RSA-SHA1')
344
+ .update(policyString)
345
+ .sign(privateKey, 'base64');
346
+ return signature;
347
+ }
348
+
349
+ _verifySignature(policyString, signature, publicKey) {
350
+ try {
351
+ return crypto
352
+ .createVerify('RSA-SHA1')
353
+ .update(policyString)
354
+ .verify(publicKey, signature, 'base64');
355
+ } catch (e) {
356
+ return false;
357
+ }
358
+ }
359
+
360
+ _sanitizeBase64(base64String) {
361
+ // CloudFront uses URL-safe base64: replace +/= with -_~
362
+ return base64String
363
+ .replace(/\+/g, '-')
364
+ .replace(/\//g, '_')
365
+ .replace(/=/g, '~');
366
+ }
367
+
368
+ _unsanitizeBase64(base64String) {
369
+ // Reverse the URL-safe encoding
370
+ return base64String
371
+ .replace(/-/g, '+')
372
+ .replace(/_/g, '/')
373
+ .replace(/~/g, '=');
374
+ }
375
+ }
376
+
377
+ module.exports = SignedUrlGenerator;