
    >j                        S r SSKrSSKrSSKrSSKJrJrJrJr  SSK	J
r
Jr  SSKJr  SSKJr  SSKJr  SSKJr  \R(                  S	   r\R(                  S
   r\R(                  R/                  SS5      R1                  5       S:H  r\R(                  R/                  SS5      r\R(                  R/                  SS5      r\R9                  SS5      S-   r\" \5      R>                  S-  r \RB                  " S\RD                  5      r#\" SSSS9r$\" SS9S 5       r%S\4S jr&S\'4S jr(\$R/                  S5      \" \&5      4S\'4S  jj5       r)\$RU                  S!5      \" \&5      4S\S\'4S" jj5       r+\$R/                  S#5      S$ 5       r,SS%K-J.r.  \$R_                  \.S&S'/S(S)/S*S+/S,9  \$RU                  S-5      S\4S. j5       r0g)/u  
WBS Public API — minimal authenticated proxy to Turso.

Architecture: FastAPI app behind Cloudflare Tunnel + Cloudflare Access.
- GET /          → serves the WBS dashboard HTML
- POST /turso    → validates JWT, allowlists SQL, forwards to Turso HTTP API
- Everything else → 404

Security layers (defense in depth):
  1. Cloudflare Access (email/OAuth auth wall at the edge)
  2. JWT verification (validates Cf-Access-Jwt-Assertion header)
  3. SQL statement allowlist (DML only: SELECT/INSERT/UPDATE/DELETE)
  4. Parameterized queries (handled by dashboard, preserved by proxy)

Auth toggle: AUTH_ENABLED env var. Defaults to true (fail-closed).
Set to "false" only for local testing before Cloudflare Access is configured.
    N)FastAPIRequestHTTPExceptionDepends)FileResponseJSONResponse)jwt)JWTError)	lru_cache)PathTURSO_DATABASE_URLTURSO_AUTH_TOKENAUTH_ENABLEDtrueCF_ACCESS_TEAM_DOMAIN CF_ACCESS_AUD_TAGz	libsql://https://z/v2/pipelinestaticz#^\s*(SELECT|INSERT|UPDATE|DELETE)\bzWBS Public API)titledocs_url	redoc_url   )maxsizec                      S[          S3n [        R                  " SS9 nUR                  U 5      R	                  5       sSSS5        $ ! , (       d  f       g= f)z.Fetch and cache Cloudflare Access public keys.r   z/cdn-cgi/access/certs
   timeoutN)CF_TEAM_DOMAINhttpxClientgetjson)urlclients     +/home/ubuntu/second-brain/public-api/app.pyget_cf_jwksr'   1   sB     ^$$9
:C	b	!Vzz###% 
"	!	!s   A
Arequestc                 X   [         (       d  SS0$ U R                  R                  S5      nU(       d
  [        SSS9e[        (       a  [
        (       d
  [        SSS9e [        5       n[        R                  " UUS	/[
        S
[         3S9nU$ ! [         a  n[        SSU 3S9eSnAff = f)u   Validate the Cf-Access-Jwt-Assertion header. Raises 401 on failure.

When AUTH_ENABLED=false, returns a stub claim — for local testing ONLY.
subzauth-disabled-local-testzCf-Access-Jwt-Assertioni  zMissing Cloudflare Access tokenstatus_codedetaili  z Cloudflare Access not configuredRS256r   )
algorithmsaudienceissuerzInvalid token: N)
r   headersr"   r   r   
CF_AUD_TAGr'   r	   decoder
   )r(   tokenjwksclaimses        r&   verify_cf_accessr9   9   s    
 <122OO 9:E4UVV>4VWWK}yn-.
  KoaS4IJJKs   /B 
B)B$$B)bodyc                     U R                  S/ 5      nU Hf  nUR                  S5      S:w  a  M  UR                  S0 5      R                  SS5      n[        R                  U5      (       a  MX  [        SSUS	S
  3S9e   g	)z@Walk the Turso pipeline payload; reject anything that isn't DML.requeststypeexecutestmtsqlr     zLSQL statement not allowed. Only SELECT/INSERT/UPDATE/DELETE permitted. Got: NP   r+   )r"   ALLOWED_SQL_PATTERNmatchr   )r:   r<   reqr@   s       r&   validate_sql_statementsrF   T   s    xx
B'H776?i'ggfb!%%eR0"((--efijmkmfneop      /r7   c                 .   #    [        [        S-  5      $ 7f)Nz
index.html)r   
STATIC_DIR)r7   s    r&   serve_dashboardrK   c   s     
\122s   z/tursoc                 ~  #    U R                  5       I S h  vN n[        U5        [        R                  " SS9 IS h  vN nUR	                  [
        USS[         30S9I S h  vN nS S S 5      IS h  vN   [        WR                  5       UR                  S9$  N N^ N: N,! , IS h  vN  (       d  f       NA= f7f)N   r   AuthorizationBearer r#   r2   contentr,   )	r#   rF   r    AsyncClientpostTURSO_HTTP_URLr   r   r,   )r(   r7   r:   r%   resps        r&   turso_proxyrW   h   s     DD!  ,,[[$0@/A&BC ! 
 
 -, 		9I9IJJ   -
 -,,,sg   B=B'B=BB="B#$B%B#)B=4B!5'B=B=B#!B=#B:)B,*B:6B=z/healthzc                     #    SS0$ 7f)z6Unauthenticated health check for systemd / monitoring.statusok r[   rG   r&   healthzr\   v   s      ds   )CORSMiddlewarez$https://megsnexttrip.dumbbugbaby.comz$http://ubuntu.tail8a4639.ts.net:8087POSTOPTIONSrN   zContent-Type)allow_originsallow_methodsallow_headersz/turso-travelc                   #    U R                  5       I Sh  vN nUR                  S/ 5       HC  nUR                  S0 5      R                  SS5      nSUR                  5       ;  d  M;  [        SSS	9e   [        R
                  " S
S9 ISh  vN nUR                  [        USS[         30S9I Sh  vN nSSS5      ISh  vN   [        WR                  5       UR                  S9$  N N^ N: N,! , ISh  vN  (       d  f       NA= f7f)uD   Unauthenticated proxy — restricted to travel_checklist table only.Nr<   r?   r@   r   travel_checklistrA   z&Only travel_checklist table permitted.r+   rM   r   rN   rO   rP   rQ   )r#   r"   lowerr   r    rS   rT   rU   r   r   r,   )r(   r:   rE   r@   r%   rV   s         r&   turso_travel_proxyrf      s      Dxx
B'ggfb!%%eR0SYY[0C8`aa (   ,,[[$0@/A&BC ! 
 
 -, 		9I9IJJ  
 -
 -,,,sp   DC)AD($DC+D"C12C-3C17DC/'D+D-C1/D1D7C:8DD)1__doc__osrer    fastapir   r   r   r   fastapi.responsesr   r   joser	   jose.exceptionsr
   	functoolsr   pathlibr   environr   r   r"   re   r   r   r3   replacerU   __file__parentrJ   compile
IGNORECASErC   appr'   r9   dictrF   rK   rT   rW   r\   fastapi.middleware.corsr]   add_middlewarerf   r[   rG   r&   <module>rz      s  " 
 	  < < 8  $   ZZ 45 ::01  zz~~nf5;;=G 7<ZZ^^/4
 $++KD~U(^""X-
 jj!GW $ttD 1& &Kg K6$  )01A)B 3$ 3 3 (7>?O7P 
Kw 
K 
K 
K  
 3   9;ab9%"N3	   /Kg K KrG   