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.
Files changed (158) hide show
  1. package/README.md +138 -32
  2. package/bucket/b.txt +1 -0
  3. package/dev/index.ts +215 -0
  4. package/dist/authentication/Session.d.ts +4 -1
  5. package/dist/authentication/interface.d.ts +16 -0
  6. package/dist/email/interface.d.ts +1 -1
  7. package/dist/graphql/resolvers.d.ts +4 -2
  8. package/dist/hooks/index.d.ts +1 -0
  9. package/dist/index.d.ts +0 -1
  10. package/dist/index.js +8713 -8867
  11. package/dist/server/index.d.ts +4 -2
  12. package/dist/utils/crypto.d.ts +7 -0
  13. package/dist/utils/helper.d.ts +4 -1
  14. package/generated/schema.graphql +16 -14
  15. package/generated/wabe.ts +4 -4
  16. package/package.json +15 -15
  17. package/src/authentication/OTP.test.ts +69 -0
  18. package/src/authentication/OTP.ts +66 -0
  19. package/src/authentication/Session.test.ts +665 -0
  20. package/src/authentication/Session.ts +529 -0
  21. package/src/authentication/defaultAuthentication.ts +214 -0
  22. package/src/authentication/index.ts +3 -0
  23. package/src/authentication/interface.ts +157 -0
  24. package/src/authentication/oauth/GitHub.test.ts +105 -0
  25. package/src/authentication/oauth/GitHub.ts +133 -0
  26. package/src/authentication/oauth/Google.test.ts +105 -0
  27. package/src/authentication/oauth/Google.ts +110 -0
  28. package/src/authentication/oauth/Oauth2Client.test.ts +225 -0
  29. package/src/authentication/oauth/Oauth2Client.ts +140 -0
  30. package/src/authentication/oauth/index.ts +2 -0
  31. package/src/authentication/oauth/utils.test.ts +35 -0
  32. package/src/authentication/oauth/utils.ts +28 -0
  33. package/src/authentication/providers/EmailOTP.test.ts +138 -0
  34. package/src/authentication/providers/EmailOTP.ts +93 -0
  35. package/src/authentication/providers/EmailPassword.test.ts +187 -0
  36. package/src/authentication/providers/EmailPassword.ts +130 -0
  37. package/src/authentication/providers/EmailPasswordSRP.test.ts +206 -0
  38. package/src/authentication/providers/EmailPasswordSRP.ts +184 -0
  39. package/src/authentication/providers/GitHub.ts +30 -0
  40. package/src/authentication/providers/Google.ts +30 -0
  41. package/src/authentication/providers/OAuth.test.ts +185 -0
  42. package/src/authentication/providers/OAuth.ts +112 -0
  43. package/src/authentication/providers/PhonePassword.test.ts +187 -0
  44. package/src/authentication/providers/PhonePassword.ts +129 -0
  45. package/src/authentication/providers/QRCodeOTP.test.ts +79 -0
  46. package/src/authentication/providers/QRCodeOTP.ts +65 -0
  47. package/src/authentication/providers/index.ts +6 -0
  48. package/src/authentication/resolvers/refreshResolver.test.ts +37 -0
  49. package/src/authentication/resolvers/refreshResolver.ts +20 -0
  50. package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
  51. package/src/authentication/resolvers/signInWithResolver.test.ts +307 -0
  52. package/src/authentication/resolvers/signInWithResolver.ts +102 -0
  53. package/src/authentication/resolvers/signOutResolver.test.ts +41 -0
  54. package/src/authentication/resolvers/signOutResolver.ts +22 -0
  55. package/src/authentication/resolvers/signUpWithResolver.test.ts +186 -0
  56. package/src/authentication/resolvers/signUpWithResolver.ts +69 -0
  57. package/src/authentication/resolvers/verifyChallenge.test.ts +136 -0
  58. package/src/authentication/resolvers/verifyChallenge.ts +69 -0
  59. package/src/authentication/roles.test.ts +59 -0
  60. package/src/authentication/roles.ts +40 -0
  61. package/src/authentication/utils.test.ts +99 -0
  62. package/src/authentication/utils.ts +43 -0
  63. package/src/cache/InMemoryCache.test.ts +62 -0
  64. package/src/cache/InMemoryCache.ts +45 -0
  65. package/src/cron/index.test.ts +17 -0
  66. package/src/cron/index.ts +46 -0
  67. package/src/database/DatabaseController.test.ts +625 -0
  68. package/src/database/DatabaseController.ts +983 -0
  69. package/src/database/index.test.ts +1230 -0
  70. package/src/database/index.ts +9 -0
  71. package/src/database/interface.ts +312 -0
  72. package/src/email/DevAdapter.ts +8 -0
  73. package/src/email/EmailController.test.ts +29 -0
  74. package/src/email/EmailController.ts +13 -0
  75. package/src/email/index.ts +2 -0
  76. package/src/email/interface.ts +36 -0
  77. package/src/email/templates/sendOtpCode.ts +120 -0
  78. package/src/file/FileController.ts +28 -0
  79. package/src/file/FileDevAdapter.ts +54 -0
  80. package/src/file/hookDeleteFile.ts +27 -0
  81. package/src/file/hookReadFile.ts +70 -0
  82. package/src/file/hookUploadFile.ts +53 -0
  83. package/src/file/index.test.ts +979 -0
  84. package/src/file/index.ts +2 -0
  85. package/src/file/interface.ts +42 -0
  86. package/src/graphql/GraphQLSchema.test.ts +4399 -0
  87. package/src/graphql/GraphQLSchema.ts +928 -0
  88. package/src/graphql/index.ts +2 -0
  89. package/src/graphql/parseGraphqlSchema.ts +94 -0
  90. package/src/graphql/parser.test.ts +217 -0
  91. package/src/graphql/parser.ts +566 -0
  92. package/src/graphql/pointerAndRelationFunction.ts +200 -0
  93. package/src/graphql/resolvers.ts +467 -0
  94. package/src/graphql/tests/aggregation.test.ts +1123 -0
  95. package/src/graphql/tests/e2e.test.ts +596 -0
  96. package/src/graphql/tests/scalars.test.ts +250 -0
  97. package/src/graphql/types.ts +219 -0
  98. package/src/hooks/HookObject.test.ts +122 -0
  99. package/src/hooks/HookObject.ts +168 -0
  100. package/src/hooks/authentication.ts +76 -0
  101. package/src/hooks/createUser.test.ts +77 -0
  102. package/src/hooks/createUser.ts +10 -0
  103. package/src/hooks/defaultFields.test.ts +187 -0
  104. package/src/hooks/defaultFields.ts +40 -0
  105. package/src/hooks/deleteSession.test.ts +181 -0
  106. package/src/hooks/deleteSession.ts +20 -0
  107. package/src/hooks/hashFieldHook.test.ts +163 -0
  108. package/src/hooks/hashFieldHook.ts +97 -0
  109. package/src/hooks/index.test.ts +207 -0
  110. package/src/hooks/index.ts +430 -0
  111. package/src/hooks/permissions.test.ts +424 -0
  112. package/src/hooks/permissions.ts +113 -0
  113. package/src/hooks/protected.test.ts +551 -0
  114. package/src/hooks/protected.ts +72 -0
  115. package/src/hooks/searchableFields.test.ts +166 -0
  116. package/src/hooks/searchableFields.ts +98 -0
  117. package/src/hooks/session.test.ts +138 -0
  118. package/src/hooks/session.ts +78 -0
  119. package/src/hooks/setEmail.test.ts +216 -0
  120. package/src/hooks/setEmail.ts +35 -0
  121. package/src/hooks/setupAcl.test.ts +589 -0
  122. package/src/hooks/setupAcl.ts +29 -0
  123. package/src/index.ts +9 -0
  124. package/src/schema/Schema.test.ts +484 -0
  125. package/src/schema/Schema.ts +795 -0
  126. package/src/schema/defaultResolvers.ts +94 -0
  127. package/src/schema/index.ts +1 -0
  128. package/src/schema/resolvers/meResolver.test.ts +62 -0
  129. package/src/schema/resolvers/meResolver.ts +14 -0
  130. package/src/schema/resolvers/newFile.ts +0 -0
  131. package/src/schema/resolvers/resetPassword.test.ts +345 -0
  132. package/src/schema/resolvers/resetPassword.ts +64 -0
  133. package/src/schema/resolvers/sendEmail.test.ts +118 -0
  134. package/src/schema/resolvers/sendEmail.ts +21 -0
  135. package/src/schema/resolvers/sendOtpCode.test.ts +153 -0
  136. package/src/schema/resolvers/sendOtpCode.ts +52 -0
  137. package/src/security.test.ts +3461 -0
  138. package/src/server/defaultSessionHandler.test.ts +66 -0
  139. package/src/server/defaultSessionHandler.ts +115 -0
  140. package/src/server/generateCodegen.ts +476 -0
  141. package/src/server/index.test.ts +552 -0
  142. package/src/server/index.ts +354 -0
  143. package/src/server/interface.ts +11 -0
  144. package/src/server/routes/authHandler.ts +187 -0
  145. package/src/server/routes/index.ts +40 -0
  146. package/src/utils/crypto.test.ts +41 -0
  147. package/src/utils/crypto.ts +121 -0
  148. package/src/utils/export.ts +13 -0
  149. package/src/utils/helper.ts +195 -0
  150. package/src/utils/index.test.ts +11 -0
  151. package/src/utils/index.ts +201 -0
  152. package/src/utils/preload.ts +8 -0
  153. package/src/utils/testHelper.ts +117 -0
  154. package/tsconfig.json +32 -0
  155. package/bunfig.toml +0 -4
  156. package/dist/ai/index.d.ts +0 -1
  157. package/dist/ai/interface.d.ts +0 -9
  158. /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
@@ -0,0 +1,307 @@
1
+ import { describe, expect, it, mock, spyOn, afterEach } from 'bun:test'
2
+ import { signInWithResolver } from './signInWithResolver'
3
+ import { Session } from '../Session'
4
+ import { SecondaryFactor } from '../interface'
5
+
6
+ describe('SignInWith', () => {
7
+ const mockOnLogin = mock(() =>
8
+ Promise.resolve({
9
+ user: {
10
+ id: 'id',
11
+ },
12
+ }),
13
+ )
14
+ const mockOnSignUp = mock(() =>
15
+ Promise.resolve({
16
+ authenticationDataToSave: {
17
+ id: 'id',
18
+ },
19
+ }),
20
+ )
21
+
22
+ const mockCreateObject = mock(() => Promise.resolve({}))
23
+
24
+ const mockOnSendChallenge = mock(() => Promise.resolve())
25
+ const mockOnVerifyChallenge = mock(() => Promise.resolve(true))
26
+
27
+ const context = {
28
+ wabe: {
29
+ config: {
30
+ authentication: {
31
+ session: {
32
+ cookieSession: true,
33
+ },
34
+ customAuthenticationMethods: [
35
+ {
36
+ name: 'emailPassword',
37
+ input: {
38
+ email: { type: 'Email', required: true },
39
+ password: { type: 'String', required: true },
40
+ },
41
+ provider: {
42
+ onSignUp: mockOnSignUp,
43
+ onSignIn: mockOnLogin,
44
+ },
45
+ },
46
+ {
47
+ name: 'emailOTP',
48
+ input: {
49
+ email: {
50
+ type: 'Email',
51
+ required: true,
52
+ },
53
+ code: {
54
+ type: 'String',
55
+ required: true,
56
+ },
57
+ },
58
+ provider: {
59
+ onSendChallenge: mockOnSendChallenge,
60
+ onVerifyChallenge: mockOnVerifyChallenge,
61
+ },
62
+ },
63
+ ],
64
+ },
65
+ },
66
+ },
67
+ }
68
+
69
+ afterEach(() => {
70
+ mockCreateObject.mockClear()
71
+ mockOnLogin.mockClear()
72
+ mockOnSignUp.mockClear()
73
+ })
74
+
75
+ it('should call the secondary factor authentication on signIn', async () => {
76
+ mockOnLogin.mockResolvedValueOnce({
77
+ user: {
78
+ id: 'id',
79
+ // @ts-expect-error
80
+ email: 'email@test.fr',
81
+ secondFA: {
82
+ enabled: true,
83
+ provider: SecondaryFactor.EmailOTP,
84
+ },
85
+ },
86
+ })
87
+
88
+ const res = await signInWithResolver(
89
+ {},
90
+ {
91
+ input: {
92
+ authentication: {
93
+ emailPassword: {
94
+ email: 'email@test.fr',
95
+ password: 'password',
96
+ },
97
+ },
98
+ },
99
+ },
100
+ // @ts-expect-error
101
+ context,
102
+ )
103
+
104
+ expect(mockOnLogin).toHaveBeenCalledTimes(1)
105
+ expect(mockOnLogin).toHaveBeenCalledWith({
106
+ input: {
107
+ email: 'email@test.fr',
108
+ password: 'password',
109
+ },
110
+ context: expect.any(Object),
111
+ })
112
+
113
+ expect(mockOnSendChallenge).toHaveBeenCalledTimes(1)
114
+ expect(mockOnSendChallenge).toHaveBeenCalledWith({
115
+ context: expect.any(Object),
116
+ user: expect.objectContaining({
117
+ email: 'email@test.fr',
118
+ }),
119
+ })
120
+
121
+ expect(res).toEqual({
122
+ accessToken: null,
123
+ refreshToken: null,
124
+ user: {
125
+ id: 'id',
126
+ email: 'email@test.fr',
127
+ secondFA: {
128
+ enabled: true,
129
+ // @ts-expect-error
130
+ provider: SecondaryFactor.EmailOTP,
131
+ },
132
+ },
133
+ })
134
+ })
135
+
136
+ it('should throw an error if no custom authentication configuration is provided', () => {
137
+ expect(
138
+ signInWithResolver(
139
+ {},
140
+ {
141
+ input: {
142
+ authentication: {
143
+ emailPassword: {
144
+ email: 'email@test.fr',
145
+ password: 'password',
146
+ },
147
+ },
148
+ },
149
+ },
150
+ { wabe: { config: { authentication: undefined } } } as any,
151
+ ),
152
+ ).rejects.toThrow('No custom authentication methods found')
153
+ })
154
+
155
+ it('should throw an error if a custom authentication is provided but not in the custom authentication config', () => {
156
+ expect(
157
+ signInWithResolver(
158
+ {},
159
+ {
160
+ input: {
161
+ authentication: {
162
+ emailPassword: {
163
+ email: 'email@test.fr',
164
+ password: 'password',
165
+ },
166
+ },
167
+ },
168
+ },
169
+ {
170
+ wabe: {
171
+ config: {
172
+ authentication: {
173
+ customAuthenticationMethods: [
174
+ {
175
+ name: 'phonePassword',
176
+ input: {
177
+ email: {
178
+ type: 'Email',
179
+ required: true,
180
+ },
181
+ password: {
182
+ type: 'String',
183
+ required: true,
184
+ },
185
+ },
186
+ provider: {
187
+ onSignUp: mockOnSignUp,
188
+ onSignIn: mockOnLogin,
189
+ },
190
+ },
191
+ ],
192
+ },
193
+ },
194
+ },
195
+ } as any,
196
+ ),
197
+ ).rejects.toThrow('No available custom authentication methods found')
198
+ })
199
+
200
+ it('should signInWith email and password when the user already exist (on cookieSession)', async () => {
201
+ const mockCreateSession = spyOn(
202
+ Session.prototype,
203
+ 'create',
204
+ ).mockResolvedValue({
205
+ refreshToken: 'refreshToken',
206
+ accessToken: 'accessToken',
207
+ csrfToken: 'csrfToken',
208
+ } as any)
209
+
210
+ const mockSetCookie = mock(() => {})
211
+
212
+ const mockResponse = {
213
+ setCookie: mockSetCookie,
214
+ }
215
+
216
+ const res = await signInWithResolver(
217
+ {},
218
+ {
219
+ input: {
220
+ authentication: {
221
+ emailPassword: {
222
+ email: 'email@test.fr',
223
+ password: 'password',
224
+ },
225
+ },
226
+ },
227
+ },
228
+ {
229
+ ...context,
230
+ response: mockResponse,
231
+ } as any,
232
+ )
233
+
234
+ expect(res).toEqual({
235
+ accessToken: 'accessToken',
236
+ refreshToken: 'refreshToken',
237
+ csrfToken: 'csrfToken',
238
+ user: {
239
+ id: 'id',
240
+ },
241
+ srp: undefined,
242
+ })
243
+ expect(mockOnLogin).toHaveBeenCalledTimes(1)
244
+ expect(mockOnLogin).toHaveBeenCalledWith({
245
+ input: {
246
+ email: 'email@test.fr',
247
+ password: 'password',
248
+ },
249
+ context: expect.any(Object),
250
+ })
251
+
252
+ expect(mockSetCookie).toHaveBeenCalledTimes(3)
253
+ expect(mockSetCookie).toHaveBeenNthCalledWith(
254
+ 1,
255
+ 'refreshToken',
256
+ 'refreshToken',
257
+ {
258
+ httpOnly: true,
259
+ path: '/',
260
+ secure: true,
261
+ sameSite: 'Strict',
262
+ expires: expect.any(Date),
263
+ },
264
+ )
265
+
266
+ expect(mockSetCookie).toHaveBeenNthCalledWith(
267
+ 2,
268
+ 'accessToken',
269
+ 'accessToken',
270
+ {
271
+ httpOnly: true,
272
+ path: '/',
273
+ secure: true,
274
+ sameSite: 'Strict',
275
+ expires: expect.any(Date),
276
+ },
277
+ )
278
+
279
+ expect(mockSetCookie).toHaveBeenNthCalledWith(3, 'csrfToken', 'csrfToken', {
280
+ httpOnly: true,
281
+ path: '/',
282
+ secure: true,
283
+ sameSite: 'Strict',
284
+ expires: expect.any(Date),
285
+ })
286
+
287
+ // @ts-expect-error
288
+ const refreshTokenExpiresIn = mockSetCookie.mock.calls[0][2].expires
289
+ // @ts-expect-error
290
+ const accessTokenExpiresIn = mockSetCookie.mock.calls[1][2].expires
291
+
292
+ // - 1000 to avoid flaky
293
+ expect(refreshTokenExpiresIn.getTime() - Date.now()).toBeGreaterThanOrEqual(
294
+ 1000 * 7 * 24 * 60 * 60 - 1000,
295
+ )
296
+ expect(accessTokenExpiresIn.getTime() - Date.now()).toBeGreaterThanOrEqual(
297
+ 1000 * 15 * 60 - 1000,
298
+ )
299
+
300
+ expect(mockCreateSession).toHaveBeenCalledTimes(1)
301
+ expect(mockCreateSession).toHaveBeenCalledWith('id', expect.anything())
302
+
303
+ expect(mockOnSignUp).toHaveBeenCalledTimes(0)
304
+
305
+ mockCreateSession.mockRestore()
306
+ })
307
+ })
@@ -0,0 +1,102 @@
1
+ import type { SignInWithInput } from '../../../generated/wabe'
2
+ import type { WabeContext } from '../../server/interface'
3
+ import type { DevWabeTypes } from '../../utils/helper'
4
+ import { Session } from '../Session'
5
+ import type {
6
+ ProviderInterface,
7
+ SecondaryProviderInterface,
8
+ } from '../interface'
9
+ import { getAuthenticationMethod } from '../utils'
10
+
11
+ // 0 - Get the authentication method
12
+ // 1 - We check if the signIn is possible (call onSign)
13
+ // 2 - If secondaryFactor is present, we call the onSendChallenge method of the provider
14
+ // 3 - We create session
15
+ export const signInWithResolver = async (
16
+ _: any,
17
+ {
18
+ input,
19
+ }: {
20
+ input: SignInWithInput
21
+ },
22
+ context: WabeContext<DevWabeTypes>,
23
+ ) => {
24
+ const { provider, name } = getAuthenticationMethod<
25
+ DevWabeTypes,
26
+ ProviderInterface<DevWabeTypes>
27
+ >(Object.keys(input.authentication || {}), context)
28
+
29
+ const inputOfTheGoodAuthenticationMethod =
30
+ // @ts-expect-error
31
+ input.authentication[name]
32
+
33
+ // 1 - We call the onSignIn method of the provider
34
+ const { user, srp } = await provider.onSignIn({
35
+ input: inputOfTheGoodAuthenticationMethod,
36
+ context,
37
+ })
38
+
39
+ const userId = user.id
40
+
41
+ if (!userId) throw new Error('Authentication failed')
42
+
43
+ const secondFAObject = user.secondFA
44
+
45
+ // 2 - We call the onSendChallenge method of the provider
46
+ if (secondFAObject?.enabled) {
47
+ const secondaryProvider = getAuthenticationMethod<
48
+ DevWabeTypes,
49
+ SecondaryProviderInterface<DevWabeTypes>
50
+ >([secondFAObject.provider], context)
51
+
52
+ await secondaryProvider.provider.onSendChallenge?.({
53
+ context,
54
+ // @ts-expect-error
55
+ user,
56
+ })
57
+
58
+ return { accessToken: null, refreshToken: null, user }
59
+ }
60
+
61
+ const session = new Session()
62
+
63
+ const { refreshToken, accessToken, csrfToken } = await session.create(
64
+ userId,
65
+ context,
66
+ )
67
+
68
+ if (context.wabe.config.authentication?.session?.cookieSession) {
69
+ const accessTokenExpiresAt = session.getAccessTokenExpireAt(
70
+ context.wabe.config,
71
+ )
72
+ const refreshTokenExpiresAt = session.getRefreshTokenExpireAt(
73
+ context.wabe.config,
74
+ )
75
+
76
+ context.response?.setCookie('refreshToken', refreshToken, {
77
+ httpOnly: true,
78
+ path: '/',
79
+ sameSite: 'Strict',
80
+ secure: true,
81
+ expires: refreshTokenExpiresAt,
82
+ })
83
+
84
+ context.response?.setCookie('accessToken', accessToken, {
85
+ httpOnly: true,
86
+ path: '/',
87
+ sameSite: 'Strict',
88
+ secure: true,
89
+ expires: accessTokenExpiresAt,
90
+ })
91
+
92
+ context.response?.setCookie('csrfToken', csrfToken, {
93
+ httpOnly: true,
94
+ path: '/',
95
+ sameSite: 'Strict',
96
+ secure: true,
97
+ expires: accessTokenExpiresAt,
98
+ })
99
+ }
100
+
101
+ return { accessToken, refreshToken, csrfToken, user, srp }
102
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it, mock, spyOn } from 'bun:test'
2
+ import { signOutResolver } from './signOutResolver'
3
+ import { Session } from '../Session'
4
+
5
+ describe('signOut', () => {
6
+ const mockDeleteCookie = mock(() => {})
7
+
8
+ const context = {
9
+ sessionId: 'sessionId',
10
+ wabe: {
11
+ config: {
12
+ authentication: {
13
+ session: {
14
+ cookieSession: true,
15
+ },
16
+ },
17
+ },
18
+ },
19
+ response: {
20
+ deleteCookie: mockDeleteCookie,
21
+ },
22
+ } as any
23
+
24
+ it('should sign out the current user', async () => {
25
+ const spyDeleteSession = spyOn(
26
+ Session.prototype,
27
+ 'delete',
28
+ ).mockResolvedValue(undefined)
29
+
30
+ const res = await signOutResolver(undefined, {}, context)
31
+
32
+ expect(res).toBe(true)
33
+
34
+ expect(spyDeleteSession).toHaveBeenCalledTimes(1)
35
+ expect(spyDeleteSession).toHaveBeenCalledWith(context)
36
+
37
+ expect(mockDeleteCookie).toHaveBeenCalledTimes(2)
38
+ expect(mockDeleteCookie).toHaveBeenNthCalledWith(1, 'accessToken')
39
+ expect(mockDeleteCookie).toHaveBeenNthCalledWith(2, 'refreshToken')
40
+ })
41
+ })
@@ -0,0 +1,22 @@
1
+ import type { WabeContext } from '../../server/interface'
2
+ import type { DevWabeTypes } from '../../utils/helper'
3
+ import { Session } from '../Session'
4
+
5
+ export const signOutResolver = async (
6
+ _: any,
7
+ __: any,
8
+ context: WabeContext<DevWabeTypes>,
9
+ ) => {
10
+ const session = new Session()
11
+
12
+ // For the moment we only delete the session because we suppose the token
13
+ // are used with headers. We will need to delete the cookies in the future.
14
+ await session.delete(context)
15
+
16
+ if (context.wabe.config.authentication?.session?.cookieSession) {
17
+ context.response?.deleteCookie('accessToken')
18
+ context.response?.deleteCookie('refreshToken')
19
+ }
20
+
21
+ return true
22
+ }
@@ -0,0 +1,186 @@
1
+ import { beforeAll, afterAll, describe, expect, it, beforeEach } from 'bun:test'
2
+ import { type DevWabeTypes, getAnonymousClient } from '../../utils/helper'
3
+ import type { Wabe } from '../../server'
4
+ import { gql } from 'graphql-request'
5
+ import { setupTests, closeTests } from '../../utils/testHelper'
6
+
7
+ describe('SignUpWith', () => {
8
+ let wabe: Wabe<DevWabeTypes>
9
+
10
+ beforeAll(async () => {
11
+ const setup = await setupTests()
12
+ wabe = setup.wabe
13
+ })
14
+
15
+ beforeEach(async () => {
16
+ await wabe.controllers.database.clearDatabase()
17
+ })
18
+
19
+ afterAll(async () => {
20
+ await closeTests(wabe)
21
+ })
22
+
23
+ it('should throw an error if user already exist with emailPassword', async () => {
24
+ const anonymousClient = getAnonymousClient(wabe.config.port)
25
+
26
+ await anonymousClient.request<any>(
27
+ gql`
28
+ mutation signUpWith($input: SignUpWithInput!) {
29
+ signUpWith(input: $input) {
30
+ id
31
+ }
32
+ }
33
+ `,
34
+ {
35
+ input: {
36
+ authentication: {
37
+ emailPassword: {
38
+ email: 'test@gmail.com',
39
+ password: 'password',
40
+ },
41
+ },
42
+ },
43
+ },
44
+ )
45
+
46
+ expect(
47
+ anonymousClient.request<any>(
48
+ gql`
49
+ mutation signUpWith($input: SignUpWithInput!) {
50
+ signUpWith(input: $input) {
51
+ id
52
+ }
53
+ }
54
+ `,
55
+ {
56
+ input: {
57
+ authentication: {
58
+ emailPassword: {
59
+ email: 'test@gmail.com',
60
+ password: 'password',
61
+ },
62
+ },
63
+ },
64
+ },
65
+ ),
66
+ ).rejects.toThrow('Not authorized to create user')
67
+ })
68
+
69
+ it('should throw an error if the signUp is disabled', () => {
70
+ if (wabe.config) {
71
+ wabe.config.authentication = {
72
+ ...wabe.config.authentication,
73
+ disableSignUp: true,
74
+ }
75
+ }
76
+ const anonymousClient = getAnonymousClient(wabe.config.port)
77
+
78
+ const userSchema = wabe.config.schema?.classes?.find(
79
+ (classItem) => classItem.name === 'User',
80
+ )
81
+
82
+ if (!userSchema) throw new Error('Failed to find user schema')
83
+
84
+ // @ts-expect-error
85
+ userSchema.permissions.create.requireAuthentication = true
86
+
87
+ expect(
88
+ anonymousClient.request<any>(
89
+ gql`
90
+ mutation signUpWith($input: SignUpWithInput!) {
91
+ signUpWith(input: $input) {
92
+ id
93
+ }
94
+ }
95
+ `,
96
+ {
97
+ input: {
98
+ authentication: {
99
+ emailPassword: {
100
+ email: 'email@test.fr',
101
+ password: 'password',
102
+ },
103
+ },
104
+ },
105
+ },
106
+ ),
107
+ ).rejects.toThrow('SignUp is disabled')
108
+
109
+ if (wabe.config) {
110
+ wabe.config.authentication = {
111
+ ...wabe.config.authentication,
112
+ disableSignUp: false,
113
+ }
114
+ }
115
+ })
116
+
117
+ it('should block the signUpWith if the user creation is blocked for anonymous (the creation is done with root to avoid ACL issues)', () => {
118
+ const anonymousClient = getAnonymousClient(wabe.config.port)
119
+
120
+ const userSchema = wabe.config.schema?.classes?.find(
121
+ (classItem) => classItem.name === 'User',
122
+ )
123
+
124
+ if (!userSchema) throw new Error('Failed to find user schema')
125
+
126
+ // @ts-expect-error
127
+ userSchema.permissions.create.requireAuthentication = true
128
+
129
+ expect(
130
+ anonymousClient.request<any>(
131
+ gql`
132
+ mutation signUpWith($input: SignUpWithInput!) {
133
+ signUpWith(input: $input) {
134
+ id
135
+ }
136
+ }
137
+ `,
138
+ {
139
+ input: {
140
+ authentication: {
141
+ emailPassword: {
142
+ email: 'email@test.fr',
143
+ password: 'password',
144
+ },
145
+ },
146
+ },
147
+ },
148
+ ),
149
+ ).rejects.toThrow('Permission denied to create class User')
150
+
151
+ // @ts-expect-error
152
+ userSchema.permissions.create.requireAuthentication = false
153
+ })
154
+
155
+ it('should signUpWith email and password when the user not exist', async () => {
156
+ const anonymousClient = getAnonymousClient(wabe.config.port)
157
+
158
+ const res = await anonymousClient.request<any>(
159
+ gql`
160
+ mutation signUpWith($input: SignUpWithInput!) {
161
+ signUpWith(input: $input) {
162
+ id
163
+ accessToken
164
+ refreshToken
165
+ csrfToken
166
+ }
167
+ }
168
+ `,
169
+ {
170
+ input: {
171
+ authentication: {
172
+ emailPassword: {
173
+ email: 'test@gmail.com',
174
+ password: 'password',
175
+ },
176
+ },
177
+ },
178
+ },
179
+ )
180
+
181
+ expect(res.signUpWith.id).toEqual(expect.any(String))
182
+ expect(res.signUpWith.accessToken).toEqual(expect.any(String))
183
+ expect(res.signUpWith.refreshToken).toEqual(expect.any(String))
184
+ expect(res.signUpWith.csrfToken).toEqual(expect.any(String))
185
+ })
186
+ })