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