@driveflux/auth 4.0.29 → 4.0.31
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 +24 -52
- 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 -22
- package/dist/server/credentials-provider.js +2 -2
- package/dist/server/next-auth.js +96 -86
- package/dist/server/prisma-adapter.js +52 -88
- package/dist/server/verfiy-token.js +24 -39
- package/dist/translations.js +4 -4
- package/dist/types.js +1 -1
- 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,42 +138,44 @@ 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 }) {
|
|
150
|
+
const { password, permissions, stripeCustomerId, ...newUser } = { ...user };
|
|
151
151
|
const finalSession = {
|
|
152
152
|
user: newUser,
|
|
153
|
-
expires: new Date(session.expires).toISOString()
|
|
153
|
+
expires: new Date(session.expires).toISOString(),
|
|
154
154
|
};
|
|
155
|
-
const decodedToken = session.sessionToken
|
|
155
|
+
const decodedToken = session.sessionToken
|
|
156
|
+
? decodeJwt(session.sessionToken)
|
|
157
|
+
: null;
|
|
156
158
|
const tokenRoles = decodedToken?.roles;
|
|
157
159
|
if (session.sessionToken) {
|
|
158
|
-
if (trigger === 'update' ||
|
|
160
|
+
if (trigger === 'update' ||
|
|
161
|
+
!tokenRoles ||
|
|
162
|
+
!areArraysSimilar(tokenRoles, user.groups)) {
|
|
159
163
|
const newSessionToken = await generateSessionToken(user);
|
|
160
164
|
// We can't call the update session from the patch because it searches by sessionToken and not by ID
|
|
161
165
|
await prisma.session.update({
|
|
162
166
|
where: {
|
|
163
|
-
sessionToken: session.sessionToken
|
|
167
|
+
sessionToken: session.sessionToken,
|
|
164
168
|
},
|
|
165
169
|
data: {
|
|
166
|
-
sessionToken: newSessionToken
|
|
167
|
-
}
|
|
170
|
+
sessionToken: newSessionToken,
|
|
171
|
+
},
|
|
168
172
|
});
|
|
169
173
|
// @ts-expect-error dirty property to be removed in the patch
|
|
170
174
|
finalSession.newSessionToken = newSessionToken;
|
|
171
175
|
}
|
|
172
176
|
}
|
|
173
177
|
return finalSession;
|
|
174
|
-
}
|
|
178
|
+
},
|
|
175
179
|
},
|
|
176
180
|
cookies: {
|
|
177
181
|
sessionToken: {
|
|
@@ -181,8 +185,10 @@ export const authOptions = {
|
|
|
181
185
|
sameSite: 'lax',
|
|
182
186
|
path: '/',
|
|
183
187
|
secure: useSecureCookies,
|
|
184
|
-
domain: nextAuthUrl === 'localhost'
|
|
185
|
-
|
|
188
|
+
domain: nextAuthUrl === 'localhost'
|
|
189
|
+
? `.${nextAuthUrl}`
|
|
190
|
+
: `.${new URL(nextAuthUrl).hostname}`,
|
|
191
|
+
},
|
|
186
192
|
},
|
|
187
193
|
callbackUrl: {
|
|
188
194
|
name: AUTH_COOKIE_CALLBACK_URL,
|
|
@@ -190,8 +196,8 @@ export const authOptions = {
|
|
|
190
196
|
httpOnly: true,
|
|
191
197
|
sameSite: 'lax',
|
|
192
198
|
path: '/',
|
|
193
|
-
secure: useSecureCookies
|
|
194
|
-
}
|
|
199
|
+
secure: useSecureCookies,
|
|
200
|
+
},
|
|
195
201
|
},
|
|
196
202
|
csrfToken: {
|
|
197
203
|
name: `${useSecureCookies ? '__Host-' : ''}${AUTH_COOKIE_CSRF_TOKEN}`,
|
|
@@ -199,8 +205,8 @@ export const authOptions = {
|
|
|
199
205
|
httpOnly: true,
|
|
200
206
|
sameSite: 'lax',
|
|
201
207
|
path: '/',
|
|
202
|
-
secure: useSecureCookies
|
|
203
|
-
}
|
|
208
|
+
secure: useSecureCookies,
|
|
209
|
+
},
|
|
204
210
|
},
|
|
205
211
|
pkceCodeVerifier: {
|
|
206
212
|
name: AUTH_COOKIE_PKCE_CODE_VERIFIER,
|
|
@@ -209,8 +215,8 @@ export const authOptions = {
|
|
|
209
215
|
sameSite: 'lax',
|
|
210
216
|
path: '/',
|
|
211
217
|
secure: useSecureCookies,
|
|
212
|
-
maxAge: 900
|
|
213
|
-
}
|
|
218
|
+
maxAge: 900,
|
|
219
|
+
},
|
|
214
220
|
},
|
|
215
221
|
state: {
|
|
216
222
|
name: AUTH_COOKIE_STATE,
|
|
@@ -219,8 +225,8 @@ export const authOptions = {
|
|
|
219
225
|
sameSite: 'lax',
|
|
220
226
|
path: '/',
|
|
221
227
|
secure: useSecureCookies,
|
|
222
|
-
maxAge: 900
|
|
223
|
-
}
|
|
228
|
+
maxAge: 900,
|
|
229
|
+
},
|
|
224
230
|
},
|
|
225
231
|
nonce: {
|
|
226
232
|
name: AUTH_COOKIE_NONCE,
|
|
@@ -228,13 +234,13 @@ export const authOptions = {
|
|
|
228
234
|
httpOnly: true,
|
|
229
235
|
sameSite: 'lax',
|
|
230
236
|
path: '/',
|
|
231
|
-
secure: useSecureCookies
|
|
232
|
-
}
|
|
233
|
-
}
|
|
237
|
+
secure: useSecureCookies,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
234
240
|
},
|
|
235
241
|
useSecureCookies,
|
|
236
242
|
jwt: {
|
|
237
|
-
async encode
|
|
243
|
+
async encode(params) {
|
|
238
244
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
239
245
|
const alg = 'HS256';
|
|
240
246
|
const tokenId = params.token?.sub;
|
|
@@ -243,36 +249,40 @@ export const authOptions = {
|
|
|
243
249
|
}
|
|
244
250
|
const user = await prisma.user.findUnique({
|
|
245
251
|
where: {
|
|
246
|
-
id: tokenId
|
|
247
|
-
}
|
|
252
|
+
id: tokenId,
|
|
253
|
+
},
|
|
248
254
|
});
|
|
249
255
|
if (!user) {
|
|
250
256
|
throw new Error('No user found');
|
|
251
257
|
}
|
|
252
258
|
const token = await new SignJWT({
|
|
253
259
|
...params.token,
|
|
254
|
-
roles: user.groups
|
|
255
|
-
})
|
|
256
|
-
alg
|
|
257
|
-
|
|
260
|
+
roles: user.groups,
|
|
261
|
+
})
|
|
262
|
+
.setProtectedHeader({ alg })
|
|
263
|
+
.setIssuedAt()
|
|
264
|
+
.setSubject(user.id)
|
|
265
|
+
.setIssuer('flux.website')
|
|
266
|
+
.setAudience('flux.website')
|
|
267
|
+
.sign(secret);
|
|
258
268
|
if (adapter.createSession) {
|
|
259
269
|
await adapter.createSession({
|
|
260
270
|
sessionToken: token,
|
|
261
271
|
userId: user.id,
|
|
262
|
-
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
272
|
+
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000),
|
|
263
273
|
});
|
|
264
274
|
}
|
|
265
275
|
return token;
|
|
266
|
-
}
|
|
276
|
+
},
|
|
267
277
|
},
|
|
268
278
|
session: {
|
|
269
279
|
strategy: 'database',
|
|
270
280
|
maxAge: MAX_AGE,
|
|
271
|
-
generateSessionToken: async (user)=>{
|
|
281
|
+
generateSessionToken: async (user) => {
|
|
272
282
|
return await generateSessionToken(user);
|
|
273
|
-
}
|
|
283
|
+
},
|
|
274
284
|
},
|
|
275
285
|
pages: {
|
|
276
|
-
signIn: '/signin'
|
|
277
|
-
}
|
|
286
|
+
signIn: '/signin',
|
|
287
|
+
},
|
|
278
288
|
};
|
|
@@ -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
|
};
|