@driveflux/auth 4.0.49 → 4.0.50
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/dist/AuthProvider.js +76 -59
- package/dist/authorization/constants.js +45 -24
- package/dist/authorization/define.js +57 -28
- package/dist/authorization/fields/index.js +4 -7
- package/dist/authorization/helpers.js +10 -8
- package/dist/authorization/index.js +6 -6
- package/dist/authorization/permissions-list.js +5 -7
- package/dist/authorization/quick.js +1 -1
- package/dist/authorization/roles/admin/business-development-executive.js +20 -7
- package/dist/authorization/roles/admin/ceo.js +4 -2
- package/dist/authorization/roles/admin/common.js +4 -2
- package/dist/authorization/roles/admin/concierge.js +35 -10
- package/dist/authorization/roles/admin/customer-success-executive.js +40 -10
- package/dist/authorization/roles/admin/data-analyst.js +7 -4
- package/dist/authorization/roles/admin/designer.js +7 -4
- package/dist/authorization/roles/admin/engineer.js +7 -4
- package/dist/authorization/roles/admin/finance-executive.js +11 -4
- package/dist/authorization/roles/admin/head-of-business-development.js +14 -4
- package/dist/authorization/roles/admin/head-of-data-analytics.js +14 -4
- package/dist/authorization/roles/admin/head-of-engineering.js +17 -6
- package/dist/authorization/roles/admin/head-of-finance.js +8 -3
- package/dist/authorization/roles/admin/head-of-human-resources.js +13 -5
- package/dist/authorization/roles/admin/head-of-marketing.js +17 -5
- package/dist/authorization/roles/admin/head-of-operations.js +8 -3
- package/dist/authorization/roles/admin/head-of-product.js +17 -6
- package/dist/authorization/roles/admin/head-of-sales.js +17 -5
- package/dist/authorization/roles/admin/human-resources-executive.js +12 -5
- package/dist/authorization/roles/admin/marketing-executive.js +7 -4
- package/dist/authorization/roles/admin/product-manager.js +7 -4
- package/dist/authorization/roles/admin/sales-executive.js +24 -8
- package/dist/authorization/roles/consumer/business-admin.js +19 -6
- package/dist/authorization/roles/consumer/business-user.js +18 -6
- package/dist/authorization/roles/consumer/member.js +16 -6
- package/dist/authorization/types.js +1 -1
- package/dist/authorization/update-user-permissions.js +22 -15
- package/dist/authorization/utils.js +26 -11
- package/dist/context.js +8 -9
- package/dist/default.js +1 -1
- package/dist/server/authenticate-user.js +11 -7
- package/dist/server/cors.js +23 -12
- package/dist/server/credentials-provider.js +2 -2
- package/dist/server/next-auth.js +90 -103
- package/dist/server/prisma-adapter.js +88 -52
- package/dist/server/verfiy-token.js +39 -24
- package/dist/translations.js +4 -4
- package/dist/use-auth.js +1 -1
- package/dist/use-session.js +1 -1
- package/package.json +2 -2
package/dist/server/next-auth.js
CHANGED
|
@@ -8,7 +8,7 @@ import { nanoid } from 'nanoid';
|
|
|
8
8
|
import CredentialsProvider from 'next-auth/providers/credentials';
|
|
9
9
|
import FacebookProvider from 'next-auth/providers/facebook';
|
|
10
10
|
import GoogleProvider from 'next-auth/providers/google';
|
|
11
|
-
import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE
|
|
11
|
+
import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE } from '../constants.js';
|
|
12
12
|
import { extractDefault } from '../default.js';
|
|
13
13
|
import { translations } from '../translations.js';
|
|
14
14
|
import { authenticateUser } from './authenticate-user.js';
|
|
@@ -20,80 +20,79 @@ const nextAuthUrl = process.env.NEXTAUTH_URL;
|
|
|
20
20
|
if (!nextAuthUrl) {
|
|
21
21
|
throw new Error('NEXTAUTH_URL is not set');
|
|
22
22
|
}
|
|
23
|
-
export const generateSessionToken = async (user)
|
|
23
|
+
export const generateSessionToken = async (user)=>{
|
|
24
24
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
25
25
|
const alg = 'HS256';
|
|
26
26
|
const token = await new SignJWT({
|
|
27
|
-
roles: user.groups
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.setSubject(user.id)
|
|
32
|
-
.setIssuer('flux.website')
|
|
33
|
-
.setAudience('flux.website')
|
|
34
|
-
.sign(secret);
|
|
27
|
+
roles: user.groups
|
|
28
|
+
}).setProtectedHeader({
|
|
29
|
+
alg
|
|
30
|
+
}).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
|
|
35
31
|
return token.toString();
|
|
36
32
|
};
|
|
37
|
-
export const getCredentialsOptions = ()
|
|
33
|
+
export const getCredentialsOptions = ()=>{
|
|
38
34
|
return {
|
|
39
35
|
name: 'Credentials',
|
|
40
36
|
credentials: {
|
|
41
|
-
login: {
|
|
42
|
-
|
|
37
|
+
login: {
|
|
38
|
+
label: translations.email,
|
|
39
|
+
type: 'text'
|
|
40
|
+
},
|
|
41
|
+
password: {
|
|
42
|
+
label: translations.password,
|
|
43
|
+
type: 'password'
|
|
44
|
+
}
|
|
43
45
|
},
|
|
44
|
-
async authorize(credentials) {
|
|
46
|
+
async authorize (credentials) {
|
|
45
47
|
if (!credentials) {
|
|
46
48
|
return null;
|
|
47
49
|
}
|
|
48
50
|
const authResult = await authenticateUser(credentials);
|
|
49
51
|
return authResult.ok ? authResult.val : null;
|
|
50
|
-
}
|
|
52
|
+
}
|
|
51
53
|
};
|
|
52
54
|
};
|
|
53
55
|
export const authOptions = {
|
|
54
56
|
adapter,
|
|
55
57
|
providers: [
|
|
56
|
-
...
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}),
|
|
70
|
-
]
|
|
71
|
-
: []),
|
|
72
|
-
extractDefault(CredentialsProvider)(getCredentialsOptions()),
|
|
58
|
+
...config.auth.google ? [
|
|
59
|
+
extractDefault(GoogleProvider)({
|
|
60
|
+
...config.auth.google,
|
|
61
|
+
allowDangerousEmailAccountLinking: true
|
|
62
|
+
})
|
|
63
|
+
] : [],
|
|
64
|
+
...config.auth.facebook ? [
|
|
65
|
+
extractDefault(FacebookProvider)({
|
|
66
|
+
...config.auth.facebook,
|
|
67
|
+
allowDangerousEmailAccountLinking: true
|
|
68
|
+
})
|
|
69
|
+
] : [],
|
|
70
|
+
extractDefault(CredentialsProvider)(getCredentialsOptions())
|
|
73
71
|
],
|
|
74
72
|
callbacks: {
|
|
75
|
-
async signIn({ account, profile }) {
|
|
76
|
-
const processName = (profile)
|
|
73
|
+
async signIn ({ account, profile }) {
|
|
74
|
+
const processName = (profile)=>{
|
|
77
75
|
if (profile?.given_name || profile?.family_name) {
|
|
78
76
|
return {
|
|
79
77
|
firstName: profile?.given_name || '',
|
|
80
|
-
lastName: profile?.family_name || ''
|
|
78
|
+
lastName: profile?.family_name || ''
|
|
81
79
|
};
|
|
82
80
|
}
|
|
83
81
|
if (!profile?.name) {
|
|
84
82
|
return {
|
|
85
83
|
firstName: '',
|
|
86
|
-
lastName: ''
|
|
84
|
+
lastName: ''
|
|
87
85
|
};
|
|
88
86
|
}
|
|
89
|
-
const r = (str)
|
|
87
|
+
const r = (str)=>str.replace(/\s+/g, ' ').trim();
|
|
90
88
|
const names = profile?.name.trim();
|
|
91
89
|
const nameSegments = names.split(' ');
|
|
92
|
-
const firstName = r(nameSegments
|
|
93
|
-
.filter((_s, i) => i !== nameSegments?.length - 1)
|
|
94
|
-
.join(' '));
|
|
90
|
+
const firstName = r(nameSegments.filter((_s, i)=>i !== nameSegments?.length - 1).join(' '));
|
|
95
91
|
const lastName = r(nameSegments?.[nameSegments?.length - 1]);
|
|
96
|
-
return {
|
|
92
|
+
return {
|
|
93
|
+
firstName,
|
|
94
|
+
lastName
|
|
95
|
+
};
|
|
97
96
|
};
|
|
98
97
|
if (account?.provider === 'google') {
|
|
99
98
|
if (!profile?.email) {
|
|
@@ -104,7 +103,7 @@ export const authOptions = {
|
|
|
104
103
|
// const password = await bcrypt.hash(nanoid(), nanoid())
|
|
105
104
|
await prisma.user.upsert({
|
|
106
105
|
where: {
|
|
107
|
-
email: profile.email
|
|
106
|
+
email: profile.email
|
|
108
107
|
},
|
|
109
108
|
create: {
|
|
110
109
|
id: generateId('User'),
|
|
@@ -114,13 +113,12 @@ export const authOptions = {
|
|
|
114
113
|
password,
|
|
115
114
|
registrationComplete: false,
|
|
116
115
|
metadata: {
|
|
117
|
-
signupProvider: 'google'
|
|
118
|
-
}
|
|
116
|
+
signupProvider: 'google'
|
|
117
|
+
}
|
|
119
118
|
},
|
|
120
|
-
update: {}
|
|
119
|
+
update: {}
|
|
121
120
|
});
|
|
122
|
-
}
|
|
123
|
-
else if (account?.provider === 'facebook') {
|
|
121
|
+
} else if (account?.provider === 'facebook') {
|
|
124
122
|
if (!profile?.email) {
|
|
125
123
|
throw new Error('Unauthenticated');
|
|
126
124
|
}
|
|
@@ -128,7 +126,7 @@ export const authOptions = {
|
|
|
128
126
|
const password = `${nanoid()}-${nanoid()}`;
|
|
129
127
|
await prisma.user.upsert({
|
|
130
128
|
where: {
|
|
131
|
-
email: profile.email
|
|
129
|
+
email: profile.email
|
|
132
130
|
},
|
|
133
131
|
create: {
|
|
134
132
|
id: generateId('User'),
|
|
@@ -138,53 +136,50 @@ export const authOptions = {
|
|
|
138
136
|
password,
|
|
139
137
|
registrationComplete: false,
|
|
140
138
|
metadata: {
|
|
141
|
-
signupProvider: 'facebook'
|
|
142
|
-
}
|
|
139
|
+
signupProvider: 'facebook'
|
|
140
|
+
}
|
|
143
141
|
},
|
|
144
|
-
update: {}
|
|
142
|
+
update: {}
|
|
145
143
|
});
|
|
146
144
|
}
|
|
147
145
|
return true;
|
|
148
146
|
},
|
|
149
|
-
async session({ session, user, trigger, token, ...others }) {
|
|
150
|
-
const { password, permissions, stripeCustomerId, ...newUser } = {
|
|
147
|
+
async session ({ session, user, trigger, token, ...others }) {
|
|
148
|
+
const { password, permissions, stripeCustomerId, ...newUser } = {
|
|
149
|
+
...user
|
|
150
|
+
};
|
|
151
151
|
const finalSession = {
|
|
152
152
|
user: newUser,
|
|
153
153
|
expires: new Date(session.expires).toISOString(),
|
|
154
154
|
id: session.id,
|
|
155
|
-
sessionToken: session.sessionToken
|
|
155
|
+
sessionToken: session.sessionToken
|
|
156
156
|
};
|
|
157
|
-
const decodedToken = session.sessionToken
|
|
158
|
-
? decodeJwt(session.sessionToken)
|
|
159
|
-
: null;
|
|
157
|
+
const decodedToken = session.sessionToken ? decodeJwt(session.sessionToken) : null;
|
|
160
158
|
const tokenRoles = decodedToken?.roles;
|
|
161
159
|
if (session.sessionToken) {
|
|
162
|
-
if (trigger === 'update' ||
|
|
163
|
-
!tokenRoles ||
|
|
164
|
-
!areArraysSimilar(tokenRoles, user.groups)) {
|
|
160
|
+
if (trigger === 'update' || !tokenRoles || !areArraysSimilar(tokenRoles, user.groups)) {
|
|
165
161
|
const newSessionToken = await generateSessionToken(user);
|
|
166
162
|
// We can't call the update session from the patch because it searches by sessionToken and not by ID
|
|
167
163
|
try {
|
|
168
164
|
await prisma.session.update({
|
|
169
165
|
where: {
|
|
170
|
-
sessionToken: session.sessionToken
|
|
166
|
+
sessionToken: session.sessionToken
|
|
171
167
|
},
|
|
172
168
|
data: {
|
|
173
|
-
sessionToken: newSessionToken
|
|
174
|
-
}
|
|
169
|
+
sessionToken: newSessionToken
|
|
170
|
+
}
|
|
175
171
|
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// Nothing to do in this case
|
|
172
|
+
} catch (_e) {
|
|
173
|
+
// Sometimes, concurrent requests can happen and one would update
|
|
174
|
+
// before the other, so prisma won't find it based on sessionToken and throw
|
|
175
|
+
// Nothing to do in this case
|
|
181
176
|
}
|
|
182
177
|
// @ts-expect-error dirty property to be removed in the patch
|
|
183
178
|
finalSession.newSessionToken = newSessionToken;
|
|
184
179
|
}
|
|
185
180
|
}
|
|
186
181
|
return finalSession;
|
|
187
|
-
}
|
|
182
|
+
}
|
|
188
183
|
},
|
|
189
184
|
cookies: {
|
|
190
185
|
sessionToken: {
|
|
@@ -194,12 +189,8 @@ export const authOptions = {
|
|
|
194
189
|
sameSite: 'lax',
|
|
195
190
|
path: '/',
|
|
196
191
|
secure: useSecureCookies,
|
|
197
|
-
domain: process.env.NO_COOKIE_DOMAIN === 'true'
|
|
198
|
-
|
|
199
|
-
: nextAuthUrl === 'localhost'
|
|
200
|
-
? `.${nextAuthUrl}`
|
|
201
|
-
: `.${new URL(nextAuthUrl).hostname}`,
|
|
202
|
-
},
|
|
192
|
+
domain: process.env.NO_COOKIE_DOMAIN === 'true' ? undefined : nextAuthUrl === 'localhost' ? `.${nextAuthUrl}` : `.${new URL(nextAuthUrl).hostname}`
|
|
193
|
+
}
|
|
203
194
|
},
|
|
204
195
|
callbackUrl: {
|
|
205
196
|
name: AUTH_COOKIE_CALLBACK_URL,
|
|
@@ -207,8 +198,8 @@ export const authOptions = {
|
|
|
207
198
|
httpOnly: true,
|
|
208
199
|
sameSite: 'lax',
|
|
209
200
|
path: '/',
|
|
210
|
-
secure: useSecureCookies
|
|
211
|
-
}
|
|
201
|
+
secure: useSecureCookies
|
|
202
|
+
}
|
|
212
203
|
},
|
|
213
204
|
csrfToken: {
|
|
214
205
|
name: `${useSecureCookies ? '__Host-' : ''}${AUTH_COOKIE_CSRF_TOKEN}`,
|
|
@@ -216,8 +207,8 @@ export const authOptions = {
|
|
|
216
207
|
httpOnly: true,
|
|
217
208
|
sameSite: 'lax',
|
|
218
209
|
path: '/',
|
|
219
|
-
secure: useSecureCookies
|
|
220
|
-
}
|
|
210
|
+
secure: useSecureCookies
|
|
211
|
+
}
|
|
221
212
|
},
|
|
222
213
|
pkceCodeVerifier: {
|
|
223
214
|
name: AUTH_COOKIE_PKCE_CODE_VERIFIER,
|
|
@@ -226,8 +217,8 @@ export const authOptions = {
|
|
|
226
217
|
sameSite: 'lax',
|
|
227
218
|
path: '/',
|
|
228
219
|
secure: useSecureCookies,
|
|
229
|
-
maxAge: 900
|
|
230
|
-
}
|
|
220
|
+
maxAge: 900
|
|
221
|
+
}
|
|
231
222
|
},
|
|
232
223
|
state: {
|
|
233
224
|
name: AUTH_COOKIE_STATE,
|
|
@@ -236,8 +227,8 @@ export const authOptions = {
|
|
|
236
227
|
sameSite: 'lax',
|
|
237
228
|
path: '/',
|
|
238
229
|
secure: useSecureCookies,
|
|
239
|
-
maxAge: 900
|
|
240
|
-
}
|
|
230
|
+
maxAge: 900
|
|
231
|
+
}
|
|
241
232
|
},
|
|
242
233
|
nonce: {
|
|
243
234
|
name: AUTH_COOKIE_NONCE,
|
|
@@ -245,13 +236,13 @@ export const authOptions = {
|
|
|
245
236
|
httpOnly: true,
|
|
246
237
|
sameSite: 'lax',
|
|
247
238
|
path: '/',
|
|
248
|
-
secure: useSecureCookies
|
|
249
|
-
}
|
|
250
|
-
}
|
|
239
|
+
secure: useSecureCookies
|
|
240
|
+
}
|
|
241
|
+
}
|
|
251
242
|
},
|
|
252
243
|
useSecureCookies,
|
|
253
244
|
jwt: {
|
|
254
|
-
async encode(params) {
|
|
245
|
+
async encode (params) {
|
|
255
246
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
256
247
|
const alg = 'HS256';
|
|
257
248
|
const tokenId = params.token?.sub;
|
|
@@ -260,40 +251,36 @@ export const authOptions = {
|
|
|
260
251
|
}
|
|
261
252
|
const user = await prisma.user.findUnique({
|
|
262
253
|
where: {
|
|
263
|
-
id: tokenId
|
|
264
|
-
}
|
|
254
|
+
id: tokenId
|
|
255
|
+
}
|
|
265
256
|
});
|
|
266
257
|
if (!user) {
|
|
267
258
|
throw new Error('No user found');
|
|
268
259
|
}
|
|
269
260
|
const token = await new SignJWT({
|
|
270
261
|
...params.token,
|
|
271
|
-
roles: user.groups
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
.setSubject(user.id)
|
|
276
|
-
.setIssuer('flux.website')
|
|
277
|
-
.setAudience('flux.website')
|
|
278
|
-
.sign(secret);
|
|
262
|
+
roles: user.groups
|
|
263
|
+
}).setProtectedHeader({
|
|
264
|
+
alg
|
|
265
|
+
}).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
|
|
279
266
|
if (adapter.createSession) {
|
|
280
267
|
await adapter.createSession({
|
|
281
268
|
sessionToken: token,
|
|
282
269
|
userId: user.id,
|
|
283
|
-
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
270
|
+
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
284
271
|
});
|
|
285
272
|
}
|
|
286
273
|
return token;
|
|
287
|
-
}
|
|
274
|
+
}
|
|
288
275
|
},
|
|
289
276
|
session: {
|
|
290
277
|
strategy: 'database',
|
|
291
278
|
maxAge: MAX_AGE,
|
|
292
|
-
generateSessionToken: async (user)
|
|
279
|
+
generateSessionToken: async (user)=>{
|
|
293
280
|
return await generateSessionToken(user);
|
|
294
|
-
}
|
|
281
|
+
}
|
|
295
282
|
},
|
|
296
283
|
pages: {
|
|
297
|
-
signIn: '/signin'
|
|
298
|
-
}
|
|
284
|
+
signIn: '/signin'
|
|
285
|
+
}
|
|
299
286
|
};
|
|
@@ -4,136 +4,172 @@ export function PrismaAdapter() {
|
|
|
4
4
|
return {
|
|
5
5
|
// TODO
|
|
6
6
|
// @ts-expect-error TypeScript is not working here
|
|
7
|
-
createUser: async ({ id, groups, permissions, emailVerified, ...data })
|
|
7
|
+
createUser: async ({ id, groups, permissions, emailVerified, ...data })=>{
|
|
8
8
|
// @ts-expect-error
|
|
9
9
|
const userData = {
|
|
10
10
|
id: id || generateId('User'),
|
|
11
|
-
groups: groups || [
|
|
11
|
+
groups: groups || [
|
|
12
|
+
'member'
|
|
13
|
+
],
|
|
12
14
|
permissions: permissions || {},
|
|
13
15
|
emailVerified: Boolean(emailVerified),
|
|
14
16
|
email: data.email.toLowerCase().trim(),
|
|
15
|
-
...data
|
|
17
|
+
...data
|
|
16
18
|
};
|
|
17
19
|
const user = await prisma.user.create({
|
|
18
20
|
data: {
|
|
19
|
-
...userData
|
|
20
|
-
}
|
|
21
|
+
...userData
|
|
22
|
+
}
|
|
21
23
|
});
|
|
22
24
|
return user;
|
|
23
25
|
},
|
|
24
26
|
// TODO
|
|
25
27
|
// @ts-expect-error
|
|
26
|
-
getUser: (id)
|
|
28
|
+
getUser: (id)=>prisma.user.findUnique({
|
|
29
|
+
where: {
|
|
30
|
+
id
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
27
33
|
// TODO
|
|
28
34
|
// @ts-expect-error
|
|
29
|
-
getUserByEmail: (email)
|
|
35
|
+
getUserByEmail: (email)=>prisma.user.findUnique({
|
|
36
|
+
where: {
|
|
37
|
+
email: email.toLowerCase().trim()
|
|
38
|
+
}
|
|
39
|
+
}),
|
|
30
40
|
// TODO
|
|
31
41
|
// @ts-expect-error
|
|
32
|
-
async getUserByAccount(provider_providerAccountId) {
|
|
42
|
+
async getUserByAccount (provider_providerAccountId) {
|
|
33
43
|
const account = await prisma.account.findUnique({
|
|
34
|
-
where: {
|
|
35
|
-
|
|
44
|
+
where: {
|
|
45
|
+
provider_providerAccountId
|
|
46
|
+
},
|
|
47
|
+
select: {
|
|
48
|
+
user: true
|
|
49
|
+
}
|
|
36
50
|
});
|
|
37
51
|
return account?.user ?? null;
|
|
38
52
|
},
|
|
39
53
|
// TODO
|
|
40
54
|
// @ts-expect-error
|
|
41
|
-
updateUser: ({ id, ...data })
|
|
55
|
+
updateUser: ({ id, ...data })=>{
|
|
42
56
|
// @ts-expect-error
|
|
43
57
|
const userData = {
|
|
44
58
|
email: data.email?.toLowerCase().trim(),
|
|
45
|
-
...data
|
|
59
|
+
...data
|
|
46
60
|
};
|
|
47
|
-
return prisma.user.update({
|
|
61
|
+
return prisma.user.update({
|
|
62
|
+
where: {
|
|
63
|
+
id
|
|
64
|
+
},
|
|
65
|
+
data: {
|
|
66
|
+
...userData
|
|
67
|
+
}
|
|
68
|
+
});
|
|
48
69
|
},
|
|
49
70
|
// TODO
|
|
50
71
|
// @ts-expect-error
|
|
51
|
-
deleteUser: (id)
|
|
72
|
+
deleteUser: (id)=>prisma.user.delete({
|
|
73
|
+
where: {
|
|
74
|
+
id
|
|
75
|
+
}
|
|
76
|
+
}),
|
|
52
77
|
// @ts-expect-error
|
|
53
|
-
linkAccount: ({ id, ...data })
|
|
78
|
+
linkAccount: ({ id, ...data })=>{
|
|
54
79
|
return prisma.account.create({
|
|
55
80
|
// @ts-expect-error
|
|
56
81
|
data: {
|
|
57
82
|
id: id || generateId('Account'),
|
|
58
|
-
...data
|
|
59
|
-
}
|
|
83
|
+
...data
|
|
84
|
+
}
|
|
60
85
|
});
|
|
61
86
|
},
|
|
62
87
|
// @ts-expect-error
|
|
63
|
-
unlinkAccount: (provider_providerAccountId)
|
|
64
|
-
|
|
65
|
-
|
|
88
|
+
unlinkAccount: (provider_providerAccountId)=>prisma.account.delete({
|
|
89
|
+
where: {
|
|
90
|
+
provider_providerAccountId
|
|
91
|
+
}
|
|
92
|
+
}),
|
|
66
93
|
// TODO
|
|
67
94
|
// @ts-expect-error
|
|
68
|
-
async getSessionAndUser(sessionToken) {
|
|
95
|
+
async getSessionAndUser (sessionToken) {
|
|
69
96
|
const userAndSession = await prisma.session.findUnique({
|
|
70
|
-
where: {
|
|
71
|
-
|
|
97
|
+
where: {
|
|
98
|
+
sessionToken
|
|
99
|
+
},
|
|
100
|
+
include: {
|
|
101
|
+
user: true
|
|
102
|
+
}
|
|
72
103
|
});
|
|
73
|
-
if (!userAndSession)
|
|
74
|
-
return null;
|
|
104
|
+
if (!userAndSession) return null;
|
|
75
105
|
const { user, ...session } = userAndSession;
|
|
76
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
user,
|
|
108
|
+
session
|
|
109
|
+
};
|
|
77
110
|
},
|
|
78
111
|
// TODO
|
|
79
112
|
// @ts-expect-error
|
|
80
|
-
async createSession({ id, ...data }) {
|
|
113
|
+
async createSession ({ id, ...data }) {
|
|
81
114
|
const session = await prisma.session.create({
|
|
82
115
|
data: {
|
|
83
116
|
id: id || generateId('Session'),
|
|
84
|
-
...data
|
|
85
|
-
}
|
|
117
|
+
...data
|
|
118
|
+
}
|
|
86
119
|
});
|
|
87
120
|
return session;
|
|
88
121
|
},
|
|
89
|
-
updateSession: (data)
|
|
122
|
+
updateSession: (data)=>{
|
|
90
123
|
return prisma.session.update({
|
|
91
|
-
where: {
|
|
92
|
-
|
|
124
|
+
where: {
|
|
125
|
+
sessionToken: data.sessionToken
|
|
126
|
+
},
|
|
127
|
+
data
|
|
93
128
|
});
|
|
94
129
|
},
|
|
95
|
-
deleteSession: async (sessionToken)
|
|
130
|
+
deleteSession: async (sessionToken)=>{
|
|
96
131
|
try {
|
|
97
|
-
await prisma.session.delete({
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
await prisma.session.delete({
|
|
133
|
+
where: {
|
|
134
|
+
sessionToken
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
} catch (_e) {
|
|
138
|
+
// TODO
|
|
139
|
+
// DO nothing for now
|
|
102
140
|
}
|
|
103
141
|
},
|
|
104
142
|
// TODO
|
|
105
143
|
// @ts-expect-error
|
|
106
|
-
async createVerificationToken({ id, ...data }) {
|
|
144
|
+
async createVerificationToken ({ id, ...data }) {
|
|
107
145
|
const verificationToken = await prisma.verificationToken.create({
|
|
108
146
|
data: {
|
|
109
147
|
id: id || generateId('VerificationToken'),
|
|
110
|
-
...data
|
|
111
|
-
}
|
|
148
|
+
...data
|
|
149
|
+
}
|
|
112
150
|
});
|
|
113
151
|
// TODO
|
|
114
152
|
// @ts-expect-errors // MongoDB needs an ID, but we don't
|
|
115
|
-
if (verificationToken.id)
|
|
116
|
-
verificationToken.id = undefined;
|
|
153
|
+
if (verificationToken.id) verificationToken.id = undefined;
|
|
117
154
|
return verificationToken;
|
|
118
155
|
},
|
|
119
|
-
async useVerificationToken(identifier_token) {
|
|
156
|
+
async useVerificationToken (identifier_token) {
|
|
120
157
|
try {
|
|
121
158
|
const verificationToken = await prisma.verificationToken.delete({
|
|
122
|
-
where: {
|
|
159
|
+
where: {
|
|
160
|
+
identifier_token
|
|
161
|
+
}
|
|
123
162
|
});
|
|
124
163
|
// TODO
|
|
125
164
|
// @ts-expect-errors // MongoDB needs an ID, but we don't
|
|
126
|
-
if (verificationToken.id)
|
|
127
|
-
verificationToken.id = undefined;
|
|
165
|
+
if (verificationToken.id) verificationToken.id = undefined;
|
|
128
166
|
return verificationToken;
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
167
|
+
} catch (error) {
|
|
131
168
|
// If token already used/deleted, just return null
|
|
132
169
|
// https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
|
|
133
|
-
if (error.code === 'P2025')
|
|
134
|
-
return null;
|
|
170
|
+
if (error.code === 'P2025') return null;
|
|
135
171
|
throw error;
|
|
136
172
|
}
|
|
137
|
-
}
|
|
173
|
+
}
|
|
138
174
|
};
|
|
139
175
|
}
|
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
import { prisma } from '@driveflux/db';
|
|
2
|
-
import { makeProblem, PROBLEM_CORRUPT, PROBLEM_EXPIRED, PROBLEM_INVALID_DATA
|
|
2
|
+
import { makeProblem, PROBLEM_CORRUPT, PROBLEM_EXPIRED, PROBLEM_INVALID_DATA } from '@driveflux/problem';
|
|
3
3
|
import { Err, Ok } from '@driveflux/result';
|
|
4
|
-
export const verifyToken = async (tokenIdOrValue, verifications, option)
|
|
5
|
-
const token = typeof tokenIdOrValue === 'object'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
export const verifyToken = async (tokenIdOrValue, verifications, option)=>{
|
|
5
|
+
const token = typeof tokenIdOrValue === 'object' ? tokenIdOrValue : await prisma.token.findFirst({
|
|
6
|
+
where: {
|
|
7
|
+
OR: [
|
|
8
|
+
{
|
|
9
|
+
id: tokenIdOrValue
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
value: tokenIdOrValue
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
...option?.includeUser ? {
|
|
17
|
+
include: {
|
|
18
|
+
user: true
|
|
19
|
+
}
|
|
20
|
+
} : {}
|
|
21
|
+
});
|
|
13
22
|
if (!token) {
|
|
14
23
|
return new Err(makeProblem(PROBLEM_INVALID_DATA, 'Invalid token'));
|
|
15
24
|
}
|
|
16
25
|
if (token.expiresAt && token.expiresAt.getTime() < Date.now()) {
|
|
17
26
|
return new Err(makeProblem(PROBLEM_EXPIRED, 'This token has expired'));
|
|
18
27
|
}
|
|
19
|
-
if (typeof verifications?.scope !== 'undefined' &&
|
|
20
|
-
token.scope !== verifications.scope) {
|
|
28
|
+
if (typeof verifications?.scope !== 'undefined' && token.scope !== verifications.scope) {
|
|
21
29
|
return new Err(makeProblem(PROBLEM_INVALID_DATA, 'Invalid token scope'));
|
|
22
30
|
}
|
|
23
31
|
if (typeof verifications?.metadata !== 'undefined') {
|
|
24
|
-
for (const key of Object.keys(verifications.metadata))
|
|
25
|
-
if (typeof verifications.metadata[key] !== 'undefined' &&
|
|
26
|
-
verifications.metadata[key] !== token.metadata?.[key]) {
|
|
32
|
+
for (const key of Object.keys(verifications.metadata)){
|
|
33
|
+
if (typeof verifications.metadata[key] !== 'undefined' && verifications.metadata[key] !== token.metadata?.[key]) {
|
|
27
34
|
return new Err(makeProblem(PROBLEM_INVALID_DATA, 'Invalid token data'));
|
|
28
35
|
}
|
|
29
36
|
}
|
|
@@ -33,22 +40,30 @@ export const verifyToken = async (tokenIdOrValue, verifications, option) => {
|
|
|
33
40
|
}
|
|
34
41
|
return new Ok(token);
|
|
35
42
|
};
|
|
36
|
-
export const clearToken = async (tokenId)
|
|
43
|
+
export const clearToken = async (tokenId)=>{
|
|
37
44
|
try {
|
|
38
45
|
await prisma.token.delete({
|
|
39
46
|
where: {
|
|
40
|
-
id: tokenId
|
|
41
|
-
}
|
|
47
|
+
id: tokenId
|
|
48
|
+
}
|
|
42
49
|
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Nothing to for now
|
|
50
|
+
} catch (_e) {
|
|
51
|
+
// Nothing to for now
|
|
46
52
|
}
|
|
47
53
|
};
|
|
48
|
-
export const clearExpiredTokens = async ()
|
|
54
|
+
export const clearExpiredTokens = async ()=>{
|
|
49
55
|
await prisma.token.deleteMany({
|
|
50
56
|
where: {
|
|
51
|
-
OR: [
|
|
52
|
-
|
|
57
|
+
OR: [
|
|
58
|
+
{
|
|
59
|
+
expiresAt: {
|
|
60
|
+
lte: new Date()
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
invalid: true
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
53
68
|
});
|
|
54
69
|
};
|