@@ -53,7 +53,7 @@ pub async fn router(
5353 . route ( "/" , post ( create_verification_handler) )
5454 . route ( "/{id}" , get ( get_verification_handler) )
5555 . route ( "/{id}/await" , get ( await_verification_handler) )
56- . route ( "/price " , get ( get_price_handler ) )
56+ . route ( "/info " , get ( get_info_handler ) )
5757 . with_state ( state) )
5858}
5959
@@ -128,9 +128,11 @@ async fn await_verification_handler(
128128 }
129129}
130130
131- /// Get the configured Lightning invoice price handler
132- async fn get_price_handler ( State ( state) : State < AppState > ) -> Json < GetPriceResponse > {
133- Json ( GetPriceResponse {
131+ /// Get Lightning verification info handler.
132+ /// Used by Franky to check if the user is in a country which allows Lightning verification.
133+ /// IP-based geo-blocking is done at the nginx level; this endpoint confirms service availability.
134+ async fn get_info_handler ( State ( state) : State < AppState > ) -> Json < GetInfoResponse > {
135+ Json ( GetInfoResponse {
134136 amount_sat : state. ln_service . get_price_sat ( ) ,
135137 } )
136138}
@@ -176,7 +178,7 @@ impl GetVerificationResponse {
176178
177179#[ derive( Debug , serde:: Serialize , serde:: Deserialize ) ]
178180#[ serde( rename_all = "camelCase" ) ]
179- pub struct GetPriceResponse {
181+ pub struct GetInfoResponse {
180182 amount_sat : u64 ,
181183}
182184
@@ -199,3 +201,60 @@ impl IntoResponse for LnVerificationError {
199201 ( status, self . to_string ( ) ) . into_response ( )
200202 }
201203}
204+
205+ #[ cfg( test) ]
206+ mod tests {
207+ use super :: * ;
208+ use crate :: infrastructure:: sql:: SqlDb ;
209+ use crate :: ln_verification:: phoenixd_api:: PhoenixdAPI ;
210+ use crate :: shared:: HomeserverAdminAPI ;
211+ use axum_test:: TestServer ;
212+ use sqlx:: PgPool ;
213+
214+ /// Creates a test router for LN verification WITHOUT starting the background sync task.
215+ /// This is suitable for testing endpoints that don't require websocket connectivity.
216+ async fn create_test_router ( pool : PgPool ) -> Router {
217+ let db = SqlDb :: test ( pool) . await ;
218+ // Use placeholder URLs - these won't be called for the /info endpoint
219+ let phoenixd_api = PhoenixdAPI :: new ( & "http://localhost:1" . parse ( ) . unwrap ( ) , "unused" ) ;
220+ let homeserver_api = HomeserverAdminAPI :: new (
221+ & "http://localhost:1" . parse ( ) . unwrap ( ) ,
222+ "unused" ,
223+ "test-homeserver-pubky" ,
224+ ) ;
225+
226+ let ln_service = crate :: ln_verification:: service:: LnVerificationService :: new (
227+ db,
228+ phoenixd_api,
229+ homeserver_api. clone ( ) ,
230+ 1000 , // amount_sat
231+ "Test Invoice" . to_string ( ) ,
232+ 600 , // invoice_expiry_seconds
233+ ) ;
234+ let ln_service = std:: sync:: Arc :: new ( ln_service) ;
235+
236+ // Note: We intentionally skip spawning the background sync task for this test
237+ let state = AppState :: new ( ln_service, homeserver_api) ;
238+ Router :: new ( )
239+ . route ( "/info" , get ( get_info_handler) )
240+ . with_state ( state)
241+ }
242+
243+ /// Tests the /info endpoint returns 200 OK with the configured price.
244+ /// This endpoint is used by Franky to check if Lightning verification is available
245+ /// (geo-blocking is done at nginx level).
246+ #[ sqlx:: test]
247+ async fn test_info_endpoint_returns_ok_with_price ( pool : PgPool ) {
248+ let router = create_test_router ( pool) . await ;
249+ let server = TestServer :: new ( router) . expect ( "Failed to create test server" ) ;
250+
251+ let response = server. get ( "/info" ) . await ;
252+ response. assert_status_ok ( ) ;
253+
254+ let body: serde_json:: Value = response. json ( ) ;
255+ assert_eq ! (
256+ body[ "amountSat" ] , 1000 ,
257+ "Response should include the configured price"
258+ ) ;
259+ }
260+ }
0 commit comments