@@ -3,7 +3,8 @@ import "server-only";
3
3
4
4
import { COOKIE_ACTIVE_ACCOUNT , COOKIE_PREFIX_TOKEN } from "@/constants/cookie" ;
5
5
import { API_SERVER_URL , THIRDWEB_API_SECRET } from "@/constants/env" ;
6
- import { cookies } from "next/headers" ;
6
+ import { ipAddress } from "@vercel/functions" ;
7
+ import { cookies , headers } from "next/headers" ;
7
8
import { getAddress } from "thirdweb" ;
8
9
import type {
9
10
GenerateLoginPayloadParams ,
@@ -36,11 +37,90 @@ export async function getLoginPayload(
36
37
return ( await res . json ( ) ) . data . payload ;
37
38
}
38
39
39
- export async function doLogin ( payload : VerifyLoginPayloadParams ) {
40
+ export async function doLogin (
41
+ payload : VerifyLoginPayloadParams ,
42
+ turnstileToken : string ,
43
+ ) {
40
44
if ( ! THIRDWEB_API_SECRET ) {
41
45
throw new Error ( "API_SERVER_SECRET is not set" ) ;
42
46
}
43
47
48
+ if ( ! turnstileToken ) {
49
+ return {
50
+ error : "Missing Turnstile token." ,
51
+ } ;
52
+ }
53
+
54
+ // get the request headers
55
+ const requestHeaders = await headers ( ) ;
56
+ if ( ! requestHeaders ) {
57
+ return {
58
+ error : "Failed to get request headers. Please try again." ,
59
+ } ;
60
+ }
61
+ // CF header, fallback to req.ip, then X-Forwarded-For
62
+ const [ ip , errors ] = ( ( ) => {
63
+ let ip : string | null = null ;
64
+ const errors : string [ ] = [ ] ;
65
+ try {
66
+ ip = requestHeaders . get ( "CF-Connecting-IP" ) || null ;
67
+ } catch ( err ) {
68
+ console . error ( "failed to get IP address from CF-Connecting-IP" , err ) ;
69
+ errors . push ( "failed to get IP address from CF-Connecting-IP" ) ;
70
+ }
71
+ if ( ! ip ) {
72
+ try {
73
+ ip = ipAddress ( requestHeaders ) || null ;
74
+ } catch ( err ) {
75
+ console . error (
76
+ "failed to get IP address from ipAddress() function" ,
77
+ err ,
78
+ ) ;
79
+ errors . push ( "failed to get IP address from ipAddress() function" ) ;
80
+ }
81
+ }
82
+ if ( ! ip ) {
83
+ try {
84
+ ip = requestHeaders . get ( "X-Forwarded-For" ) ;
85
+ } catch ( err ) {
86
+ console . error ( "failed to get IP address from X-Forwarded-For" , err ) ;
87
+ errors . push ( "failed to get IP address from X-Forwarded-For" ) ;
88
+ }
89
+ }
90
+ return [ ip , errors ] ;
91
+ } ) ( ) ;
92
+
93
+ if ( ! ip ) {
94
+ return {
95
+ error : "Could not get IP address. Please try again." ,
96
+ context : errors ,
97
+ } ;
98
+ }
99
+
100
+ // https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
101
+ // Validate the token by calling the "/siteverify" API endpoint.
102
+ const result = await fetch (
103
+ "https://challenges.cloudflare.com/turnstile/v0/siteverify" ,
104
+ {
105
+ body : JSON . stringify ( {
106
+ secret : process . env . TURNSTILE_SECRET_KEY ,
107
+ response : turnstileToken ,
108
+ remoteip : ip ,
109
+ } ) ,
110
+ method : "POST" ,
111
+ headers : {
112
+ "Content-Type" : "application/json" ,
113
+ } ,
114
+ } ,
115
+ ) ;
116
+
117
+ const outcome = await result . json ( ) ;
118
+ if ( ! outcome . success ) {
119
+ return {
120
+ error : "Could not validate captcha." ,
121
+ } ;
122
+ }
123
+
44
124
const cookieStore = await cookies ( ) ;
45
125
const utmCookies = cookieStore
46
126
. getAll ( )
@@ -86,7 +166,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
86
166
res . statusText ,
87
167
response ,
88
168
) ;
89
- throw new Error ( "Failed to login - api call failed" ) ;
169
+ return {
170
+ error : "Failed to login. Please try again later." ,
171
+ } ;
90
172
} catch {
91
173
// just log the basics
92
174
console . error (
@@ -95,7 +177,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
95
177
res . statusText ,
96
178
) ;
97
179
}
98
- throw new Error ( "Failed to login - api call failed" ) ;
180
+ return {
181
+ error : "Failed to login. Please try again later." ,
182
+ } ;
99
183
}
100
184
101
185
const json = await res . json ( ) ;
@@ -104,7 +188,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
104
188
105
189
if ( ! jwt ) {
106
190
console . error ( "Failed to login - invalid json" , json ) ;
107
- throw new Error ( "Failed to login - invalid json" ) ;
191
+ return {
192
+ error : "Failed to login. Please try again later." ,
193
+ } ;
108
194
}
109
195
110
196
// set the token cookie
@@ -128,6 +214,10 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
128
214
// 3 days
129
215
maxAge : 3 * 24 * 60 * 60 ,
130
216
} ) ;
217
+
218
+ return {
219
+ success : true ,
220
+ } ;
131
221
}
132
222
133
223
export async function doLogout ( ) {
0 commit comments