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