@@ -21,85 +21,98 @@ export const GET: RequestHandler = async ({ url, platform, cookies }) => {
2121 redirect ( 302 , '/login?error=invalid_state' ) ;
2222 }
2323
24- const tokenResponse = await fetch ( GOOGLE_TOKEN_URL , {
25- method : 'POST' ,
26- headers : { 'Content-Type' : 'application/json' } ,
27- body : JSON . stringify ( {
28- client_id : env . GOOGLE_CLIENT_ID ,
29- client_secret : env . GOOGLE_CLIENT_SECRET ,
30- code,
31- redirect_uri : `${ env . APP_URL } /api/auth/callback/google` ,
32- grant_type : 'authorization_code'
33- } )
34- } ) ;
35-
36- const tokenData = await tokenResponse . json ( ) ;
37- if ( tokenData . error || ! tokenData . access_token ) {
38- redirect ( 302 , '/login?error=token_failed' ) ;
39- }
40-
41- const userResponse = await fetch ( GOOGLE_USERINFO_URL , {
42- headers : { Authorization : `Bearer ${ tokenData . access_token } ` }
43- } ) ;
44-
45- const googleUser = await userResponse . json ( ) ;
46- if ( ! googleUser . id || ! googleUser . email ) {
47- redirect ( 302 , '/login?error=user_failed' ) ;
48- }
49-
50- const userId = `google_${ googleUser . id } ` ;
51- const reservedUsernames = [ 'openboot' , 'admin' , 'api' , 'dashboard' , 'install' , 'login' , 'logout' , 'settings' , 'help' , 'support' , 'docs' , 'blog' ] ;
52-
53- let username = slugify ( googleUser . email . split ( '@' ) [ 0 ] ) ;
54- if ( reservedUsernames . includes ( username . toLowerCase ( ) ) || username . length < 3 ) {
55- username = `user-${ googleUser . id . slice ( - 8 ) } ` ;
56- }
57-
58- const existingUser = await env . DB . prepare ( 'SELECT username FROM users WHERE id = ?' ) . bind ( userId ) . first ( ) ;
59- if ( existingUser ) {
60- username = ( existingUser as { username : string } ) . username ;
61- }
24+ try {
25+ const tokenResponse = await fetch ( GOOGLE_TOKEN_URL , {
26+ method : 'POST' ,
27+ headers : { 'Content-Type' : 'application/x-www-form-urlencoded' } ,
28+ body : new URLSearchParams ( {
29+ client_id : env . GOOGLE_CLIENT_ID ,
30+ client_secret : env . GOOGLE_CLIENT_SECRET ,
31+ code,
32+ redirect_uri : `${ env . APP_URL } /api/auth/callback/google` ,
33+ grant_type : 'authorization_code'
34+ } )
35+ } ) ;
36+
37+ const tokenData = await tokenResponse . json ( ) ;
38+ if ( tokenData . error || ! tokenData . access_token ) {
39+ redirect ( 302 , '/login?error=token_failed' ) ;
40+ }
41+
42+ const userResponse = await fetch ( GOOGLE_USERINFO_URL , {
43+ headers : { Authorization : `Bearer ${ tokenData . access_token } ` }
44+ } ) ;
45+
46+ const googleUser = await userResponse . json ( ) ;
47+ if ( ! googleUser . id || ! googleUser . email ) {
48+ redirect ( 302 , '/login?error=user_failed' ) ;
49+ }
50+
51+ const userId = `google_${ googleUser . id } ` ;
52+ const reservedUsernames = [ 'openboot' , 'admin' , 'api' , 'dashboard' , 'install' , 'login' , 'logout' , 'settings' , 'help' , 'support' , 'docs' , 'blog' ] ;
53+
54+ let username = slugify ( googleUser . email . split ( '@' ) [ 0 ] ) ;
55+ if ( reservedUsernames . includes ( username . toLowerCase ( ) ) || username . length < 3 ) {
56+ username = `user-${ googleUser . id . slice ( - 8 ) } ` ;
57+ }
58+
59+ const existingUser = await env . DB . prepare ( 'SELECT username FROM users WHERE id = ?' ) . bind ( userId ) . first ( ) ;
60+ if ( existingUser ) {
61+ username = ( existingUser as { username : string } ) . username ;
62+ } else {
63+ const usernameTaken = await env . DB . prepare ( 'SELECT id FROM users WHERE username = ?' ) . bind ( username ) . first ( ) ;
64+ if ( usernameTaken ) {
65+ username = `${ username } -${ googleUser . id . slice ( - 6 ) } ` ;
66+ }
67+ }
6268
63- await env . DB . prepare (
64- `
65- INSERT INTO users (id, username, email, avatar_url, updated_at)
66- VALUES (?, ?, ?, ?, datetime('now'))
67- ON CONFLICT(id) DO UPDATE SET
68- email = excluded.email,
69- avatar_url = excluded.avatar_url,
70- updated_at = datetime('now')
71- `
72- )
73- . bind ( userId , username , googleUser . email , googleUser . picture || '' )
74- . run ( ) ;
75-
76- const existingConfig = await env . DB . prepare ( 'SELECT id FROM configs WHERE user_id = ? AND slug = ?' ) . bind ( userId , 'default' ) . first ( ) ;
77-
78- if ( ! existingConfig ) {
7969 await env . DB . prepare (
8070 `
81- INSERT INTO configs (id, user_id, slug, name, description, base_preset, packages)
82- VALUES (?, ?, 'default', 'Default', 'My default configuration', 'developer', '[]')
71+ INSERT INTO users (id, username, email, avatar_url, updated_at)
72+ VALUES (?, ?, ?, ?, datetime('now'))
73+ ON CONFLICT(id) DO UPDATE SET
74+ email = excluded.email,
75+ avatar_url = excluded.avatar_url,
76+ updated_at = datetime('now')
8377 `
8478 )
85- . bind ( generateId ( ) , userId )
79+ . bind ( userId , username , googleUser . email , googleUser . picture || '' )
8680 . run ( ) ;
87- }
88-
89- const thirtyDays = 30 * 24 * 60 * 60 ;
90- const token = await signToken ( { userId, username, exp : Date . now ( ) + thirtyDays * 1000 } , env . JWT_SECRET ) ;
9181
92- cookies . set ( 'session' , token , {
93- path : '/' ,
94- httpOnly : true ,
95- secure : true ,
96- sameSite : 'lax' ,
97- maxAge : thirtyDays
98- } ) ;
82+ const existingConfig = await env . DB . prepare ( 'SELECT id FROM configs WHERE user_id = ? AND slug = ?' ) . bind ( userId , 'default' ) . first ( ) ;
9983
100- const returnTo = cookies . get ( 'auth_return_to' ) || '/dashboard' ;
101- cookies . delete ( 'auth_state' , { path : '/' } ) ;
102- cookies . delete ( 'auth_return_to' , { path : '/' } ) ;
103-
104- redirect ( 302 , returnTo ) ;
84+ if ( ! existingConfig ) {
85+ await env . DB . prepare (
86+ `
87+ INSERT INTO configs (id, user_id, slug, name, description, base_preset, packages)
88+ VALUES (?, ?, 'default', 'Default', 'My default configuration', 'developer', '[]')
89+ `
90+ )
91+ . bind ( generateId ( ) , userId )
92+ . run ( ) ;
93+ }
94+
95+ const thirtyDays = 30 * 24 * 60 * 60 ;
96+ const token = await signToken ( { userId, username, exp : Date . now ( ) + thirtyDays * 1000 } , env . JWT_SECRET ) ;
97+
98+ cookies . set ( 'session' , token , {
99+ path : '/' ,
100+ httpOnly : true ,
101+ secure : true ,
102+ sameSite : 'lax' ,
103+ maxAge : thirtyDays
104+ } ) ;
105+
106+ const returnTo = cookies . get ( 'auth_return_to' ) || '/dashboard' ;
107+ cookies . delete ( 'auth_state' , { path : '/' } ) ;
108+ cookies . delete ( 'auth_return_to' , { path : '/' } ) ;
109+
110+ redirect ( 302 , returnTo ) ;
111+ } catch ( err ) {
112+ if ( err && typeof err === 'object' && 'status' in err && 'location' in err ) {
113+ throw err ;
114+ }
115+ console . error ( 'Google auth callback error:' , err ) ;
116+ redirect ( 302 , '/login?error=server_error' ) ;
117+ }
105118} ;
0 commit comments