nvidiaclass2 / auth.py
qwendashcoder's picture
Update auth.py
d22239c verified
Raw History Blame Contribute Delete
11.3 kB
import json
import time
from huggingface_hub import HfApi, hf_hub_download
from werkzeug.security import generate_password_hash, check_password_hash
import gradio as gr
from retry import retry # Requires `pip install retry`
# Handle HfHubHTTPError import gracefully (it's in utils, and may vary by version)
try:
from huggingface_hub.utils import HfHubHTTPError
except ImportError:
from requests.exceptions import HTTPError as HfHubHTTPError # Fallback to base HTTPError for compatibility
# ================== ALLOWED USERS + AUDIT LOG ==================
def is_allowed_username(username, auth_globals):
username = username.strip().lower()
try:
path = hf_hub_download(repo_id=auth_globals["user_repo"], filename="allowed_users.json", repo_type="dataset", token=auth_globals["hf_token"])
with open(path, 'r') as f:
allowed = json.load(f)
return username in [u.strip().lower() for u in allowed]
except HfHubHTTPError as e:
gr.Warning(f"Failed to check allowed users: {str(e)}")
return False
except Exception as e:
gr.Warning(f"Unexpected error in is_allowed_username: {str(e)}")
return False
@retry(tries=3, delay=1, backoff=2) # Retry on transient errors
def log_activity(action, username, details="", auth_globals=None):
if not auth_globals or not username:
return
try:
hf_api = HfApi(token=auth_globals["hf_token"])
user_repo = auth_globals["user_repo"]
try:
path = hf_hub_download(repo_id=user_repo, filename="activity_log.json", repo_type="dataset", token=auth_globals["hf_token"])
with open(path, 'r') as f:
log = json.load(f)
except HfHubHTTPError:
log = [] # Initialize if file doesn't exist
entry = {
"timestamp": time.time(),
"datetime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"action": action,
"username": username.strip().lower(),
"details": details
}
log.append(entry)
hf_api.upload_file(
path_or_fileobj=json.dumps(log, indent=2).encode(),
path_in_repo="activity_log.json",
repo_id=user_repo,
repo_type="dataset",
token=auth_globals["hf_token"]
)
except Exception as e:
gr.Warning(f"Failed to log activity: {str(e)}") # Better than silent failure
def get_total_accounts(auth_globals):
try:
hf_api = HfApi(token=auth_globals["hf_token"])
files = hf_api.list_repo_files(repo_id=auth_globals["user_repo"], repo_type="dataset")
return sum(1 for f in files if f.endswith('.json') and f not in ["allowed_users.json", "activity_log.json"])
except HfHubHTTPError as e:
gr.Warning(f"Failed to get total accounts: {str(e)}")
return 0
except Exception as e:
gr.Warning(f"Unexpected error in get_total_accounts: {str(e)}")
return 0
# ================== HELPER FOR FAILURE RETURNS ==================
def failure_return(logged_in_username, message, user_chats=None, current_title=None, history=None, dropdown=None, context_tb=None, save_btn=None):
# Defaults are set to None and computed here to avoid NameError on evaluation
if user_chats is None:
user_chats = []
if current_title is None:
current_title = None
if history is None:
history = []
if dropdown is None:
dropdown = gr.update(choices=[], value=None)
if context_tb is None:
context_tb = gr.update(visible=bool(logged_in_username), value="")
if save_btn is None:
save_btn = gr.update(visible=bool(logged_in_username))
return (
user_chats, current_title, history, dropdown, logged_in_username, f"❌ {message}",
gr.update(visible=bool(logged_in_username)), gr.update(visible=False), gr.update(visible=False), context_tb, save_btn
)
# ================== REGISTER ==================
def register_user(username, password, logged_in_username, auth_globals):
hf_token = auth_globals["hf_token"]
user_repo = auth_globals["user_repo"]
hf_api = HfApi(token=hf_token)
username = username.strip().lower()
if not username.isalnum(): # Added: Sanitize username (alphanumeric only)
return failure_return(logged_in_username, "Username must be alphanumeric.")
if get_total_accounts(auth_globals) >= 20:
return failure_return(logged_in_username, "Maximum 20 accounts reached.")
if not username or not password:
return failure_return(logged_in_username, "Please fill username and password.")
if not is_allowed_username(username, auth_globals):
return failure_return(logged_in_username, "This username is not pre-approved by admin.")
try:
# Check if already exists
hf_hub_download(repo_id=user_repo, filename=f"{username}.json", repo_type="dataset", token=hf_token)
return failure_return(logged_in_username, "User already exists!")
except HfHubHTTPError: # Expected if file doesn't exist
pass
except Exception as e:
return failure_return(logged_in_username, f"Registration check failed: {str(e)}")
try:
user_data = {
"password": generate_password_hash(password),
"chats": []
}
hf_api.upload_file(
path_or_fileobj=json.dumps(user_data).encode('utf-8'),
path_in_repo=f"{username}.json",
repo_id=user_repo,
repo_type="dataset",
token=hf_token
)
log_activity("REGISTER", username, "New account created", auth_globals)
return [], None, [], gr.update(choices=[], value=None), username, "βœ… Registration successful! Logged in.", gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(visible=True, value=""), gr.update(visible=True)
except Exception as e:
return failure_return(logged_in_username, f"Registration failed: {str(e)}")
# ================== LOGIN ==================
def login_user(username, password, logged_in_username, auth_globals):
hf_token = auth_globals["hf_token"]
user_repo = auth_globals["user_repo"]
hf_api = HfApi(token=hf_token)
username = username.strip().lower()
if not username or not password:
return failure_return(logged_in_username, "Please enter username and password.")
if not is_allowed_username(username, auth_globals):
return failure_return(logged_in_username, "This username is not pre-approved by admin.")
try:
user_file = hf_hub_download(repo_id=user_repo, filename=f"{username}.json", repo_type="dataset", token=hf_token)
with open(user_file, 'r') as f:
data = json.load(f)
if check_password_hash(data["password"], password):
chats = data.get("chats", [])
if chats:
current_title = chats[-1]["title"]
history = chats[-1]["history"]
context = chats[-1].get("context", "") # Added: Load context
choices = [chat["title"] for chat in chats]
value = current_title
else:
current_title = None
history = []
context = ""
choices = []
value = None
dropdown = gr.update(choices=choices, value=value)
log_activity("LOGIN", username, "Successful login", auth_globals)
return chats, current_title, history, dropdown, username, "βœ… Login successful!", gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(visible=True, value=context), gr.update(visible=True)
else:
return failure_return(logged_in_username, "Incorrect password.")
except HfHubHTTPError as e:
return failure_return(logged_in_username, f"Login failed: User not found ({str(e)}).")
except Exception as e:
return failure_return(logged_in_username, f"Login failed: {str(e)}")
# ================== LOGOUT ==================
def logout_user():
return [], None, [], gr.update(choices=[], value=None), None, "Logged out successfully!", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False, value=""), gr.update(visible=False)
# ================== SAVE CHATS ==================
@retry(tries=3, delay=1, backoff=2) # Added retry for reliability
def save_chats(username, chats, auth_globals):
if not username:
return "No user logged in!"
try:
hf_token = auth_globals["hf_token"]
user_repo = auth_globals["user_repo"]
hf_api = HfApi(token=hf_token)
user_file = hf_hub_download(repo_id=user_repo, filename=f"{username}.json", repo_type="dataset", token=hf_token)
with open(user_file, 'r') as f:
data = json.load(f)
data["chats"] = chats # Chats now include "context"
hf_api.upload_file(path_or_fileobj=json.dumps(data).encode('utf-8'), path_in_repo=f"{username}.json", repo_id=user_repo, repo_type="dataset", token=hf_token)
log_activity("SAVE_CHATS", username, "Chats updated", auth_globals) # Added logging for saves
return "Chats saved automatically!"
except HfHubHTTPError as e:
return f"Failed to save chats: {str(e)} (HF API error)"
except Exception as e:
return f"Failed to save chats: {str(e)}"
# ================== DELETE ACCOUNT ==================
def delete_account(confirm_username, logged_in_username, auth_globals):
confirm_username = confirm_username.strip().lower()
if not logged_in_username or confirm_username != logged_in_username:
return "❌ Username does not match.", logged_in_username, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, None, None, None, gr.update(visible=True), gr.update(visible=True)
if not is_allowed_username(logged_in_username, auth_globals):
return "❌ Not allowed.", logged_in_username, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, None, None, None, gr.update(visible=True), gr.update(visible=True)
hf_token = auth_globals["hf_token"]
user_repo = auth_globals["user_repo"]
hf_api = HfApi(token=hf_token)
try:
hf_api.delete_file(path_in_repo=f"{logged_in_username}.json", repo_id=user_repo, repo_type="dataset", token=hf_token)
log_activity("DELETE_ACCOUNT", logged_in_username, "Account permanently deleted", auth_globals)
return "βœ… Account permanently deleted.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), [], None, [], gr.update(choices=[], value=None), gr.update(visible=False, value=""), gr.update(visible=False)
except HfHubHTTPError as e:
return f"❌ Deletion failed: {str(e)}", logged_in_username, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, None, None, None, gr.update(visible=True), gr.update(visible=True)
except Exception as e:
return f"❌ Deletion failed: {str(e)}", logged_in_username, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, None, None, None, gr.update(visible=True), gr.update(visible=True)