Update
This commit is contained in:
parent
4626fafef7
commit
944584e28a
@ -1,3 +1,4 @@
|
||||
CLIENT_NAME="YourAPINme (Dev)/1.0"
|
||||
VRCHAT_API_BASE="https://api.vrchat.cloud/api/1"
|
||||
IS_RENDER=False
|
||||
IS_DISTANT=False
|
||||
DISTANT_URL_CONTEXT="https://distant.vrchat.cloud/data/account.json"
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,4 +5,5 @@ venv/
|
||||
*.log
|
||||
"@ | Out-File -Encoding utf8 .gitignore
|
||||
.env
|
||||
data/*
|
||||
data/
|
||||
account.json.php
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
define('ACCESS_TOKEN', 'mon_token_de_securite_ici');
|
||||
|
||||
if (!isset($_GET['token']) || $_GET['token'] !== ACCESS_TOKEN) {
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$jsonContent = <<<'JSON'
|
||||
{
|
||||
"manual_username": "user123",
|
||||
"displayName": "User Display Name",
|
||||
"user_id": "abcdef123456",
|
||||
"auth": "xxxxxxxxxxxxxxx==",
|
||||
"auth_cookie": "yyyyyyyyyyyyyy",
|
||||
"created_at": "2025-06-22T14:00:00+00:00"
|
||||
}
|
||||
JSON;
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo $jsonContent;
|
||||
|
||||
?>
|
@ -1,9 +1,16 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
import json
|
||||
from fastapi import APIRouter
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
def load_context():
|
||||
VRChatContext.load()
|
||||
vrchat = VRChatContext.get()
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/health")
|
||||
def health_check():
|
||||
return {"status": "ok"}
|
||||
@router.get("/ping")
|
||||
def ping():
|
||||
return {"message": "pong"}
|
||||
|
||||
@router.get("/status")
|
||||
def status_check():
|
||||
return {"status": "ok" if vrchat.auth_cookie else "not authenticated"}
|
||||
|
@ -1,23 +1,22 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
import json
|
||||
from app.env import CLIENT_NAME, API_BASE, TOKEN_FILE
|
||||
from app.env import CLIENT_NAME, API_BASE
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def load_token():
|
||||
if not TOKEN_FILE.exists():
|
||||
return None
|
||||
with open(TOKEN_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
def load_context():
|
||||
VRChatContext.load()
|
||||
|
||||
@router.get("/groups/{group_id}")
|
||||
async def get_groups(group_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -39,11 +38,12 @@ async def get_groups(group_id: str):
|
||||
|
||||
@router.get("/groups/{group_id}/instances")
|
||||
async def get_groups_instances(group_id: str, user_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -61,11 +61,12 @@ async def get_groups_instances(group_id: str, user_id: str):
|
||||
|
||||
@router.get("/groups/{group_id}/posts")
|
||||
async def get_groups_posts(group_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -89,11 +90,12 @@ async def get_groups_posts(group_id: str):
|
||||
|
||||
@router.get("/groups/{group_id}/bans")
|
||||
async def get_groups_bans(group_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -115,11 +117,12 @@ async def get_groups_bans(group_id: str):
|
||||
|
||||
@router.get("/groups/{group_id}/roles")
|
||||
async def get_groups_roles(group_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -137,11 +140,12 @@ async def get_groups_roles(group_id: str):
|
||||
|
||||
@router.get("/groups/{group_id}/members")
|
||||
async def get_groups_members(group_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
|
49
app/api/vrchat_search.py
Normal file
49
app/api/vrchat_search.py
Normal file
@ -0,0 +1,49 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
import json
|
||||
from app.env import CLIENT_NAME, API_BASE, TOKEN_FILE
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def load_context():
|
||||
VRChatContext.load()
|
||||
|
||||
def load_token():
|
||||
if not TOKEN_FILE.exists():
|
||||
return None
|
||||
with open(TOKEN_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
@router.get("/auth/exists/{type}/{text}")
|
||||
async def get_if_exists_per_type(type: str, text: str):
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
|
||||
if type not in ["username", "email"]:
|
||||
raise HTTPException(status_code=400, detail="Invalid type, must be 'username' or 'email'")
|
||||
|
||||
if not text:
|
||||
raise HTTPException(status_code=400, detail="Text cannot be empty")
|
||||
|
||||
if not text.startswith("usr_") or text.startswith("group_"):
|
||||
raise HTTPException(status_code=400, detail="Invalid text format, must start with 'usr_' or 'group_'")
|
||||
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
headers = {"User-Agent": CLIENT_NAME}
|
||||
cookies = {"auth": auth_cookie}
|
||||
url = f"{API_BASE}/auth/exists?{type}={text}{'&displayName=' + text if type == 'username' else ''}"
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.get(url, headers=headers, cookies=cookies)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=r.status_code, detail=f"Failed to fetch if {type} exists: {r.text}")
|
||||
|
||||
return r.json()
|
@ -1,23 +1,45 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
import json
|
||||
from app.env import CLIENT_NAME, API_BASE, TOKEN_FILE
|
||||
from app.env import CLIENT_NAME, API_BASE
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def load_token():
|
||||
if not TOKEN_FILE.exists():
|
||||
return None
|
||||
with open(TOKEN_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
def load_context():
|
||||
VRChatContext.load()
|
||||
|
||||
@router.get("/users/me")
|
||||
async def get_bot_users_profile():
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
headers = {"User-Agent": CLIENT_NAME}
|
||||
cookies = {"auth": auth_cookie}
|
||||
url = f"{API_BASE}/users/{vrchat.user_id}"
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.get(url, headers=headers, cookies=cookies)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=r.status_code, detail=f"Failed to fetch user (current bot) info: {r.text}")
|
||||
|
||||
return r.json()
|
||||
|
||||
@router.get("/users/{user_id}")
|
||||
async def get_user(user_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -35,11 +57,12 @@ async def get_user(user_id: str):
|
||||
|
||||
@router.get("/users/{user_id}/friends/status")
|
||||
async def get_user_friend_status(user_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -57,11 +80,12 @@ async def get_user_friend_status(user_id: str):
|
||||
|
||||
@router.get("/users/{user_id}/worlds")
|
||||
async def get_user_worlds(user_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
@ -87,11 +111,12 @@ async def get_user_worlds(user_id: str):
|
||||
|
||||
@router.get("/users/{user_id}/groups")
|
||||
async def get_user_groups(user_id: str):
|
||||
token = load_token()
|
||||
if not token:
|
||||
load_context()
|
||||
vrchat = VRChatContext.get()
|
||||
if not vrchat:
|
||||
raise HTTPException(status_code=401, detail="Token not found, please authenticate first")
|
||||
|
||||
auth_cookie = token.get("auth_cookie")
|
||||
auth_cookie = vrchat.auth_cookie
|
||||
if not auth_cookie:
|
||||
raise HTTPException(status_code=401, detail="Auth cookie missing in token")
|
||||
|
||||
|
@ -6,4 +6,4 @@ load_dotenv(dotenv_path=Path(__file__).parent.parent / ".env")
|
||||
CLIENT_NAME = os.getenv("CLIENT_NAME", "default-client-name")
|
||||
API_BASE = os.getenv("VRCHAT_API_BASE", "https://api.vrchat.cloud/api/1")
|
||||
TOKEN_FILE = Path(os.getenv("TOKEN_FILE", "data/auth/account.json"))
|
||||
IS_RENDER = os.getenv("IS_RENDER", "false").lower() in ("true", "1", "t")
|
||||
IS_DISTANT = os.getenv("IS_DISTANT", "false").lower() in ("true", "1", "t")
|
12
app/main.py
12
app/main.py
@ -1,7 +1,13 @@
|
||||
from fastapi import FastAPI
|
||||
from app.api.vrchat_search import router as search
|
||||
from app.api.vrchat_users import router as users
|
||||
from app.api.vrchat_groups import router as groups
|
||||
from app.api.system import router as system
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
def load_context():
|
||||
VRChatContext.load()
|
||||
vrchat = VRChatContext.get()
|
||||
|
||||
app = FastAPI(
|
||||
title="K-API",
|
||||
@ -24,11 +30,13 @@ app = FastAPI(
|
||||
swagger_ui_parameters={"defaultModelsExpandDepth": -1},
|
||||
docs_url="/docs",
|
||||
redoc_url=None,
|
||||
openapi_url="/openapi.json",
|
||||
contact={"name": "Kryscau", "url": "https://vrchat.com/home/user/usr_323befe7-edbc-46fe-af9d-560f7e6b290c", "email": "kryscau@kvs.fyi" }
|
||||
openapi_url="/api.json",
|
||||
contact={"name": "Unstealable", "url": "https://vrchat.com/home/user/usr_3e354294-5925-42bb-a5e6-511c39a390eb"}
|
||||
)
|
||||
prefix = "/api"
|
||||
|
||||
if vrchat.auth_cookie:
|
||||
app.include_router(search, prefix=prefix, tags=["Search"])
|
||||
app.include_router(users, prefix=prefix, tags=["Users"])
|
||||
app.include_router(groups, prefix=prefix, tags=["Groups"])
|
||||
app.include_router(system, prefix=prefix, tags=["System"])
|
68
app/vrchat_context.py
Normal file
68
app/vrchat_context.py
Normal file
@ -0,0 +1,68 @@
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import os
|
||||
import httpx
|
||||
|
||||
from app.env import IS_DISTANT
|
||||
|
||||
@dataclass
|
||||
class VRChatData:
|
||||
display_name: str
|
||||
user_id: str
|
||||
auth_cookie: str
|
||||
auth_header: str
|
||||
manual_username: str
|
||||
|
||||
class VRChatContext:
|
||||
_instance: Optional["VRChatContext"] = None
|
||||
|
||||
def __init__(self):
|
||||
self._token: Optional[VRChatData] = None
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
if IS_DISTANT:
|
||||
cls._load_from_remote()
|
||||
else:
|
||||
cls._load_from_local()
|
||||
|
||||
@classmethod
|
||||
def _load_from_local(cls, path: Path = Path("data/account.json")):
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"account.json file not found: {path}")
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
cls._set_instance(data)
|
||||
|
||||
@classmethod
|
||||
def _load_from_remote(cls):
|
||||
remote_url = os.getenv("DISTANT_TOKEN_URL")
|
||||
if not remote_url:
|
||||
raise EnvironmentError("DISTANT_TOKEN_URL is not defined in environment")
|
||||
|
||||
try:
|
||||
response = httpx.get(remote_url, timeout=5.0)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
cls._set_instance(data)
|
||||
except httpx.RequestError as e:
|
||||
raise ConnectionError(f"Could not fetch remote VRChat Data: {e}")
|
||||
|
||||
@classmethod
|
||||
def _set_instance(cls, data: dict):
|
||||
cls._instance = cls()
|
||||
cls._instance._token = VRChatData(
|
||||
display_name=data.get("displayName", ""),
|
||||
user_id=data.get("user_id", ""),
|
||||
auth_cookie=data.get("auth_cookie", ""),
|
||||
auth_header=data.get("auth", ""),
|
||||
manual_username=data.get("manual_username", "")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get(cls) -> VRChatData:
|
||||
if not cls._instance or not cls._instance._token:
|
||||
raise RuntimeError("VRChatContext not initialized. Call VRChatContext.load() first.")
|
||||
return cls._instance._token
|
34
distant_accounts.json.php
Normal file
34
distant_accounts.json.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
$authorized_ip = '0.0.0.0';
|
||||
$allowed_origin_prefix = 'https://vrchatapi-';
|
||||
$allowed_origin_suffix = '.kvs.fyi';
|
||||
|
||||
$client_ip = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
|
||||
function startsWith($haystack, $needle) {
|
||||
return substr($haystack, 0, strlen($needle)) === $needle;
|
||||
}
|
||||
|
||||
function endsWith($haystack, $needle) {
|
||||
return substr($haystack, -strlen($needle)) === $needle;
|
||||
}
|
||||
|
||||
$is_ip_allowed = $client_ip === $authorized_ip;
|
||||
$is_origin_allowed = startsWith($origin, $allowed_origin_prefix) && endsWith($origin, $allowed_origin_suffix);
|
||||
|
||||
if (!$is_ip_allowed && !$is_origin_allowed) {
|
||||
header("Location: https://github.com/unstealable");
|
||||
exit;
|
||||
}
|
||||
|
||||
$vrchat_token = [
|
||||
"manual_username" => "TonUsername",
|
||||
"displayName" => "TonDisplayName",
|
||||
"user_id" => "usr_abcdef1234567890",
|
||||
"auth" => "ZGF0YQ==",
|
||||
"auth_cookie" => "auth_cookie_valeur"
|
||||
];
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($vrchat_token, JSON_PRETTY_PRINT);
|
@ -6,28 +6,8 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parent.parent))
|
||||
from env import CLIENT_NAME, API_BASE, TOKEN_FILE, IS_RENDER
|
||||
|
||||
if IS_RENDER:
|
||||
print("⚠️ Running in Render environment, skipping VRChat auth.")
|
||||
sys.exit(0)
|
||||
|
||||
def save_token(data):
|
||||
data["created_at"] = datetime.now(timezone.utc).isoformat()
|
||||
TOKEN_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(TOKEN_FILE, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
def load_token():
|
||||
if not TOKEN_FILE.exists():
|
||||
return None
|
||||
with open(TOKEN_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
created = datetime.fromisoformat(data.get("created_at", "2000-01-01T00:00:00+00:00"))
|
||||
if datetime.now(timezone.utc) - created > timedelta(days=30):
|
||||
print("⚠️ Token expired. Reconnection required.")
|
||||
return None
|
||||
return data
|
||||
from app.env import CLIENT_NAME, API_BASE, TOKEN_FILE, IS_DISTANT
|
||||
from app.vrchat_context import VRChatContext
|
||||
|
||||
def verify_auth_cookie(auth_cookie):
|
||||
cookies = {"auth": auth_cookie}
|
||||
@ -36,6 +16,51 @@ def verify_auth_cookie(auth_cookie):
|
||||
r = client.get("/auth")
|
||||
return r.status_code == 200 and r.json().get("ok", False)
|
||||
|
||||
def get_or_create_token():
|
||||
if IS_DISTANT:
|
||||
print("⚠️ Running in distant environment, using VRChatContext.")
|
||||
try:
|
||||
VRChatContext.load()
|
||||
token = VRChatContext.get()
|
||||
if not verify_auth_cookie(token.auth_cookie):
|
||||
print("❌ Remote token invalid. Please regenerate the token and update the distant source.")
|
||||
return None
|
||||
print("🔓 Auth ready from distant environment.")
|
||||
return {
|
||||
"manual_username": token.manual_username,
|
||||
"displayName": token.display_name,
|
||||
"user_id": token.user_id,
|
||||
"auth": token.auth_header,
|
||||
"auth_cookie": token.auth_cookie
|
||||
}
|
||||
except Exception as e:
|
||||
print("❌ Failed to initialize VRChatContext:", e)
|
||||
return None
|
||||
|
||||
if not TOKEN_FILE.exists():
|
||||
return None
|
||||
|
||||
with open(TOKEN_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
created = datetime.fromisoformat(data.get("created_at", "2000-01-01T00:00:00+00:00"))
|
||||
if datetime.now(timezone.utc) - created > timedelta(days=30):
|
||||
print("⚠️ Token expired. Reconnection required.")
|
||||
return None
|
||||
|
||||
if not verify_auth_cookie(data.get("auth_cookie", "")):
|
||||
print("❌ Local token invalid. Please log in again.")
|
||||
return None
|
||||
|
||||
print("🟢 Local token valid.")
|
||||
return data
|
||||
|
||||
def save_token(data):
|
||||
data["created_at"] = datetime.now(timezone.utc).isoformat()
|
||||
TOKEN_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(TOKEN_FILE, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
def login():
|
||||
print("🔐 Connecting to VRChat")
|
||||
manual_username = input("Username: ")
|
||||
@ -51,7 +76,6 @@ def login():
|
||||
}
|
||||
|
||||
with httpx.Client(base_url=API_BASE, headers=headers) as client:
|
||||
# 1 - First GET call to /auth/user with Basic Auth
|
||||
r = client.get("/auth/user")
|
||||
if r.status_code != 200:
|
||||
print("❌ Connection failed:", r.text)
|
||||
@ -59,12 +83,10 @@ def login():
|
||||
|
||||
data = r.json()
|
||||
|
||||
# 2 - Check 2FA
|
||||
if "requiresTwoFactorAuth" in data:
|
||||
mfa_types = data["requiresTwoFactorAuth"]
|
||||
print(f"🔐 2FA required: {mfa_types}")
|
||||
|
||||
# The Authorization header is removed for the following request
|
||||
client.headers.pop("Authorization", None)
|
||||
|
||||
if "otp" in mfa_types:
|
||||
@ -84,7 +106,6 @@ def login():
|
||||
return None
|
||||
print("✅ 2FA verified!")
|
||||
|
||||
# 3 - Repeat a GET /auth/user without Basic Auth to confirm the session
|
||||
r3 = client.get("/auth/user")
|
||||
if r3.status_code != 200:
|
||||
print("❌ Failed to fetch user data after 2FA:", r3.text)
|
||||
@ -92,7 +113,6 @@ def login():
|
||||
|
||||
data = r3.json()
|
||||
|
||||
# 4 - Retrieve auth cookie
|
||||
auth_cookie = None
|
||||
for cookie in client.cookies.jar:
|
||||
if cookie.name == "auth":
|
||||
@ -103,14 +123,12 @@ def login():
|
||||
print("❌ Auth cookie not found after login.")
|
||||
return None
|
||||
|
||||
# 5 - Check cookie
|
||||
if not verify_auth_cookie(auth_cookie):
|
||||
print("❌ Auth cookie invalid.")
|
||||
return None
|
||||
|
||||
print("✅ Connected and verified.")
|
||||
|
||||
# 6 - Prepare the information to be backed up
|
||||
display_name = data.get("displayName", manual_username)
|
||||
user_id = data.get("id", "")
|
||||
|
||||
@ -122,25 +140,11 @@ def login():
|
||||
"auth_cookie": auth_cookie
|
||||
}
|
||||
|
||||
def get_or_create_token():
|
||||
token = load_token()
|
||||
if token:
|
||||
print("🔑 Found saved token, verifying...")
|
||||
if verify_auth_cookie(token.get("auth_cookie", "")):
|
||||
print("🟢 Token already valid.")
|
||||
return token
|
||||
else:
|
||||
print("⚠️ Saved token invalid, need to login again.")
|
||||
|
||||
new_token = login()
|
||||
if new_token:
|
||||
save_token(new_token)
|
||||
return new_token
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
token_data = get_or_create_token()
|
||||
if token_data:
|
||||
print("🔓 Auth ready. Token stored.")
|
||||
if not IS_DISTANT:
|
||||
save_token(token_data)
|
||||
else:
|
||||
print("❌ Unable to obtain a valid token.")
|
@ -3,3 +3,4 @@ uvicorn[standard]
|
||||
httpx
|
||||
orjson
|
||||
python-dotenv
|
||||
email-validator
|
Loading…
x
Reference in New Issue
Block a user