1p / src /components /auth_component.py
pythoneerHiro's picture
Upload 54 files
4585d4c verified
import streamlit as st
from typing import Dict, List, Callable, Optional
from utils.auth_utils import run_one_round_authentication
def one_round_auth(
secret: str,
direction_mapping: Dict[str, str],
colors: List[str],
direction_map: Dict[str, str],
domains: Dict[str, Dict],
session_key: str = "one_round_auth",
on_success: Optional[Callable] = None,
on_failure: Optional[Callable] = None,
show_reference: bool = True
) -> bool:
"""
Streamlit component for one-round 1P authentication.
Args:
secret: The user's secret character
direction_mapping: Mapping of colors to directions
colors: List of available colors
direction_map: Mapping of direction names to codes
domains: Available character domains
session_key: Unique key for session state
on_success: Optional callback function when auth succeeds
on_failure: Optional callback function when auth fails
show_reference: Whether to show direction mapping reference
Returns:
True if authentication is completed successfully, False otherwise
"""
# Initialize session state for this component
if session_key not in st.session_state:
st.session_state[session_key] = {
'started': False,
'completed': False,
'success': False,
'grid_html': None,
'expected': None
}
sess = st.session_state[session_key]
# If not started yet, show start button
if not sess['started']:
st.info("Click 'Authenticate' to verify your identity")
if st.button("🔐 Authenticate", type="primary", key=f"{session_key}_start_btn"):
# Generate challenge
grid_html, expected = run_one_round_authentication(
secret, direction_mapping, colors, direction_map, domains
)
# Update session state
sess['started'] = True
sess['grid_html'] = grid_html
sess['expected'] = expected
st.rerun()
return False
# If already completed, return result
if sess['completed']:
return sess['success']
# Display the challenge grid
st.markdown(sess['grid_html'], unsafe_allow_html=True)
# Show direction mapping as reference if requested
if show_reference:
with st.expander("🧭 Your Direction Mapping Reference"):
col1, col2 = st.columns(2)
with col1:
for color in colors[:len(colors)//2]:
direction = direction_mapping.get(color, "Skip")
emoji_map = {"Up": "⬆️", "Down": "⬇️", "Left": "⬅️", "Right": "➡️", "Skip": "⏭️"}
st.markdown(f"**{color.title()}**: {direction} {emoji_map[direction]}")
with col2:
for color in colors[len(colors)//2:]:
direction = direction_mapping.get(color, "Skip")
emoji_map = {"Up": "⬆️", "Down": "⬇️", "Left": "⬅️", "Right": "➡️", "Skip": "⏭️"}
st.markdown(f"**{color.title()}**: {direction} {emoji_map[direction]}")
# Input for the direction
col1, col2 = st.columns([3, 1])
with col1:
user_input = st.radio(
"What direction do you see?",
options=["⬆️ Up", "⬇️ Down", "⬅️ Left", "➡️ Right", "⏭️ Skip"],
key=f"{session_key}_input",
horizontal=True
)
with col2:
st.markdown("<br>", unsafe_allow_html=True) # Spacing
if st.button("Submit", type="primary", key=f"{session_key}_submit_btn"):
# Map emoji selection to direction code
direction_code = {
"⬆️ Up": "U",
"⬇️ Down": "D",
"⬅️ Left": "L",
"➡️ Right": "R",
"⏭️ Skip": "S"
}[user_input]
# Check if the answer is correct
success = direction_code == sess['expected']
# Update session state
sess['completed'] = True
sess['success'] = success
# Call callbacks if provided
if success and on_success is not None:
on_success()
elif not success and on_failure is not None:
on_failure()
st.rerun()
return False