wabe 0.6.12 → 0.6.13
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/package.json +4 -1
- package/dev/index.ts +0 -215
- package/generated/schema.graphql +0 -1945
- package/generated/wabe.ts +0 -448
- package/src/authentication/OTP.test.ts +0 -69
- package/src/authentication/OTP.ts +0 -64
- package/src/authentication/Session.test.ts +0 -629
- package/src/authentication/Session.ts +0 -517
- package/src/authentication/cookies.ts +0 -10
- package/src/authentication/defaultAuthentication.ts +0 -209
- package/src/authentication/index.ts +0 -4
- package/src/authentication/interface.ts +0 -177
- package/src/authentication/oauth/GitHub.test.ts +0 -91
- package/src/authentication/oauth/GitHub.ts +0 -121
- package/src/authentication/oauth/Google.test.ts +0 -91
- package/src/authentication/oauth/Google.ts +0 -101
- package/src/authentication/oauth/Oauth2Client.test.ts +0 -219
- package/src/authentication/oauth/Oauth2Client.ts +0 -135
- package/src/authentication/oauth/index.ts +0 -2
- package/src/authentication/oauth/utils.test.ts +0 -33
- package/src/authentication/oauth/utils.ts +0 -27
- package/src/authentication/providers/EmailOTP.test.ts +0 -127
- package/src/authentication/providers/EmailOTP.ts +0 -95
- package/src/authentication/providers/EmailPassword.test.ts +0 -263
- package/src/authentication/providers/EmailPassword.ts +0 -138
- package/src/authentication/providers/EmailPasswordSRP.test.ts +0 -208
- package/src/authentication/providers/EmailPasswordSRP.ts +0 -191
- package/src/authentication/providers/GitHub.ts +0 -24
- package/src/authentication/providers/Google.ts +0 -24
- package/src/authentication/providers/OAuth.test.ts +0 -185
- package/src/authentication/providers/OAuth.ts +0 -106
- package/src/authentication/providers/PhonePassword.test.ts +0 -221
- package/src/authentication/providers/PhonePassword.ts +0 -136
- package/src/authentication/providers/QRCodeOTP.test.ts +0 -77
- package/src/authentication/providers/QRCodeOTP.ts +0 -69
- package/src/authentication/providers/index.ts +0 -6
- package/src/authentication/resolvers/refreshResolver.test.ts +0 -30
- package/src/authentication/resolvers/refreshResolver.ts +0 -19
- package/src/authentication/resolvers/signInWithResolver.inte.test.ts +0 -59
- package/src/authentication/resolvers/signInWithResolver.test.ts +0 -306
- package/src/authentication/resolvers/signInWithResolver.ts +0 -106
- package/src/authentication/resolvers/signOutResolver.test.ts +0 -38
- package/src/authentication/resolvers/signOutResolver.ts +0 -18
- package/src/authentication/resolvers/signUpWithResolver.test.ts +0 -180
- package/src/authentication/resolvers/signUpWithResolver.ts +0 -68
- package/src/authentication/resolvers/verifyChallenge.test.ts +0 -230
- package/src/authentication/resolvers/verifyChallenge.ts +0 -78
- package/src/authentication/roles.test.ts +0 -49
- package/src/authentication/roles.ts +0 -40
- package/src/authentication/security.ts +0 -278
- package/src/authentication/utils.test.ts +0 -97
- package/src/authentication/utils.ts +0 -39
- package/src/cache/InMemoryCache.test.ts +0 -62
- package/src/cache/InMemoryCache.ts +0 -45
- package/src/cron/index.test.ts +0 -17
- package/src/cron/index.ts +0 -43
- package/src/database/DatabaseController.test.ts +0 -613
- package/src/database/DatabaseController.ts +0 -1415
- package/src/database/index.test.ts +0 -1551
- package/src/database/index.ts +0 -9
- package/src/database/interface.ts +0 -308
- package/src/email/DevAdapter.ts +0 -7
- package/src/email/EmailController.test.ts +0 -29
- package/src/email/EmailController.ts +0 -13
- package/src/email/index.ts +0 -2
- package/src/email/interface.ts +0 -36
- package/src/email/templates/sendOtpCode.ts +0 -120
- package/src/file/FileController.ts +0 -28
- package/src/file/FileDevAdapter.ts +0 -51
- package/src/file/hookDeleteFile.ts +0 -25
- package/src/file/hookReadFile.ts +0 -66
- package/src/file/hookUploadFile.ts +0 -52
- package/src/file/index.test.ts +0 -1031
- package/src/file/index.ts +0 -2
- package/src/file/interface.ts +0 -63
- package/src/file/security.ts +0 -156
- package/src/graphql/GraphQLSchema.test.ts +0 -5099
- package/src/graphql/GraphQLSchema.ts +0 -886
- package/src/graphql/index.ts +0 -2
- package/src/graphql/parseGraphqlSchema.ts +0 -85
- package/src/graphql/parser.test.ts +0 -203
- package/src/graphql/parser.ts +0 -707
- package/src/graphql/pointerAndRelationFunction.ts +0 -191
- package/src/graphql/resolvers.ts +0 -464
- package/src/graphql/tests/aggregation.test.ts +0 -1115
- package/src/graphql/tests/e2e.test.ts +0 -590
- package/src/graphql/tests/scalars.test.ts +0 -250
- package/src/graphql/types.ts +0 -227
- package/src/hooks/HookObject.test.ts +0 -122
- package/src/hooks/HookObject.ts +0 -165
- package/src/hooks/authentication.ts +0 -67
- package/src/hooks/createUser.test.ts +0 -77
- package/src/hooks/createUser.ts +0 -10
- package/src/hooks/defaultFields.test.ts +0 -176
- package/src/hooks/defaultFields.ts +0 -32
- package/src/hooks/deleteSession.test.ts +0 -181
- package/src/hooks/deleteSession.ts +0 -20
- package/src/hooks/hashFieldHook.test.ts +0 -152
- package/src/hooks/hashFieldHook.ts +0 -89
- package/src/hooks/index.test.ts +0 -258
- package/src/hooks/index.ts +0 -420
- package/src/hooks/permissions.test.ts +0 -412
- package/src/hooks/permissions.ts +0 -93
- package/src/hooks/protected.test.ts +0 -551
- package/src/hooks/protected.ts +0 -74
- package/src/hooks/searchableFields.test.ts +0 -147
- package/src/hooks/searchableFields.ts +0 -86
- package/src/hooks/session.test.ts +0 -134
- package/src/hooks/session.ts +0 -76
- package/src/hooks/setEmail.test.ts +0 -216
- package/src/hooks/setEmail.ts +0 -33
- package/src/hooks/setupAcl.test.ts +0 -618
- package/src/hooks/setupAcl.ts +0 -25
- package/src/hooks/virtualFields.test.ts +0 -228
- package/src/hooks/virtualFields.ts +0 -48
- package/src/index.ts +0 -9
- package/src/schema/Schema.test.ts +0 -482
- package/src/schema/Schema.ts +0 -839
- package/src/schema/defaultResolvers.ts +0 -93
- package/src/schema/index.ts +0 -1
- package/src/schema/resolvers/meResolver.test.ts +0 -62
- package/src/schema/resolvers/meResolver.ts +0 -10
- package/src/schema/resolvers/resetPassword.test.ts +0 -341
- package/src/schema/resolvers/resetPassword.ts +0 -63
- package/src/schema/resolvers/sendEmail.test.ts +0 -118
- package/src/schema/resolvers/sendEmail.ts +0 -21
- package/src/schema/resolvers/sendOtpCode.test.ts +0 -141
- package/src/schema/resolvers/sendOtpCode.ts +0 -52
- package/src/security.test.ts +0 -4136
- package/src/server/defaultSessionHandler.test.ts +0 -62
- package/src/server/defaultSessionHandler.ts +0 -104
- package/src/server/generateCodegen.ts +0 -433
- package/src/server/index.test.ts +0 -843
- package/src/server/index.ts +0 -336
- package/src/server/interface.ts +0 -11
- package/src/server/routes/authHandler.ts +0 -171
- package/src/server/routes/index.ts +0 -48
- package/src/utils/crypto.test.ts +0 -41
- package/src/utils/crypto.ts +0 -105
- package/src/utils/database.ts +0 -8
- package/src/utils/export.ts +0 -12
- package/src/utils/helper.ts +0 -204
- package/src/utils/index.test.ts +0 -11
- package/src/utils/index.ts +0 -196
- package/src/utils/preload.ts +0 -8
- package/src/utils/testHelper.ts +0 -124
- package/tsconfig.json +0 -32
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import type { WabeTypes } from '..'
|
|
2
|
-
import type { CustomAuthenticationMethods, ProviderInterface } from './interface'
|
|
3
|
-
import { GitHub, QRCodeOTP } from './providers'
|
|
4
|
-
import { Google } from './providers'
|
|
5
|
-
import { EmailOTP } from './providers/EmailOTP'
|
|
6
|
-
import { EmailPassword } from './providers/EmailPassword'
|
|
7
|
-
import { EmailPasswordSRPChallenge, EmailPasswordSRP } from './providers/EmailPasswordSRP'
|
|
8
|
-
import { PhonePassword } from './providers/PhonePassword'
|
|
9
|
-
|
|
10
|
-
export const defaultAuthenticationMethods = <T extends WabeTypes>(): CustomAuthenticationMethods<
|
|
11
|
-
T,
|
|
12
|
-
ProviderInterface<T>
|
|
13
|
-
>[] => [
|
|
14
|
-
{
|
|
15
|
-
name: 'emailPasswordSRPChallenge',
|
|
16
|
-
input: {
|
|
17
|
-
email: {
|
|
18
|
-
type: 'Email',
|
|
19
|
-
required: true,
|
|
20
|
-
},
|
|
21
|
-
clientPublic: {
|
|
22
|
-
type: 'String',
|
|
23
|
-
required: true,
|
|
24
|
-
},
|
|
25
|
-
clientSessionProof: {
|
|
26
|
-
type: 'String',
|
|
27
|
-
required: true,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
// @ts-expect-error
|
|
31
|
-
provider: new EmailPasswordSRPChallenge(),
|
|
32
|
-
isSecondaryFactor: true,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'emailPasswordSRP',
|
|
36
|
-
input: {
|
|
37
|
-
email: {
|
|
38
|
-
type: 'Email',
|
|
39
|
-
required: true,
|
|
40
|
-
},
|
|
41
|
-
clientPublic: {
|
|
42
|
-
type: 'String',
|
|
43
|
-
},
|
|
44
|
-
salt: {
|
|
45
|
-
type: 'String',
|
|
46
|
-
},
|
|
47
|
-
verifier: {
|
|
48
|
-
type: 'String',
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
dataToStore: {
|
|
52
|
-
email: {
|
|
53
|
-
type: 'Email',
|
|
54
|
-
required: true,
|
|
55
|
-
},
|
|
56
|
-
salt: {
|
|
57
|
-
type: 'String',
|
|
58
|
-
required: true,
|
|
59
|
-
},
|
|
60
|
-
verifier: {
|
|
61
|
-
type: 'String',
|
|
62
|
-
required: true,
|
|
63
|
-
},
|
|
64
|
-
serverSecret: {
|
|
65
|
-
type: 'String',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
// @ts-expect-error
|
|
69
|
-
provider: new EmailPasswordSRP(),
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: 'emailOTP',
|
|
73
|
-
input: {
|
|
74
|
-
email: {
|
|
75
|
-
type: 'Email',
|
|
76
|
-
required: true,
|
|
77
|
-
},
|
|
78
|
-
otp: {
|
|
79
|
-
type: 'String',
|
|
80
|
-
required: true,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
// @ts-expect-error
|
|
84
|
-
provider: new EmailOTP(),
|
|
85
|
-
isSecondaryFactor: true,
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: 'qrCodeOTP',
|
|
89
|
-
input: {
|
|
90
|
-
email: {
|
|
91
|
-
type: 'Email',
|
|
92
|
-
required: true,
|
|
93
|
-
},
|
|
94
|
-
otp: {
|
|
95
|
-
type: 'String',
|
|
96
|
-
required: true,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
// @ts-expect-error
|
|
100
|
-
provider: new QRCodeOTP(),
|
|
101
|
-
isSecondaryFactor: true,
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'phonePassword',
|
|
105
|
-
input: {
|
|
106
|
-
phone: {
|
|
107
|
-
type: 'Phone',
|
|
108
|
-
required: true,
|
|
109
|
-
},
|
|
110
|
-
password: {
|
|
111
|
-
type: 'Hash',
|
|
112
|
-
required: true,
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
dataToStore: {
|
|
116
|
-
phone: {
|
|
117
|
-
type: 'Phone',
|
|
118
|
-
required: true,
|
|
119
|
-
},
|
|
120
|
-
password: {
|
|
121
|
-
type: 'Hash',
|
|
122
|
-
required: true,
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
// @ts-expect-error
|
|
126
|
-
provider: new PhonePassword(),
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'emailPassword',
|
|
130
|
-
input: {
|
|
131
|
-
email: {
|
|
132
|
-
type: 'Email',
|
|
133
|
-
required: true,
|
|
134
|
-
},
|
|
135
|
-
password: {
|
|
136
|
-
type: 'Hash',
|
|
137
|
-
required: true,
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
dataToStore: {
|
|
141
|
-
email: {
|
|
142
|
-
type: 'Email',
|
|
143
|
-
required: true,
|
|
144
|
-
},
|
|
145
|
-
password: {
|
|
146
|
-
type: 'Hash',
|
|
147
|
-
required: true,
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
// @ts-expect-error
|
|
151
|
-
provider: new EmailPassword(),
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
name: 'google',
|
|
155
|
-
input: {
|
|
156
|
-
authorizationCode: {
|
|
157
|
-
type: 'String',
|
|
158
|
-
required: true,
|
|
159
|
-
},
|
|
160
|
-
codeVerifier: {
|
|
161
|
-
type: 'String',
|
|
162
|
-
required: true,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
dataToStore: {
|
|
166
|
-
email: {
|
|
167
|
-
type: 'Email',
|
|
168
|
-
required: true,
|
|
169
|
-
},
|
|
170
|
-
verifiedEmail: {
|
|
171
|
-
type: 'Boolean',
|
|
172
|
-
required: true,
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
// There is no signUp method for Google provider
|
|
176
|
-
// @ts-expect-error
|
|
177
|
-
provider: new Google(),
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
name: 'github',
|
|
181
|
-
input: {
|
|
182
|
-
authorizationCode: {
|
|
183
|
-
type: 'String',
|
|
184
|
-
required: true,
|
|
185
|
-
},
|
|
186
|
-
codeVerifier: {
|
|
187
|
-
type: 'String',
|
|
188
|
-
required: true,
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
dataToStore: {
|
|
192
|
-
email: {
|
|
193
|
-
type: 'Email',
|
|
194
|
-
required: true,
|
|
195
|
-
},
|
|
196
|
-
avatarUrl: {
|
|
197
|
-
type: 'String',
|
|
198
|
-
required: true,
|
|
199
|
-
},
|
|
200
|
-
username: {
|
|
201
|
-
type: 'String',
|
|
202
|
-
required: true,
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
// There is no signUp method for Google provider
|
|
206
|
-
// @ts-expect-error
|
|
207
|
-
provider: new GitHub(),
|
|
208
|
-
},
|
|
209
|
-
]
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import type { User } from '../../generated/wabe'
|
|
2
|
-
import type { WabeContext } from '../server/interface'
|
|
3
|
-
import type { SchemaFields } from '../schema'
|
|
4
|
-
import type { WabeTypes, WobeCustomContext } from '../server'
|
|
5
|
-
import type { SelectType } from '../database/interface'
|
|
6
|
-
|
|
7
|
-
export enum ProviderEnum {
|
|
8
|
-
google = 'google',
|
|
9
|
-
github = 'github',
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ProviderConfig {
|
|
13
|
-
clientId: string
|
|
14
|
-
clientSecret: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type AuthenticationEventsOptions<T extends WabeTypes, K> = {
|
|
18
|
-
context: WabeContext<T>
|
|
19
|
-
input: K
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type AuthenticationEventsOptionsWithUserId<
|
|
23
|
-
T extends WabeTypes,
|
|
24
|
-
K,
|
|
25
|
-
> = AuthenticationEventsOptions<T, K> & {
|
|
26
|
-
userId: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export type OnSendChallengeOptions<T extends WabeTypes> = {
|
|
30
|
-
context: WabeContext<T>
|
|
31
|
-
user: T['types']['User']
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type OnVerifyChallengeOptions<T extends WabeTypes, K> = {
|
|
35
|
-
context: WabeContext<T>
|
|
36
|
-
input: K
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type ProviderInterface<T extends WabeTypes, K = any> = {
|
|
40
|
-
onSignIn: (options: AuthenticationEventsOptions<T, K>) => Promise<{
|
|
41
|
-
user: Partial<User>
|
|
42
|
-
srp?: {
|
|
43
|
-
salt: string
|
|
44
|
-
serverPublic: string
|
|
45
|
-
}
|
|
46
|
-
}>
|
|
47
|
-
onSignUp: (
|
|
48
|
-
options: AuthenticationEventsOptions<T, K>,
|
|
49
|
-
) => Promise<{ authenticationDataToSave: any }>
|
|
50
|
-
onUpdateAuthenticationData?: (
|
|
51
|
-
options: AuthenticationEventsOptionsWithUserId<T, K>,
|
|
52
|
-
) => Promise<{ authenticationDataToSave: any }>
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export type SecondaryProviderInterface<T extends WabeTypes, K = any> = {
|
|
56
|
-
onSendChallenge?: (options: OnSendChallengeOptions<T>) => Promise<void> | void
|
|
57
|
-
onVerifyChallenge: (options: OnVerifyChallengeOptions<T, K>) =>
|
|
58
|
-
| Promise<{
|
|
59
|
-
userId: string
|
|
60
|
-
srp?: { serverSessionProof: string }
|
|
61
|
-
} | null>
|
|
62
|
-
| ({ userId: string; srp?: { serverSessionProof: string } } | null)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export type CustomAuthenticationMethods<
|
|
66
|
-
T extends WabeTypes,
|
|
67
|
-
U = ProviderInterface<T> | SecondaryProviderInterface<T>,
|
|
68
|
-
K = SchemaFields<T>,
|
|
69
|
-
W = SchemaFields<T>,
|
|
70
|
-
> = {
|
|
71
|
-
name: string
|
|
72
|
-
input: K
|
|
73
|
-
dataToStore?: W
|
|
74
|
-
provider: U
|
|
75
|
-
isSecondaryFactor?: boolean
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export type RoleConfig = Array<string>
|
|
79
|
-
|
|
80
|
-
export interface SessionConfig<T extends WabeTypes> {
|
|
81
|
-
/**
|
|
82
|
-
* The time in milliseconds that the access token will expire
|
|
83
|
-
*/
|
|
84
|
-
accessTokenExpiresInMs?: number
|
|
85
|
-
/**
|
|
86
|
-
* The time in milliseconds that the refresh token will expire
|
|
87
|
-
*/
|
|
88
|
-
refreshTokenExpiresInMs?: number
|
|
89
|
-
/**
|
|
90
|
-
* Set to true to automatically store the session tokens in cookies
|
|
91
|
-
*/
|
|
92
|
-
cookieSession?: boolean
|
|
93
|
-
/**
|
|
94
|
-
* The JWT secret used to sign the session tokens
|
|
95
|
-
*/
|
|
96
|
-
jwtSecret: string
|
|
97
|
-
/**
|
|
98
|
-
* Optional audience to embed and verify in JWTs
|
|
99
|
-
*/
|
|
100
|
-
jwtAudience?: string
|
|
101
|
-
/**
|
|
102
|
-
* Optional issuer to embed and verify in JWTs
|
|
103
|
-
*/
|
|
104
|
-
jwtIssuer?: string
|
|
105
|
-
/**
|
|
106
|
-
* Secret dedicated to CSRF token HMAC (defaults to jwtSecret)
|
|
107
|
-
*/
|
|
108
|
-
csrfSecret?: string
|
|
109
|
-
/**
|
|
110
|
-
* Secret used to encrypt session tokens at rest (defaults to jwtSecret)
|
|
111
|
-
*/
|
|
112
|
-
tokenSecret?: string
|
|
113
|
-
/**
|
|
114
|
-
* A selection of fields to include in the JWT token in the "user" fields
|
|
115
|
-
*/
|
|
116
|
-
jwtTokenFields?: SelectType<T, 'User', keyof T['types']['User']>
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface AuthenticationRateLimitConfig {
|
|
120
|
-
/**
|
|
121
|
-
* Enable this rate limiter. Enabled by default in production.
|
|
122
|
-
*/
|
|
123
|
-
enabled?: boolean
|
|
124
|
-
maxAttempts?: number
|
|
125
|
-
windowMs?: number
|
|
126
|
-
blockDurationMs?: number
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface AuthenticationSecurityConfig {
|
|
130
|
-
signInRateLimit?: AuthenticationRateLimitConfig
|
|
131
|
-
signUpRateLimit?: AuthenticationRateLimitConfig
|
|
132
|
-
verifyChallengeRateLimit?: AuthenticationRateLimitConfig
|
|
133
|
-
mfaChallengeTtlMs?: number
|
|
134
|
-
/**
|
|
135
|
-
* Require a valid challenge token during verifyChallenge in production.
|
|
136
|
-
*/
|
|
137
|
-
requireMfaChallengeInProduction?: boolean
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export interface AuthenticationConfig<T extends WabeTypes> {
|
|
141
|
-
session?: SessionConfig<T>
|
|
142
|
-
roles?: RoleConfig
|
|
143
|
-
successRedirectPath?: string
|
|
144
|
-
failureRedirectPath?: string
|
|
145
|
-
frontDomain?: string
|
|
146
|
-
backDomain?: string
|
|
147
|
-
providers?: Partial<Record<ProviderEnum, ProviderConfig>>
|
|
148
|
-
customAuthenticationMethods?: CustomAuthenticationMethods<T>[]
|
|
149
|
-
sessionHandler?: (context: WobeCustomContext<T>) => void | Promise<void>
|
|
150
|
-
disableSignUp?: boolean
|
|
151
|
-
security?: AuthenticationSecurityConfig
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface CreateTokenFromAuthorizationCodeOptions {
|
|
155
|
-
code: string
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export interface refreshTokenOptions {
|
|
159
|
-
refreshToken: string
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export interface Provider {
|
|
163
|
-
createTokenFromAuthorizationCode(options: CreateTokenFromAuthorizationCodeOptions): Promise<void>
|
|
164
|
-
refreshToken(options: refreshTokenOptions): Promise<void>
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export enum AuthenticationProvider {
|
|
168
|
-
GitHub = 'github',
|
|
169
|
-
Google = 'google',
|
|
170
|
-
EmailPassword = 'emailPassword',
|
|
171
|
-
PhonePassword = 'phonePassword',
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export enum SecondaryFactor {
|
|
175
|
-
EmailOTP = 'emailOTP',
|
|
176
|
-
QRCodeOTP = 'qrcodeOTP',
|
|
177
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, spyOn } from 'bun:test'
|
|
2
|
-
import { GitHub } from './GitHub'
|
|
3
|
-
import { OAuth2Client } from './Oauth2Client'
|
|
4
|
-
|
|
5
|
-
describe('GitHub oauth', () => {
|
|
6
|
-
const config = {
|
|
7
|
-
port: 3001,
|
|
8
|
-
authentication: {
|
|
9
|
-
backDomain: 'api.wabe.dev',
|
|
10
|
-
providers: {
|
|
11
|
-
github: {
|
|
12
|
-
clientId: 'clientId',
|
|
13
|
-
clientSecret: 'clientSecret',
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
} as any
|
|
18
|
-
|
|
19
|
-
const githubOauth = new GitHub(config)
|
|
20
|
-
|
|
21
|
-
it('should create authorization url', () => {
|
|
22
|
-
const spyOauth2ClientCreateAuthorizationUrl = spyOn(
|
|
23
|
-
OAuth2Client.prototype,
|
|
24
|
-
'createAuthorizationURL',
|
|
25
|
-
).mockReturnValue(new URL('https://url') as never)
|
|
26
|
-
|
|
27
|
-
const authorizationUrl = githubOauth.createAuthorizationURL('state', 'codeVerifier')
|
|
28
|
-
|
|
29
|
-
expect(authorizationUrl.toString()).toBe(
|
|
30
|
-
'https://url/?access_type=offline&prompt=select_account',
|
|
31
|
-
)
|
|
32
|
-
expect(spyOauth2ClientCreateAuthorizationUrl).toHaveBeenCalledTimes(1)
|
|
33
|
-
expect(spyOauth2ClientCreateAuthorizationUrl).toHaveBeenCalledWith({
|
|
34
|
-
state: 'state',
|
|
35
|
-
codeVerifier: 'codeVerifier',
|
|
36
|
-
scopes: ['read:user', 'user:email'],
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
spyOauth2ClientCreateAuthorizationUrl.mockRestore()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should validate authorization code', async () => {
|
|
43
|
-
const spyOauth2ClientValidateAuthorizationCode = spyOn(
|
|
44
|
-
OAuth2Client.prototype,
|
|
45
|
-
'validateAuthorizationCode',
|
|
46
|
-
).mockResolvedValue({
|
|
47
|
-
access_token: 'access_token',
|
|
48
|
-
refresh_token: 'refresh_token',
|
|
49
|
-
expires_in: 3600,
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const res = await githubOauth.validateAuthorizationCode('code', 'codeVerifier')
|
|
53
|
-
|
|
54
|
-
expect(spyOauth2ClientValidateAuthorizationCode).toHaveBeenCalledTimes(1)
|
|
55
|
-
expect(spyOauth2ClientValidateAuthorizationCode).toHaveBeenCalledWith('code', {
|
|
56
|
-
authenticateWith: 'request_body',
|
|
57
|
-
credentials: 'clientSecret',
|
|
58
|
-
codeVerifier: 'codeVerifier',
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// +100 to avoid flaky
|
|
62
|
-
expect((res.accessTokenExpiresAt?.getTime() || 0) + 100).toBeGreaterThanOrEqual(
|
|
63
|
-
Date.now() + 3600 * 1000,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
spyOauth2ClientValidateAuthorizationCode.mockRestore()
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should refresh access token', async () => {
|
|
70
|
-
const spyOauth2ClientRefreshAccessToken = spyOn(
|
|
71
|
-
OAuth2Client.prototype,
|
|
72
|
-
'refreshAccessToken',
|
|
73
|
-
).mockResolvedValue({
|
|
74
|
-
access_token: 'access_token',
|
|
75
|
-
expires_in: 3600,
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const res = await githubOauth.refreshAccessToken('refresh_token')
|
|
79
|
-
|
|
80
|
-
expect(spyOauth2ClientRefreshAccessToken).toHaveBeenCalledTimes(1)
|
|
81
|
-
expect(spyOauth2ClientRefreshAccessToken).toHaveBeenCalledWith('refresh_token', {
|
|
82
|
-
authenticateWith: 'request_body',
|
|
83
|
-
credentials: 'clientSecret',
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
expect(res.accessToken).toBe('access_token')
|
|
87
|
-
expect(res.accessTokenExpiresAt?.getTime()).toBeGreaterThanOrEqual(Date.now() + 3600 * 1000)
|
|
88
|
-
|
|
89
|
-
spyOauth2ClientRefreshAccessToken.mockRestore()
|
|
90
|
-
})
|
|
91
|
-
})
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { OAuth2Client } from '.'
|
|
2
|
-
import type { WabeConfig } from '../../server'
|
|
3
|
-
import type { OAuth2ProviderWithPKCE, Tokens } from './utils'
|
|
4
|
-
|
|
5
|
-
const authorizeEndpoint = 'https://github.com/login/oauth/authorize'
|
|
6
|
-
const tokenEndpoint = 'https://github.com/login/oauth/access_token'
|
|
7
|
-
|
|
8
|
-
interface AuthorizationCodeResponseBody {
|
|
9
|
-
access_token: string
|
|
10
|
-
refresh_token?: string
|
|
11
|
-
expires_in: number
|
|
12
|
-
id_token: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface RefreshTokenResponseBody {
|
|
16
|
-
access_token: string
|
|
17
|
-
expires_in: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class GitHub implements OAuth2ProviderWithPKCE {
|
|
21
|
-
private client: OAuth2Client
|
|
22
|
-
private clientSecret: string
|
|
23
|
-
|
|
24
|
-
constructor(config: WabeConfig<any>) {
|
|
25
|
-
const githubConfig = config.authentication?.providers?.github
|
|
26
|
-
|
|
27
|
-
if (!githubConfig) throw new Error('GitHub config not found')
|
|
28
|
-
|
|
29
|
-
const baseUrl = `http${config.isProduction ? 's' : ''}://${config.authentication?.backDomain || '127.0.0.1:' + config.port || 3001}`
|
|
30
|
-
|
|
31
|
-
const redirectURI = `${baseUrl}/auth/oauth/callback`
|
|
32
|
-
|
|
33
|
-
this.client = new OAuth2Client(
|
|
34
|
-
githubConfig.clientId,
|
|
35
|
-
authorizeEndpoint,
|
|
36
|
-
tokenEndpoint,
|
|
37
|
-
redirectURI,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
this.clientSecret = githubConfig.clientSecret
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
createAuthorizationURL(
|
|
44
|
-
state: string,
|
|
45
|
-
codeVerifier: string,
|
|
46
|
-
options?: {
|
|
47
|
-
scopes?: string[]
|
|
48
|
-
},
|
|
49
|
-
): URL {
|
|
50
|
-
const scopes = options?.scopes ?? []
|
|
51
|
-
const url = this.client.createAuthorizationURL({
|
|
52
|
-
state,
|
|
53
|
-
codeVerifier,
|
|
54
|
-
scopes: [...scopes, 'read:user', 'user:email'],
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
url.searchParams.set('access_type', 'offline')
|
|
58
|
-
url.searchParams.set('prompt', 'select_account')
|
|
59
|
-
|
|
60
|
-
return url
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async validateAuthorizationCode(code: string, codeVerifier: string): Promise<Tokens> {
|
|
64
|
-
const { access_token, expires_in, refresh_token, id_token } =
|
|
65
|
-
await this.client.validateAuthorizationCode<AuthorizationCodeResponseBody>(code, {
|
|
66
|
-
authenticateWith: 'request_body',
|
|
67
|
-
codeVerifier,
|
|
68
|
-
credentials: this.clientSecret,
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
accessToken: access_token,
|
|
73
|
-
refreshToken: refresh_token,
|
|
74
|
-
accessTokenExpiresAt: new Date(Date.now() + expires_in * 1000),
|
|
75
|
-
idToken: id_token,
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async refreshAccessToken(refreshToken: string): Promise<Tokens> {
|
|
80
|
-
const { access_token, expires_in } =
|
|
81
|
-
await this.client.refreshAccessToken<RefreshTokenResponseBody>(refreshToken, {
|
|
82
|
-
authenticateWith: 'request_body',
|
|
83
|
-
credentials: this.clientSecret,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
accessToken: access_token,
|
|
88
|
-
accessTokenExpiresAt: new Date(Date.now() + expires_in * 1000),
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async getUserInfo(accessToken: string) {
|
|
93
|
-
const userInfoResponse = await fetch('https://api.github.com/user', {
|
|
94
|
-
headers: {
|
|
95
|
-
Authorization: `Bearer ${accessToken}`,
|
|
96
|
-
Accept: 'application/vnd.github.v3+json',
|
|
97
|
-
},
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
const userEmailResponse = await fetch('https://api.github.com/user/emails', {
|
|
101
|
-
headers: {
|
|
102
|
-
Authorization: `Bearer ${accessToken}`,
|
|
103
|
-
Accept: 'application/vnd.github.v3+json',
|
|
104
|
-
},
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
if (!userInfoResponse.ok || !userEmailResponse.ok)
|
|
108
|
-
throw new Error('Failed to fetch user information from GitHub')
|
|
109
|
-
|
|
110
|
-
const userInfo = await userInfoResponse.json()
|
|
111
|
-
const userEmails = await userEmailResponse.json()
|
|
112
|
-
|
|
113
|
-
const primaryEmail = userEmails.find((email: any) => email.primary)?.email
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
email: primaryEmail || null,
|
|
117
|
-
username: userInfo.login,
|
|
118
|
-
avatarUrl: userInfo.avatar_url,
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, spyOn } from 'bun:test'
|
|
2
|
-
import { Google } from './Google'
|
|
3
|
-
import { OAuth2Client } from './Oauth2Client'
|
|
4
|
-
|
|
5
|
-
describe('Google oauth', () => {
|
|
6
|
-
const config = {
|
|
7
|
-
port: 3001,
|
|
8
|
-
authentication: {
|
|
9
|
-
backDomain: 'api.wabe.com',
|
|
10
|
-
providers: {
|
|
11
|
-
google: {
|
|
12
|
-
clientId: 'clientId',
|
|
13
|
-
clientSecret: 'clientSecret',
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
} as any
|
|
18
|
-
|
|
19
|
-
const googleOauth = new Google(config)
|
|
20
|
-
|
|
21
|
-
it('should create authorization url', () => {
|
|
22
|
-
const spyOauth2ClientCreateAuthorizationUrl = spyOn(
|
|
23
|
-
OAuth2Client.prototype,
|
|
24
|
-
'createAuthorizationURL',
|
|
25
|
-
).mockReturnValue(new URL('https://url') as never)
|
|
26
|
-
|
|
27
|
-
const authorizationUrl = googleOauth.createAuthorizationURL('state', 'codeVerifier')
|
|
28
|
-
|
|
29
|
-
expect(authorizationUrl.toString()).toBe(
|
|
30
|
-
'https://url/?access_type=offline&prompt=select_account',
|
|
31
|
-
)
|
|
32
|
-
expect(spyOauth2ClientCreateAuthorizationUrl).toHaveBeenCalledTimes(1)
|
|
33
|
-
expect(spyOauth2ClientCreateAuthorizationUrl).toHaveBeenCalledWith({
|
|
34
|
-
state: 'state',
|
|
35
|
-
codeVerifier: 'codeVerifier',
|
|
36
|
-
scopes: ['openid'],
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
spyOauth2ClientCreateAuthorizationUrl.mockRestore()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should validate authorization code', async () => {
|
|
43
|
-
const spyOauth2ClientValidateAuthorizationCode = spyOn(
|
|
44
|
-
OAuth2Client.prototype,
|
|
45
|
-
'validateAuthorizationCode',
|
|
46
|
-
).mockResolvedValue({
|
|
47
|
-
access_token: 'access_token',
|
|
48
|
-
refresh_token: 'refresh_token',
|
|
49
|
-
expires_in: 3600,
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const res = await googleOauth.validateAuthorizationCode('code', 'codeVerifier')
|
|
53
|
-
|
|
54
|
-
expect(spyOauth2ClientValidateAuthorizationCode).toHaveBeenCalledTimes(1)
|
|
55
|
-
expect(spyOauth2ClientValidateAuthorizationCode).toHaveBeenCalledWith('code', {
|
|
56
|
-
authenticateWith: 'request_body',
|
|
57
|
-
credentials: 'clientSecret',
|
|
58
|
-
codeVerifier: 'codeVerifier',
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// +100 to avoid flaky
|
|
62
|
-
expect((res.accessTokenExpiresAt?.getTime() || 0) + 100).toBeGreaterThanOrEqual(
|
|
63
|
-
Date.now() + 3600 * 1000,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
spyOauth2ClientValidateAuthorizationCode.mockRestore()
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should refresh access token', async () => {
|
|
70
|
-
const spyOauth2ClientRefreshAccessToken = spyOn(
|
|
71
|
-
OAuth2Client.prototype,
|
|
72
|
-
'refreshAccessToken',
|
|
73
|
-
).mockResolvedValue({
|
|
74
|
-
access_token: 'access_token',
|
|
75
|
-
expires_in: 3600,
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const res = await googleOauth.refreshAccessToken('refresh_token')
|
|
79
|
-
|
|
80
|
-
expect(spyOauth2ClientRefreshAccessToken).toHaveBeenCalledTimes(1)
|
|
81
|
-
expect(spyOauth2ClientRefreshAccessToken).toHaveBeenCalledWith('refresh_token', {
|
|
82
|
-
authenticateWith: 'request_body',
|
|
83
|
-
credentials: 'clientSecret',
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
expect(res.accessToken).toBe('access_token')
|
|
87
|
-
expect(res.accessTokenExpiresAt?.getTime()).toBeGreaterThanOrEqual(Date.now() + 3600 * 1000)
|
|
88
|
-
|
|
89
|
-
spyOauth2ClientRefreshAccessToken.mockRestore()
|
|
90
|
-
})
|
|
91
|
-
})
|