@driveflux/auth 4.0.35 → 4.0.37
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 -23
- package/dist/server/credentials-provider.js +2 -2
- package/dist/server/next-auth.js +98 -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 +3 -3
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,12 @@ export const authOptions = {
|
|
|
181
185
|
sameSite: 'lax',
|
|
182
186
|
path: '/',
|
|
183
187
|
secure: useSecureCookies,
|
|
184
|
-
domain: process.env.NO_COOKIE_DOMAIN === 'true'
|
|
185
|
-
|
|
188
|
+
domain: process.env.NO_COOKIE_DOMAIN === 'true'
|
|
189
|
+
? undefined
|
|
190
|
+
: nextAuthUrl === 'localhost'
|
|
191
|
+
? `.${nextAuthUrl}`
|
|
192
|
+
: `.${new URL(nextAuthUrl).hostname}`,
|
|
193
|
+
},
|
|
186
194
|
},
|
|
187
195
|
callbackUrl: {
|
|
188
196
|
name: AUTH_COOKIE_CALLBACK_URL,
|
|
@@ -190,8 +198,8 @@ export const authOptions = {
|
|
|
190
198
|
httpOnly: true,
|
|
191
199
|
sameSite: 'lax',
|
|
192
200
|
path: '/',
|
|
193
|
-
secure: useSecureCookies
|
|
194
|
-
}
|
|
201
|
+
secure: useSecureCookies,
|
|
202
|
+
},
|
|
195
203
|
},
|
|
196
204
|
csrfToken: {
|
|
197
205
|
name: `${useSecureCookies ? '__Host-' : ''}${AUTH_COOKIE_CSRF_TOKEN}`,
|
|
@@ -199,8 +207,8 @@ export const authOptions = {
|
|
|
199
207
|
httpOnly: true,
|
|
200
208
|
sameSite: 'lax',
|
|
201
209
|
path: '/',
|
|
202
|
-
secure: useSecureCookies
|
|
203
|
-
}
|
|
210
|
+
secure: useSecureCookies,
|
|
211
|
+
},
|
|
204
212
|
},
|
|
205
213
|
pkceCodeVerifier: {
|
|
206
214
|
name: AUTH_COOKIE_PKCE_CODE_VERIFIER,
|
|
@@ -209,8 +217,8 @@ export const authOptions = {
|
|
|
209
217
|
sameSite: 'lax',
|
|
210
218
|
path: '/',
|
|
211
219
|
secure: useSecureCookies,
|
|
212
|
-
maxAge: 900
|
|
213
|
-
}
|
|
220
|
+
maxAge: 900,
|
|
221
|
+
},
|
|
214
222
|
},
|
|
215
223
|
state: {
|
|
216
224
|
name: AUTH_COOKIE_STATE,
|
|
@@ -219,8 +227,8 @@ export const authOptions = {
|
|
|
219
227
|
sameSite: 'lax',
|
|
220
228
|
path: '/',
|
|
221
229
|
secure: useSecureCookies,
|
|
222
|
-
maxAge: 900
|
|
223
|
-
}
|
|
230
|
+
maxAge: 900,
|
|
231
|
+
},
|
|
224
232
|
},
|
|
225
233
|
nonce: {
|
|
226
234
|
name: AUTH_COOKIE_NONCE,
|
|
@@ -228,13 +236,13 @@ export const authOptions = {
|
|
|
228
236
|
httpOnly: true,
|
|
229
237
|
sameSite: 'lax',
|
|
230
238
|
path: '/',
|
|
231
|
-
secure: useSecureCookies
|
|
232
|
-
}
|
|
233
|
-
}
|
|
239
|
+
secure: useSecureCookies,
|
|
240
|
+
},
|
|
241
|
+
},
|
|
234
242
|
},
|
|
235
243
|
useSecureCookies,
|
|
236
244
|
jwt: {
|
|
237
|
-
async encode
|
|
245
|
+
async encode(params) {
|
|
238
246
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
239
247
|
const alg = 'HS256';
|
|
240
248
|
const tokenId = params.token?.sub;
|
|
@@ -243,36 +251,40 @@ export const authOptions = {
|
|
|
243
251
|
}
|
|
244
252
|
const user = await prisma.user.findUnique({
|
|
245
253
|
where: {
|
|
246
|
-
id: tokenId
|
|
247
|
-
}
|
|
254
|
+
id: tokenId,
|
|
255
|
+
},
|
|
248
256
|
});
|
|
249
257
|
if (!user) {
|
|
250
258
|
throw new Error('No user found');
|
|
251
259
|
}
|
|
252
260
|
const token = await new SignJWT({
|
|
253
261
|
...params.token,
|
|
254
|
-
roles: user.groups
|
|
255
|
-
})
|
|
256
|
-
alg
|
|
257
|
-
|
|
262
|
+
roles: user.groups,
|
|
263
|
+
})
|
|
264
|
+
.setProtectedHeader({ alg })
|
|
265
|
+
.setIssuedAt()
|
|
266
|
+
.setSubject(user.id)
|
|
267
|
+
.setIssuer('flux.website')
|
|
268
|
+
.setAudience('flux.website')
|
|
269
|
+
.sign(secret);
|
|
258
270
|
if (adapter.createSession) {
|
|
259
271
|
await adapter.createSession({
|
|
260
272
|
sessionToken: token,
|
|
261
273
|
userId: user.id,
|
|
262
|
-
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
274
|
+
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000),
|
|
263
275
|
});
|
|
264
276
|
}
|
|
265
277
|
return token;
|
|
266
|
-
}
|
|
278
|
+
},
|
|
267
279
|
},
|
|
268
280
|
session: {
|
|
269
281
|
strategy: 'database',
|
|
270
282
|
maxAge: MAX_AGE,
|
|
271
|
-
generateSessionToken: async (user)=>{
|
|
283
|
+
generateSessionToken: async (user) => {
|
|
272
284
|
return await generateSessionToken(user);
|
|
273
|
-
}
|
|
285
|
+
},
|
|
274
286
|
},
|
|
275
287
|
pages: {
|
|
276
|
-
signIn: '/signin'
|
|
277
|
-
}
|
|
288
|
+
signIn: '/signin',
|
|
289
|
+
},
|
|
278
290
|
};
|
|
@@ -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
|
};
|