@graphql-mesh/hmac-upstream-signature 1.2.7-alpha-20241114122631-5a3a4345bb55e05e6bd057ae38f412d5d33315fd → 1.2.7-alpha-54b3273d0d9033d32f549a6b937921426c35b08b

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md ADDED
@@ -0,0 +1,354 @@
1
+ # @graphql-mesh/hmac-upstream-signature
2
+
3
+ ## 1.2.7-alpha-54b3273d0d9033d32f549a6b937921426c35b08b
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`16fa46b`](https://github.com/graphql-hive/gateway/commit/16fa46b0e31d1fcbfee977fe02efa5e3eabdb150)]:
8
+ - @graphql-mesh/transport-common@0.7.14-alpha-54b3273d0d9033d32f549a6b937921426c35b08b
9
+
10
+ ## 1.2.6
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+ [[`eee53b9`](https://github.com/ardatan/graphql-mesh/commit/eee53b9f455653166c39bca627b3261fbefe4eb7)]:
16
+ - @graphql-mesh/utils@0.102.12
17
+ - @graphql-mesh/types@0.102.12
18
+ - @graphql-mesh/transport-common@0.7.13
19
+
20
+ ## 1.2.5
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies
25
+ [[`de41fc2`](https://github.com/ardatan/graphql-mesh/commit/de41fc2932433f8da35b9de9492720e6c8c100af),
26
+ [`de41fc2`](https://github.com/ardatan/graphql-mesh/commit/de41fc2932433f8da35b9de9492720e6c8c100af),
27
+ [`de41fc2`](https://github.com/ardatan/graphql-mesh/commit/de41fc2932433f8da35b9de9492720e6c8c100af)]:
28
+ - @graphql-mesh/transport-common@0.7.12
29
+ - @graphql-mesh/types@0.102.11
30
+ - @graphql-mesh/utils@0.102.11
31
+
32
+ ## 1.2.4
33
+
34
+ ## 1.2.3
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies
39
+ [[`997b81c`](https://github.com/ardatan/graphql-mesh/commit/997b81c8a5d28508057806b4f16eecc5b713cf71),
40
+ [`997b81c`](https://github.com/ardatan/graphql-mesh/commit/997b81c8a5d28508057806b4f16eecc5b713cf71),
41
+ [`997b81c`](https://github.com/ardatan/graphql-mesh/commit/997b81c8a5d28508057806b4f16eecc5b713cf71)]:
42
+ - @graphql-mesh/transport-common@0.7.11
43
+ - @graphql-mesh/types@0.102.10
44
+ - @graphql-mesh/utils@0.102.10
45
+
46
+ ## 1.2.2
47
+
48
+ ### Patch Changes
49
+
50
+ - Updated dependencies
51
+ [[`fad4d27`](https://github.com/ardatan/graphql-mesh/commit/fad4d27bfebb80a374c2041b86ffab509845effe)]:
52
+ - @graphql-mesh/utils@0.102.9
53
+ - @graphql-mesh/types@0.102.9
54
+ - @graphql-mesh/transport-common@0.7.10
55
+
56
+ ## 1.2.1
57
+
58
+ ## 1.2.0
59
+
60
+ ### Patch Changes
61
+
62
+ - Updated dependencies
63
+ [[`518c42c`](https://github.com/ardatan/graphql-mesh/commit/518c42c5a2bee00e224df95c2beb758a28d1323c),
64
+ [`518c42c`](https://github.com/ardatan/graphql-mesh/commit/518c42c5a2bee00e224df95c2beb758a28d1323c),
65
+ [`518c42c`](https://github.com/ardatan/graphql-mesh/commit/518c42c5a2bee00e224df95c2beb758a28d1323c)]:
66
+ - @graphql-mesh/transport-common@0.7.9
67
+ - @graphql-mesh/types@0.102.8
68
+ - @graphql-mesh/utils@0.102.8
69
+
70
+ ## 1.1.1
71
+
72
+ ### Patch Changes
73
+
74
+ - Updated dependencies
75
+ [[`50bf472`](https://github.com/ardatan/graphql-mesh/commit/50bf4723657d27dc196d80407bda40c93aa5c9be),
76
+ [`50bf472`](https://github.com/ardatan/graphql-mesh/commit/50bf4723657d27dc196d80407bda40c93aa5c9be),
77
+ [`50bf472`](https://github.com/ardatan/graphql-mesh/commit/50bf4723657d27dc196d80407bda40c93aa5c9be)]:
78
+ - @graphql-mesh/transport-common@0.7.8
79
+ - @graphql-mesh/types@0.102.7
80
+ - @graphql-mesh/utils@0.102.7
81
+
82
+ ## 1.1.0
83
+
84
+ ## 1.0.5
85
+
86
+ ### Patch Changes
87
+
88
+ - Updated dependencies
89
+ [[`bf588d3`](https://github.com/ardatan/graphql-mesh/commit/bf588d372c0078378aaa24beea2da794af7949e6)]:
90
+ - @graphql-mesh/utils@0.102.6
91
+ - @graphql-mesh/types@0.102.6
92
+ - @graphql-mesh/transport-common@0.7.7
93
+
94
+ ## 1.0.4
95
+
96
+ ## 1.0.3
97
+
98
+ ## 1.0.2
99
+
100
+ ## 1.0.1
101
+
102
+ ## 1.0.0
103
+
104
+ ## 0.4.4
105
+
106
+ ## 0.4.3
107
+
108
+ ## 0.4.2
109
+
110
+ ## 0.4.1
111
+
112
+ ## 0.4.0
113
+
114
+ ### Minor Changes
115
+
116
+ - [#7580](https://github.com/ardatan/graphql-mesh/pull/7580)
117
+ [`75e9f63`](https://github.com/ardatan/graphql-mesh/commit/75e9f63d09514a0af786f909dc8c32ac09a1a849)
118
+ Thanks [@ardatan](https://github.com/ardatan)! - BREAKING: All types prefixed with `MeshServe`,
119
+ now are prefixed with `Gateway`. e.g. `MeshServeRuntime` -> `GatewayRuntime`
120
+
121
+ Runtime factory is renamed; `createServeRuntime` -> `createGatewayRuntime`
122
+
123
+ The expected export name for config files are renamed from `serveConfig` to `gatewayConfig`
124
+
125
+ RENAMING:
126
+
127
+ You can rename the product, config file name etc by using the following config options;
128
+
129
+ For example;
130
+
131
+ ```ts
132
+ productName = 'Mesh Gateway';
133
+ productDescription =
134
+ 'Mesh Gateway is a GraphQL Gateway that can be used to serve a supergraph schema.';
135
+ productLogo = '<svg>...</svg>';
136
+ productPackageName = '@graphql-mesh/gateway';
137
+ ```
138
+
139
+ ### Patch Changes
140
+
141
+ - [#7594](https://github.com/ardatan/graphql-mesh/pull/7594)
142
+ [`9f01438`](https://github.com/ardatan/graphql-mesh/commit/9f01438fbdf327c0a4bfa0cf440d890ec871ffcc)
143
+ Thanks [@ardatan](https://github.com/ardatan)! - Adding these plugins to serve-runtime by default,
144
+ and make them configurable through the configuration;
145
+
146
+ - `useResponseCache`
147
+ - `useContentEncoding`
148
+ - `useDeferStream`
149
+ - `useExecutionCancellation`
150
+ - `useUpstreamCancellation`
151
+ - `useDisableIntrospection`
152
+ - `useCSRFPrevention`
153
+ - `useCustomAgent`
154
+ - `useGenericAuth`
155
+ - `useHMACUpstreamSignature`
156
+ - `useWebhooks`
157
+
158
+ In addition, the following ones are added to the serve-cli:
159
+
160
+ - `useJWT`
161
+ - `usePrometheus`
162
+ - `useOpenTelemetry`
163
+ - `useRateLimit`
164
+
165
+ - Updated dependencies
166
+ [[`3bf14b3`](https://github.com/ardatan/graphql-mesh/commit/3bf14b33ee621cce004a329928b8a04a68218016),
167
+ [`b7f6ebf`](https://github.com/ardatan/graphql-mesh/commit/b7f6ebfa077957c3a1ecad1fed449e972cb09ae0),
168
+ [`0a3e52c`](https://github.com/ardatan/graphql-mesh/commit/0a3e52c2ad2941e7c48f0e80706db41644797c2d)]:
169
+ - @graphql-mesh/utils@0.102.5
170
+ - @graphql-mesh/types@0.102.5
171
+ - @graphql-mesh/transport-common@0.7.6
172
+
173
+ ## 0.3.6
174
+
175
+ ### Patch Changes
176
+
177
+ - Updated dependencies
178
+ [[`5146df0`](https://github.com/ardatan/graphql-mesh/commit/5146df0fd3313227d5d7df2beb726ca89e13923f)]:
179
+ - @graphql-mesh/transport-common@0.7.5
180
+
181
+ ## 0.3.5
182
+
183
+ ### Patch Changes
184
+
185
+ - Updated dependencies
186
+ [[`edbc074`](https://github.com/ardatan/graphql-mesh/commit/edbc074523ebc86114bb3342f86b7bcd9268d005),
187
+ [`edbc074`](https://github.com/ardatan/graphql-mesh/commit/edbc074523ebc86114bb3342f86b7bcd9268d005),
188
+ [`edbc074`](https://github.com/ardatan/graphql-mesh/commit/edbc074523ebc86114bb3342f86b7bcd9268d005)]:
189
+ - @graphql-mesh/transport-common@0.7.4
190
+ - @graphql-mesh/types@0.102.4
191
+ - @graphql-mesh/utils@0.102.4
192
+
193
+ ## 0.3.4
194
+
195
+ ### Patch Changes
196
+
197
+ - Updated dependencies
198
+ [[`14ec31f`](https://github.com/ardatan/graphql-mesh/commit/14ec31f95bc06e9a3d06fae387fc40cc534e01f4),
199
+ [`14ec31f`](https://github.com/ardatan/graphql-mesh/commit/14ec31f95bc06e9a3d06fae387fc40cc534e01f4),
200
+ [`14ec31f`](https://github.com/ardatan/graphql-mesh/commit/14ec31f95bc06e9a3d06fae387fc40cc534e01f4)]:
201
+ - @graphql-mesh/transport-common@0.7.3
202
+ - @graphql-mesh/types@0.102.3
203
+ - @graphql-mesh/utils@0.102.3
204
+
205
+ ## 0.3.3
206
+
207
+ ## 0.3.2
208
+
209
+ ### Patch Changes
210
+
211
+ - Updated dependencies
212
+ [[`5d95aad`](https://github.com/ardatan/graphql-mesh/commit/5d95aad185448e8e3a004a08e364f98ee9bbee2a)]:
213
+ - @graphql-mesh/utils@0.102.2
214
+ - @graphql-mesh/types@0.102.2
215
+ - @graphql-mesh/transport-common@0.7.2
216
+
217
+ ## 0.3.1
218
+
219
+ ### Patch Changes
220
+
221
+ - Updated dependencies
222
+ [[`e49a7e6`](https://github.com/ardatan/graphql-mesh/commit/e49a7e69475b652a53a0f289a44247e8b7ea96de),
223
+ [`60bfc22`](https://github.com/ardatan/graphql-mesh/commit/60bfc2240108af0a599a66451517a146cace879d)]:
224
+ - @graphql-mesh/utils@0.102.1
225
+ - @graphql-mesh/transport-common@0.7.1
226
+ - @graphql-mesh/types@0.102.1
227
+
228
+ ## 0.3.0
229
+
230
+ ### Patch Changes
231
+
232
+ - Updated dependencies
233
+ [[`db41f96`](https://github.com/ardatan/graphql-mesh/commit/db41f96b392de95d5f3aff958df399bf58575373)]:
234
+ - @graphql-mesh/types@0.102.0
235
+ - @graphql-mesh/utils@0.102.0
236
+ - @graphql-mesh/transport-common@0.7.0
237
+
238
+ ## 0.2.3
239
+
240
+ ## 0.2.2
241
+
242
+ ### Patch Changes
243
+
244
+ - [#7518](https://github.com/ardatan/graphql-mesh/pull/7518)
245
+ [`b0cdc83`](https://github.com/ardatan/graphql-mesh/commit/b0cdc839699a1dd90d125289b49b75f703cbb18e)
246
+ Thanks [@enisdenjo](https://github.com/enisdenjo)! - dependencies updates:
247
+ - Updated dependency
248
+ [`@graphql-mesh/transport-common@^0.6.1` ↗︎](https://www.npmjs.com/package/@graphql-mesh/transport-common/v/0.6.1)
249
+ (from `^0.6.0`, in `dependencies`)
250
+
251
+ ## 0.2.1
252
+
253
+ ### Patch Changes
254
+
255
+ - Updated dependencies
256
+ [[`67e1062`](https://github.com/ardatan/graphql-mesh/commit/67e10629c70ec553234c1ffc99af4b89ddb31985)]:
257
+ - @graphql-mesh/transport-common@0.6.1
258
+
259
+ ## 0.2.0
260
+
261
+ ### Patch Changes
262
+
263
+ - Updated dependencies
264
+ [[`d784488`](https://github.com/ardatan/graphql-mesh/commit/d784488dcf04b3b0bf32f386baf8b48e1f20d27e),
265
+ [`190e9ec`](https://github.com/ardatan/graphql-mesh/commit/190e9ece9bc050a0564f3b5292ab5229e63d40a6),
266
+ [`d784488`](https://github.com/ardatan/graphql-mesh/commit/d784488dcf04b3b0bf32f386baf8b48e1f20d27e),
267
+ [`190e9ec`](https://github.com/ardatan/graphql-mesh/commit/190e9ece9bc050a0564f3b5292ab5229e63d40a6),
268
+ [`d784488`](https://github.com/ardatan/graphql-mesh/commit/d784488dcf04b3b0bf32f386baf8b48e1f20d27e),
269
+ [`190e9ec`](https://github.com/ardatan/graphql-mesh/commit/190e9ece9bc050a0564f3b5292ab5229e63d40a6),
270
+ [`d784488`](https://github.com/ardatan/graphql-mesh/commit/d784488dcf04b3b0bf32f386baf8b48e1f20d27e)]:
271
+ - @graphql-mesh/transport-common@0.6.0
272
+ - @graphql-mesh/types@0.101.0
273
+ - @graphql-mesh/utils@0.101.0
274
+
275
+ ## 0.1.0
276
+
277
+ ### Patch Changes
278
+
279
+ - Updated dependencies
280
+ [[`c06a048`](https://github.com/ardatan/graphql-mesh/commit/c06a0482e7431683f0b75fde3aebbb97aca00c4c),
281
+ [`c06a048`](https://github.com/ardatan/graphql-mesh/commit/c06a0482e7431683f0b75fde3aebbb97aca00c4c),
282
+ [`c06a048`](https://github.com/ardatan/graphql-mesh/commit/c06a0482e7431683f0b75fde3aebbb97aca00c4c),
283
+ [`a324c5e`](https://github.com/ardatan/graphql-mesh/commit/a324c5ef300c25dcfa265f3457453b50af0b83e7),
284
+ [`4d1eb28`](https://github.com/ardatan/graphql-mesh/commit/4d1eb285c2b703c5f80473ad0f316004306fac7f),
285
+ [`a324c5e`](https://github.com/ardatan/graphql-mesh/commit/a324c5ef300c25dcfa265f3457453b50af0b83e7)]:
286
+ - @graphql-mesh/transport-common@0.5.0
287
+ - @graphql-mesh/types@0.100.0
288
+ - @graphql-mesh/utils@0.100.0
289
+
290
+ ## 0.0.9
291
+
292
+ ### Patch Changes
293
+
294
+ - Updated dependencies
295
+ [[`a1bfc49`](https://github.com/ardatan/graphql-mesh/commit/a1bfc492ac3378f22b79a51824407e776b496a84)]:
296
+ - @graphql-mesh/types@0.99.7
297
+ - @graphql-mesh/utils@0.99.7
298
+ - @graphql-mesh/transport-common@0.4.7
299
+
300
+ ## 0.0.8
301
+
302
+ ### Patch Changes
303
+
304
+ - Updated dependencies
305
+ [[`6c67e77`](https://github.com/ardatan/graphql-mesh/commit/6c67e77d3c308615a733577293ecb6dd55793aeb),
306
+ [`6c67e77`](https://github.com/ardatan/graphql-mesh/commit/6c67e77d3c308615a733577293ecb6dd55793aeb),
307
+ [`6c67e77`](https://github.com/ardatan/graphql-mesh/commit/6c67e77d3c308615a733577293ecb6dd55793aeb),
308
+ [`6c67e77`](https://github.com/ardatan/graphql-mesh/commit/6c67e77d3c308615a733577293ecb6dd55793aeb),
309
+ [`6c67e77`](https://github.com/ardatan/graphql-mesh/commit/6c67e77d3c308615a733577293ecb6dd55793aeb)]:
310
+ - @graphql-mesh/transport-common@0.4.6
311
+ - @graphql-mesh/types@0.99.6
312
+ - @graphql-mesh/utils@0.99.6
313
+
314
+ ## 0.0.7
315
+
316
+ ## 0.0.6
317
+
318
+ ## 0.0.5
319
+
320
+ ## 0.0.4
321
+
322
+ ### Patch Changes
323
+
324
+ - Updated dependencies
325
+ [[`33c23e8`](https://github.com/ardatan/graphql-mesh/commit/33c23e83a60328df806a8adc8d262a0c6de7e5a4)]:
326
+ - @graphql-mesh/utils@0.99.5
327
+ - @graphql-mesh/types@0.99.5
328
+ - @graphql-mesh/transport-common@0.4.5
329
+
330
+ ## 0.0.3
331
+
332
+ ### Patch Changes
333
+
334
+ - Updated dependencies
335
+ [[`597e790`](https://github.com/ardatan/graphql-mesh/commit/597e7905e542be06e7f576d8ffde3f94d7b0630b),
336
+ [`597e790`](https://github.com/ardatan/graphql-mesh/commit/597e7905e542be06e7f576d8ffde3f94d7b0630b)]:
337
+ - @graphql-mesh/utils@0.99.4
338
+ - @graphql-mesh/types@0.99.4
339
+ - @graphql-mesh/transport-common@0.4.4
340
+
341
+ ## 0.0.2
342
+
343
+ ### Patch Changes
344
+
345
+ - [#7318](https://github.com/ardatan/graphql-mesh/pull/7318)
346
+ [`f2af8a3`](https://github.com/ardatan/graphql-mesh/commit/f2af8a3ca005c2173b74f2b6e3aa9cf48e38b153)
347
+ Thanks [@dotansimha](https://github.com/dotansimha)! - Initial commit and introduce a new plugin.
348
+
349
+ - Updated dependencies
350
+ [[`5e5dec5`](https://github.com/ardatan/graphql-mesh/commit/5e5dec51b571df8d23a4379f61fd7fbd7a3df58e),
351
+ [`5e5dec5`](https://github.com/ardatan/graphql-mesh/commit/5e5dec51b571df8d23a4379f61fd7fbd7a3df58e)]:
352
+ - @graphql-mesh/utils@0.99.3
353
+ - @graphql-mesh/types@0.99.3
354
+ - @graphql-mesh/transport-common@0.4.3
package/dist/index.cjs ADDED
@@ -0,0 +1,161 @@
1
+ 'use strict';
2
+
3
+ var transportCommon = require('@graphql-mesh/transport-common');
4
+ var utils = require('@graphql-mesh/utils');
5
+ var jsonStableStringify = require('json-stable-stringify');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var jsonStableStringify__default = /*#__PURE__*/_interopDefault(jsonStableStringify);
10
+
11
+ const DEFAULT_EXTENSION_NAME = "hmac-signature";
12
+ const DEFAULT_SHOULD_SIGN_FN = () => true;
13
+ const defaultExecutionRequestSerializer = (executionRequest) => jsonStableStringify__default.default({
14
+ query: transportCommon.defaultPrintFn(executionRequest.document),
15
+ variables: executionRequest.variables
16
+ });
17
+ const defaultParamsSerializer = (params) => jsonStableStringify__default.default({
18
+ query: params.query,
19
+ variables: params.variables
20
+ });
21
+ function createCryptoKey({
22
+ textEncoder,
23
+ crypto,
24
+ secret,
25
+ usages
26
+ }) {
27
+ return crypto.subtle.importKey(
28
+ "raw",
29
+ textEncoder.encode(secret),
30
+ { name: "HMAC", hash: "SHA-256" },
31
+ false,
32
+ usages
33
+ );
34
+ }
35
+ function useHmacUpstreamSignature(options) {
36
+ if (!options.secret) {
37
+ throw new Error(
38
+ 'Property "secret" is required for useHmacUpstreamSignature plugin'
39
+ );
40
+ }
41
+ const shouldSign = options.shouldSign || DEFAULT_SHOULD_SIGN_FN;
42
+ const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
43
+ const serializeExecutionRequest = options.serializeExecutionRequest || defaultExecutionRequestSerializer;
44
+ let key$;
45
+ let fetchAPI;
46
+ let textEncoder;
47
+ return {
48
+ onYogaInit({ yoga }) {
49
+ fetchAPI = yoga.fetchAPI;
50
+ },
51
+ onSubgraphExecute({
52
+ subgraphName,
53
+ subgraph,
54
+ executionRequest,
55
+ setExecutionRequest,
56
+ logger
57
+ }) {
58
+ logger?.debug(`running shouldSign for subgraph ${subgraphName}`);
59
+ if (shouldSign({ subgraphName, subgraph, executionRequest })) {
60
+ logger?.debug(
61
+ `shouldSign is true for subgraph ${subgraphName}, signing request`
62
+ );
63
+ textEncoder ||= new fetchAPI.TextEncoder();
64
+ key$ ||= createCryptoKey({
65
+ textEncoder,
66
+ crypto: fetchAPI.crypto,
67
+ secret: options.secret,
68
+ usages: ["sign"]
69
+ });
70
+ return utils.mapMaybePromise(key$, async (key) => {
71
+ key$ = key;
72
+ const serializedExecutionRequest = serializeExecutionRequest(executionRequest);
73
+ const encodedContent = textEncoder.encode(serializedExecutionRequest);
74
+ const signature = await fetchAPI.crypto.subtle.sign(
75
+ "HMAC",
76
+ key,
77
+ encodedContent
78
+ );
79
+ const extensionValue = btoa(
80
+ String.fromCharCode(...new Uint8Array(signature))
81
+ );
82
+ logger?.debug(
83
+ `produced hmac signature for subgraph ${subgraphName}, signature: ${signature}, signed payload: ${serializedExecutionRequest}`
84
+ );
85
+ setExecutionRequest({
86
+ ...executionRequest,
87
+ extensions: {
88
+ ...executionRequest.extensions,
89
+ [extensionName]: extensionValue
90
+ }
91
+ });
92
+ });
93
+ } else {
94
+ logger?.debug(
95
+ `shouldSign is false for subgraph ${subgraphName}, skipping hmac signature`
96
+ );
97
+ }
98
+ }
99
+ };
100
+ }
101
+ function useHmacSignatureValidation(options) {
102
+ if (!options.secret) {
103
+ throw new Error(
104
+ 'Property "secret" is required for useHmacSignatureValidation plugin'
105
+ );
106
+ }
107
+ const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
108
+ let key$;
109
+ let textEncoder;
110
+ let logger;
111
+ const paramsSerializer = options.serializeParams || defaultParamsSerializer;
112
+ return {
113
+ onYogaInit({ yoga }) {
114
+ logger = yoga.logger;
115
+ },
116
+ onParams({ params, fetchAPI }) {
117
+ textEncoder ||= new fetchAPI.TextEncoder();
118
+ const extension = params.extensions?.[extensionName];
119
+ if (!extension) {
120
+ logger.warn(
121
+ `Missing HMAC signature: extension ${extensionName} not found in request.`
122
+ );
123
+ throw new Error(
124
+ `Missing HMAC signature: extension ${extensionName} not found in request.`
125
+ );
126
+ }
127
+ key$ ||= createCryptoKey({
128
+ textEncoder,
129
+ crypto: fetchAPI.crypto,
130
+ secret: options.secret,
131
+ usages: ["verify"]
132
+ });
133
+ return key$.then(async (key) => {
134
+ const sigBuf = Uint8Array.from(atob(extension), (c) => c.charCodeAt(0));
135
+ const serializedParams = paramsSerializer(params);
136
+ logger.debug(
137
+ `HMAC signature will be calculate based on serialized params: ${serializedParams}`
138
+ );
139
+ const result = await fetchAPI.crypto.subtle.verify(
140
+ "HMAC",
141
+ key,
142
+ sigBuf,
143
+ textEncoder.encode(serializedParams)
144
+ );
145
+ if (!result) {
146
+ logger.error(
147
+ `HMAC signature does not match the body content. short circuit request.`
148
+ );
149
+ throw new Error(
150
+ `Invalid HMAC signature: extension ${extensionName} does not match the body content.`
151
+ );
152
+ }
153
+ });
154
+ }
155
+ };
156
+ }
157
+
158
+ exports.defaultExecutionRequestSerializer = defaultExecutionRequestSerializer;
159
+ exports.defaultParamsSerializer = defaultParamsSerializer;
160
+ exports.useHmacSignatureValidation = useHmacSignatureValidation;
161
+ exports.useHmacUpstreamSignature = useHmacUpstreamSignature;
@@ -0,0 +1,95 @@
1
+ import { ExecutionRequest, Executor, MaybePromise, Maybe } from '@graphql-tools/utils';
2
+ import { Plugin, YogaInitialContext, GraphQLParams } from 'graphql-yoga';
3
+ import { TransportEntry } from '@graphql-mesh/transport-common';
4
+ import { Logger, OnFetchHook, MeshFetch, MeshPubSub, KeyValueCache } from '@graphql-mesh/types';
5
+ import { GraphQLSchema, ExecutionResult } from 'graphql';
6
+
7
+ declare module 'graphql' {
8
+ interface GraphQLResolveInfo {
9
+ executionRequest?: ExecutionRequest;
10
+ }
11
+ }
12
+ interface UnifiedGraphPlugin<TContext> {
13
+ onSubgraphExecute?: OnSubgraphExecuteHook<TContext>;
14
+ }
15
+ type OnSubgraphExecuteHook<TContext = any> = (payload: OnSubgraphExecutePayload<TContext>) => MaybePromise<Maybe<OnSubgraphExecuteDoneHook | void>>;
16
+ interface OnSubgraphExecutePayload<TContext> {
17
+ subgraph: GraphQLSchema;
18
+ subgraphName: string;
19
+ transportEntry?: TransportEntry;
20
+ executionRequest: ExecutionRequest<any, TContext>;
21
+ setExecutionRequest(executionRequest: ExecutionRequest): void;
22
+ executor: Executor;
23
+ setExecutor(executor: Executor): void;
24
+ requestId?: string;
25
+ logger?: Logger;
26
+ }
27
+ interface OnSubgraphExecuteDonePayload {
28
+ result: AsyncIterable<ExecutionResult> | ExecutionResult;
29
+ setResult(result: AsyncIterable<ExecutionResult> | ExecutionResult): void;
30
+ }
31
+ type OnSubgraphExecuteDoneHook = (payload: OnSubgraphExecuteDonePayload) => MaybePromise<Maybe<OnSubgraphExecuteDoneResult | void>>;
32
+ type OnSubgraphExecuteDoneResultOnNext = (payload: OnSubgraphExecuteDoneOnNextPayload) => MaybePromise<void>;
33
+ interface OnSubgraphExecuteDoneOnNextPayload {
34
+ result: ExecutionResult;
35
+ setResult(result: ExecutionResult): void;
36
+ }
37
+ type OnSubgraphExecuteDoneResultOnEnd = () => MaybePromise<void>;
38
+ type OnSubgraphExecuteDoneResult = {
39
+ onNext?: OnSubgraphExecuteDoneResultOnNext;
40
+ onEnd?: OnSubgraphExecuteDoneResultOnEnd;
41
+ };
42
+
43
+ interface GatewayConfigContext {
44
+ /**
45
+ * WHATWG compatible Fetch implementation.
46
+ */
47
+ fetch: MeshFetch;
48
+ /**
49
+ * The logger to use throught Mesh and it's plugins.
50
+ */
51
+ logger: Logger;
52
+ /**
53
+ * Current working directory.
54
+ */
55
+ cwd: string;
56
+ /**
57
+ * Event bus for pub/sub.
58
+ */
59
+ pubsub?: MeshPubSub;
60
+ /**
61
+ * Cache Storage
62
+ */
63
+ cache?: KeyValueCache;
64
+ }
65
+ interface GatewayContext extends GatewayConfigContext, YogaInitialContext {
66
+ /**
67
+ * Environment agnostic HTTP headers provided with the request.
68
+ */
69
+ headers: Record<string, string>;
70
+ /**
71
+ * Runtime context available within WebSocket connections.
72
+ */
73
+ connectionParams: Record<string, string>;
74
+ }
75
+ type GatewayPlugin<TPluginContext extends Record<string, any> = Record<string, any>, TContext extends Record<string, any> = Record<string, any>> = Plugin<Partial<TPluginContext> & GatewayContext & TContext> & UnifiedGraphPlugin<Partial<TPluginContext> & GatewayContext & TContext> & {
76
+ onFetch?: OnFetchHook<Partial<TPluginContext> & GatewayContext & TContext>;
77
+ } & Partial<Disposable | AsyncDisposable>;
78
+
79
+ type HMACUpstreamSignatureOptions = {
80
+ secret: string;
81
+ shouldSign?: (input: Pick<OnSubgraphExecutePayload<{}>, 'subgraph' | 'subgraphName' | 'executionRequest'>) => boolean;
82
+ extensionName?: string;
83
+ serializeExecutionRequest?: (executionRequest: ExecutionRequest) => string;
84
+ };
85
+ declare const defaultExecutionRequestSerializer: (executionRequest: ExecutionRequest) => string;
86
+ declare const defaultParamsSerializer: (params: GraphQLParams) => string;
87
+ declare function useHmacUpstreamSignature(options: HMACUpstreamSignatureOptions): GatewayPlugin;
88
+ type HMACUpstreamSignatureValidationOptions = {
89
+ secret: string;
90
+ extensionName?: string;
91
+ serializeParams?: (params: GraphQLParams) => string;
92
+ };
93
+ declare function useHmacSignatureValidation(options: HMACUpstreamSignatureValidationOptions): Plugin;
94
+
95
+ export { type HMACUpstreamSignatureOptions, type HMACUpstreamSignatureValidationOptions, defaultExecutionRequestSerializer, defaultParamsSerializer, useHmacSignatureValidation, useHmacUpstreamSignature };
@@ -0,0 +1,95 @@
1
+ import { ExecutionRequest, Executor, MaybePromise, Maybe } from '@graphql-tools/utils';
2
+ import { Plugin, YogaInitialContext, GraphQLParams } from 'graphql-yoga';
3
+ import { TransportEntry } from '@graphql-mesh/transport-common';
4
+ import { Logger, OnFetchHook, MeshFetch, MeshPubSub, KeyValueCache } from '@graphql-mesh/types';
5
+ import { GraphQLSchema, ExecutionResult } from 'graphql';
6
+
7
+ declare module 'graphql' {
8
+ interface GraphQLResolveInfo {
9
+ executionRequest?: ExecutionRequest;
10
+ }
11
+ }
12
+ interface UnifiedGraphPlugin<TContext> {
13
+ onSubgraphExecute?: OnSubgraphExecuteHook<TContext>;
14
+ }
15
+ type OnSubgraphExecuteHook<TContext = any> = (payload: OnSubgraphExecutePayload<TContext>) => MaybePromise<Maybe<OnSubgraphExecuteDoneHook | void>>;
16
+ interface OnSubgraphExecutePayload<TContext> {
17
+ subgraph: GraphQLSchema;
18
+ subgraphName: string;
19
+ transportEntry?: TransportEntry;
20
+ executionRequest: ExecutionRequest<any, TContext>;
21
+ setExecutionRequest(executionRequest: ExecutionRequest): void;
22
+ executor: Executor;
23
+ setExecutor(executor: Executor): void;
24
+ requestId?: string;
25
+ logger?: Logger;
26
+ }
27
+ interface OnSubgraphExecuteDonePayload {
28
+ result: AsyncIterable<ExecutionResult> | ExecutionResult;
29
+ setResult(result: AsyncIterable<ExecutionResult> | ExecutionResult): void;
30
+ }
31
+ type OnSubgraphExecuteDoneHook = (payload: OnSubgraphExecuteDonePayload) => MaybePromise<Maybe<OnSubgraphExecuteDoneResult | void>>;
32
+ type OnSubgraphExecuteDoneResultOnNext = (payload: OnSubgraphExecuteDoneOnNextPayload) => MaybePromise<void>;
33
+ interface OnSubgraphExecuteDoneOnNextPayload {
34
+ result: ExecutionResult;
35
+ setResult(result: ExecutionResult): void;
36
+ }
37
+ type OnSubgraphExecuteDoneResultOnEnd = () => MaybePromise<void>;
38
+ type OnSubgraphExecuteDoneResult = {
39
+ onNext?: OnSubgraphExecuteDoneResultOnNext;
40
+ onEnd?: OnSubgraphExecuteDoneResultOnEnd;
41
+ };
42
+
43
+ interface GatewayConfigContext {
44
+ /**
45
+ * WHATWG compatible Fetch implementation.
46
+ */
47
+ fetch: MeshFetch;
48
+ /**
49
+ * The logger to use throught Mesh and it's plugins.
50
+ */
51
+ logger: Logger;
52
+ /**
53
+ * Current working directory.
54
+ */
55
+ cwd: string;
56
+ /**
57
+ * Event bus for pub/sub.
58
+ */
59
+ pubsub?: MeshPubSub;
60
+ /**
61
+ * Cache Storage
62
+ */
63
+ cache?: KeyValueCache;
64
+ }
65
+ interface GatewayContext extends GatewayConfigContext, YogaInitialContext {
66
+ /**
67
+ * Environment agnostic HTTP headers provided with the request.
68
+ */
69
+ headers: Record<string, string>;
70
+ /**
71
+ * Runtime context available within WebSocket connections.
72
+ */
73
+ connectionParams: Record<string, string>;
74
+ }
75
+ type GatewayPlugin<TPluginContext extends Record<string, any> = Record<string, any>, TContext extends Record<string, any> = Record<string, any>> = Plugin<Partial<TPluginContext> & GatewayContext & TContext> & UnifiedGraphPlugin<Partial<TPluginContext> & GatewayContext & TContext> & {
76
+ onFetch?: OnFetchHook<Partial<TPluginContext> & GatewayContext & TContext>;
77
+ } & Partial<Disposable | AsyncDisposable>;
78
+
79
+ type HMACUpstreamSignatureOptions = {
80
+ secret: string;
81
+ shouldSign?: (input: Pick<OnSubgraphExecutePayload<{}>, 'subgraph' | 'subgraphName' | 'executionRequest'>) => boolean;
82
+ extensionName?: string;
83
+ serializeExecutionRequest?: (executionRequest: ExecutionRequest) => string;
84
+ };
85
+ declare const defaultExecutionRequestSerializer: (executionRequest: ExecutionRequest) => string;
86
+ declare const defaultParamsSerializer: (params: GraphQLParams) => string;
87
+ declare function useHmacUpstreamSignature(options: HMACUpstreamSignatureOptions): GatewayPlugin;
88
+ type HMACUpstreamSignatureValidationOptions = {
89
+ secret: string;
90
+ extensionName?: string;
91
+ serializeParams?: (params: GraphQLParams) => string;
92
+ };
93
+ declare function useHmacSignatureValidation(options: HMACUpstreamSignatureValidationOptions): Plugin;
94
+
95
+ export { type HMACUpstreamSignatureOptions, type HMACUpstreamSignatureValidationOptions, defaultExecutionRequestSerializer, defaultParamsSerializer, useHmacSignatureValidation, useHmacUpstreamSignature };
package/dist/index.js ADDED
@@ -0,0 +1,152 @@
1
+ import { defaultPrintFn } from '@graphql-mesh/transport-common';
2
+ import { mapMaybePromise } from '@graphql-mesh/utils';
3
+ import jsonStableStringify from 'json-stable-stringify';
4
+
5
+ const DEFAULT_EXTENSION_NAME = "hmac-signature";
6
+ const DEFAULT_SHOULD_SIGN_FN = () => true;
7
+ const defaultExecutionRequestSerializer = (executionRequest) => jsonStableStringify({
8
+ query: defaultPrintFn(executionRequest.document),
9
+ variables: executionRequest.variables
10
+ });
11
+ const defaultParamsSerializer = (params) => jsonStableStringify({
12
+ query: params.query,
13
+ variables: params.variables
14
+ });
15
+ function createCryptoKey({
16
+ textEncoder,
17
+ crypto,
18
+ secret,
19
+ usages
20
+ }) {
21
+ return crypto.subtle.importKey(
22
+ "raw",
23
+ textEncoder.encode(secret),
24
+ { name: "HMAC", hash: "SHA-256" },
25
+ false,
26
+ usages
27
+ );
28
+ }
29
+ function useHmacUpstreamSignature(options) {
30
+ if (!options.secret) {
31
+ throw new Error(
32
+ 'Property "secret" is required for useHmacUpstreamSignature plugin'
33
+ );
34
+ }
35
+ const shouldSign = options.shouldSign || DEFAULT_SHOULD_SIGN_FN;
36
+ const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
37
+ const serializeExecutionRequest = options.serializeExecutionRequest || defaultExecutionRequestSerializer;
38
+ let key$;
39
+ let fetchAPI;
40
+ let textEncoder;
41
+ return {
42
+ onYogaInit({ yoga }) {
43
+ fetchAPI = yoga.fetchAPI;
44
+ },
45
+ onSubgraphExecute({
46
+ subgraphName,
47
+ subgraph,
48
+ executionRequest,
49
+ setExecutionRequest,
50
+ logger
51
+ }) {
52
+ logger?.debug(`running shouldSign for subgraph ${subgraphName}`);
53
+ if (shouldSign({ subgraphName, subgraph, executionRequest })) {
54
+ logger?.debug(
55
+ `shouldSign is true for subgraph ${subgraphName}, signing request`
56
+ );
57
+ textEncoder ||= new fetchAPI.TextEncoder();
58
+ key$ ||= createCryptoKey({
59
+ textEncoder,
60
+ crypto: fetchAPI.crypto,
61
+ secret: options.secret,
62
+ usages: ["sign"]
63
+ });
64
+ return mapMaybePromise(key$, async (key) => {
65
+ key$ = key;
66
+ const serializedExecutionRequest = serializeExecutionRequest(executionRequest);
67
+ const encodedContent = textEncoder.encode(serializedExecutionRequest);
68
+ const signature = await fetchAPI.crypto.subtle.sign(
69
+ "HMAC",
70
+ key,
71
+ encodedContent
72
+ );
73
+ const extensionValue = btoa(
74
+ String.fromCharCode(...new Uint8Array(signature))
75
+ );
76
+ logger?.debug(
77
+ `produced hmac signature for subgraph ${subgraphName}, signature: ${signature}, signed payload: ${serializedExecutionRequest}`
78
+ );
79
+ setExecutionRequest({
80
+ ...executionRequest,
81
+ extensions: {
82
+ ...executionRequest.extensions,
83
+ [extensionName]: extensionValue
84
+ }
85
+ });
86
+ });
87
+ } else {
88
+ logger?.debug(
89
+ `shouldSign is false for subgraph ${subgraphName}, skipping hmac signature`
90
+ );
91
+ }
92
+ }
93
+ };
94
+ }
95
+ function useHmacSignatureValidation(options) {
96
+ if (!options.secret) {
97
+ throw new Error(
98
+ 'Property "secret" is required for useHmacSignatureValidation plugin'
99
+ );
100
+ }
101
+ const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
102
+ let key$;
103
+ let textEncoder;
104
+ let logger;
105
+ const paramsSerializer = options.serializeParams || defaultParamsSerializer;
106
+ return {
107
+ onYogaInit({ yoga }) {
108
+ logger = yoga.logger;
109
+ },
110
+ onParams({ params, fetchAPI }) {
111
+ textEncoder ||= new fetchAPI.TextEncoder();
112
+ const extension = params.extensions?.[extensionName];
113
+ if (!extension) {
114
+ logger.warn(
115
+ `Missing HMAC signature: extension ${extensionName} not found in request.`
116
+ );
117
+ throw new Error(
118
+ `Missing HMAC signature: extension ${extensionName} not found in request.`
119
+ );
120
+ }
121
+ key$ ||= createCryptoKey({
122
+ textEncoder,
123
+ crypto: fetchAPI.crypto,
124
+ secret: options.secret,
125
+ usages: ["verify"]
126
+ });
127
+ return key$.then(async (key) => {
128
+ const sigBuf = Uint8Array.from(atob(extension), (c) => c.charCodeAt(0));
129
+ const serializedParams = paramsSerializer(params);
130
+ logger.debug(
131
+ `HMAC signature will be calculate based on serialized params: ${serializedParams}`
132
+ );
133
+ const result = await fetchAPI.crypto.subtle.verify(
134
+ "HMAC",
135
+ key,
136
+ sigBuf,
137
+ textEncoder.encode(serializedParams)
138
+ );
139
+ if (!result) {
140
+ logger.error(
141
+ `HMAC signature does not match the body content. short circuit request.`
142
+ );
143
+ throw new Error(
144
+ `Invalid HMAC signature: extension ${extensionName} does not match the body content.`
145
+ );
146
+ }
147
+ });
148
+ }
149
+ };
150
+ }
151
+
152
+ export { defaultExecutionRequestSerializer, defaultParamsSerializer, useHmacSignatureValidation, useHmacUpstreamSignature };
package/package.json CHANGED
@@ -1,48 +1,62 @@
1
1
  {
2
2
  "name": "@graphql-mesh/hmac-upstream-signature",
3
- "version": "1.2.7-alpha-20241114122631-5a3a4345bb55e05e6bd057ae38f412d5d33315fd",
4
- "sideEffects": false,
5
- "peerDependencies": {
6
- "@graphql-mesh/types": "0.102.13-alpha-20241114122631-5a3a4345bb55e05e6bd057ae38f412d5d33315fd",
7
- "@graphql-mesh/utils": "0.102.13-alpha-20241114122631-5a3a4345bb55e05e6bd057ae38f412d5d33315fd",
8
- "graphql": "*",
9
- "tslib": "^2.4.0"
10
- },
11
- "dependencies": {
12
- "@graphql-mesh/transport-common": "^0.7.13",
13
- "json-stable-stringify": "^1.1.1"
14
- },
3
+ "version": "1.2.7-alpha-54b3273d0d9033d32f549a6b937921426c35b08b",
4
+ "type": "module",
15
5
  "repository": {
16
6
  "type": "git",
17
- "url": "ardatan/graphql-mesh",
7
+ "url": "git+https://github.com/graphql-hive/gateway.git",
18
8
  "directory": "packages/plugins/hmac-upstream-signature"
19
9
  },
10
+ "author": {
11
+ "email": "contact@the-guild.dev",
12
+ "name": "The Guild",
13
+ "url": "https://the-guild.dev"
14
+ },
20
15
  "license": "MIT",
21
16
  "engines": {
22
- "node": ">=16.0.0"
17
+ "node": ">=18.0.0"
23
18
  },
24
- "main": "cjs/index.js",
25
- "module": "esm/index.js",
26
- "typings": "typings/index.d.ts",
27
- "typescript": {
28
- "definition": "typings/index.d.ts"
29
- },
30
- "type": "module",
19
+ "main": "./dist/index.js",
31
20
  "exports": {
32
21
  ".": {
33
22
  "require": {
34
- "types": "./typings/index.d.cts",
35
- "default": "./cjs/index.js"
23
+ "types": "./dist/index.d.cts",
24
+ "default": "./dist/index.cjs"
36
25
  },
37
26
  "import": {
38
- "types": "./typings/index.d.ts",
39
- "default": "./esm/index.js"
40
- },
41
- "default": {
42
- "types": "./typings/index.d.ts",
43
- "default": "./esm/index.js"
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
44
29
  }
45
30
  },
46
31
  "./package.json": "./package.json"
47
- }
32
+ },
33
+ "types": "./dist/index.d.ts",
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "scripts": {
38
+ "build": "pkgroll --clean-dist",
39
+ "prepack": "yarn build"
40
+ },
41
+ "peerDependencies": {
42
+ "graphql": "^15.9.0 || ^16.9.0"
43
+ },
44
+ "dependencies": {
45
+ "@graphql-mesh/cross-helpers": "^0.4.7",
46
+ "@graphql-mesh/store": "^0.102.12",
47
+ "@graphql-mesh/transport-common": "^0.7.14-alpha-54b3273d0d9033d32f549a6b937921426c35b08b",
48
+ "@graphql-mesh/types": "^0.102.12",
49
+ "@graphql-mesh/utils": "^0.102.12",
50
+ "@graphql-tools/utils": "^10.5.5",
51
+ "json-stable-stringify": "^1.1.1",
52
+ "tslib": "^2.4.0"
53
+ },
54
+ "devDependencies": {
55
+ "@graphql-hive/gateway": "1.5.0-alpha-54b3273d0d9033d32f549a6b937921426c35b08b",
56
+ "@types/json-stable-stringify": "^1.1.0",
57
+ "graphql": "^16.9.0",
58
+ "graphql-yoga": "^5.7.0",
59
+ "pkgroll": "2.5.1"
60
+ },
61
+ "sideEffects": false
48
62
  }
package/cjs/index.js DELETED
@@ -1,110 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultParamsSerializer = exports.defaultExecutionRequestSerializer = void 0;
4
- exports.useHmacUpstreamSignature = useHmacUpstreamSignature;
5
- exports.useHmacSignatureValidation = useHmacSignatureValidation;
6
- const tslib_1 = require("tslib");
7
- const json_stable_stringify_1 = tslib_1.__importDefault(require("json-stable-stringify"));
8
- const transport_common_1 = require("@graphql-mesh/transport-common");
9
- const utils_1 = require("@graphql-mesh/utils");
10
- const DEFAULT_EXTENSION_NAME = 'hmac-signature';
11
- const DEFAULT_SHOULD_SIGN_FN = () => true;
12
- const defaultExecutionRequestSerializer = (executionRequest) => (0, json_stable_stringify_1.default)({
13
- query: (0, transport_common_1.defaultPrintFn)(executionRequest.document),
14
- variables: executionRequest.variables,
15
- });
16
- exports.defaultExecutionRequestSerializer = defaultExecutionRequestSerializer;
17
- const defaultParamsSerializer = (params) => (0, json_stable_stringify_1.default)({
18
- query: params.query,
19
- variables: params.variables,
20
- });
21
- exports.defaultParamsSerializer = defaultParamsSerializer;
22
- function createCryptoKey({ textEncoder, crypto, secret, usages, }) {
23
- return crypto.subtle.importKey('raw', textEncoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, usages);
24
- }
25
- function useHmacUpstreamSignature(options) {
26
- if (!options.secret) {
27
- throw new Error('Property "secret" is required for useHmacUpstreamSignature plugin');
28
- }
29
- const shouldSign = options.shouldSign || DEFAULT_SHOULD_SIGN_FN;
30
- const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
31
- const serializeExecutionRequest = options.serializeExecutionRequest || exports.defaultExecutionRequestSerializer;
32
- let key$;
33
- let fetchAPI;
34
- let textEncoder;
35
- return {
36
- onYogaInit({ yoga }) {
37
- fetchAPI = yoga.fetchAPI;
38
- },
39
- onSubgraphExecute({ subgraphName, subgraph, executionRequest, setExecutionRequest, logger }) {
40
- logger.debug(`running shouldSign for subgraph ${subgraphName}`);
41
- if (shouldSign({ subgraphName, subgraph, executionRequest })) {
42
- logger.debug(`shouldSign is true for subgraph ${subgraphName}, signing request`);
43
- textEncoder ||= new fetchAPI.TextEncoder();
44
- key$ ||= createCryptoKey({
45
- textEncoder,
46
- crypto: fetchAPI.crypto,
47
- secret: options.secret,
48
- usages: ['sign'],
49
- });
50
- return (0, utils_1.mapMaybePromise)(key$, async (key) => {
51
- key$ = key;
52
- const serializedExecutionRequest = serializeExecutionRequest(executionRequest);
53
- const encodedContent = textEncoder.encode(serializedExecutionRequest);
54
- const signature = await fetchAPI.crypto.subtle.sign('HMAC', key, encodedContent);
55
- const extensionValue = btoa(String.fromCharCode(...new Uint8Array(signature)));
56
- logger.debug(`produced hmac signature for subgraph ${subgraphName}, signature: ${signature}, signed payload: ${serializedExecutionRequest}`);
57
- setExecutionRequest({
58
- ...executionRequest,
59
- extensions: {
60
- ...executionRequest.extensions,
61
- [extensionName]: extensionValue,
62
- },
63
- });
64
- });
65
- }
66
- else {
67
- logger.debug(`shouldSign is false for subgraph ${subgraphName}, skipping hmac signature`);
68
- }
69
- },
70
- };
71
- }
72
- function useHmacSignatureValidation(options) {
73
- if (!options.secret) {
74
- throw new Error('Property "secret" is required for useHmacSignatureValidation plugin');
75
- }
76
- const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
77
- let key$;
78
- let textEncoder;
79
- let logger;
80
- const paramsSerializer = options.serializeParams || exports.defaultParamsSerializer;
81
- return {
82
- onYogaInit({ yoga }) {
83
- logger = yoga.logger;
84
- },
85
- onParams({ params, fetchAPI }) {
86
- textEncoder ||= new fetchAPI.TextEncoder();
87
- const extension = params.extensions?.[extensionName];
88
- if (!extension) {
89
- logger.warn(`Missing HMAC signature: extension ${extensionName} not found in request.`);
90
- throw new Error(`Missing HMAC signature: extension ${extensionName} not found in request.`);
91
- }
92
- key$ ||= createCryptoKey({
93
- textEncoder,
94
- crypto: fetchAPI.crypto,
95
- secret: options.secret,
96
- usages: ['verify'],
97
- });
98
- return key$.then(async (key) => {
99
- const sigBuf = Uint8Array.from(atob(extension), c => c.charCodeAt(0));
100
- const serializedParams = paramsSerializer(params);
101
- logger.debug(`HMAC signature will be calculate based on serialized params: ${serializedParams}`);
102
- const result = await fetchAPI.crypto.subtle.verify('HMAC', key, sigBuf, textEncoder.encode(serializedParams));
103
- if (!result) {
104
- logger.error(`HMAC signature does not match the body content. short circuit request.`);
105
- throw new Error(`Invalid HMAC signature: extension ${extensionName} does not match the body content.`);
106
- }
107
- });
108
- },
109
- };
110
- }
package/cjs/package.json DELETED
@@ -1 +0,0 @@
1
- {"type":"commonjs"}
package/esm/index.js DELETED
@@ -1,102 +0,0 @@
1
- import jsonStableStringify from 'json-stable-stringify';
2
- import { defaultPrintFn } from '@graphql-mesh/transport-common';
3
- import { mapMaybePromise } from '@graphql-mesh/utils';
4
- const DEFAULT_EXTENSION_NAME = 'hmac-signature';
5
- const DEFAULT_SHOULD_SIGN_FN = () => true;
6
- export const defaultExecutionRequestSerializer = (executionRequest) => jsonStableStringify({
7
- query: defaultPrintFn(executionRequest.document),
8
- variables: executionRequest.variables,
9
- });
10
- export const defaultParamsSerializer = (params) => jsonStableStringify({
11
- query: params.query,
12
- variables: params.variables,
13
- });
14
- function createCryptoKey({ textEncoder, crypto, secret, usages, }) {
15
- return crypto.subtle.importKey('raw', textEncoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, usages);
16
- }
17
- export function useHmacUpstreamSignature(options) {
18
- if (!options.secret) {
19
- throw new Error('Property "secret" is required for useHmacUpstreamSignature plugin');
20
- }
21
- const shouldSign = options.shouldSign || DEFAULT_SHOULD_SIGN_FN;
22
- const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
23
- const serializeExecutionRequest = options.serializeExecutionRequest || defaultExecutionRequestSerializer;
24
- let key$;
25
- let fetchAPI;
26
- let textEncoder;
27
- return {
28
- onYogaInit({ yoga }) {
29
- fetchAPI = yoga.fetchAPI;
30
- },
31
- onSubgraphExecute({ subgraphName, subgraph, executionRequest, setExecutionRequest, logger }) {
32
- logger.debug(`running shouldSign for subgraph ${subgraphName}`);
33
- if (shouldSign({ subgraphName, subgraph, executionRequest })) {
34
- logger.debug(`shouldSign is true for subgraph ${subgraphName}, signing request`);
35
- textEncoder ||= new fetchAPI.TextEncoder();
36
- key$ ||= createCryptoKey({
37
- textEncoder,
38
- crypto: fetchAPI.crypto,
39
- secret: options.secret,
40
- usages: ['sign'],
41
- });
42
- return mapMaybePromise(key$, async (key) => {
43
- key$ = key;
44
- const serializedExecutionRequest = serializeExecutionRequest(executionRequest);
45
- const encodedContent = textEncoder.encode(serializedExecutionRequest);
46
- const signature = await fetchAPI.crypto.subtle.sign('HMAC', key, encodedContent);
47
- const extensionValue = btoa(String.fromCharCode(...new Uint8Array(signature)));
48
- logger.debug(`produced hmac signature for subgraph ${subgraphName}, signature: ${signature}, signed payload: ${serializedExecutionRequest}`);
49
- setExecutionRequest({
50
- ...executionRequest,
51
- extensions: {
52
- ...executionRequest.extensions,
53
- [extensionName]: extensionValue,
54
- },
55
- });
56
- });
57
- }
58
- else {
59
- logger.debug(`shouldSign is false for subgraph ${subgraphName}, skipping hmac signature`);
60
- }
61
- },
62
- };
63
- }
64
- export function useHmacSignatureValidation(options) {
65
- if (!options.secret) {
66
- throw new Error('Property "secret" is required for useHmacSignatureValidation plugin');
67
- }
68
- const extensionName = options.extensionName || DEFAULT_EXTENSION_NAME;
69
- let key$;
70
- let textEncoder;
71
- let logger;
72
- const paramsSerializer = options.serializeParams || defaultParamsSerializer;
73
- return {
74
- onYogaInit({ yoga }) {
75
- logger = yoga.logger;
76
- },
77
- onParams({ params, fetchAPI }) {
78
- textEncoder ||= new fetchAPI.TextEncoder();
79
- const extension = params.extensions?.[extensionName];
80
- if (!extension) {
81
- logger.warn(`Missing HMAC signature: extension ${extensionName} not found in request.`);
82
- throw new Error(`Missing HMAC signature: extension ${extensionName} not found in request.`);
83
- }
84
- key$ ||= createCryptoKey({
85
- textEncoder,
86
- crypto: fetchAPI.crypto,
87
- secret: options.secret,
88
- usages: ['verify'],
89
- });
90
- return key$.then(async (key) => {
91
- const sigBuf = Uint8Array.from(atob(extension), c => c.charCodeAt(0));
92
- const serializedParams = paramsSerializer(params);
93
- logger.debug(`HMAC signature will be calculate based on serialized params: ${serializedParams}`);
94
- const result = await fetchAPI.crypto.subtle.verify('HMAC', key, sigBuf, textEncoder.encode(serializedParams));
95
- if (!result) {
96
- logger.error(`HMAC signature does not match the body content. short circuit request.`);
97
- throw new Error(`Invalid HMAC signature: extension ${extensionName} does not match the body content.`);
98
- }
99
- });
100
- },
101
- };
102
- }
@@ -1,19 +0,0 @@
1
- import type { GraphQLParams, Plugin as YogaPlugin } from 'graphql-yoga';
2
- import type { GatewayPlugin } from '@graphql-hive/gateway';
3
- import type { OnSubgraphExecutePayload } from '@graphql-mesh/fusion-runtime';
4
- import type { ExecutionRequest } from '@graphql-tools/utils';
5
- export type HMACUpstreamSignatureOptions = {
6
- secret: string;
7
- shouldSign?: (input: Pick<OnSubgraphExecutePayload<{}>, 'subgraph' | 'subgraphName' | 'executionRequest'>) => boolean;
8
- extensionName?: string;
9
- serializeExecutionRequest?: (executionRequest: ExecutionRequest) => string;
10
- };
11
- export declare const defaultExecutionRequestSerializer: (executionRequest: ExecutionRequest) => any;
12
- export declare const defaultParamsSerializer: (params: GraphQLParams) => any;
13
- export declare function useHmacUpstreamSignature(options: HMACUpstreamSignatureOptions): GatewayPlugin;
14
- export type HMACUpstreamSignatureValidationOptions = {
15
- secret: string;
16
- extensionName?: string;
17
- serializeParams?: (params: GraphQLParams) => string;
18
- };
19
- export declare function useHmacSignatureValidation(options: HMACUpstreamSignatureValidationOptions): YogaPlugin;
@@ -1,19 +0,0 @@
1
- import type { GraphQLParams, Plugin as YogaPlugin } from 'graphql-yoga';
2
- import type { GatewayPlugin } from '@graphql-hive/gateway';
3
- import type { OnSubgraphExecutePayload } from '@graphql-mesh/fusion-runtime';
4
- import type { ExecutionRequest } from '@graphql-tools/utils';
5
- export type HMACUpstreamSignatureOptions = {
6
- secret: string;
7
- shouldSign?: (input: Pick<OnSubgraphExecutePayload<{}>, 'subgraph' | 'subgraphName' | 'executionRequest'>) => boolean;
8
- extensionName?: string;
9
- serializeExecutionRequest?: (executionRequest: ExecutionRequest) => string;
10
- };
11
- export declare const defaultExecutionRequestSerializer: (executionRequest: ExecutionRequest) => any;
12
- export declare const defaultParamsSerializer: (params: GraphQLParams) => any;
13
- export declare function useHmacUpstreamSignature(options: HMACUpstreamSignatureOptions): GatewayPlugin;
14
- export type HMACUpstreamSignatureValidationOptions = {
15
- secret: string;
16
- extensionName?: string;
17
- serializeParams?: (params: GraphQLParams) => string;
18
- };
19
- export declare function useHmacSignatureValidation(options: HMACUpstreamSignatureValidationOptions): YogaPlugin;