@@ -3,7 +3,8 @@ import "server-only";
33
44import { COOKIE_ACTIVE_ACCOUNT , COOKIE_PREFIX_TOKEN } from "@/constants/cookie" ;
55import { 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" ;
78import { getAddress } from "thirdweb" ;
89import type {
910 GenerateLoginPayloadParams ,
@@ -36,11 +37,90 @@ export async function getLoginPayload(
3637 return ( await res . json ( ) ) . data . payload ;
3738}
3839
39- export async function doLogin ( payload : VerifyLoginPayloadParams ) {
40+ export async function doLogin (
41+ payload : VerifyLoginPayloadParams ,
42+ turnstileToken : string ,
43+ ) {
4044 if ( ! THIRDWEB_API_SECRET ) {
4145 throw new Error ( "API_SERVER_SECRET is not set" ) ;
4246 }
4347
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+
44124 const cookieStore = await cookies ( ) ;
45125 const utmCookies = cookieStore
46126 . getAll ( )
@@ -86,7 +166,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
86166 res . statusText ,
87167 response ,
88168 ) ;
89- throw new Error ( "Failed to login - api call failed" ) ;
169+ return {
170+ error : "Failed to login. Please try again later." ,
171+ } ;
90172 } catch {
91173 // just log the basics
92174 console . error (
@@ -95,7 +177,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
95177 res . statusText ,
96178 ) ;
97179 }
98- throw new Error ( "Failed to login - api call failed" ) ;
180+ return {
181+ error : "Failed to login. Please try again later." ,
182+ } ;
99183 }
100184
101185 const json = await res . json ( ) ;
@@ -104,7 +188,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
104188
105189 if ( ! jwt ) {
106190 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+ } ;
108194 }
109195
110196 // set the token cookie
@@ -128,6 +214,10 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
128214 // 3 days
129215 maxAge : 3 * 24 * 60 * 60 ,
130216 } ) ;
217+
218+ return {
219+ success : true ,
220+ } ;
131221}
132222
133223export async function doLogout ( ) {
0 commit comments