graphql-shield-node23 7.6.5

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 (56) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/cjs/constructors.js +134 -0
  3. package/dist/cjs/generator.js +205 -0
  4. package/dist/cjs/index.js +15 -0
  5. package/dist/cjs/package.json +1 -0
  6. package/dist/cjs/rules.js +402 -0
  7. package/dist/cjs/shield.js +52 -0
  8. package/dist/cjs/types.js +2 -0
  9. package/dist/cjs/utils.js +97 -0
  10. package/dist/cjs/validation.js +84 -0
  11. package/dist/esm/constructors.js +124 -0
  12. package/dist/esm/generator.js +201 -0
  13. package/dist/esm/index.js +2 -0
  14. package/dist/esm/rules.js +366 -0
  15. package/dist/esm/shield.js +45 -0
  16. package/dist/esm/types.js +1 -0
  17. package/dist/esm/utils.js +88 -0
  18. package/dist/esm/validation.js +79 -0
  19. package/dist/package.json +47 -0
  20. package/dist/typings/constructors.d.cts +91 -0
  21. package/dist/typings/constructors.d.ts +91 -0
  22. package/dist/typings/generator.d.cts +11 -0
  23. package/dist/typings/generator.d.ts +11 -0
  24. package/dist/typings/index.d.cts +3 -0
  25. package/dist/typings/index.d.ts +3 -0
  26. package/dist/typings/rules.d.cts +159 -0
  27. package/dist/typings/rules.d.ts +159 -0
  28. package/dist/typings/shield.d.cts +11 -0
  29. package/dist/typings/shield.d.ts +11 -0
  30. package/dist/typings/types.d.cts +64 -0
  31. package/dist/typings/types.d.ts +64 -0
  32. package/dist/typings/utils.d.cts +52 -0
  33. package/dist/typings/utils.d.ts +52 -0
  34. package/dist/typings/validation.d.cts +19 -0
  35. package/dist/typings/validation.d.ts +19 -0
  36. package/package.json +67 -0
  37. package/src/constructors.ts +157 -0
  38. package/src/generator.ts +294 -0
  39. package/src/index.ts +13 -0
  40. package/src/rules.ts +521 -0
  41. package/src/shield.ts +53 -0
  42. package/src/types.ts +94 -0
  43. package/src/utils.ts +101 -0
  44. package/src/validation.ts +90 -0
  45. package/tests/__snapshots__/input.test.ts.snap +7 -0
  46. package/tests/cache.test.ts +545 -0
  47. package/tests/constructors.test.ts +136 -0
  48. package/tests/fallback.test.ts +618 -0
  49. package/tests/fragments.test.ts +113 -0
  50. package/tests/generator.test.ts +356 -0
  51. package/tests/input.test.ts +63 -0
  52. package/tests/integration.test.ts +65 -0
  53. package/tests/logic.test.ts +530 -0
  54. package/tests/utils.test.ts +55 -0
  55. package/tests/validation.test.ts +139 -0
  56. package/tsconfig.json +10 -0
@@ -0,0 +1,356 @@
1
+ import { makeExecutableSchema } from '@graphql-tools/schema'
2
+ import { applyMiddleware } from 'graphql-middleware'
3
+ import { shield, rule } from '../src'
4
+ import { graphql } from 'graphql'
5
+
6
+ describe('generates correct middleware', () => {
7
+ test('correctly applies schema rule to schema', async () => {
8
+ /* Schema */
9
+
10
+ const typeDefs = `
11
+ type Query {
12
+ a: String
13
+ type: Type
14
+ }
15
+ type Type {
16
+ a: String
17
+ }
18
+ `
19
+
20
+ const resolvers = {
21
+ Query: {
22
+ a: () => 'a',
23
+ type: () => ({}),
24
+ },
25
+ Type: {
26
+ a: () => 'a',
27
+ },
28
+ }
29
+
30
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
31
+
32
+ /* Permissions */
33
+
34
+ const allowMock = jest.fn().mockResolvedValue(true)
35
+ const permissions = shield(rule({ cache: 'no_cache' })(allowMock))
36
+
37
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
38
+
39
+ /* Execution */
40
+ const query = `
41
+ query {
42
+ a
43
+ type {
44
+ a
45
+ }
46
+ }
47
+ `
48
+
49
+ const res = await graphql({
50
+ schema: schemaWithPermissions,
51
+ source: query,
52
+ })
53
+
54
+ /* Tests */
55
+
56
+ expect(res).toEqual({
57
+ data: {
58
+ a: 'a',
59
+ type: {
60
+ a: 'a',
61
+ },
62
+ },
63
+ })
64
+ expect(allowMock).toBeCalledTimes(3)
65
+ })
66
+
67
+ test('correctly applies type rule to type', async () => {
68
+ /* Schema */
69
+
70
+ const typeDefs = `
71
+ type Query {
72
+ a: String
73
+ type: Type
74
+ }
75
+ type Type {
76
+ a: String
77
+ }
78
+ `
79
+
80
+ const resolvers = {
81
+ Query: {
82
+ a: () => 'a',
83
+ type: () => ({}),
84
+ },
85
+ Type: {
86
+ a: () => 'a',
87
+ },
88
+ }
89
+
90
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
91
+
92
+ /* Permissions */
93
+
94
+ const allowMock = jest.fn().mockResolvedValue(true)
95
+ const permissions = shield({
96
+ Query: rule({ cache: 'no_cache' })(allowMock),
97
+ })
98
+
99
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
100
+
101
+ /* Execution */
102
+ const query = `
103
+ query {
104
+ a
105
+ type {
106
+ a
107
+ }
108
+ }
109
+ `
110
+
111
+ const res = await graphql({
112
+ schema: schemaWithPermissions,
113
+ source: query,
114
+ })
115
+
116
+ /* Tests */
117
+
118
+ expect(res).toEqual({
119
+ data: {
120
+ a: 'a',
121
+ type: {
122
+ a: 'a',
123
+ },
124
+ },
125
+ })
126
+ expect(allowMock).toBeCalledTimes(2)
127
+ })
128
+
129
+ test('correctly applies field rule to field', async () => {
130
+ /* Schema */
131
+
132
+ const typeDefs = `
133
+ type Query {
134
+ a: String
135
+ type: Type
136
+ }
137
+ type Type {
138
+ a: String
139
+ }
140
+ `
141
+
142
+ const resolvers = {
143
+ Query: {
144
+ a: () => 'a',
145
+ type: () => ({}),
146
+ },
147
+ Type: {
148
+ a: () => 'a',
149
+ },
150
+ }
151
+
152
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
153
+
154
+ /* Permissions */
155
+
156
+ const allowMock = jest.fn().mockResolvedValue(true)
157
+ const permissions = shield({
158
+ Query: { a: rule({ cache: 'no_cache' })(allowMock) },
159
+ })
160
+
161
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
162
+
163
+ /* Execution */
164
+ const query = `
165
+ query {
166
+ a
167
+ type {
168
+ a
169
+ }
170
+ }
171
+ `
172
+
173
+ const res = await graphql({
174
+ schema: schemaWithPermissions,
175
+ source: query,
176
+ })
177
+
178
+ /* Tests */
179
+
180
+ expect(res).toEqual({
181
+ data: {
182
+ a: 'a',
183
+ type: {
184
+ a: 'a',
185
+ },
186
+ },
187
+ })
188
+ expect(allowMock).toBeCalledTimes(1)
189
+ })
190
+
191
+ test('correctly applies wildcard rule to type', async () => {
192
+ /* Schema */
193
+
194
+ const typeDefs = `
195
+ type Query {
196
+ a: String
197
+ b: String
198
+ type: Type
199
+ }
200
+ type Type {
201
+ field1: String
202
+ field2: String
203
+ }
204
+ `
205
+
206
+ const resolvers = {
207
+ Query: {
208
+ a: () => 'a',
209
+ b: () => 'b',
210
+ type: () => ({
211
+ field1: 'field1',
212
+ field2: 'field2',
213
+ }),
214
+ },
215
+ }
216
+
217
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
218
+
219
+ /* Permissions */
220
+
221
+ const allowMock = jest.fn().mockResolvedValue(true)
222
+ const defaultQueryMock = jest.fn().mockResolvedValue(true)
223
+ const defaultTypeMock = jest.fn().mockResolvedValue(true)
224
+
225
+ const permissions = shield({
226
+ Query: {
227
+ a: rule({ cache: 'no_cache' })(allowMock),
228
+ type: rule({ cache: 'no_cache' })(jest.fn().mockResolvedValue(true)),
229
+ '*': rule({ cache: 'no_cache' })(defaultQueryMock),
230
+ },
231
+ Type: {
232
+ '*': rule({ cache: 'no_cache' })(defaultTypeMock),
233
+ },
234
+ })
235
+
236
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
237
+
238
+ /* Execution */
239
+ const query = `
240
+ query {
241
+ a
242
+ b
243
+ type {
244
+ field1
245
+ field2
246
+ }
247
+ }
248
+ `
249
+
250
+ const res = await graphql({
251
+ schema: schemaWithPermissions,
252
+ source: query,
253
+ })
254
+
255
+ /* Tests */
256
+
257
+ expect(res).toEqual({
258
+ data: {
259
+ a: 'a',
260
+ b: 'b',
261
+ type: {
262
+ field1: 'field1',
263
+ field2: 'field2',
264
+ },
265
+ },
266
+ })
267
+ expect(allowMock).toBeCalledTimes(1)
268
+ expect(defaultQueryMock).toBeCalledTimes(1)
269
+ expect(defaultTypeMock).toBeCalledTimes(2)
270
+ })
271
+
272
+ test('correctly allows multiple uses of the same wildcard rule', async () => {
273
+ /* Schema */
274
+
275
+ const typeDefs = `
276
+ type Query {
277
+ a: String
278
+ b: String
279
+ type: Type
280
+ }
281
+ type Type {
282
+ field1: String
283
+ field2: String
284
+ }
285
+ `
286
+
287
+ const resolvers = {
288
+ Query: {
289
+ a: () => 'a',
290
+ b: () => 'b',
291
+ type: () => ({
292
+ field1: 'field1',
293
+ field2: 'field2',
294
+ }),
295
+ },
296
+ }
297
+
298
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
299
+
300
+ /* Permissions */
301
+
302
+ const allowMock = jest.fn().mockResolvedValue(true)
303
+ const defaultQueryMock = jest.fn().mockResolvedValue(true)
304
+ const defaultTypeMock = jest.fn().mockResolvedValue(true)
305
+
306
+ const permissions = shield({
307
+ Query: {
308
+ a: rule({ cache: 'no_cache' })(allowMock),
309
+ type: rule({ cache: 'no_cache' })(jest.fn().mockResolvedValue(true)),
310
+ '*': rule({ cache: 'no_cache' })(defaultQueryMock),
311
+ },
312
+ Type: {
313
+ '*': rule({ cache: 'no_cache' })(defaultTypeMock),
314
+ },
315
+ })
316
+
317
+ /* First usage */
318
+ applyMiddleware(schema, permissions)
319
+
320
+ /* Second usage */
321
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
322
+
323
+ /* Execution */
324
+ const query = `
325
+ query {
326
+ a
327
+ b
328
+ type {
329
+ field1
330
+ field2
331
+ }
332
+ }
333
+ `
334
+
335
+ const res = await graphql({
336
+ schema: schemaWithPermissions,
337
+ source: query,
338
+ })
339
+
340
+ /* Tests */
341
+
342
+ expect(res).toEqual({
343
+ data: {
344
+ a: 'a',
345
+ b: 'b',
346
+ type: {
347
+ field1: 'field1',
348
+ field2: 'field2',
349
+ },
350
+ },
351
+ })
352
+ expect(allowMock).toBeCalledTimes(1)
353
+ expect(defaultQueryMock).toBeCalledTimes(1)
354
+ expect(defaultTypeMock).toBeCalledTimes(2)
355
+ })
356
+ })
@@ -0,0 +1,63 @@
1
+ import { graphql } from 'graphql'
2
+ import { applyMiddleware } from 'graphql-middleware'
3
+ import { makeExecutableSchema } from '@graphql-tools/schema'
4
+ import { shield, inputRule } from '../src'
5
+
6
+ describe('input rule', () => {
7
+ test('schema validation works as expected', async () => {
8
+ const typeDefs = `
9
+ type Query {
10
+ hello: String!
11
+ }
12
+
13
+ type Mutation {
14
+ login(email: String!): String
15
+ }
16
+ `
17
+
18
+ const resolvers = {
19
+ Query: {
20
+ hello: () => 'world',
21
+ },
22
+ Mutation: {
23
+ login: () => 'pass',
24
+ },
25
+ }
26
+
27
+ const schema = makeExecutableSchema({ typeDefs, resolvers })
28
+
29
+ // Permissions
30
+ const permissions = shield({
31
+ Mutation: {
32
+ login: inputRule()((yup) =>
33
+ yup.object({
34
+ email: yup.string().email('It has to be an email!').required(),
35
+ }),
36
+ ),
37
+ },
38
+ })
39
+
40
+ const schemaWithPermissions = applyMiddleware(schema, permissions)
41
+
42
+ /* Execution */
43
+
44
+ const query = `
45
+ mutation {
46
+ success: login(email: "shield@graphql.com")
47
+ failure: login(email: "notemail")
48
+ }
49
+ `
50
+ const res = await graphql({
51
+ schema: schemaWithPermissions,
52
+ source: query,
53
+ })
54
+
55
+ /* Tests */
56
+
57
+ expect(res.data).toEqual({
58
+ success: 'pass',
59
+ failure: null,
60
+ })
61
+ expect(res.errors).toMatchSnapshot()
62
+ })
63
+ })
@@ -0,0 +1,65 @@
1
+ import { makeExecutableSchema } from '@graphql-tools/schema'
2
+ import { gql, ApolloServer } from 'apollo-server'
3
+ import fetch from 'node-fetch'
4
+ import { applyMiddleware } from 'graphql-middleware'
5
+
6
+ import { shield, allow, deny } from '../src'
7
+
8
+ describe('integration tests', () => {
9
+ test('works with ApolloServer', async () => {
10
+ /* Schema */
11
+
12
+ const typeDefs = gql`
13
+ type Query {
14
+ allow: String
15
+ deny: String
16
+ }
17
+ `
18
+
19
+ const resolvers = {
20
+ Query: {
21
+ allow: () => 'allow',
22
+ deny: () => 'deny',
23
+ },
24
+ }
25
+
26
+ /* Permissions */
27
+
28
+ const permissions = shield({
29
+ Query: {
30
+ allow: allow,
31
+ deny: deny,
32
+ },
33
+ })
34
+
35
+ const server = new ApolloServer({
36
+ schema: applyMiddleware(makeExecutableSchema({ typeDefs, resolvers }), permissions),
37
+ })
38
+
39
+ await server.listen({ port: 8008 })
40
+ const uri = `http://localhost:8008/`
41
+
42
+ /* Tests */
43
+
44
+ const query = `
45
+ query {
46
+ allow
47
+ deny
48
+ }
49
+ `
50
+
51
+ const res = await fetch(uri, {
52
+ method: 'POST',
53
+ body: JSON.stringify({ query }),
54
+ headers: { 'Content-Type': 'application/json' },
55
+ }).then((res) => res.json())
56
+
57
+ expect(res.data).toEqual({
58
+ allow: 'allow',
59
+ deny: null,
60
+ })
61
+ expect(res.errors.length).toBe(1)
62
+
63
+ await server.stop()
64
+ })
65
+ })