sitepaige-mcp-server 1.0.2 → 1.1.0
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/components/IntegrationComponent.tsx +1 -0
- package/components/admin.tsx +30 -27
- package/components/auth.tsx +9 -9
- package/components/cta.tsx +3 -10
- package/components/headerlogin.tsx +9 -9
- package/components/login.tsx +90 -11
- package/components/logincallback.tsx +1 -0
- package/components/menu.tsx +0 -6
- package/components/profile.tsx +12 -11
- package/defaultapp/api/Auth/resend-verification/route.ts +130 -0
- package/defaultapp/api/Auth/route.ts +39 -49
- package/defaultapp/api/Auth/signup/route.ts +5 -15
- package/defaultapp/api/Auth/verify-email/route.ts +12 -5
- package/defaultapp/api/admin/users/route.ts +5 -3
- package/defaultapp/auth/auth.ts +9 -9
- package/defaultapp/db-mysql.ts +1 -1
- package/defaultapp/db-password-auth.ts +37 -0
- package/defaultapp/db-postgres.ts +1 -1
- package/defaultapp/db-sqlite.ts +1 -1
- package/defaultapp/db-users.ts +73 -73
- package/defaultapp/middleware.ts +15 -17
- package/dist/components/IntegrationComponent.tsx +1 -0
- package/dist/components/admin.tsx +30 -27
- package/dist/components/auth.tsx +9 -9
- package/dist/components/cta.tsx +3 -10
- package/dist/components/headerlogin.tsx +9 -9
- package/dist/components/login.tsx +90 -11
- package/dist/components/logincallback.tsx +1 -0
- package/dist/components/menu.tsx +0 -6
- package/dist/components/profile.tsx +12 -11
- package/dist/defaultapp/api/Auth/resend-verification/route.ts +130 -0
- package/dist/defaultapp/api/Auth/route.ts +39 -49
- package/dist/defaultapp/api/Auth/signup/route.ts +5 -15
- package/dist/defaultapp/api/Auth/verify-email/route.ts +12 -5
- package/dist/defaultapp/api/admin/users/route.ts +5 -3
- package/dist/defaultapp/auth/auth.ts +9 -9
- package/dist/defaultapp/db-mysql.ts +1 -1
- package/dist/defaultapp/db-password-auth.ts +37 -0
- package/dist/defaultapp/db-postgres.ts +1 -1
- package/dist/defaultapp/db-sqlite.ts +1 -1
- package/dist/defaultapp/db-users.ts +73 -73
- package/dist/defaultapp/middleware.ts +15 -17
- package/dist/generators/sql.js +11 -3
- package/dist/generators/sql.js.map +1 -1
- package/dist/generators/views.js +14 -14
- package/dist/generators/views.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,6 @@ import * as crypto from 'node:crypto';
|
|
|
10
10
|
|
|
11
11
|
import { db_init, db_query } from '../../db';
|
|
12
12
|
import { upsertUser, storeOAuthToken, validateSession, rotateSession } from '../../db-users';
|
|
13
|
-
import { validateCsrfToken } from '../../csrf';
|
|
14
13
|
|
|
15
14
|
type OAuthProvider = 'google' | 'facebook' | 'apple' | 'github';
|
|
16
15
|
|
|
@@ -42,7 +41,7 @@ export async function POST(request: Request) {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
// Handle username/password authentication
|
|
45
|
-
if (provider === '
|
|
44
|
+
if (provider === 'userpass') {
|
|
46
45
|
if (!email || !password) {
|
|
47
46
|
return NextResponse.json(
|
|
48
47
|
{ error: 'Email and password are required' },
|
|
@@ -70,7 +69,7 @@ export async function POST(request: Request) {
|
|
|
70
69
|
// Create or update user in the main Users table
|
|
71
70
|
const user = await upsertUser(
|
|
72
71
|
`password_${authRecord.id}`, // Unique OAuth ID for password users
|
|
73
|
-
'
|
|
72
|
+
'userpass' as any, // Source type
|
|
74
73
|
email.split('@')[0], // Username from email
|
|
75
74
|
email,
|
|
76
75
|
undefined // No avatar for password auth
|
|
@@ -78,14 +77,14 @@ export async function POST(request: Request) {
|
|
|
78
77
|
|
|
79
78
|
// Delete existing sessions for this user
|
|
80
79
|
const existingSessions = await db_query(db,
|
|
81
|
-
"SELECT
|
|
80
|
+
"SELECT id FROM usersession WHERE userid = ?",
|
|
82
81
|
[user.userid]
|
|
83
82
|
);
|
|
84
83
|
|
|
85
84
|
if (existingSessions && existingSessions.length > 0) {
|
|
86
|
-
const sessionIds = existingSessions.map(session => session.
|
|
85
|
+
const sessionIds = existingSessions.map(session => session.id);
|
|
87
86
|
const placeholders = sessionIds.map(() => '?').join(',');
|
|
88
|
-
await db_query(db, `DELETE FROM usersession WHERE
|
|
87
|
+
await db_query(db, `DELETE FROM usersession WHERE id IN (${placeholders})`, sessionIds);
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
// Generate secure session token and ID
|
|
@@ -94,7 +93,7 @@ export async function POST(request: Request) {
|
|
|
94
93
|
|
|
95
94
|
// Create new session with secure token
|
|
96
95
|
await db_query(db,
|
|
97
|
-
"INSERT INTO usersession (
|
|
96
|
+
"INSERT INTO usersession (id, sessiontoken, userid, expirationdate) VALUES (?, ?, ?, ?)",
|
|
98
97
|
[sessionId, sessionToken, user.userid, new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()]
|
|
99
98
|
);
|
|
100
99
|
|
|
@@ -113,10 +112,10 @@ export async function POST(request: Request) {
|
|
|
113
112
|
// Create a completely clean object to avoid any database result object issues
|
|
114
113
|
const cleanUserData = {
|
|
115
114
|
userid: String(user.userid),
|
|
116
|
-
userName: String(user.
|
|
117
|
-
avatarURL: String(user.
|
|
118
|
-
userLevel: Number(user.
|
|
119
|
-
isAdmin: Number(user.
|
|
115
|
+
userName: String(user.username),
|
|
116
|
+
avatarURL: String(user.avatarurl || ''),
|
|
117
|
+
userLevel: Number(user.userlevel),
|
|
118
|
+
isAdmin: Number(user.userlevel) === 2
|
|
120
119
|
};
|
|
121
120
|
|
|
122
121
|
return NextResponse.json({
|
|
@@ -153,7 +152,7 @@ export async function POST(request: Request) {
|
|
|
153
152
|
}
|
|
154
153
|
|
|
155
154
|
let userData = {
|
|
156
|
-
|
|
155
|
+
id: '',
|
|
157
156
|
name: '',
|
|
158
157
|
email: '',
|
|
159
158
|
avatar_url: '',
|
|
@@ -204,28 +203,28 @@ export async function POST(request: Request) {
|
|
|
204
203
|
switch (validProvider) {
|
|
205
204
|
|
|
206
205
|
case 'google':
|
|
207
|
-
userData.
|
|
206
|
+
userData.id = fetchedUserData.id;
|
|
208
207
|
userData.name = fetchedUserData.name;
|
|
209
208
|
userData.email = fetchedUserData.email;
|
|
210
209
|
userData.avatar_url = fetchedUserData.picture;
|
|
211
210
|
break;
|
|
212
211
|
|
|
213
212
|
case 'facebook':
|
|
214
|
-
userData.
|
|
213
|
+
userData.id = fetchedUserData.id;
|
|
215
214
|
userData.name = fetchedUserData.name;
|
|
216
215
|
userData.email = fetchedUserData.email;
|
|
217
216
|
userData.avatar_url = fetchedUserData.picture?.data?.url;
|
|
218
217
|
break;
|
|
219
218
|
|
|
220
219
|
case 'apple':
|
|
221
|
-
userData.
|
|
220
|
+
userData.id = fetchedUserData.sub;
|
|
222
221
|
userData.name = `${fetchedUserData.given_name || ''} ${fetchedUserData.family_name || ''}`.trim();
|
|
223
222
|
userData.email = fetchedUserData.email;
|
|
224
223
|
// Apple doesn't provide avatar URL
|
|
225
224
|
break;
|
|
226
225
|
|
|
227
226
|
case 'github':
|
|
228
|
-
userData.
|
|
227
|
+
userData.id = fetchedUserData.id?.toString();
|
|
229
228
|
userData.name = fetchedUserData.name || fetchedUserData.login;
|
|
230
229
|
userData.email = fetchedUserData.email;
|
|
231
230
|
userData.avatar_url = fetchedUserData.avatar_url;
|
|
@@ -240,7 +239,7 @@ export async function POST(request: Request) {
|
|
|
240
239
|
|
|
241
240
|
// Create or update user using the new user management system
|
|
242
241
|
const user = await upsertUser(
|
|
243
|
-
userData.
|
|
242
|
+
userData.id,
|
|
244
243
|
validProvider,
|
|
245
244
|
userData.name,
|
|
246
245
|
userData.email,
|
|
@@ -258,14 +257,14 @@ export async function POST(request: Request) {
|
|
|
258
257
|
|
|
259
258
|
// Delete existing sessions for this user
|
|
260
259
|
const existingSessions = await db_query(db,
|
|
261
|
-
"SELECT
|
|
260
|
+
"SELECT id FROM usersession WHERE userid = ?",
|
|
262
261
|
[user.userid]
|
|
263
262
|
);
|
|
264
263
|
|
|
265
264
|
if (existingSessions && existingSessions.length > 0) {
|
|
266
|
-
const sessionIds = existingSessions.map(session => session.
|
|
265
|
+
const sessionIds = existingSessions.map(session => session.id);
|
|
267
266
|
const placeholders = sessionIds.map(() => '?').join(',');
|
|
268
|
-
await db_query(db, `DELETE FROM usersession WHERE
|
|
267
|
+
await db_query(db, `DELETE FROM usersession WHERE id IN (${placeholders})`, sessionIds);
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
// Generate secure session token and ID
|
|
@@ -274,7 +273,7 @@ export async function POST(request: Request) {
|
|
|
274
273
|
|
|
275
274
|
// Create new session with secure token
|
|
276
275
|
await db_query(db,
|
|
277
|
-
"INSERT INTO usersession (
|
|
276
|
+
"INSERT INTO usersession (id, sessiontoken, userid, expirationdate) VALUES (?, ?, ?, ?)",
|
|
278
277
|
[sessionId, sessionToken, user.userid, new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()]
|
|
279
278
|
);
|
|
280
279
|
|
|
@@ -293,10 +292,10 @@ export async function POST(request: Request) {
|
|
|
293
292
|
// Create a completely clean object to avoid any database result object issues
|
|
294
293
|
const cleanUserData = {
|
|
295
294
|
userid: String(user.userid),
|
|
296
|
-
userName: String(user.
|
|
297
|
-
avatarURL: String(user.
|
|
298
|
-
userLevel: Number(user.
|
|
299
|
-
isAdmin: Number(user.
|
|
295
|
+
userName: String(user.username),
|
|
296
|
+
avatarURL: String(user.avatarurl || ''),
|
|
297
|
+
userLevel: Number(user.userlevel),
|
|
298
|
+
isAdmin: Number(user.userlevel) === 2
|
|
300
299
|
};
|
|
301
300
|
|
|
302
301
|
return NextResponse.json({
|
|
@@ -347,13 +346,13 @@ export async function GET() {
|
|
|
347
346
|
const response = NextResponse.json({
|
|
348
347
|
user: {
|
|
349
348
|
userid: sessionData.user.userid,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
349
|
+
username: sessionData.user.username,
|
|
350
|
+
avatarurl: sessionData.user.avatarurl,
|
|
351
|
+
email: sessionData.user.email,
|
|
352
|
+
userlevel: sessionData.user.userlevel,
|
|
353
|
+
isadmin: sessionData.user.userlevel === 2,
|
|
354
|
+
source: sessionData.user.source,
|
|
355
|
+
lastlogindate: sessionData.user.lastlogindate
|
|
357
356
|
}
|
|
358
357
|
});
|
|
359
358
|
|
|
@@ -376,13 +375,13 @@ export async function GET() {
|
|
|
376
375
|
return NextResponse.json({
|
|
377
376
|
user: {
|
|
378
377
|
userid: sessionData.user.userid,
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
378
|
+
username: sessionData.user.username,
|
|
379
|
+
avatarurl: sessionData.user.avatarurl,
|
|
380
|
+
email: sessionData.user.email,
|
|
381
|
+
userlevel: sessionData.user.userlevel,
|
|
382
|
+
isadmin: sessionData.user.userlevel === 2,
|
|
383
|
+
source: sessionData.user.source,
|
|
384
|
+
lastlogindate: sessionData.user.lastlogindate
|
|
386
385
|
}
|
|
387
386
|
});
|
|
388
387
|
|
|
@@ -395,15 +394,6 @@ export async function GET() {
|
|
|
395
394
|
}
|
|
396
395
|
|
|
397
396
|
export async function DELETE(request: Request) {
|
|
398
|
-
// Validate CSRF token for logout
|
|
399
|
-
const isValidCsrf = await validateCsrfToken(request);
|
|
400
|
-
if (!isValidCsrf) {
|
|
401
|
-
return NextResponse.json(
|
|
402
|
-
{ error: 'Invalid CSRF token' },
|
|
403
|
-
{ status: 403 }
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
397
|
const db = await db_init();
|
|
408
398
|
|
|
409
399
|
try {
|
|
@@ -420,7 +410,7 @@ export async function DELETE(request: Request) {
|
|
|
420
410
|
|
|
421
411
|
// Delete session from database using the actual session token
|
|
422
412
|
await db_query(db,
|
|
423
|
-
"DELETE FROM usersession WHERE
|
|
413
|
+
"DELETE FROM usersession WHERE sessiontoken = ?",
|
|
424
414
|
[sessionToken]
|
|
425
415
|
);
|
|
426
416
|
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { NextResponse } from 'next/server';
|
|
7
|
-
import { validateCsrfToken } from '../../../csrf';
|
|
8
7
|
import { createPasswordAuth } from '../../../db-password-auth';
|
|
9
8
|
import { send_email } from '../../../storage/email';
|
|
10
9
|
|
|
@@ -15,15 +14,6 @@ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
15
14
|
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
|
|
16
15
|
|
|
17
16
|
export async function POST(request: Request) {
|
|
18
|
-
// Validate CSRF token
|
|
19
|
-
const isValidCsrf = await validateCsrfToken(request);
|
|
20
|
-
if (!isValidCsrf) {
|
|
21
|
-
return NextResponse.json(
|
|
22
|
-
{ error: 'Invalid CSRF token' },
|
|
23
|
-
{ status: 403 }
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
17
|
try {
|
|
28
18
|
const { email, password } = await request.json();
|
|
29
19
|
|
|
@@ -62,11 +52,11 @@ export async function POST(request: Request) {
|
|
|
62
52
|
.button {
|
|
63
53
|
display: inline-block;
|
|
64
54
|
padding: 12px 24px;
|
|
65
|
-
background-color: #
|
|
66
|
-
color:
|
|
55
|
+
background-color: #f0f0f0;
|
|
56
|
+
color: #000000;
|
|
67
57
|
text-decoration: none;
|
|
68
|
-
border
|
|
69
|
-
|
|
58
|
+
border: 1px solid #cccccc;
|
|
59
|
+
border-radius: 4px;
|
|
70
60
|
}
|
|
71
61
|
.footer { margin-top: 30px; font-size: 12px; color: #666; }
|
|
72
62
|
</style>
|
|
@@ -79,7 +69,7 @@ export async function POST(request: Request) {
|
|
|
79
69
|
<a href="${verificationUrl}" class="button">Verify Email Address</a>
|
|
80
70
|
</p>
|
|
81
71
|
<p>Or copy and paste this link into your browser:</p>
|
|
82
|
-
<p style="word-break: break-all; color: #
|
|
72
|
+
<p style="word-break: break-all; color: #0066cc;">${verificationUrl}</p>
|
|
83
73
|
<p>This link will expire in 24 hours.</p>
|
|
84
74
|
<div class="footer">
|
|
85
75
|
<p>If you didn't create an account, you can safely ignore this email.</p>
|
|
@@ -35,25 +35,32 @@ export async function GET(request: Request) {
|
|
|
35
35
|
// Create or update user in the main Users table
|
|
36
36
|
const user = await upsertUser(
|
|
37
37
|
`password_${authRecord.id}`, // Unique OAuth ID for password users
|
|
38
|
-
'
|
|
38
|
+
'userpass' as any, // Source type
|
|
39
39
|
authRecord.email.split('@')[0], // Username from email
|
|
40
40
|
authRecord.email,
|
|
41
41
|
undefined // No avatar for password auth
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
+
if (!user) {
|
|
45
|
+
return NextResponse.json(
|
|
46
|
+
{ error: 'Failed to create user account' },
|
|
47
|
+
{ status: 500 }
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
// Auto-login the user after verification
|
|
45
52
|
const db = await db_init();
|
|
46
53
|
|
|
47
54
|
// Delete existing sessions for this user
|
|
48
55
|
const existingSessions = await db_query(db,
|
|
49
|
-
"SELECT
|
|
56
|
+
"SELECT id FROM usersession WHERE userid = ?",
|
|
50
57
|
[user.userid]
|
|
51
58
|
);
|
|
52
59
|
|
|
53
60
|
if (existingSessions && existingSessions.length > 0) {
|
|
54
|
-
const sessionIds = existingSessions.map(session => session.
|
|
61
|
+
const sessionIds = existingSessions.map(session => session.id);
|
|
55
62
|
const placeholders = sessionIds.map(() => '?').join(',');
|
|
56
|
-
await db_query(db, `DELETE FROM usersession WHERE
|
|
63
|
+
await db_query(db, `DELETE FROM usersession WHERE id IN (${placeholders})`, sessionIds);
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
// Generate secure session token and ID
|
|
@@ -62,7 +69,7 @@ export async function GET(request: Request) {
|
|
|
62
69
|
|
|
63
70
|
// Create new session with secure token
|
|
64
71
|
await db_query(db,
|
|
65
|
-
"INSERT INTO usersession (
|
|
72
|
+
"INSERT INTO usersession (id, sessiontoken, userid, expirationdate) VALUES (?, ?, ?, ?)",
|
|
66
73
|
[sessionId, sessionToken, user.userid, new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()]
|
|
67
74
|
);
|
|
68
75
|
|
|
@@ -28,9 +28,11 @@ async function checkAdminAuth(): Promise<{ isAdmin: boolean; userId?: string }>
|
|
|
28
28
|
|
|
29
29
|
// Get session
|
|
30
30
|
const sessions = await db_query(db,
|
|
31
|
-
"SELECT userid FROM
|
|
31
|
+
"SELECT userid FROM usersession WHERE sessiontoken = ?",
|
|
32
32
|
[sessionId]
|
|
33
33
|
);
|
|
34
|
+
|
|
35
|
+
console.log(sessions);
|
|
34
36
|
|
|
35
37
|
if (sessions.length === 0) {
|
|
36
38
|
return { isAdmin: false };
|
|
@@ -38,8 +40,8 @@ async function checkAdminAuth(): Promise<{ isAdmin: boolean; userId?: string }>
|
|
|
38
40
|
|
|
39
41
|
// Check if user is admin
|
|
40
42
|
const user = await getUserByID(sessions[0].userid);
|
|
41
|
-
|
|
42
|
-
if (!user || user.
|
|
43
|
+
|
|
44
|
+
if (!user || user.userlevel !== 2) {
|
|
43
45
|
return { isAdmin: false };
|
|
44
46
|
}
|
|
45
47
|
|
package/defaultapp/auth/auth.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { cookies } from 'next/headers';
|
|
2
2
|
|
|
3
|
-
export async function check_auth(db: any, db_query: any): Promise<{ userid: string,
|
|
3
|
+
export async function check_auth(db: any, db_query: any): Promise<{ userid: string, userlevel: number, usertier: number, isadmin: boolean }> {
|
|
4
4
|
const cookieStore = await cookies();
|
|
5
5
|
const sessionId = cookieStore.get('session_id')?.value;
|
|
6
6
|
|
|
7
7
|
const sessionInfo = {
|
|
8
8
|
userid: '',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
userlevel: 0,
|
|
10
|
+
usertier: 0,
|
|
11
|
+
isadmin: false
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
if (!sessionId) {
|
|
@@ -16,16 +16,16 @@ export async function check_auth(db: any, db_query: any): Promise<{ userid: stri
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// SQLite is case-insensitive for identifiers, but use standard column names (no quotes, correct names)
|
|
19
|
-
const session = await db_query(db, 'SELECT userid FROM
|
|
19
|
+
const session = await db_query(db, 'SELECT userid FROM usersession WHERE sessiontoken = ?', [sessionId]);
|
|
20
20
|
if (session.length > 0) {
|
|
21
21
|
sessionInfo.userid = session[0].userid;
|
|
22
22
|
|
|
23
23
|
// In your Users table, the primary key is userid, and there is no IsAdmin column, but UserLevel (2 = admin)
|
|
24
|
-
const user = await db_query(db, 'SELECT
|
|
24
|
+
const user = await db_query(db, 'SELECT userlevel, usertier FROM users WHERE userid = ?', [session[0].userid]);
|
|
25
25
|
if (user.length > 0) {
|
|
26
|
-
sessionInfo.
|
|
27
|
-
sessionInfo.
|
|
28
|
-
sessionInfo.
|
|
26
|
+
sessionInfo.userlevel = user[0].userlevel;
|
|
27
|
+
sessionInfo.isadmin = user[0].userlevel === 2;
|
|
28
|
+
sessionInfo.usertier = user[0].usertier;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
return sessionInfo;
|
package/defaultapp/db-mysql.ts
CHANGED
|
@@ -95,7 +95,7 @@ export async function db_query(
|
|
|
95
95
|
*/
|
|
96
96
|
export function db_migrate(model: Model, dbType: string): string {
|
|
97
97
|
|
|
98
|
-
const sanitizedTableName = model.name;
|
|
98
|
+
const sanitizedTableName = model.name.toLowerCase().replace(/\s+/g, '_');
|
|
99
99
|
|
|
100
100
|
// Start with the model's fields
|
|
101
101
|
let fields = [...model.fields];
|
|
@@ -295,6 +295,43 @@ export async function updatePassword(email: string, currentPassword: string, new
|
|
|
295
295
|
return true;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Regenerate email verification token for unverified accounts
|
|
300
|
+
*/
|
|
301
|
+
export async function regenerateVerificationToken(email: string): Promise<{ passwordAuth: PasswordAuth; verificationToken: string } | null> {
|
|
302
|
+
const client = await db_init();
|
|
303
|
+
|
|
304
|
+
const authRecord = await getPasswordAuthByEmail(email);
|
|
305
|
+
if (!authRecord) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Only regenerate for unverified accounts
|
|
310
|
+
if (authRecord.emailverified) {
|
|
311
|
+
throw new Error('Email is already verified');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Generate new verification token
|
|
315
|
+
const verificationToken = randomBytes(32).toString('base64url');
|
|
316
|
+
const verificationTokenExpires = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
|
317
|
+
|
|
318
|
+
await db_query(client,
|
|
319
|
+
`UPDATE passwordauth
|
|
320
|
+
SET verificationtoken = ?,
|
|
321
|
+
verificationtokenexpires = ?,
|
|
322
|
+
updatedat = CURRENT_TIMESTAMP
|
|
323
|
+
WHERE id = ?`,
|
|
324
|
+
[verificationToken, verificationTokenExpires.toISOString(), authRecord.id]
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const updatedAuth = await getPasswordAuthByEmail(email);
|
|
328
|
+
if (!updatedAuth) {
|
|
329
|
+
throw new Error('Failed to update verification token');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return { passwordAuth: updatedAuth, verificationToken };
|
|
333
|
+
}
|
|
334
|
+
|
|
298
335
|
/**
|
|
299
336
|
* Check if an email is already registered
|
|
300
337
|
*/
|
|
@@ -101,7 +101,7 @@ export async function db_query(
|
|
|
101
101
|
*/
|
|
102
102
|
export function db_migrate(model: Model, dbType: string): string {
|
|
103
103
|
|
|
104
|
-
const sanitizedTableName = model.name;
|
|
104
|
+
const sanitizedTableName = model.name.toLowerCase().replace(/\s+/g, '_');
|
|
105
105
|
|
|
106
106
|
// Start with the model's fields
|
|
107
107
|
let fields = [...model.fields];
|
package/defaultapp/db-sqlite.ts
CHANGED
|
@@ -175,7 +175,7 @@ export async function db_query(
|
|
|
175
175
|
export function db_migrate(model: Model, dbType: string): string {
|
|
176
176
|
// Special handling for auth tables - create them first
|
|
177
177
|
|
|
178
|
-
const sanitizedTableName = model.name;
|
|
178
|
+
const sanitizedTableName = model.name.toLowerCase().replace(/\s+/g, '_');
|
|
179
179
|
|
|
180
180
|
// Start with the model's fields
|
|
181
181
|
let fields = [...model.fields];
|