# ========================================================= # AUTHENTICATION MODULE FOR STREAMLIT (HF SPACES SAFE) # ========================================================= import streamlit as st import hashlib from typing import Optional, Dict, Any # ========================================================= # LOAD PASSWORD HASH FROM SECRETS # ========================================================= def _get_password_hash() -> Optional[str]: try: raw = st.secrets.get("APP_PASSWORD", None) except Exception: raw = None if not raw: return None return hashlib.sha256(raw.encode("utf-8")).hexdigest() PASSWORD_HASH = _get_password_hash() # ========================================================= # SESSION UTILITIES # ========================================================= def is_logged_in() -> bool: return bool(st.session_state.get("_logged_in", False)) def set_logged_in(value: bool = True): st.session_state["_logged_in"] = bool(value) def logout(): st.session_state["_logged_in"] = False # ========================================================= # QUERY PARAM COMPATIBILITY LAYER # ========================================================= def _get_query_params() -> Dict[str, Any]: """Return query params safely across Streamlit versions""" # New Streamlit API try: if hasattr(st, "query_params"): qp = dict(st.query_params or {}) return qp except Exception: pass # Old experimental API try: if hasattr(st, "experimental_get_query_params"): qp = st.experimental_get_query_params() or {} return dict(qp) except Exception: pass return {} def _set_query_params(**kwargs): """Set query params safely across Streamlit versions""" # New Streamlit API try: if hasattr(st, "set_query_params"): st.set_query_params(**kwargs) return except Exception: pass # Old experimental API try: if hasattr(st, "experimental_set_query_params"): st.experimental_set_query_params(**kwargs) return except Exception: pass # No query-param API available → do nothing return # ========================================================= # SAFE RERUN (works on all HF Streamlit builds) # ========================================================= def _safe_rerun(): """Try every known rerun mechanism.""" try: if hasattr(st, "experimental_rerun"): st.experimental_rerun() return except Exception: pass try: if hasattr(st, "rerun"): st.rerun() return except Exception: pass # Fallback for environments where rerun is blocked try: st.markdown('', unsafe_allow_html=True) except Exception: pass # ========================================================= # LOGIN UI (Used ONLY on /pages/auth.py) # ========================================================= def login_ui() -> bool: """Returns True ONLY when login succeeds.""" st.title("🔒 Authentication") if PASSWORD_HASH is None: st.error("APP_PASSWORD not defined in Secrets.") return False pwd = st.text_input("Password", type="password") if st.button("Login"): entered_hash = hashlib.sha256(pwd.encode("utf-8")).hexdigest() if entered_hash == PASSWORD_HASH: set_logged_in(True) st.success("Login successful! Redirecting…") st.markdown("Login Successful - Click on any option from Left sidebar") return True else: st.error("Incorrect password") return False # ========================================================= # AUTH ENFORCER FOR ALL OTHER PAGES # ========================================================= def require_login(auth_page_name: str = "auth", redirect_page: str = "HOW TO USE"): """ Call this at TOP of every protected page. If not logged in → redirect to auth page. """ if "_logged_in" not in st.session_state: st.session_state["_logged_in"] = False if is_logged_in(): return # Already authenticated # Find current page params = _get_query_params() cur_page = None if "page" in params: p = params["page"] if isinstance(p, list): cur_page = p[0] if p else None else: cur_page = p # Allow rendering of auth page itself if cur_page == auth_page_name: return # Redirect user to AUTH page _set_query_params(page=auth_page_name) st.stop() # ========================================================= # AUTH PAGE HANDLER (CALLED ONLY INSIDE pages/auth.py) # ========================================================= def auth_page_handler(redirect_page="HOW TO USE"): succeeded = login_ui() if succeeded: _set_query_params(page=redirect_page) _safe_rerun() st.stop()