wabe 0.6.9 → 0.6.10
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.
- package/README.md +138 -32
- package/bucket/b.txt +1 -0
- package/dev/index.ts +215 -0
- package/dist/authentication/Session.d.ts +4 -1
- package/dist/authentication/interface.d.ts +16 -0
- package/dist/email/interface.d.ts +1 -1
- package/dist/graphql/resolvers.d.ts +4 -2
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +8713 -8867
- package/dist/server/index.d.ts +4 -2
- package/dist/utils/crypto.d.ts +7 -0
- package/dist/utils/helper.d.ts +4 -1
- package/generated/schema.graphql +16 -14
- package/generated/wabe.ts +4 -4
- package/package.json +15 -15
- package/src/authentication/OTP.test.ts +69 -0
- package/src/authentication/OTP.ts +66 -0
- package/src/authentication/Session.test.ts +665 -0
- package/src/authentication/Session.ts +529 -0
- package/src/authentication/defaultAuthentication.ts +214 -0
- package/src/authentication/index.ts +3 -0
- package/src/authentication/interface.ts +157 -0
- package/src/authentication/oauth/GitHub.test.ts +105 -0
- package/src/authentication/oauth/GitHub.ts +133 -0
- package/src/authentication/oauth/Google.test.ts +105 -0
- package/src/authentication/oauth/Google.ts +110 -0
- package/src/authentication/oauth/Oauth2Client.test.ts +225 -0
- package/src/authentication/oauth/Oauth2Client.ts +140 -0
- package/src/authentication/oauth/index.ts +2 -0
- package/src/authentication/oauth/utils.test.ts +35 -0
- package/src/authentication/oauth/utils.ts +28 -0
- package/src/authentication/providers/EmailOTP.test.ts +138 -0
- package/src/authentication/providers/EmailOTP.ts +93 -0
- package/src/authentication/providers/EmailPassword.test.ts +187 -0
- package/src/authentication/providers/EmailPassword.ts +130 -0
- package/src/authentication/providers/EmailPasswordSRP.test.ts +206 -0
- package/src/authentication/providers/EmailPasswordSRP.ts +184 -0
- package/src/authentication/providers/GitHub.ts +30 -0
- package/src/authentication/providers/Google.ts +30 -0
- package/src/authentication/providers/OAuth.test.ts +185 -0
- package/src/authentication/providers/OAuth.ts +112 -0
- package/src/authentication/providers/PhonePassword.test.ts +187 -0
- package/src/authentication/providers/PhonePassword.ts +129 -0
- package/src/authentication/providers/QRCodeOTP.test.ts +79 -0
- package/src/authentication/providers/QRCodeOTP.ts +65 -0
- package/src/authentication/providers/index.ts +6 -0
- package/src/authentication/resolvers/refreshResolver.test.ts +37 -0
- package/src/authentication/resolvers/refreshResolver.ts +20 -0
- package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
- package/src/authentication/resolvers/signInWithResolver.test.ts +307 -0
- package/src/authentication/resolvers/signInWithResolver.ts +102 -0
- package/src/authentication/resolvers/signOutResolver.test.ts +41 -0
- package/src/authentication/resolvers/signOutResolver.ts +22 -0
- package/src/authentication/resolvers/signUpWithResolver.test.ts +186 -0
- package/src/authentication/resolvers/signUpWithResolver.ts +69 -0
- package/src/authentication/resolvers/verifyChallenge.test.ts +136 -0
- package/src/authentication/resolvers/verifyChallenge.ts +69 -0
- package/src/authentication/roles.test.ts +59 -0
- package/src/authentication/roles.ts +40 -0
- package/src/authentication/utils.test.ts +99 -0
- package/src/authentication/utils.ts +43 -0
- package/src/cache/InMemoryCache.test.ts +62 -0
- package/src/cache/InMemoryCache.ts +45 -0
- package/src/cron/index.test.ts +17 -0
- package/src/cron/index.ts +46 -0
- package/src/database/DatabaseController.test.ts +625 -0
- package/src/database/DatabaseController.ts +983 -0
- package/src/database/index.test.ts +1230 -0
- package/src/database/index.ts +9 -0
- package/src/database/interface.ts +312 -0
- package/src/email/DevAdapter.ts +8 -0
- package/src/email/EmailController.test.ts +29 -0
- package/src/email/EmailController.ts +13 -0
- package/src/email/index.ts +2 -0
- package/src/email/interface.ts +36 -0
- package/src/email/templates/sendOtpCode.ts +120 -0
- package/src/file/FileController.ts +28 -0
- package/src/file/FileDevAdapter.ts +54 -0
- package/src/file/hookDeleteFile.ts +27 -0
- package/src/file/hookReadFile.ts +70 -0
- package/src/file/hookUploadFile.ts +53 -0
- package/src/file/index.test.ts +979 -0
- package/src/file/index.ts +2 -0
- package/src/file/interface.ts +42 -0
- package/src/graphql/GraphQLSchema.test.ts +4399 -0
- package/src/graphql/GraphQLSchema.ts +928 -0
- package/src/graphql/index.ts +2 -0
- package/src/graphql/parseGraphqlSchema.ts +94 -0
- package/src/graphql/parser.test.ts +217 -0
- package/src/graphql/parser.ts +566 -0
- package/src/graphql/pointerAndRelationFunction.ts +200 -0
- package/src/graphql/resolvers.ts +467 -0
- package/src/graphql/tests/aggregation.test.ts +1123 -0
- package/src/graphql/tests/e2e.test.ts +596 -0
- package/src/graphql/tests/scalars.test.ts +250 -0
- package/src/graphql/types.ts +219 -0
- package/src/hooks/HookObject.test.ts +122 -0
- package/src/hooks/HookObject.ts +168 -0
- package/src/hooks/authentication.ts +76 -0
- package/src/hooks/createUser.test.ts +77 -0
- package/src/hooks/createUser.ts +10 -0
- package/src/hooks/defaultFields.test.ts +187 -0
- package/src/hooks/defaultFields.ts +40 -0
- package/src/hooks/deleteSession.test.ts +181 -0
- package/src/hooks/deleteSession.ts +20 -0
- package/src/hooks/hashFieldHook.test.ts +163 -0
- package/src/hooks/hashFieldHook.ts +97 -0
- package/src/hooks/index.test.ts +207 -0
- package/src/hooks/index.ts +430 -0
- package/src/hooks/permissions.test.ts +424 -0
- package/src/hooks/permissions.ts +113 -0
- package/src/hooks/protected.test.ts +551 -0
- package/src/hooks/protected.ts +72 -0
- package/src/hooks/searchableFields.test.ts +166 -0
- package/src/hooks/searchableFields.ts +98 -0
- package/src/hooks/session.test.ts +138 -0
- package/src/hooks/session.ts +78 -0
- package/src/hooks/setEmail.test.ts +216 -0
- package/src/hooks/setEmail.ts +35 -0
- package/src/hooks/setupAcl.test.ts +589 -0
- package/src/hooks/setupAcl.ts +29 -0
- package/src/index.ts +9 -0
- package/src/schema/Schema.test.ts +484 -0
- package/src/schema/Schema.ts +795 -0
- package/src/schema/defaultResolvers.ts +94 -0
- package/src/schema/index.ts +1 -0
- package/src/schema/resolvers/meResolver.test.ts +62 -0
- package/src/schema/resolvers/meResolver.ts +14 -0
- package/src/schema/resolvers/newFile.ts +0 -0
- package/src/schema/resolvers/resetPassword.test.ts +345 -0
- package/src/schema/resolvers/resetPassword.ts +64 -0
- package/src/schema/resolvers/sendEmail.test.ts +118 -0
- package/src/schema/resolvers/sendEmail.ts +21 -0
- package/src/schema/resolvers/sendOtpCode.test.ts +153 -0
- package/src/schema/resolvers/sendOtpCode.ts +52 -0
- package/src/security.test.ts +3461 -0
- package/src/server/defaultSessionHandler.test.ts +66 -0
- package/src/server/defaultSessionHandler.ts +115 -0
- package/src/server/generateCodegen.ts +476 -0
- package/src/server/index.test.ts +552 -0
- package/src/server/index.ts +354 -0
- package/src/server/interface.ts +11 -0
- package/src/server/routes/authHandler.ts +187 -0
- package/src/server/routes/index.ts +40 -0
- package/src/utils/crypto.test.ts +41 -0
- package/src/utils/crypto.ts +121 -0
- package/src/utils/export.ts +13 -0
- package/src/utils/helper.ts +195 -0
- package/src/utils/index.test.ts +11 -0
- package/src/utils/index.ts +201 -0
- package/src/utils/preload.ts +8 -0
- package/src/utils/testHelper.ts +117 -0
- package/tsconfig.json +32 -0
- package/bunfig.toml +0 -4
- package/dist/ai/index.d.ts +0 -1
- package/dist/ai/interface.d.ts +0 -9
- /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import { describe, expect, it, beforeAll, afterAll } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
createUserAndUpdateRole,
|
|
4
|
+
type DevWabeTypes,
|
|
5
|
+
getAnonymousClient,
|
|
6
|
+
getGraphqlClient,
|
|
7
|
+
} from '../utils/helper'
|
|
8
|
+
import { setupTests, closeTests } from '../utils/testHelper'
|
|
9
|
+
import type { Wabe } from '../server'
|
|
10
|
+
import { RoleEnum } from '../../generated/wabe'
|
|
11
|
+
import { gql, type GraphQLClient } from 'graphql-request'
|
|
12
|
+
|
|
13
|
+
describe('Protected hook', () => {
|
|
14
|
+
let wabe: Wabe<DevWabeTypes>
|
|
15
|
+
let anonymousClient: GraphQLClient
|
|
16
|
+
let rootClient: GraphQLClient
|
|
17
|
+
|
|
18
|
+
beforeAll(async () => {
|
|
19
|
+
const setup = await setupTests([
|
|
20
|
+
{
|
|
21
|
+
name: 'Test',
|
|
22
|
+
fields: {
|
|
23
|
+
name: {
|
|
24
|
+
type: 'String',
|
|
25
|
+
protected: {
|
|
26
|
+
authorizedRoles: [RoleEnum.Client],
|
|
27
|
+
protectedOperations: ['update', 'read'],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
noOne: {
|
|
31
|
+
type: 'String',
|
|
32
|
+
protected: {
|
|
33
|
+
authorizedRoles: [],
|
|
34
|
+
protectedOperations: ['update', 'read'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
rootOnly: {
|
|
38
|
+
type: 'String',
|
|
39
|
+
protected: {
|
|
40
|
+
authorizedRoles: ['rootOnly'],
|
|
41
|
+
protectedOperations: ['update', 'read'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
notOperation: {
|
|
45
|
+
type: 'String',
|
|
46
|
+
protected: {
|
|
47
|
+
authorizedRoles: [RoleEnum.Client],
|
|
48
|
+
protectedOperations: ['update'],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
notOperationUpdate: {
|
|
52
|
+
type: 'String',
|
|
53
|
+
protected: {
|
|
54
|
+
authorizedRoles: [RoleEnum.Client],
|
|
55
|
+
protectedOperations: ['read'],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
permissions: {
|
|
60
|
+
read: {
|
|
61
|
+
authorizedRoles: ['everyone'],
|
|
62
|
+
requireAuthentication: true,
|
|
63
|
+
},
|
|
64
|
+
create: {
|
|
65
|
+
authorizedRoles: ['everyone'],
|
|
66
|
+
requireAuthentication: true,
|
|
67
|
+
},
|
|
68
|
+
update: {
|
|
69
|
+
authorizedRoles: ['everyone'],
|
|
70
|
+
requireAuthentication: true,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
])
|
|
75
|
+
wabe = setup.wabe
|
|
76
|
+
anonymousClient = getAnonymousClient(setup.port)
|
|
77
|
+
rootClient = getGraphqlClient(setup.port)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
afterAll(async () => {
|
|
81
|
+
await closeTests(wabe)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should not throw an error if the operation in not in the list of protected operations (read)', async () => {
|
|
85
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
86
|
+
anonymousClient,
|
|
87
|
+
rootClient,
|
|
88
|
+
roleName: RoleEnum.Client,
|
|
89
|
+
port: wabe.config.port,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
93
|
+
anonymousClient,
|
|
94
|
+
rootClient,
|
|
95
|
+
roleName: RoleEnum.Admin,
|
|
96
|
+
port: wabe.config.port,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
await userClient.request<any>(gql`
|
|
100
|
+
mutation createTest {
|
|
101
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
102
|
+
test {
|
|
103
|
+
name
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`)
|
|
108
|
+
|
|
109
|
+
expect(
|
|
110
|
+
userClient.request<any>(gql`
|
|
111
|
+
query tests {
|
|
112
|
+
tests {
|
|
113
|
+
edges {
|
|
114
|
+
node {
|
|
115
|
+
notOperation
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
`),
|
|
121
|
+
).resolves.toEqual(expect.anything())
|
|
122
|
+
|
|
123
|
+
expect(
|
|
124
|
+
userClient2.request<any>(gql`
|
|
125
|
+
query tests {
|
|
126
|
+
tests {
|
|
127
|
+
edges {
|
|
128
|
+
node {
|
|
129
|
+
notOperation
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`),
|
|
135
|
+
).resolves.toEqual(expect.anything())
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('should not throw an error if the operation in not in the list of protected operations (update)', async () => {
|
|
139
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
140
|
+
anonymousClient,
|
|
141
|
+
rootClient,
|
|
142
|
+
roleName: RoleEnum.Client,
|
|
143
|
+
port: wabe.config.port,
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
147
|
+
anonymousClient,
|
|
148
|
+
rootClient,
|
|
149
|
+
roleName: RoleEnum.Admin,
|
|
150
|
+
port: wabe.config.port,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
const res = await userClient.request<any>(gql`
|
|
154
|
+
mutation createTest {
|
|
155
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
156
|
+
test {
|
|
157
|
+
id
|
|
158
|
+
name
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
`)
|
|
163
|
+
|
|
164
|
+
expect(
|
|
165
|
+
userClient.request<any>(gql`
|
|
166
|
+
mutation updateTest {
|
|
167
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {notOperationUpdate: "test2"}}) {
|
|
168
|
+
ok
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
`),
|
|
172
|
+
).resolves.toEqual(expect.anything())
|
|
173
|
+
|
|
174
|
+
expect(
|
|
175
|
+
userClient2.request<any>(gql`
|
|
176
|
+
mutation updateTest {
|
|
177
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {notOperationUpdate: "test2"}}) {
|
|
178
|
+
ok
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
`),
|
|
182
|
+
).resolves.toEqual(expect.anything())
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it("should throw an error if the user doesn't have the right role on read", async () => {
|
|
186
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
187
|
+
anonymousClient,
|
|
188
|
+
rootClient,
|
|
189
|
+
roleName: RoleEnum.Client,
|
|
190
|
+
port: wabe.config.port,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
194
|
+
anonymousClient,
|
|
195
|
+
rootClient,
|
|
196
|
+
roleName: RoleEnum.Admin,
|
|
197
|
+
port: wabe.config.port,
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
await userClient.request<any>(gql`
|
|
201
|
+
mutation createTest {
|
|
202
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
203
|
+
test {
|
|
204
|
+
name
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
`)
|
|
209
|
+
|
|
210
|
+
expect(
|
|
211
|
+
userClient.request<any>(gql`
|
|
212
|
+
query tests {
|
|
213
|
+
tests {
|
|
214
|
+
edges {
|
|
215
|
+
node {
|
|
216
|
+
name
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
`),
|
|
222
|
+
).resolves.toEqual(expect.anything())
|
|
223
|
+
|
|
224
|
+
expect(
|
|
225
|
+
userClient2.request<any>(gql`
|
|
226
|
+
query tests {
|
|
227
|
+
tests {
|
|
228
|
+
edges {
|
|
229
|
+
node {
|
|
230
|
+
name
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
`),
|
|
236
|
+
).rejects.toThrowError('You are not authorized to read this field')
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it("should throw an error if the user doesn't have the right role on update", async () => {
|
|
240
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
241
|
+
anonymousClient,
|
|
242
|
+
rootClient,
|
|
243
|
+
roleName: RoleEnum.Client,
|
|
244
|
+
port: wabe.config.port,
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
248
|
+
anonymousClient,
|
|
249
|
+
rootClient,
|
|
250
|
+
roleName: RoleEnum.Admin,
|
|
251
|
+
port: wabe.config.port,
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
const res = await userClient.request<any>(gql`
|
|
255
|
+
mutation createTest {
|
|
256
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
257
|
+
test {
|
|
258
|
+
id
|
|
259
|
+
name
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
`)
|
|
264
|
+
|
|
265
|
+
await userClient.request<any>(gql`
|
|
266
|
+
mutation updateTest {
|
|
267
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {name: "test2"}}) {
|
|
268
|
+
test {
|
|
269
|
+
id
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
`)
|
|
274
|
+
|
|
275
|
+
expect(
|
|
276
|
+
userClient2.request<any>(gql`
|
|
277
|
+
mutation updateTest {
|
|
278
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {name: "test2"}}) {
|
|
279
|
+
test {
|
|
280
|
+
name
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
`),
|
|
285
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('should throw an error no one have the right role on read', async () => {
|
|
289
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
290
|
+
anonymousClient,
|
|
291
|
+
rootClient,
|
|
292
|
+
roleName: RoleEnum.Client,
|
|
293
|
+
port: wabe.config.port,
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
297
|
+
anonymousClient,
|
|
298
|
+
rootClient,
|
|
299
|
+
roleName: RoleEnum.Admin,
|
|
300
|
+
port: wabe.config.port,
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
await userClient.request<any>(gql`
|
|
304
|
+
mutation createTest {
|
|
305
|
+
createTest(input: {fields: {noOne: "test"}}) {
|
|
306
|
+
test {
|
|
307
|
+
id
|
|
308
|
+
name
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
`)
|
|
313
|
+
|
|
314
|
+
expect(
|
|
315
|
+
rootClient.request<any>(gql`
|
|
316
|
+
query tests {
|
|
317
|
+
tests {
|
|
318
|
+
edges {
|
|
319
|
+
node {
|
|
320
|
+
noOne
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
`),
|
|
326
|
+
).rejects.toThrowError('You are not authorized to read this field')
|
|
327
|
+
|
|
328
|
+
expect(
|
|
329
|
+
userClient.request<any>(gql`
|
|
330
|
+
query tests {
|
|
331
|
+
tests {
|
|
332
|
+
edges {
|
|
333
|
+
node {
|
|
334
|
+
noOne
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
`),
|
|
340
|
+
).rejects.toThrowError('You are not authorized to read this field')
|
|
341
|
+
|
|
342
|
+
expect(
|
|
343
|
+
userClient2.request<any>(gql`
|
|
344
|
+
query tests {
|
|
345
|
+
tests {
|
|
346
|
+
edges {
|
|
347
|
+
node {
|
|
348
|
+
noOne
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
`),
|
|
354
|
+
).rejects.toThrowError('You are not authorized to read this field')
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('should throw an error no one have the right role on update', async () => {
|
|
358
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
359
|
+
anonymousClient,
|
|
360
|
+
rootClient,
|
|
361
|
+
roleName: RoleEnum.Client,
|
|
362
|
+
port: wabe.config.port,
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
366
|
+
anonymousClient,
|
|
367
|
+
rootClient,
|
|
368
|
+
roleName: RoleEnum.Admin,
|
|
369
|
+
port: wabe.config.port,
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
const res = await userClient.request<any>(gql`
|
|
373
|
+
mutation createTest {
|
|
374
|
+
createTest(input: {fields: {noOne: "test"}}) {
|
|
375
|
+
test {
|
|
376
|
+
id
|
|
377
|
+
name
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
`)
|
|
382
|
+
|
|
383
|
+
expect(
|
|
384
|
+
rootClient.request<any>(gql`
|
|
385
|
+
mutation updateTest {
|
|
386
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {noOne: "test2"}}) {
|
|
387
|
+
test {
|
|
388
|
+
id
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
`),
|
|
393
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
394
|
+
|
|
395
|
+
expect(
|
|
396
|
+
userClient.request<any>(gql`
|
|
397
|
+
mutation updateTest {
|
|
398
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {noOne: "test2"}}) {
|
|
399
|
+
test {
|
|
400
|
+
id
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
`),
|
|
405
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
406
|
+
|
|
407
|
+
expect(
|
|
408
|
+
userClient2.request<any>(gql`
|
|
409
|
+
mutation updateTest {
|
|
410
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {name: "test2"}}) {
|
|
411
|
+
test {
|
|
412
|
+
name
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`),
|
|
417
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
it('should allow only root to read a field protected by rootOnly', async () => {
|
|
421
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
422
|
+
anonymousClient,
|
|
423
|
+
rootClient,
|
|
424
|
+
roleName: RoleEnum.Client,
|
|
425
|
+
port: wabe.config.port,
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
429
|
+
anonymousClient,
|
|
430
|
+
rootClient,
|
|
431
|
+
roleName: RoleEnum.Admin,
|
|
432
|
+
port: wabe.config.port,
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
await rootClient.request<any>(gql`
|
|
436
|
+
mutation createTest {
|
|
437
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
438
|
+
test {
|
|
439
|
+
id
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
`)
|
|
444
|
+
|
|
445
|
+
expect(
|
|
446
|
+
rootClient.request<any>(gql`
|
|
447
|
+
query tests {
|
|
448
|
+
tests {
|
|
449
|
+
edges {
|
|
450
|
+
node {
|
|
451
|
+
rootOnly
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
`),
|
|
457
|
+
).resolves.toEqual(expect.anything())
|
|
458
|
+
|
|
459
|
+
expect(
|
|
460
|
+
userClient.request<any>(gql`
|
|
461
|
+
query tests {
|
|
462
|
+
tests {
|
|
463
|
+
edges {
|
|
464
|
+
node {
|
|
465
|
+
rootOnly
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
`),
|
|
471
|
+
).rejects.toThrow('You are not authorized to read this field')
|
|
472
|
+
|
|
473
|
+
expect(
|
|
474
|
+
userClient2.request<any>(gql`
|
|
475
|
+
query tests {
|
|
476
|
+
tests {
|
|
477
|
+
edges {
|
|
478
|
+
node {
|
|
479
|
+
rootOnly
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
`),
|
|
485
|
+
).rejects.toThrowError('You are not authorized to read this field')
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('should allow only root to update a field protected by rootOnly', async () => {
|
|
489
|
+
const { userClient } = await createUserAndUpdateRole({
|
|
490
|
+
anonymousClient,
|
|
491
|
+
rootClient,
|
|
492
|
+
roleName: RoleEnum.Client,
|
|
493
|
+
port: wabe.config.port,
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
const { userClient: userClient2 } = await createUserAndUpdateRole({
|
|
497
|
+
anonymousClient,
|
|
498
|
+
rootClient,
|
|
499
|
+
roleName: RoleEnum.Admin,
|
|
500
|
+
port: wabe.config.port,
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
const res = await rootClient.request<any>(gql`
|
|
504
|
+
mutation createTest {
|
|
505
|
+
createTest(input: {fields: {name: "test"}}) {
|
|
506
|
+
test {
|
|
507
|
+
id
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
`)
|
|
512
|
+
|
|
513
|
+
// Root client should be able to update
|
|
514
|
+
expect(
|
|
515
|
+
rootClient.request<any>(gql`
|
|
516
|
+
mutation updateTest {
|
|
517
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {rootOnly: "updatedTest"}}) {
|
|
518
|
+
test {
|
|
519
|
+
rootOnly
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
`),
|
|
524
|
+
).resolves.toEqual(expect.anything())
|
|
525
|
+
|
|
526
|
+
// User clients should not be able to update
|
|
527
|
+
expect(
|
|
528
|
+
userClient.request<any>(gql`
|
|
529
|
+
mutation updateTest {
|
|
530
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {rootOnly: "updatedTest"}}) {
|
|
531
|
+
test {
|
|
532
|
+
rootOnly
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
`),
|
|
537
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
538
|
+
|
|
539
|
+
expect(
|
|
540
|
+
userClient2.request<any>(gql`
|
|
541
|
+
mutation updateTest {
|
|
542
|
+
updateTest(input: {id: "${res.createTest.test.id}", fields: {rootOnly: "updatedTest"}}) {
|
|
543
|
+
test {
|
|
544
|
+
rootOnly
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
`),
|
|
549
|
+
).rejects.toThrowError('You are not authorized to update this field')
|
|
550
|
+
})
|
|
551
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { OperationType } from '.'
|
|
2
|
+
import type { DevWabeTypes } from '../utils/helper'
|
|
3
|
+
import type { HookObject } from './HookObject'
|
|
4
|
+
|
|
5
|
+
const _checkProtected = (
|
|
6
|
+
hookObject: HookObject<DevWabeTypes, any>,
|
|
7
|
+
operationType: OperationType,
|
|
8
|
+
) => {
|
|
9
|
+
const schemaClass = hookObject.context.wabe.config.schema?.classes?.find(
|
|
10
|
+
(currentClass) => currentClass.name === hookObject.className,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
if (!schemaClass) return
|
|
14
|
+
|
|
15
|
+
const userRole = hookObject.getUser()?.role?.name || ''
|
|
16
|
+
const isRoot = hookObject.context.isRoot
|
|
17
|
+
|
|
18
|
+
if (operationType === OperationType.BeforeRead) {
|
|
19
|
+
Object.keys(hookObject.select).forEach((fieldName) => {
|
|
20
|
+
const protectedForCurrentField = schemaClass.fields[fieldName]?.protected
|
|
21
|
+
|
|
22
|
+
if (!protectedForCurrentField) return
|
|
23
|
+
|
|
24
|
+
if (protectedForCurrentField?.protectedOperations.includes('read')) {
|
|
25
|
+
if (
|
|
26
|
+
isRoot &&
|
|
27
|
+
protectedForCurrentField.authorizedRoles.includes('rootOnly')
|
|
28
|
+
)
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error
|
|
32
|
+
if (!protectedForCurrentField.authorizedRoles.includes(userRole))
|
|
33
|
+
throw new Error('You are not authorized to read this field')
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const fieldsUpdated = hookObject.getNewData()
|
|
41
|
+
|
|
42
|
+
const operation =
|
|
43
|
+
operationType === OperationType.BeforeUpdate ? 'update' : 'create'
|
|
44
|
+
|
|
45
|
+
Object.keys(fieldsUpdated).forEach((fieldName) => {
|
|
46
|
+
const protectedForCurrentField = schemaClass.fields[fieldName]?.protected
|
|
47
|
+
|
|
48
|
+
if (protectedForCurrentField?.protectedOperations.includes(operation)) {
|
|
49
|
+
if (
|
|
50
|
+
isRoot &&
|
|
51
|
+
protectedForCurrentField.authorizedRoles.includes('rootOnly')
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
// @ts-expect-error
|
|
56
|
+
if (!protectedForCurrentField.authorizedRoles.includes(userRole))
|
|
57
|
+
throw new Error(`You are not authorized to ${operation} this field`)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const defaultCheckProtectedOnBeforeRead = (
|
|
63
|
+
object: HookObject<DevWabeTypes, any>,
|
|
64
|
+
) => _checkProtected(object, OperationType.BeforeRead)
|
|
65
|
+
|
|
66
|
+
export const defaultCheckProtectedOnBeforeUpdate = (
|
|
67
|
+
object: HookObject<DevWabeTypes, any>,
|
|
68
|
+
) => _checkProtected(object, OperationType.BeforeUpdate)
|
|
69
|
+
|
|
70
|
+
export const defaultCheckProtectedOnBeforeCreate = (
|
|
71
|
+
object: HookObject<DevWabeTypes, any>,
|
|
72
|
+
) => _checkProtected(object, OperationType.BeforeCreate)
|