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,184 @@
1
+ import type {
2
+ AuthenticationEventsOptions,
3
+ OnVerifyChallengeOptions,
4
+ ProviderInterface,
5
+ SecondaryProviderInterface,
6
+ } from '../interface'
7
+ import { contextWithRoot } from '../../utils/export'
8
+ import type { DevWabeTypes } from '../../utils/helper'
9
+ import { createSRPServer, type Ephemeral, type Session } from 'js-srp6a'
10
+
11
+ // 🛡 Valeurs factices pour mitigation des timing attacks
12
+ const DUMMY_SALT = 'deadbeefdeadbeefdeadbeefdeadbeef'
13
+ const DUMMY_VERIFIER =
14
+ '94c8f9b69f44fa0453a8a65129a7865ea2d70b21e645cf185d6fd42a679e524c394d4f02bba2032b10517be8c80f0f58e94302cb57cce7ce1e0a21906b6d22020b84a473d8ef58ea1f53e5204f8b83f05dc334b781fda309ad7cb8fa5c91dc81f64c114b671688b22e0f693a9c97ad2f43e6f1954c83d73e81e3dc8a963b7cbce'
15
+
16
+ type EmailPasswordSRPInterface = {
17
+ clientPublic: string
18
+ email: string
19
+ salt?: string
20
+ verifier?: string
21
+ }
22
+
23
+ export class EmailPasswordSRP
24
+ implements ProviderInterface<DevWabeTypes, EmailPasswordSRPInterface>
25
+ {
26
+ async onSignIn({
27
+ input,
28
+ context,
29
+ }: AuthenticationEventsOptions<DevWabeTypes, EmailPasswordSRPInterface>) {
30
+ const server = createSRPServer('SHA-256', 3072)
31
+
32
+ const users = await context.wabe.controllers.database.getObjects({
33
+ className: 'User',
34
+ context: contextWithRoot(context),
35
+ where: {
36
+ email: { equalTo: input.email },
37
+ },
38
+ select: {
39
+ authentication: true,
40
+ role: true,
41
+ secondFA: true,
42
+ email: true,
43
+ id: true,
44
+ provider: true,
45
+ isOauth: true,
46
+ createdAt: true,
47
+ updatedAt: true,
48
+ },
49
+ first: 1,
50
+ })
51
+
52
+ const user = users[0]
53
+
54
+ const salt = user?.authentication?.emailPasswordSRP?.salt ?? DUMMY_SALT
55
+ const verifier =
56
+ user?.authentication?.emailPasswordSRP?.verifier ?? DUMMY_VERIFIER
57
+
58
+ let ephemeral: Ephemeral
59
+ try {
60
+ ephemeral = await server.generateEphemeral(verifier)
61
+ } catch {
62
+ throw new Error('Invalid authentication credentials')
63
+ }
64
+
65
+ if (!user || !user?.id) {
66
+ // Simulation d'opération pour garder le même temps
67
+ await new Promise((resolve) => setTimeout(resolve, 10))
68
+ throw new Error('Invalid authentication credentials')
69
+ }
70
+
71
+ await context.wabe.controllers.database.updateObject({
72
+ className: 'User',
73
+ context: contextWithRoot(context),
74
+ id: user.id,
75
+ data: {
76
+ authentication: {
77
+ emailPasswordSRP: {
78
+ ...user.authentication?.emailPasswordSRP,
79
+ serverSecret: ephemeral.secret,
80
+ },
81
+ },
82
+ },
83
+ select: {},
84
+ })
85
+
86
+ return { srp: { salt, serverPublic: ephemeral.public }, user }
87
+ }
88
+
89
+ async onSignUp({
90
+ input,
91
+ context,
92
+ }: AuthenticationEventsOptions<DevWabeTypes, EmailPasswordSRPInterface>) {
93
+ const users = await context.wabe.controllers.database.count({
94
+ className: 'User',
95
+ where: {
96
+ email: { equalTo: input.email },
97
+ },
98
+ context: contextWithRoot(context),
99
+ })
100
+
101
+ if (users > 0) throw new Error('Not authorized to create user')
102
+
103
+ return {
104
+ authenticationDataToSave: {
105
+ salt: input.salt,
106
+ verifier: input.verifier,
107
+ email: input.email,
108
+ serverSecret: null,
109
+ },
110
+ }
111
+ }
112
+ }
113
+
114
+ export interface EmailPasswordSRPChallengeInterface {
115
+ email: string
116
+ clientPublic: string
117
+ clientSessionProof: string
118
+ }
119
+
120
+ export class EmailPasswordSRPChallenge
121
+ implements
122
+ SecondaryProviderInterface<DevWabeTypes, EmailPasswordSRPChallengeInterface>
123
+ {
124
+ async onVerifyChallenge({
125
+ context,
126
+ input,
127
+ }: OnVerifyChallengeOptions<
128
+ DevWabeTypes,
129
+ EmailPasswordSRPChallengeInterface
130
+ >) {
131
+ const server = createSRPServer('SHA-256', 3072)
132
+
133
+ const users = await context.wabe.controllers.database.getObjects({
134
+ className: 'User',
135
+ context: contextWithRoot(context),
136
+ where: {
137
+ authentication: {
138
+ emailPasswordSRP: {
139
+ email: { equalTo: input.email },
140
+ },
141
+ },
142
+ },
143
+ select: {
144
+ id: true,
145
+ authentication: true,
146
+ },
147
+ })
148
+
149
+ const user = users[0]
150
+
151
+ const salt = user?.authentication?.emailPasswordSRP?.salt ?? DUMMY_SALT
152
+ const verifier =
153
+ user?.authentication?.emailPasswordSRP?.verifier ?? DUMMY_VERIFIER
154
+ const serverSecret =
155
+ user?.authentication?.emailPasswordSRP?.serverSecret ?? 'deadbeef'
156
+
157
+ let serverSession: Session
158
+ try {
159
+ serverSession = await server.deriveSession(
160
+ serverSecret,
161
+ input.clientPublic,
162
+ salt,
163
+ '', // no username
164
+ verifier,
165
+ input.clientSessionProof,
166
+ )
167
+ } catch {
168
+ throw new Error('Invalid authentication credentials')
169
+ }
170
+
171
+ if (!user || !user?.id) {
172
+ // Simulation pour garder un timing constant
173
+ await new Promise((resolve) => setTimeout(resolve, 10))
174
+ throw new Error('Invalid authentication credentials')
175
+ }
176
+
177
+ return {
178
+ userId: user.id,
179
+ srp: {
180
+ serverSessionProof: serverSession.proof,
181
+ },
182
+ }
183
+ }
184
+ }
@@ -0,0 +1,30 @@
1
+ import type { DevWabeTypes } from '../../utils/helper'
2
+ import {
3
+ AuthenticationProvider,
4
+ type AuthenticationEventsOptions,
5
+ type ProviderInterface,
6
+ } from '../interface'
7
+ import { oAuthAuthentication } from './OAuth'
8
+
9
+ type GitHubInterface = {
10
+ authorizationCode: string
11
+ codeVerifier: string
12
+ }
13
+
14
+ export class GitHub
15
+ implements ProviderInterface<DevWabeTypes, GitHubInterface>
16
+ {
17
+ name = 'github'
18
+ onSignIn(
19
+ options: AuthenticationEventsOptions<DevWabeTypes, GitHubInterface>,
20
+ ) {
21
+ return oAuthAuthentication(AuthenticationProvider.GitHub)(options)
22
+ }
23
+
24
+ // @ts-expect-error
25
+ onSignUp() {
26
+ throw new Error(
27
+ 'SignUp is not implemented for Oauth provider, you should use signIn instead.',
28
+ )
29
+ }
30
+ }
@@ -0,0 +1,30 @@
1
+ import type { DevWabeTypes } from '../../utils/helper'
2
+ import {
3
+ AuthenticationProvider,
4
+ type AuthenticationEventsOptions,
5
+ type ProviderInterface,
6
+ } from '../interface'
7
+ import { oAuthAuthentication } from './OAuth'
8
+
9
+ type GoogleInterface = {
10
+ authorizationCode: string
11
+ codeVerifier: string
12
+ }
13
+
14
+ export class Google
15
+ implements ProviderInterface<DevWabeTypes, GoogleInterface>
16
+ {
17
+ name = 'google'
18
+ onSignIn(
19
+ options: AuthenticationEventsOptions<DevWabeTypes, GoogleInterface>,
20
+ ) {
21
+ return oAuthAuthentication(AuthenticationProvider.Google)(options)
22
+ }
23
+
24
+ // @ts-expect-error
25
+ onSignUp() {
26
+ throw new Error(
27
+ 'SignUp is not implemented for Oauth provider, you should use signIn instead.',
28
+ )
29
+ }
30
+ }
@@ -0,0 +1,185 @@
1
+ import { afterEach, describe, expect, it, mock, spyOn } from 'bun:test'
2
+ import { GitHub } from './GitHub'
3
+ import * as OAuth from './OAuth'
4
+ import { AuthenticationProvider } from '../interface'
5
+
6
+ // Use GitHub test as use case
7
+ describe('OAuth', () => {
8
+ const mockGetObjects = mock(() => Promise.resolve([]))
9
+ const mockCount = mock(() => Promise.resolve(0)) as any
10
+ const mockCreateObject = mock(() => Promise.resolve({ id: 'userId' })) as any
11
+
12
+ const mockGetUserInfo = mock().mockResolvedValue({
13
+ email: 'email@test.fr',
14
+ avatarUrl: 'avatarUrl',
15
+ username: 'username',
16
+ })
17
+
18
+ const mockValidateAuthorizationCode = mock().mockResolvedValue({
19
+ accessToken: 'accessToken',
20
+ refreshToken: 'refreshToken',
21
+ accessTokenExpiresAt: new Date(0),
22
+ })
23
+
24
+ spyOn(OAuth, 'getProvider').mockReturnValue({
25
+ validateAuthorizationCode: mockValidateAuthorizationCode,
26
+ getUserInfo: mockGetUserInfo,
27
+ } as never)
28
+
29
+ const context = {
30
+ wabe: {
31
+ controllers: {
32
+ database: {
33
+ getObjects: mockGetObjects,
34
+ createObject: mockCreateObject,
35
+ count: mockCount,
36
+ },
37
+ },
38
+ config: {
39
+ authentication: {
40
+ providers: {
41
+ github: {
42
+ clientId: 'clientId',
43
+ clientSecret: 'clientSecret',
44
+ },
45
+ },
46
+ },
47
+ },
48
+ },
49
+ } as any
50
+
51
+ afterEach(() => {
52
+ mockGetObjects.mockClear()
53
+ mockCreateObject.mockClear()
54
+ mockCount.mockClear()
55
+ mockValidateAuthorizationCode.mockClear()
56
+ mockGetUserInfo.mockClear()
57
+ })
58
+
59
+ it('should sign up with GitHub Provider if there is no user found', async () => {
60
+ const github = new GitHub()
61
+
62
+ await github.onSignIn({
63
+ context,
64
+ input: {
65
+ authorizationCode: 'authorizationCode',
66
+ codeVerifier: 'codeVerifier',
67
+ },
68
+ })
69
+
70
+ expect(mockValidateAuthorizationCode).toHaveBeenCalledTimes(1)
71
+ expect(mockGetUserInfo).toHaveBeenCalledTimes(1)
72
+
73
+ expect(mockGetObjects).toHaveBeenCalledTimes(1)
74
+ expect(mockGetObjects).toHaveBeenCalledWith({
75
+ className: 'User',
76
+ where: {
77
+ authentication: {
78
+ github: {
79
+ email: { equalTo: 'email@test.fr' },
80
+ },
81
+ },
82
+ },
83
+ first: 1,
84
+ context: expect.any(Object),
85
+ select: {
86
+ authentication: true,
87
+ role: true,
88
+ secondFA: true,
89
+ email: true,
90
+ id: true,
91
+ provider: true,
92
+ isOauth: true,
93
+ createdAt: true,
94
+ updatedAt: true,
95
+ },
96
+ })
97
+
98
+ expect(mockCreateObject).toHaveBeenCalledTimes(1)
99
+ expect(mockCreateObject).toHaveBeenCalledWith({
100
+ className: 'User',
101
+ data: {
102
+ provider: AuthenticationProvider.GitHub,
103
+ isOauth: true,
104
+ authentication: {
105
+ github: {
106
+ email: 'email@test.fr',
107
+ username: 'username',
108
+ avatarUrl: 'avatarUrl',
109
+ },
110
+ },
111
+ },
112
+ context: expect.any(Object),
113
+ select: {
114
+ authentication: true,
115
+ role: true,
116
+ secondFA: true,
117
+ email: true,
118
+ id: true,
119
+ provider: true,
120
+ isOauth: true,
121
+ createdAt: true,
122
+ updatedAt: true,
123
+ },
124
+ })
125
+ })
126
+
127
+ it('should sign in with GitHub Provider if there is no user found', async () => {
128
+ mockGetObjects.mockResolvedValue([
129
+ {
130
+ id: 'userId',
131
+ authentication: {
132
+ github: {
133
+ email: 'email@test.fr',
134
+ verifiedEmail: true,
135
+ idToken: 'idToken',
136
+ },
137
+ },
138
+ provider: AuthenticationProvider.Google,
139
+ isOauth: true,
140
+ } as any,
141
+ ] as never)
142
+
143
+ const github = new GitHub()
144
+
145
+ await github.onSignIn({
146
+ context,
147
+ input: {
148
+ authorizationCode: 'authorizationCode',
149
+ codeVerifier: 'codeVerifier',
150
+ },
151
+ })
152
+
153
+ expect(mockValidateAuthorizationCode).toHaveBeenCalledTimes(1)
154
+ expect(mockGetUserInfo).toHaveBeenCalledTimes(1)
155
+
156
+ expect(mockGetObjects).toHaveBeenCalledTimes(1)
157
+ expect(mockGetObjects).toHaveBeenCalledWith({
158
+ className: 'User',
159
+ where: {
160
+ authentication: {
161
+ github: {
162
+ email: { equalTo: 'email@test.fr' },
163
+ },
164
+ },
165
+ },
166
+ first: 1,
167
+ context: expect.any(Object),
168
+ select: {
169
+ authentication: true,
170
+ role: true,
171
+ secondFA: true,
172
+ email: true,
173
+ id: true,
174
+ provider: true,
175
+ isOauth: true,
176
+ createdAt: true,
177
+ updatedAt: true,
178
+ },
179
+ })
180
+
181
+ expect(mockCreateObject).toHaveBeenCalledTimes(0)
182
+
183
+ mockValidateAuthorizationCode.mockRestore()
184
+ })
185
+ })
@@ -0,0 +1,112 @@
1
+ import type { WabeContext } from '../../server/interface'
2
+ import { contextWithRoot } from '../../utils/export'
3
+ import type { DevWabeTypes } from '../../utils/helper'
4
+ import {
5
+ type AuthenticationEventsOptions,
6
+ AuthenticationProvider,
7
+ } from '../interface'
8
+ import { Google } from '../oauth'
9
+ import { GitHub } from '../oauth/GitHub'
10
+
11
+ export type OAuthAuthenticationInterface = {
12
+ authorizationCode: string
13
+ codeVerifier: string
14
+ }
15
+
16
+ export const getProvider = (
17
+ context: WabeContext<DevWabeTypes>,
18
+ provider: AuthenticationProvider,
19
+ ) => {
20
+ const config = context.wabe.config
21
+
22
+ switch (provider) {
23
+ case AuthenticationProvider.Google:
24
+ return new Google(config)
25
+ case AuthenticationProvider.GitHub:
26
+ return new GitHub(config)
27
+ default:
28
+ throw new Error(`Provider ${provider} not found`)
29
+ }
30
+ }
31
+
32
+ export const oAuthAuthentication =
33
+ (oAuthProvider: AuthenticationProvider) =>
34
+ async ({
35
+ context,
36
+ input,
37
+ }: AuthenticationEventsOptions<
38
+ DevWabeTypes,
39
+ OAuthAuthenticationInterface
40
+ >) => {
41
+ const { authorizationCode, codeVerifier } = input
42
+
43
+ const provider = getProvider(context, oAuthProvider)
44
+
45
+ const { accessToken } = await provider.validateAuthorizationCode(
46
+ authorizationCode,
47
+ codeVerifier,
48
+ )
49
+
50
+ const userInfoToSave = await provider.getUserInfo(accessToken)
51
+
52
+ const user = await context.wabe.controllers.database.getObjects({
53
+ className: 'User',
54
+ where: {
55
+ authentication: {
56
+ [oAuthProvider]: {
57
+ email: { equalTo: userInfoToSave.email },
58
+ },
59
+ },
60
+ },
61
+ context: contextWithRoot(context),
62
+ first: 1,
63
+ select: {
64
+ authentication: true,
65
+ role: true,
66
+ secondFA: true,
67
+ email: true,
68
+ id: true,
69
+ provider: true,
70
+ isOauth: true,
71
+ createdAt: true,
72
+ updatedAt: true,
73
+ },
74
+ })
75
+
76
+ if (user.length === 0) {
77
+ const createdUser = await context.wabe.controllers.database.createObject({
78
+ className: 'User',
79
+ data: {
80
+ provider: oAuthProvider,
81
+ isOauth: true,
82
+ authentication: {
83
+ [oAuthProvider]: userInfoToSave,
84
+ },
85
+ },
86
+ context: contextWithRoot(context),
87
+ select: {
88
+ authentication: true,
89
+ role: true,
90
+ secondFA: true,
91
+ email: true,
92
+ id: true,
93
+ provider: true,
94
+ isOauth: true,
95
+ createdAt: true,
96
+ updatedAt: true,
97
+ },
98
+ })
99
+
100
+ if (!createdUser) throw new Error('User not found')
101
+
102
+ return {
103
+ user: createdUser,
104
+ }
105
+ }
106
+
107
+ if (!user[0]) throw new Error('User not found')
108
+
109
+ return {
110
+ user: user[0],
111
+ }
112
+ }