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