Replace token auth with single-user login
This commit is contained in:
+59
-7
@@ -2,6 +2,7 @@
|
||||
|
||||
"""Shared constants and helper utilities for ani-cli-web."""
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import ipaddress
|
||||
import json
|
||||
@@ -19,7 +20,7 @@ from uuid import uuid4
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
|
||||
APP_NAME = "ani-cli-web"
|
||||
VERSION = "0.40.6"
|
||||
VERSION = "0.41.0"
|
||||
ALLANIME_BASE = "allanime.day"
|
||||
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
||||
ALLANIME_REFERER = "https://allmanga.to"
|
||||
@@ -82,17 +83,56 @@ def remote_access_allowed():
|
||||
return env_flag("ANI_CLI_WEB_ALLOW_REMOTE")
|
||||
|
||||
|
||||
def remote_access_token():
|
||||
return str(os.environ.get("ANI_CLI_WEB_REMOTE_TOKEN") or "").strip()
|
||||
def remote_access_username(config=None):
|
||||
configured = str(os.environ.get("ANI_CLI_WEB_AUTH_USERNAME") or "").strip()
|
||||
if configured:
|
||||
return configured
|
||||
if isinstance(config, dict):
|
||||
return str(config.get("auth_username") or "").strip()
|
||||
return ""
|
||||
|
||||
|
||||
def remote_access_token_configured():
|
||||
return bool(remote_access_token())
|
||||
def remote_access_password(config=None):
|
||||
configured = str(os.environ.get("ANI_CLI_WEB_AUTH_PASSWORD") or "").strip()
|
||||
if configured:
|
||||
return configured
|
||||
if isinstance(config, dict):
|
||||
return str(config.get("auth_password") or "").strip()
|
||||
return ""
|
||||
|
||||
|
||||
def remote_access_token_matches(value):
|
||||
def remote_access_credentials_configured(config=None):
|
||||
return bool(remote_access_username(config) and remote_access_password(config))
|
||||
|
||||
|
||||
def remote_access_credentials_match(username, password, config=None):
|
||||
expected_username = remote_access_username(config)
|
||||
expected_password = remote_access_password(config)
|
||||
provided_username = str(username or "").strip()
|
||||
provided_password = str(password or "").strip()
|
||||
return bool(
|
||||
expected_username
|
||||
and expected_password
|
||||
and hmac.compare_digest(provided_username, expected_username)
|
||||
and hmac.compare_digest(provided_password, expected_password)
|
||||
)
|
||||
|
||||
|
||||
def remote_access_session_value(config=None):
|
||||
username = remote_access_username(config)
|
||||
password = remote_access_password(config)
|
||||
if not username or not password:
|
||||
return ""
|
||||
return hmac.new(
|
||||
f"{username}\0{password}".encode("utf-8"),
|
||||
b"ani-cli-web-session",
|
||||
hashlib.sha256,
|
||||
).hexdigest()
|
||||
|
||||
|
||||
def remote_access_session_matches(value, config=None):
|
||||
provided = str(value or "").strip()
|
||||
expected = remote_access_token()
|
||||
expected = remote_access_session_value(config)
|
||||
return bool(expected and provided and hmac.compare_digest(provided, expected))
|
||||
|
||||
|
||||
@@ -145,7 +185,10 @@ DEFAULT_CONFIG = {
|
||||
"auto_download_quality": "best",
|
||||
"discord_webhook_url": "",
|
||||
"discord_webhook_events": [],
|
||||
"auth_username": str(os.environ.get("ANI_CLI_WEB_AUTH_USERNAME") or "").strip(),
|
||||
"auth_password": str(os.environ.get("ANI_CLI_WEB_AUTH_PASSWORD") or "").strip(),
|
||||
}
|
||||
PRIVATE_CONFIG_KEYS = {"auth_username", "auth_password"}
|
||||
|
||||
|
||||
def now_iso():
|
||||
@@ -295,6 +338,8 @@ def normalize_config(data):
|
||||
auto_download_quality = auto_download_quality[:-1]
|
||||
webhook_url = str(config.get("discord_webhook_url") or "").strip()
|
||||
webhook_events = config.get("discord_webhook_events")
|
||||
auth_username = str(config.get("auth_username") or "").strip()
|
||||
auth_password = str(config.get("auth_password") or "").strip()
|
||||
|
||||
if isinstance(auto_refresh_enabled, str):
|
||||
auto_refresh_enabled = auto_refresh_enabled.strip().lower() in {"1", "true", "yes", "on"}
|
||||
@@ -344,9 +389,16 @@ def normalize_config(data):
|
||||
normalized_events.append(normalized_name)
|
||||
config["discord_webhook_url"] = webhook_url
|
||||
config["discord_webhook_events"] = normalized_events
|
||||
config["auth_username"] = auth_username
|
||||
config["auth_password"] = auth_password
|
||||
return config
|
||||
|
||||
|
||||
def sanitize_public_config(config):
|
||||
source = normalize_config(config or {})
|
||||
return {key: value for key, value in source.items() if key not in PRIVATE_CONFIG_KEYS}
|
||||
|
||||
|
||||
def discord_webhook_enabled(config, event_name, force=False):
|
||||
if not isinstance(config, dict):
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user