@@ -300,6 +300,7 @@ async def search_data_breaches(
300300 alert_key = datastore_client .key ("xon_alert" , email )
301301 alert_record = datastore_client .get (alert_key )
302302
303+ # Always check shieldOn first (privacy - can't cache this)
303304 if alert_record and alert_record .get ("shieldOn" , False ):
304305 raise HTTPException (status_code = 404 , detail = "Not found" )
305306
@@ -309,6 +310,13 @@ async def search_data_breaches(
309310 if not token_valid :
310311 raise HTTPException (status_code = 403 , detail = "Invalid token" )
311312
313+ # Check cache (after shieldOn/token validation)
314+ has_token = "with_token" if token else "no_token"
315+ cache_key = f"breach-analytics:{ hash_email (email )} :{ has_token } "
316+ cached_result = get_cached_breaches (cache_key )
317+ if cached_result :
318+ return BreachAnalyticsResponse (** cached_result )
319+
312320 breach_data = await get_exposure (email )
313321 sensitive_data = await get_sensitive_exposure (email ) if token else None
314322
@@ -348,24 +356,28 @@ async def search_data_breaches(
348356 ) = summary_result
349357
350358 if breach_summary or paste_summary :
351- return BreachAnalyticsResponse (
352- ExposedBreaches = exposed_breaches ,
353- BreachesSummary = breach_summary
359+ response_data = {
360+ " ExposedBreaches" : exposed_breaches ,
361+ " BreachesSummary" : breach_summary
354362 or {"domain" : "" , "site" : "" , "tmpstmp" : "" },
355- BreachMetrics = breach_metrics ,
356- PastesSummary = paste_summary or {"cnt" : 0 , "domain" : "" , "tmpstmp" : "" },
357- ExposedPastes = exposed_pastes ,
358- PasteMetrics = paste_metrics ,
359- )
360-
361- return BreachAnalyticsResponse (
362- BreachesSummary = {"domain" : "" , "site" : "" , "tmpstmp" : "" },
363- PastesSummary = {"cnt" : 0 , "domain" : "" , "tmpstmp" : "" },
364- ExposedBreaches = None ,
365- ExposedPastes = None ,
366- BreachMetrics = None ,
367- PasteMetrics = None ,
368- )
363+ "BreachMetrics" : breach_metrics ,
364+ "PastesSummary" : paste_summary
365+ or {"cnt" : 0 , "domain" : "" , "tmpstmp" : "" },
366+ "ExposedPastes" : exposed_pastes ,
367+ "PasteMetrics" : paste_metrics ,
368+ }
369+ cache_breaches (cache_key , response_data )
370+ return BreachAnalyticsResponse (** response_data )
371+
372+ empty_response = {
373+ "BreachesSummary" : {"domain" : "" , "site" : "" , "tmpstmp" : "" },
374+ "PastesSummary" : {"cnt" : 0 , "domain" : "" , "tmpstmp" : "" },
375+ "ExposedBreaches" : None ,
376+ "ExposedPastes" : None ,
377+ "BreachMetrics" : None ,
378+ "PasteMetrics" : None ,
379+ }
380+ return BreachAnalyticsResponse (** empty_response )
369381
370382 except HTTPException :
371383 raise
0 commit comments