@driveflux/auth 4.0.31 → 4.0.33
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 +52 -24
- 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 +22 -12
- package/dist/server/credentials-provider.js +2 -2
- package/dist/server/next-auth.js +86 -96
- 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 +2 -2
package/dist/server/next-auth.js
CHANGED
|
@@ -8,7 +8,7 @@ import { nanoid } from 'nanoid';
|
|
|
8
8
|
import CredentialsProvider from 'next-auth/providers/credentials';
|
|
9
9
|
import FacebookProvider from 'next-auth/providers/facebook';
|
|
10
10
|
import GoogleProvider from 'next-auth/providers/google';
|
|
11
|
-
import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE
|
|
11
|
+
import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE } from '../constants.js';
|
|
12
12
|
import { extractDefault } from '../default.js';
|
|
13
13
|
import { translations } from '../translations.js';
|
|
14
14
|
import { authenticateUser } from './authenticate-user.js';
|
|
@@ -20,80 +20,79 @@ const nextAuthUrl = process.env.NEXTAUTH_URL;
|
|
|
20
20
|
if (!nextAuthUrl) {
|
|
21
21
|
throw new Error('NEXTAUTH_URL is not set');
|
|
22
22
|
}
|
|
23
|
-
export const generateSessionToken = async (user)
|
|
23
|
+
export const generateSessionToken = async (user)=>{
|
|
24
24
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
25
25
|
const alg = 'HS256';
|
|
26
26
|
const token = await new SignJWT({
|
|
27
|
-
roles: user.groups
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.setSubject(user.id)
|
|
32
|
-
.setIssuer('flux.website')
|
|
33
|
-
.setAudience('flux.website')
|
|
34
|
-
.sign(secret);
|
|
27
|
+
roles: user.groups
|
|
28
|
+
}).setProtectedHeader({
|
|
29
|
+
alg
|
|
30
|
+
}).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
|
|
35
31
|
return token.toString();
|
|
36
32
|
};
|
|
37
|
-
export const getCredentialsOptions = ()
|
|
33
|
+
export const getCredentialsOptions = ()=>{
|
|
38
34
|
return {
|
|
39
35
|
name: 'Credentials',
|
|
40
36
|
credentials: {
|
|
41
|
-
login: {
|
|
42
|
-
|
|
37
|
+
login: {
|
|
38
|
+
label: translations.email,
|
|
39
|
+
type: 'text'
|
|
40
|
+
},
|
|
41
|
+
password: {
|
|
42
|
+
label: translations.password,
|
|
43
|
+
type: 'password'
|
|
44
|
+
}
|
|
43
45
|
},
|
|
44
|
-
async authorize(credentials) {
|
|
46
|
+
async authorize (credentials) {
|
|
45
47
|
if (!credentials) {
|
|
46
48
|
return null;
|
|
47
49
|
}
|
|
48
50
|
const authResult = await authenticateUser(credentials);
|
|
49
51
|
return authResult.ok ? authResult.val : null;
|
|
50
|
-
}
|
|
52
|
+
}
|
|
51
53
|
};
|
|
52
54
|
};
|
|
53
55
|
export const authOptions = {
|
|
54
56
|
adapter,
|
|
55
57
|
providers: [
|
|
56
|
-
...
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}),
|
|
70
|
-
]
|
|
71
|
-
: []),
|
|
72
|
-
extractDefault(CredentialsProvider)(getCredentialsOptions()),
|
|
58
|
+
...config.auth.google ? [
|
|
59
|
+
extractDefault(GoogleProvider)({
|
|
60
|
+
...config.auth.google,
|
|
61
|
+
allowDangerousEmailAccountLinking: true
|
|
62
|
+
})
|
|
63
|
+
] : [],
|
|
64
|
+
...config.auth.facebook ? [
|
|
65
|
+
extractDefault(FacebookProvider)({
|
|
66
|
+
...config.auth.facebook,
|
|
67
|
+
allowDangerousEmailAccountLinking: true
|
|
68
|
+
})
|
|
69
|
+
] : [],
|
|
70
|
+
extractDefault(CredentialsProvider)(getCredentialsOptions())
|
|
73
71
|
],
|
|
74
72
|
callbacks: {
|
|
75
|
-
async signIn({ account, profile }) {
|
|
76
|
-
const processName = (profile)
|
|
73
|
+
async signIn ({ account, profile }) {
|
|
74
|
+
const processName = (profile)=>{
|
|
77
75
|
if (profile?.given_name || profile?.family_name) {
|
|
78
76
|
return {
|
|
79
77
|
firstName: profile?.given_name || '',
|
|
80
|
-
lastName: profile?.family_name || ''
|
|
78
|
+
lastName: profile?.family_name || ''
|
|
81
79
|
};
|
|
82
80
|
}
|
|
83
81
|
if (!profile?.name) {
|
|
84
82
|
return {
|
|
85
83
|
firstName: '',
|
|
86
|
-
lastName: ''
|
|
84
|
+
lastName: ''
|
|
87
85
|
};
|
|
88
86
|
}
|
|
89
|
-
const r = (str)
|
|
87
|
+
const r = (str)=>str.replace(/\s+/g, ' ').trim();
|
|
90
88
|
const names = profile?.name.trim();
|
|
91
89
|
const nameSegments = names.split(' ');
|
|
92
|
-
const firstName = r(nameSegments
|
|
93
|
-
.filter((_s, i) => i !== nameSegments?.length - 1)
|
|
94
|
-
.join(' '));
|
|
90
|
+
const firstName = r(nameSegments.filter((_s, i)=>i !== nameSegments?.length - 1).join(' '));
|
|
95
91
|
const lastName = r(nameSegments?.[nameSegments?.length - 1]);
|
|
96
|
-
return {
|
|
92
|
+
return {
|
|
93
|
+
firstName,
|
|
94
|
+
lastName
|
|
95
|
+
};
|
|
97
96
|
};
|
|
98
97
|
if (account?.provider === 'google') {
|
|
99
98
|
if (!profile?.email) {
|
|
@@ -104,7 +103,7 @@ export const authOptions = {
|
|
|
104
103
|
// const password = await bcrypt.hash(nanoid(), nanoid())
|
|
105
104
|
await prisma.user.upsert({
|
|
106
105
|
where: {
|
|
107
|
-
email: profile.email
|
|
106
|
+
email: profile.email
|
|
108
107
|
},
|
|
109
108
|
create: {
|
|
110
109
|
id: generateId('User'),
|
|
@@ -114,13 +113,12 @@ export const authOptions = {
|
|
|
114
113
|
password,
|
|
115
114
|
registrationComplete: false,
|
|
116
115
|
metadata: {
|
|
117
|
-
signupProvider: 'google'
|
|
118
|
-
}
|
|
116
|
+
signupProvider: 'google'
|
|
117
|
+
}
|
|
119
118
|
},
|
|
120
|
-
update: {}
|
|
119
|
+
update: {}
|
|
121
120
|
});
|
|
122
|
-
}
|
|
123
|
-
else if (account?.provider === 'facebook') {
|
|
121
|
+
} else if (account?.provider === 'facebook') {
|
|
124
122
|
if (!profile?.email) {
|
|
125
123
|
throw new Error('Unauthenticated');
|
|
126
124
|
}
|
|
@@ -128,7 +126,7 @@ export const authOptions = {
|
|
|
128
126
|
const password = `${nanoid()}-${nanoid()}`;
|
|
129
127
|
await prisma.user.upsert({
|
|
130
128
|
where: {
|
|
131
|
-
email: profile.email
|
|
129
|
+
email: profile.email
|
|
132
130
|
},
|
|
133
131
|
create: {
|
|
134
132
|
id: generateId('User'),
|
|
@@ -138,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,10 +181,8 @@ export const authOptions = {
|
|
|
185
181
|
sameSite: 'lax',
|
|
186
182
|
path: '/',
|
|
187
183
|
secure: useSecureCookies,
|
|
188
|
-
domain: nextAuthUrl === 'localhost'
|
|
189
|
-
|
|
190
|
-
: `.${new URL(nextAuthUrl).hostname}`,
|
|
191
|
-
},
|
|
184
|
+
domain: nextAuthUrl === 'localhost' ? `.${nextAuthUrl}` : `.${new URL(nextAuthUrl).hostname}`
|
|
185
|
+
}
|
|
192
186
|
},
|
|
193
187
|
callbackUrl: {
|
|
194
188
|
name: AUTH_COOKIE_CALLBACK_URL,
|
|
@@ -196,8 +190,8 @@ export const authOptions = {
|
|
|
196
190
|
httpOnly: true,
|
|
197
191
|
sameSite: 'lax',
|
|
198
192
|
path: '/',
|
|
199
|
-
secure: useSecureCookies
|
|
200
|
-
}
|
|
193
|
+
secure: useSecureCookies
|
|
194
|
+
}
|
|
201
195
|
},
|
|
202
196
|
csrfToken: {
|
|
203
197
|
name: `${useSecureCookies ? '__Host-' : ''}${AUTH_COOKIE_CSRF_TOKEN}`,
|
|
@@ -205,8 +199,8 @@ export const authOptions = {
|
|
|
205
199
|
httpOnly: true,
|
|
206
200
|
sameSite: 'lax',
|
|
207
201
|
path: '/',
|
|
208
|
-
secure: useSecureCookies
|
|
209
|
-
}
|
|
202
|
+
secure: useSecureCookies
|
|
203
|
+
}
|
|
210
204
|
},
|
|
211
205
|
pkceCodeVerifier: {
|
|
212
206
|
name: AUTH_COOKIE_PKCE_CODE_VERIFIER,
|
|
@@ -215,8 +209,8 @@ export const authOptions = {
|
|
|
215
209
|
sameSite: 'lax',
|
|
216
210
|
path: '/',
|
|
217
211
|
secure: useSecureCookies,
|
|
218
|
-
maxAge: 900
|
|
219
|
-
}
|
|
212
|
+
maxAge: 900
|
|
213
|
+
}
|
|
220
214
|
},
|
|
221
215
|
state: {
|
|
222
216
|
name: AUTH_COOKIE_STATE,
|
|
@@ -225,8 +219,8 @@ export const authOptions = {
|
|
|
225
219
|
sameSite: 'lax',
|
|
226
220
|
path: '/',
|
|
227
221
|
secure: useSecureCookies,
|
|
228
|
-
maxAge: 900
|
|
229
|
-
}
|
|
222
|
+
maxAge: 900
|
|
223
|
+
}
|
|
230
224
|
},
|
|
231
225
|
nonce: {
|
|
232
226
|
name: AUTH_COOKIE_NONCE,
|
|
@@ -234,13 +228,13 @@ export const authOptions = {
|
|
|
234
228
|
httpOnly: true,
|
|
235
229
|
sameSite: 'lax',
|
|
236
230
|
path: '/',
|
|
237
|
-
secure: useSecureCookies
|
|
238
|
-
}
|
|
239
|
-
}
|
|
231
|
+
secure: useSecureCookies
|
|
232
|
+
}
|
|
233
|
+
}
|
|
240
234
|
},
|
|
241
235
|
useSecureCookies,
|
|
242
236
|
jwt: {
|
|
243
|
-
async encode(params) {
|
|
237
|
+
async encode (params) {
|
|
244
238
|
const secret = new TextEncoder().encode(config.auth.jwtSecret);
|
|
245
239
|
const alg = 'HS256';
|
|
246
240
|
const tokenId = params.token?.sub;
|
|
@@ -249,40 +243,36 @@ export const authOptions = {
|
|
|
249
243
|
}
|
|
250
244
|
const user = await prisma.user.findUnique({
|
|
251
245
|
where: {
|
|
252
|
-
id: tokenId
|
|
253
|
-
}
|
|
246
|
+
id: tokenId
|
|
247
|
+
}
|
|
254
248
|
});
|
|
255
249
|
if (!user) {
|
|
256
250
|
throw new Error('No user found');
|
|
257
251
|
}
|
|
258
252
|
const token = await new SignJWT({
|
|
259
253
|
...params.token,
|
|
260
|
-
roles: user.groups
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
.setSubject(user.id)
|
|
265
|
-
.setIssuer('flux.website')
|
|
266
|
-
.setAudience('flux.website')
|
|
267
|
-
.sign(secret);
|
|
254
|
+
roles: user.groups
|
|
255
|
+
}).setProtectedHeader({
|
|
256
|
+
alg
|
|
257
|
+
}).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
|
|
268
258
|
if (adapter.createSession) {
|
|
269
259
|
await adapter.createSession({
|
|
270
260
|
sessionToken: token,
|
|
271
261
|
userId: user.id,
|
|
272
|
-
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
262
|
+
expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
|
|
273
263
|
});
|
|
274
264
|
}
|
|
275
265
|
return token;
|
|
276
|
-
}
|
|
266
|
+
}
|
|
277
267
|
},
|
|
278
268
|
session: {
|
|
279
269
|
strategy: 'database',
|
|
280
270
|
maxAge: MAX_AGE,
|
|
281
|
-
generateSessionToken: async (user)
|
|
271
|
+
generateSessionToken: async (user)=>{
|
|
282
272
|
return await generateSessionToken(user);
|
|
283
|
-
}
|
|
273
|
+
}
|
|
284
274
|
},
|
|
285
275
|
pages: {
|
|
286
|
-
signIn: '/signin'
|
|
287
|
-
}
|
|
276
|
+
signIn: '/signin'
|
|
277
|
+
}
|
|
288
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
|
};
|