@bitblit/ratchet-epsilon-common 6.0.146-alpha → 6.0.147-alpha

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 (164) hide show
  1. package/package.json +10 -9
  2. package/src/background/background-dynamo-log-table-handler.ts +44 -0
  3. package/src/background/background-entry.ts +4 -0
  4. package/src/background/background-execution-event-type.ts +9 -0
  5. package/src/background/background-execution-event.ts +9 -0
  6. package/src/background/background-execution-listener.ts +6 -0
  7. package/src/background/background-handler.ts +352 -0
  8. package/src/background/background-http-adapter-handler.ts +166 -0
  9. package/src/background/background-meta-response-internal.ts +5 -0
  10. package/src/background/background-process-handling.ts +6 -0
  11. package/src/background/background-process-log-table-entry.ts +11 -0
  12. package/src/background/background-queue-response-internal.ts +9 -0
  13. package/src/background/background-validator.ts +105 -0
  14. package/src/background/epsilon-background-process-error.ts +110 -0
  15. package/src/background/internal-background-entry.ts +10 -0
  16. package/src/background/manager/abstract-background-manager.ts +120 -0
  17. package/src/background/manager/aws-large-payload-s3-sqs-sns-background-manager.ts +87 -0
  18. package/src/background/manager/aws-sqs-sns-background-manager.ts +201 -0
  19. package/src/background/manager/background-manager-like.ts +44 -0
  20. package/src/background/manager/background-manager.spec.ts +89 -0
  21. package/src/background/manager/single-thread-local-background-manager.ts +58 -0
  22. package/src/background/s3-background-transaction-logger.ts +65 -0
  23. package/src/build/ratchet-epsilon-common-info.ts +19 -0
  24. package/src/built-in/background/echo-processor.ts +17 -0
  25. package/src/built-in/background/log-and-enqueue-echo-processor.ts +14 -0
  26. package/src/built-in/background/log-message-background-error-processor.ts +10 -0
  27. package/src/built-in/background/no-op-processor.ts +12 -0
  28. package/src/built-in/background/retry-processor.ts +51 -0
  29. package/src/built-in/background/sample-delay-processor.ts +15 -0
  30. package/src/built-in/background/sample-input-validated-processor-data.ts +4 -0
  31. package/src/built-in/background/sample-input-validated-processor.ts +14 -0
  32. package/src/built-in/built-in-trace-id-generators.ts +22 -0
  33. package/src/built-in/daemon/daemon-authorizer-function.ts +4 -0
  34. package/src/built-in/daemon/daemon-config.ts +9 -0
  35. package/src/built-in/daemon/daemon-group-selection-function.ts +3 -0
  36. package/src/built-in/daemon/daemon-handler.ts +87 -0
  37. package/src/built-in/daemon/daemon-process-state-list.ts +9 -0
  38. package/src/built-in/http/apollo/apollo-util.ts +43 -0
  39. package/src/built-in/http/apollo/default-epsilon-apollo-context.ts +11 -0
  40. package/src/built-in/http/apollo/epsilon-apollo-context-builder-options.ts +5 -0
  41. package/src/built-in/http/apollo/epsilon-lambda-apollo-context-function-argument.ts +6 -0
  42. package/src/built-in/http/apollo/epsilon-lambda-apollo-options.ts +11 -0
  43. package/src/built-in/http/apollo-filter.ts +151 -0
  44. package/src/built-in/http/built-in-auth-filters.ts +73 -0
  45. package/src/built-in/http/built-in-authorizers.ts +22 -0
  46. package/src/built-in/http/built-in-filters.spec.ts +26 -0
  47. package/src/built-in/http/built-in-filters.ts +300 -0
  48. package/src/built-in/http/built-in-handlers.ts +85 -0
  49. package/src/built-in/http/log-level-manipulation-filter.ts +26 -0
  50. package/src/built-in/http/run-handler-as-filter.spec.ts +67 -0
  51. package/src/built-in/http/run-handler-as-filter.ts +102 -0
  52. package/src/cli/ratchet-cli-handler.ts +23 -0
  53. package/src/cli/run-background-process-from-command-line.ts +32 -0
  54. package/src/config/background/background-aws-config.ts +8 -0
  55. package/src/config/background/background-config.ts +15 -0
  56. package/src/config/background/background-error-processor.ts +5 -0
  57. package/src/config/background/background-processor.ts +14 -0
  58. package/src/config/background/background-transaction-log.ts +9 -0
  59. package/src/config/background/background-transaction-logger.ts +6 -0
  60. package/src/config/cron/abstract-cron-entry.ts +17 -0
  61. package/src/config/cron/cron-background-entry.ts +17 -0
  62. package/src/config/cron/cron-config.ts +10 -0
  63. package/src/config/dynamo-db-config.ts +6 -0
  64. package/src/config/epsilon-config.ts +30 -0
  65. package/src/config/epsilon-lambda-event-handler.ts +12 -0
  66. package/src/config/epsilon-logger-config.ts +23 -0
  67. package/src/config/espilon-server-mode.ts +10 -0
  68. package/src/config/generic-aws-event-handler-function.ts +1 -0
  69. package/src/config/http/authorizer-function.ts +9 -0
  70. package/src/config/http/epsilon-authorization-context.ts +5 -0
  71. package/src/config/http/epsilon-cors-approach.ts +7 -0
  72. package/src/config/http/extended-api-gateway-event.ts +8 -0
  73. package/src/config/http/filter-chain-context.ts +15 -0
  74. package/src/config/http/filter-function.ts +3 -0
  75. package/src/config/http/handler-function.ts +4 -0
  76. package/src/config/http/http-config.ts +27 -0
  77. package/src/config/http/http-processing-config.ts +23 -0
  78. package/src/config/http/mapped-http-processing-config.ts +12 -0
  79. package/src/config/http/null-returned-object-handling.ts +7 -0
  80. package/src/config/inter-api/inter-api-aws-config.ts +5 -0
  81. package/src/config/inter-api/inter-api-config.ts +7 -0
  82. package/src/config/inter-api/inter-api-process-mapping.ts +11 -0
  83. package/src/config/local-server/local-server-event-logging-style.ts +8 -0
  84. package/src/config/local-server/local-server-http-method-handling.ts +7 -0
  85. package/src/config/local-server/local-server-options.ts +12 -0
  86. package/src/config/logging-trace-id-generator.ts +3 -0
  87. package/src/config/no-handlers-found-error.ts +6 -0
  88. package/src/config/open-api/open-api-document-components.ts +4 -0
  89. package/src/config/open-api/open-api-document.ts +7 -0
  90. package/src/config/s3-config.ts +8 -0
  91. package/src/config/sns-config.ts +7 -0
  92. package/src/config/sqs-config.ts +7 -0
  93. package/src/epsilon-build-properties.ts +21 -0
  94. package/src/epsilon-constants.ts +62 -0
  95. package/src/epsilon-global-handler.ts +238 -0
  96. package/src/epsilon-instance.ts +20 -0
  97. package/src/epsilon-logging-extension-processor.ts +19 -0
  98. package/src/http/auth/api-gateway-adapter-authentication-handler.ts +95 -0
  99. package/src/http/auth/auth0-web-token-manipulator.ts +69 -0
  100. package/src/http/auth/basic-auth-token.ts +7 -0
  101. package/src/http/auth/google-web-token-manipulator.spec.ts +15 -0
  102. package/src/http/auth/google-web-token-manipulator.ts +80 -0
  103. package/src/http/auth/jwt-ratchet-local-web-token-manipulator.ts +37 -0
  104. package/src/http/auth/local-web-token-manipulator.spec.ts +34 -0
  105. package/src/http/auth/local-web-token-manipulator.ts +114 -0
  106. package/src/http/auth/web-token-manipulator.ts +9 -0
  107. package/src/http/error/bad-gateway.ts +11 -0
  108. package/src/http/error/bad-request-error.ts +11 -0
  109. package/src/http/error/conflict-error.ts +12 -0
  110. package/src/http/error/forbidden-error.ts +12 -0
  111. package/src/http/error/gateway-timeout.ts +12 -0
  112. package/src/http/error/method-not-allowed-error.ts +12 -0
  113. package/src/http/error/misconfigured-error.ts +12 -0
  114. package/src/http/error/not-found-error.ts +12 -0
  115. package/src/http/error/not-implemented.ts +12 -0
  116. package/src/http/error/request-timeout-error.ts +12 -0
  117. package/src/http/error/service-unavailable.ts +12 -0
  118. package/src/http/error/too-many-requests-error.ts +12 -0
  119. package/src/http/error/unauthorized-error.ts +12 -0
  120. package/src/http/event-util.spec.ts +190 -0
  121. package/src/http/event-util.ts +272 -0
  122. package/src/http/response-util.spec.ts +117 -0
  123. package/src/http/response-util.ts +164 -0
  124. package/src/http/route/epsilon-router.ts +9 -0
  125. package/src/http/route/extended-auth-response-context.ts +7 -0
  126. package/src/http/route/route-and-parse.ts +8 -0
  127. package/src/http/route/route-mapping.ts +21 -0
  128. package/src/http/route/route-validator-config.ts +5 -0
  129. package/src/http/route/router-util.spec.ts +33 -0
  130. package/src/http/route/router-util.ts +314 -0
  131. package/src/http/web-handler.spec.ts +99 -0
  132. package/src/http/web-handler.ts +157 -0
  133. package/src/http/web-v2-handler.ts +34 -0
  134. package/src/inter-api/inter-api-entry.ts +8 -0
  135. package/src/inter-api/inter-api-util.spec.ts +77 -0
  136. package/src/inter-api/inter-api-util.ts +71 -0
  137. package/src/inter-api-manager.ts +75 -0
  138. package/src/lambda-event-handler/cron-epsilon-lambda-event-handler.spec.ts +130 -0
  139. package/src/lambda-event-handler/cron-epsilon-lambda-event-handler.ts +132 -0
  140. package/src/lambda-event-handler/dynamo-epsilon-lambda-event-handler.ts +42 -0
  141. package/src/lambda-event-handler/generic-sns-epsilon-lambda-event-handler.ts +38 -0
  142. package/src/lambda-event-handler/generic-sqs-epsilon-lambda-event-handler.ts +43 -0
  143. package/src/lambda-event-handler/inter-api-epsilon-lambda-event-handler.ts +33 -0
  144. package/src/lambda-event-handler/s3-epsilon-lambda-event-handler.ts +50 -0
  145. package/src/local-container-server.ts +128 -0
  146. package/src/local-server.spec.ts +16 -0
  147. package/src/local-server.ts +426 -0
  148. package/src/open-api-util/open-api-doc-modifications.ts +9 -0
  149. package/src/open-api-util/open-api-doc-modifier.spec.ts +22 -0
  150. package/src/open-api-util/open-api-doc-modifier.ts +90 -0
  151. package/src/open-api-util/yaml-combiner.spec.ts +26 -0
  152. package/src/open-api-util/yaml-combiner.ts +35 -0
  153. package/src/sample/sample-server-components-with-apollo.ts +87 -0
  154. package/src/sample/sample-server-components.ts +183 -0
  155. package/src/sample/sample-server-static-files.ts +614 -0
  156. package/src/sample/test-error-server.ts +140 -0
  157. package/src/util/aws-util.ts +89 -0
  158. package/src/util/context-global-data.ts +13 -0
  159. package/src/util/context-util.ts +156 -0
  160. package/src/util/cron-util.spec.ts +190 -0
  161. package/src/util/cron-util.ts +86 -0
  162. package/src/util/epsilon-config-parser.ts +90 -0
  163. package/src/util/epsilon-server-util.spec.ts +18 -0
  164. package/src/util/epsilon-server-util.ts +16 -0
@@ -0,0 +1,80 @@
1
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
2
+ import jwt from 'jsonwebtoken';
3
+ import jwks from 'jwks-rsa';
4
+ import { WebTokenManipulator } from './web-token-manipulator.js';
5
+ import fetch from 'cross-fetch';
6
+ import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet';
7
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
8
+
9
+ export class GoogleWebTokenManipulator implements WebTokenManipulator<JwtTokenBase> {
10
+ private static readonly GOOGLE_DISCOVERY_DOCUMENT: string = 'https://accounts.google.com/.well-known/openid-configuration';
11
+ private cacheGoogleDiscoveryDocument: any;
12
+ private jwksClient: any;
13
+
14
+ constructor(private clientId: string) {}
15
+
16
+ public async extractTokenFromAuthorizationHeader(authHeader: string): Promise<JwtTokenBase> {
17
+ let tokenString: string = StringRatchet.trimToEmpty(authHeader);
18
+ if (tokenString.toLowerCase().startsWith('bearer ')) {
19
+ tokenString = tokenString.substring(7);
20
+ }
21
+ const validated: JwtTokenBase = tokenString ? await this.parseAndValidateGoogleToken(tokenString, false) : null;
22
+ return validated;
23
+ }
24
+
25
+ public async parseAndValidateGoogleToken(googleToken: string, allowExpired: boolean = false): Promise<JwtTokenBase> {
26
+ Logger.debug('Auth : %s', StringRatchet.obscure(googleToken, 4));
27
+
28
+ // First decode so we can get the keys
29
+ const fullToken: any = jwt.decode(googleToken, { complete: true });
30
+ const kid: string = fullToken.header.kid;
31
+ const nowEpochSeconds: number = Math.floor(new Date().getTime() / 1000);
32
+
33
+ const pubKey: string = await this.fetchSigningKey(kid);
34
+ const validated: any = jwt.verify(googleToken, pubKey, {
35
+ audience: this.clientId,
36
+ issuer: ['https://accounts.google.com', 'accounts.google.com'],
37
+ ignoreExpiration: allowExpired,
38
+ clockTimestamp: nowEpochSeconds,
39
+ });
40
+
41
+ return validated;
42
+ }
43
+
44
+ private async fetchSigningKey(kid: string): Promise<string> {
45
+ const jClient: any = await this.fetchJwksClient();
46
+
47
+ return new Promise<string>((res, rej) => {
48
+ jClient.getSigningKey(kid, (err, key) => {
49
+ if (err) {
50
+ rej(err);
51
+ } else {
52
+ res(key.publicKey || key.rsaPublicKey);
53
+ }
54
+ });
55
+ });
56
+ }
57
+
58
+ private async fetchJwksClient(): Promise<any> {
59
+ if (!this.jwksClient) {
60
+ const discDoc: any = await this.fetchGoogleDiscoveryDocument();
61
+ const client: any = jwks({
62
+ cache: true,
63
+ cacheMaxEntries: 5,
64
+ cacheMaxAge: 1000 * 60 * 60 * 10,
65
+ jwksUri: discDoc.jwks_uri,
66
+ });
67
+ this.jwksClient = client;
68
+ }
69
+ return this.jwksClient;
70
+ }
71
+
72
+ private async fetchGoogleDiscoveryDocument(): Promise<any> {
73
+ if (!this.cacheGoogleDiscoveryDocument) {
74
+ const resp: Response = await fetch(GoogleWebTokenManipulator.GOOGLE_DISCOVERY_DOCUMENT);
75
+ const doc: any = await resp.json();
76
+ this.cacheGoogleDiscoveryDocument = doc;
77
+ }
78
+ return this.cacheGoogleDiscoveryDocument;
79
+ }
80
+ }
@@ -0,0 +1,37 @@
1
+ import { WebTokenManipulator } from './web-token-manipulator.js';
2
+
3
+ import { RequireRatchet } from '@bitblit/ratchet-common/lang/require-ratchet';
4
+ import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet';
5
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
6
+ import { JwtRatchetLike } from '@bitblit/ratchet-node-only/jwt/jwt-ratchet-like';
7
+ import { ExpiredJwtHandling } from '@bitblit/ratchet-common/jwt/expired-jwt-handling';
8
+
9
+ /**
10
+ * Service for handling jwt tokens
11
+ */
12
+ export class JwtRatchetLocalWebTokenManipulator<T extends JwtTokenBase> implements WebTokenManipulator<T> {
13
+ constructor(
14
+ private _jwtRatchet: JwtRatchetLike,
15
+ private _issuer: string,
16
+ ) {
17
+ RequireRatchet.notNullOrUndefined(_jwtRatchet, '_jwtRatchet');
18
+ RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(_issuer), '_issuer');
19
+ }
20
+
21
+ public get jwtRatchet(): JwtRatchetLike {
22
+ return this._jwtRatchet;
23
+ }
24
+
25
+ public get issuer(): string {
26
+ return this._issuer;
27
+ }
28
+
29
+ public async extractTokenFromAuthorizationHeader<T>(header: string): Promise<T> {
30
+ let tokenString: string = StringRatchet.trimToEmpty(header);
31
+ if (tokenString.toLowerCase().startsWith('bearer ')) {
32
+ tokenString = tokenString.substring(7);
33
+ }
34
+ const validated: T = tokenString ? await this.jwtRatchet.decodeToken(tokenString, ExpiredJwtHandling.THROW_EXCEPTION) : null;
35
+ return validated;
36
+ }
37
+ }
@@ -0,0 +1,34 @@
1
+ import { LocalWebTokenManipulator } from './local-web-token-manipulator.js';
2
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
3
+ import { LoggerLevelName } from '@bitblit/ratchet-common/logger/logger-level-name';
4
+ import { CommonJwtToken } from '@bitblit/ratchet-common/jwt/common-jwt-token';
5
+ import { describe, expect, test } from 'vitest';
6
+
7
+ describe('#localWebTokenManipulator', function () {
8
+ test('should round trip a JWT token', async () => {
9
+ const svc: LocalWebTokenManipulator<CommonJwtToken<any>> = new LocalWebTokenManipulator(['1234567890'], 'test')
10
+ .withParseFailureLogLevel(LoggerLevelName.info)
11
+ .withExtraDecryptionKeys(['abcdefabcdef'])
12
+ .withOldKeyUseLogLevel(LoggerLevelName.info);
13
+
14
+ const testUser: any = {
15
+ data1: 'test',
16
+ data2: 15,
17
+ };
18
+
19
+ const token: string = await svc.createJWTStringAsync('test123@test.com', testUser);
20
+
21
+ Logger.info('Generated token : %s', token);
22
+
23
+ expect(token).toBeTruthy();
24
+
25
+ const outputUser: CommonJwtToken<any> = await svc.parseAndValidateJWTStringAsync(token);
26
+
27
+ Logger.info('Got result : %j', outputUser);
28
+
29
+ expect(outputUser).toBeTruthy();
30
+ expect(outputUser.user).toBeTruthy();
31
+ expect(outputUser.user['data1']).toEqual(testUser.data1);
32
+ expect(outputUser.user['data2']).toEqual(testUser.data2);
33
+ });
34
+ });
@@ -0,0 +1,114 @@
1
+ import { WebTokenManipulator } from './web-token-manipulator.js';
2
+ import { UnauthorizedError } from '../error/unauthorized-error.js';
3
+
4
+ import { RequireRatchet } from '@bitblit/ratchet-common/lang/require-ratchet';
5
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
6
+ import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet';
7
+ import { LoggerLevelName } from '@bitblit/ratchet-common/logger/logger-level-name';
8
+ import { CommonJwtToken } from '@bitblit/ratchet-common/jwt/common-jwt-token';
9
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
10
+ import { ExpiredJwtHandling } from '@bitblit/ratchet-common/jwt/expired-jwt-handling';
11
+ import { JwtRatchet } from '@bitblit/ratchet-node-only/jwt/jwt-ratchet';
12
+ import { JwtRatchetConfig } from '@bitblit/ratchet-node-only/jwt/jwt-ratchet-config';
13
+
14
+ /**
15
+ * Service for handling jwt tokens
16
+ */
17
+ export class LocalWebTokenManipulator<T extends JwtTokenBase> implements WebTokenManipulator<T> {
18
+ private _ratchet: JwtRatchet;
19
+
20
+ constructor(
21
+ private encryptionKeys: string[],
22
+ private issuer: string,
23
+ ) {
24
+ RequireRatchet.notNullOrUndefined(encryptionKeys, 'encryptionKeys');
25
+ RequireRatchet.noNullOrUndefinedValuesInArray(encryptionKeys, encryptionKeys.length);
26
+ const cfg: JwtRatchetConfig = {
27
+ encryptionKeyPromise: Promise.resolve(encryptionKeys),
28
+ };
29
+
30
+ this._ratchet = new JwtRatchet(cfg);
31
+ }
32
+
33
+ public withExtraDecryptionKeys(keys: string[]): LocalWebTokenManipulator<T> {
34
+ RequireRatchet.notNullOrUndefined(keys, 'keys');
35
+ RequireRatchet.noNullOrUndefinedValuesInArray(keys, keys.length);
36
+
37
+ const cfg: JwtRatchetConfig = this._ratchet.copyConfig;
38
+ cfg.decryptKeysPromise = Promise.resolve(keys);
39
+
40
+ this._ratchet = new JwtRatchet(cfg);
41
+ return this;
42
+ }
43
+
44
+ public withParseFailureLogLevel(logLevel: LoggerLevelName): LocalWebTokenManipulator<T> {
45
+ const cfg: JwtRatchetConfig = this._ratchet.copyConfig;
46
+ cfg.parseFailureLogLevel = logLevel;
47
+ this._ratchet = new JwtRatchet(cfg);
48
+ return this;
49
+ }
50
+
51
+ public withOldKeyUseLogLevel(logLevel: LoggerLevelName): LocalWebTokenManipulator<T> {
52
+ const cfg: JwtRatchetConfig = this._ratchet.copyConfig;
53
+ cfg.decryptOnlyKeyUseLogLevel = logLevel;
54
+ this._ratchet = new JwtRatchet(cfg);
55
+ return this;
56
+ }
57
+
58
+ public get jwtRatchet(): JwtRatchet {
59
+ return this._ratchet;
60
+ }
61
+
62
+ public get selectRandomEncryptionKey(): Promise<string> {
63
+ return this._ratchet.selectRandomEncryptionKey();
64
+ }
65
+
66
+ public createRefreshedJWTString(tokenString: string, expirationSeconds: number, allowExpired?: boolean): Promise<string> {
67
+ return this._ratchet.refreshJWTString(tokenString, allowExpired || false, expirationSeconds);
68
+ }
69
+
70
+ public async parseAndValidateJWTStringAsync<T extends JwtTokenBase>(tokenString: string): Promise<T> {
71
+ const payload: T = await this._ratchet.decodeToken(tokenString, ExpiredJwtHandling.ADD_FLAG);
72
+
73
+ if (JwtRatchet.hasExpiredFlag(payload)) {
74
+ throw new UnauthorizedError('Failing JWT token read/validate - token expired on ' + payload.exp);
75
+ } else {
76
+ return payload;
77
+ }
78
+ }
79
+
80
+ public async createJWTStringAsync<T>(
81
+ principal: string,
82
+ userObject: T,
83
+ roles: string[] = ['USER'],
84
+ expirationSeconds: number = 3600,
85
+ proxyUser: T = null,
86
+ ): Promise<string> {
87
+ Logger.info('Creating JWT token for %s that expires in %s', principal, expirationSeconds);
88
+ const now = new Date().getTime();
89
+ const expires = now + expirationSeconds * 1000;
90
+
91
+ // Build token data and add claims
92
+ const tokenData: CommonJwtToken<T> = {
93
+ exp: expires,
94
+ iss: this.issuer,
95
+ sub: principal,
96
+ iat: now,
97
+
98
+ user: userObject,
99
+ proxy: proxyUser,
100
+ };
101
+
102
+ const token: string = await this._ratchet.createTokenString(tokenData, expirationSeconds);
103
+ return token;
104
+ }
105
+
106
+ public async extractTokenFromAuthorizationHeader<T extends JwtTokenBase>(header: string): Promise<T> {
107
+ let tokenString: string = StringRatchet.trimToEmpty(header);
108
+ if (tokenString.toLowerCase().startsWith('bearer ')) {
109
+ tokenString = tokenString.substring(7);
110
+ }
111
+ const validated: T = tokenString ? await this.parseAndValidateJWTStringAsync(tokenString) : null;
112
+ return validated;
113
+ }
114
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Service for handling auth tokens
3
+ */
4
+
5
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
6
+
7
+ export interface WebTokenManipulator<T extends JwtTokenBase> {
8
+ extractTokenFromAuthorizationHeader(header: string): Promise<T>;
9
+ }
@@ -0,0 +1,11 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class BadGateway<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 502;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, BadGateway.prototype);
9
+ this.withHttpStatusCode(BadGateway.HTTP_CODE);
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class BadRequestError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 400;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, BadRequestError.prototype);
9
+ this.withHttpStatusCode(BadRequestError.HTTP_CODE);
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class ConflictError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 409;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, ConflictError.prototype);
9
+
10
+ this.withHttpStatusCode(ConflictError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class ForbiddenError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 403;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, ForbiddenError.prototype);
9
+
10
+ this.withHttpStatusCode(ForbiddenError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class GatewayTimeout<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 504;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, GatewayTimeout.prototype);
9
+
10
+ this.withHttpStatusCode(GatewayTimeout.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class MethodNotAllowedError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 405;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, MethodNotAllowedError.prototype);
9
+
10
+ this.withHttpStatusCode(MethodNotAllowedError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class MisconfiguredError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 500;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, MisconfiguredError.prototype);
9
+
10
+ this.withHttpStatusCode(MisconfiguredError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class NotFoundError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 404;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, NotFoundError.prototype);
9
+
10
+ this.withHttpStatusCode(NotFoundError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class NotImplemented<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 501;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, NotImplemented.prototype);
9
+
10
+ this.withHttpStatusCode(NotImplemented.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class RequestTimeoutError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 500;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, RequestTimeoutError.prototype);
9
+
10
+ this.withHttpStatusCode(RequestTimeoutError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class ServiceUnavailable<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 503;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, ServiceUnavailable.prototype);
9
+
10
+ this.withHttpStatusCode(ServiceUnavailable.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class TooManyRequestsError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 429;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, TooManyRequestsError.prototype);
9
+
10
+ this.withHttpStatusCode(TooManyRequestsError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
2
+
3
+ export class UnauthorizedError<T = void> extends RestfulApiHttpError<T> {
4
+ public static readonly HTTP_CODE: number = 401;
5
+
6
+ constructor(...errors: string[]) {
7
+ super(...errors);
8
+ Object.setPrototypeOf(this, UnauthorizedError.prototype);
9
+
10
+ this.withHttpStatusCode(UnauthorizedError.HTTP_CODE);
11
+ }
12
+ }
@@ -0,0 +1,190 @@
1
+ import { APIGatewayEvent, APIGatewayEventRequestContext } from 'aws-lambda';
2
+ import { EventUtil } from './event-util.js';
3
+ import { BasicAuthToken } from './auth/basic-auth-token.js';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { EsmRatchet } from '@bitblit/ratchet-common/lang/esm-ratchet';
7
+ import { describe, expect, test } from 'vitest';
8
+
9
+ describe('#eventUtil', function () {
10
+ test('should extract pieces', function () {
11
+ const evt: APIGatewayEvent = {
12
+ httpMethod: 'GET',
13
+ path: '/cw/meta/server',
14
+ body: null,
15
+ headers: {
16
+ Host: 'api.test.com',
17
+ 'X-Forwarded-Proto': 'https',
18
+ },
19
+ multiValueHeaders: {
20
+ Host: ['api.test.com'],
21
+ 'X-Forwarded-Proto': ['https'],
22
+ },
23
+ multiValueQueryStringParameters: null,
24
+ isBase64Encoded: false,
25
+ pathParameters: null,
26
+ queryStringParameters: null,
27
+ stageVariables: null,
28
+ resource: '/{proxy+}',
29
+ requestContext: {
30
+ httpMethod: 'GET',
31
+ accountId: '1234',
32
+ apiId: '7890',
33
+ stage: 'v0',
34
+ path: '/cw/meta/server',
35
+ domainName: 'api.test.com',
36
+ identity: null,
37
+ requestId: 'asdf1234',
38
+ requestTimeEpoch: 1234,
39
+ resourceId: '1234',
40
+ resourcePath: '/{proxy+}',
41
+ } as APIGatewayEventRequestContext,
42
+ } as APIGatewayEvent;
43
+
44
+ expect(EventUtil.extractStage(evt)).toEqual('cw');
45
+ expect(EventUtil.extractApiGatewayStage(evt)).toEqual('v0');
46
+ expect(EventUtil.extractFullPrefix(evt)).toEqual('https://api.test.com/cw');
47
+ expect(EventUtil.extractFullPath(evt)).toEqual('https://api.test.com/cw/meta/server');
48
+ expect(EventUtil.extractHostHeader(evt)).toEqual('api.test.com');
49
+ });
50
+
51
+ test('should fix still encoded query params', function () {
52
+ const evt: APIGatewayEvent = {
53
+ httpMethod: 'GET',
54
+ path: '/cw/meta/server',
55
+ body: null,
56
+ headers: {
57
+ Host: 'api.test.com',
58
+ 'X-Forwarded-Proto': 'https',
59
+ },
60
+ multiValueHeaders: {
61
+ Host: ['api.test.com'],
62
+ 'X-Forwarded-Proto': ['https'],
63
+ },
64
+ isBase64Encoded: false,
65
+ pathParameters: null,
66
+ multiValueQueryStringParameters: {
67
+ a: ['b'],
68
+ 'amp;c': ['d'],
69
+ },
70
+ queryStringParameters: {
71
+ a: 'b',
72
+ 'amp;c': 'd',
73
+ },
74
+ stageVariables: null,
75
+ resource: '/{proxy+}',
76
+ requestContext: {
77
+ httpMethod: 'GET',
78
+ accountId: '1234',
79
+ apiId: '7890',
80
+ stage: 'v0',
81
+ path: '/cw/meta/server',
82
+ domainName: 'api.test.com',
83
+ identity: null,
84
+ requestId: 'asdf1234',
85
+ requestTimeEpoch: 1234,
86
+ resourceId: '1234',
87
+ resourcePath: '/{proxy+}',
88
+ } as APIGatewayEventRequestContext,
89
+ } as APIGatewayEvent;
90
+
91
+ expect(evt.queryStringParameters['a']).toBeTruthy();
92
+ expect(evt.queryStringParameters['amp;c']).toBeTruthy();
93
+ expect(evt.queryStringParameters['c']).toBeUndefined();
94
+
95
+ EventUtil.fixStillEncodedQueryParams(evt);
96
+
97
+ expect(evt.queryStringParameters['a']).toBeTruthy();
98
+ expect(evt.queryStringParameters['amp;c']).toBeUndefined();
99
+ expect(evt.queryStringParameters['c']).toBeTruthy();
100
+ });
101
+
102
+ test('should extract basic auth from headers', function () {
103
+ const evt: APIGatewayEvent = {
104
+ httpMethod: 'GET',
105
+ path: '/cw/meta/server',
106
+ body: null,
107
+ headers: {
108
+ Host: 'api.test.com',
109
+ 'X-Forwarded-Proto': 'https',
110
+ Authorization: 'Basic dGVzdHVzZXI6dGVzdHBhc3M=',
111
+ },
112
+ multiValueHeaders: {
113
+ Host: ['api.test.com'],
114
+ 'X-Forwarded-Proto': ['https'],
115
+ Authorization: ['Basic dGVzdHVzZXI6dGVzdHBhc3M='],
116
+ },
117
+ isBase64Encoded: false,
118
+ pathParameters: null,
119
+ multiValueQueryStringParameters: {
120
+ a: ['b'],
121
+ 'amp;c': ['d'],
122
+ },
123
+ queryStringParameters: {
124
+ a: 'b',
125
+ 'amp;c': 'd',
126
+ },
127
+ stageVariables: null,
128
+ resource: '/{proxy+}',
129
+ requestContext: {
130
+ httpMethod: 'GET',
131
+ accountId: '1234',
132
+ apiId: '7890',
133
+ stage: 'v0',
134
+ path: '/cw/meta/server',
135
+ domainName: 'api.test.com',
136
+ identity: null,
137
+ requestId: 'asdf1234',
138
+ requestTimeEpoch: 1234,
139
+ resourceId: '1234',
140
+ resourcePath: '/{proxy+}',
141
+ } as APIGatewayEventRequestContext,
142
+ } as APIGatewayEvent;
143
+
144
+ const basic: BasicAuthToken = EventUtil.extractBasicAuthenticationToken(evt);
145
+ expect(basic).toBeTruthy();
146
+ expect(basic.username).toBeTruthy();
147
+ expect(basic.password).toBeTruthy();
148
+ expect(basic.username).toEqual('testuser');
149
+ expect(basic.password).toEqual('testpass');
150
+ });
151
+
152
+ test('should add a token to an event, along with downstream stuff', function () {
153
+ const evt: APIGatewayEvent = JSON.parse(
154
+ fs
155
+ .readFileSync(
156
+ path.join(EsmRatchet.fetchDirName(import.meta.url), '../../../../test-data/epsilon/sample-json/sample-request-1.json'),
157
+ )
158
+ .toString(),
159
+ );
160
+ const jwtToken: string =
161
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODg1MzY3NzU4ODcsImlzcyI6Im5lb24uYWRvbW5pLmNvbSIsInN1YiI6ImJpdGJsaXRAZ21haWwuY29tIiwiaWF0IjoxNTg4NTMzMTc1ODg3LCJ1c2VyIjp7ImlkIjo2LCJmaXJzdE5hbWUiOiJDaHJpcyIsImxhc3ROYW1lIjoiV2Vpc3MiLCJjb21wYW55IjoiQWRvbW5pIiwiZW1haWwiOiJiaXRibGl0QGdtYWlsLmNvbSIsImN1c3RvbWVyVHlwZSI6IkFETUlOIn0sImFjdGluZ1VzZXJJZCI6NiwiZ2xvYmFsIjp0cnVlLCJhZG1pbiI6eyJpZCI6NiwiZmlyc3ROYW1lIjoiQ2hyaXMiLCJsYXN0TmFtZSI6IldlaXNzIiwiY29tcGFueSI6IkFkb21uaSIsImVtYWlsIjoiYml0YmxpdEBnbWFpbC5jb20iLCJjdXN0b21lclR5cGUiOiJBRE1JTiJ9LCJzdWJVc2VycyI6W119.mwRSek5GwkvxpN44UTp49W6_9U_ARsFXThAyiqaF-eQ';
162
+ EventUtil.applyTokenToEventForTesting(evt, jwtToken);
163
+
164
+ const roundTripTokenString: string = EventUtil.extractBearerTokenFromEvent(evt);
165
+ expect(roundTripTokenString).toEqual(jwtToken);
166
+ });
167
+
168
+ test('should check if an event is a graphql introspection', function () {
169
+ const evt1: APIGatewayEvent = JSON.parse(
170
+ fs
171
+ .readFileSync(
172
+ path.join(EsmRatchet.fetchDirName(import.meta.url), '../../../../test-data/epsilon/sample-json/sample-request-1.json'),
173
+ )
174
+ .toString(),
175
+ );
176
+ const evt2: APIGatewayEvent = JSON.parse(
177
+ fs
178
+ .readFileSync(
179
+ path.join(EsmRatchet.fetchDirName(import.meta.url), '../../../../test-data/epsilon/sample-json/sample-gql-introspection.json'),
180
+ )
181
+ .toString(),
182
+ );
183
+
184
+ const res1: boolean = EventUtil.eventIsAGraphQLIntrospection(evt1);
185
+ const res2: boolean = EventUtil.eventIsAGraphQLIntrospection(evt2);
186
+
187
+ expect(res1).toBeFalsy();
188
+ expect(res2).toBeTruthy();
189
+ });
190
+ });