- Remove py312 from Black target-version (unsupported) - Format mdclient/auth.py and mdclient/client.py with Black - Update code style: double quotes for strings Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
179 lines
5.3 KiB
Python
179 lines
5.3 KiB
Python
"""
|
||
MDclient 認證模組
|
||
"""
|
||
|
||
import requests
|
||
import json
|
||
from pathlib import Path
|
||
from typing import Optional, Dict
|
||
|
||
|
||
class MDAuth:
|
||
"""Markdown 筆記服務認證類"""
|
||
|
||
def __init__(self, base_url: str = "https://codimd.lotimmy.com", cookie_file: str = "key.conf"):
|
||
"""
|
||
初始化認證類
|
||
|
||
Args:
|
||
base_url: 伺服器位址
|
||
cookie_file: Cookie 儲存檔案路徑
|
||
"""
|
||
self.base_url = base_url.rstrip("/")
|
||
self.login_url = f"{self.base_url}/login"
|
||
self.cookie_file = Path(cookie_file)
|
||
|
||
def save_cookie(self, cookies: Dict[str, str]) -> Dict[str, str]:
|
||
"""
|
||
儲存 Cookie 到檔案
|
||
|
||
Args:
|
||
cookies: Cookie 字典
|
||
|
||
Returns:
|
||
儲存的 Cookie 字典
|
||
"""
|
||
with open(self.cookie_file, "w", encoding="utf-8") as f:
|
||
json.dump(cookies, f, indent=2)
|
||
|
||
print(f"✓ Cookie 已儲存到: {self.cookie_file}")
|
||
return cookies
|
||
|
||
def load_cookie(self) -> Optional[Dict[str, str]]:
|
||
"""
|
||
從檔案載入 Cookie
|
||
|
||
Returns:
|
||
Cookie 字典,如果檔案不存在則返回 None
|
||
"""
|
||
if not self.cookie_file.exists():
|
||
return None
|
||
|
||
with open(self.cookie_file, "r", encoding="utf-8") as f:
|
||
return json.load(f)
|
||
|
||
def login(self, email: str, password: str) -> bool:
|
||
"""
|
||
登入並取得 Cookie
|
||
|
||
Args:
|
||
email: 登入信箱
|
||
password: 登入密碼
|
||
|
||
Returns:
|
||
是否登入成功
|
||
"""
|
||
print(f"正在登入 {self.base_url}...")
|
||
|
||
session = requests.Session()
|
||
|
||
try:
|
||
print("1. 取得登入頁面...")
|
||
response = session.get(self.login_url, timeout=10)
|
||
print(f" 狀態碼: {response.status_code}")
|
||
|
||
print("2. 傳送登入請求...")
|
||
|
||
login_data = {
|
||
"email": email,
|
||
"password": password,
|
||
}
|
||
|
||
headers = {
|
||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
"Origin": self.base_url,
|
||
"Referer": self.login_url,
|
||
}
|
||
|
||
# 嘗試不同的登入端點
|
||
login_endpoints = ["/login", "/auth/login", "/api/login", "/signin"]
|
||
|
||
for endpoint in login_endpoints:
|
||
try:
|
||
login_url = f"{self.base_url}{endpoint}"
|
||
print(f" 嘗試: {login_url}")
|
||
|
||
response = session.post(
|
||
login_url,
|
||
data=login_data,
|
||
headers=headers,
|
||
allow_redirects=True,
|
||
timeout=10,
|
||
)
|
||
|
||
print(f" 狀態碼: {response.status_code}")
|
||
print(f" Cookies: {dict(session.cookies)}")
|
||
|
||
if response.status_code in [200, 302, 301]:
|
||
if session.cookies:
|
||
print(f" ✓ 取得到 {len(session.cookies)} 個 Cookie")
|
||
|
||
# 轉換為字典
|
||
cookie_dict = {}
|
||
for cookie in session.cookies:
|
||
cookie_dict[cookie.name] = cookie.value
|
||
|
||
# 儲存 cookie
|
||
self.save_cookie(cookie_dict)
|
||
|
||
# 顯示主要 cookie 資訊
|
||
for name, value in cookie_dict.items():
|
||
if "sid" in name.lower() or "session" in name.lower():
|
||
print(f" → {name}: {value[:20]}...")
|
||
|
||
return True
|
||
|
||
except requests.RequestException as e:
|
||
print(f" ✗ 請求失敗: {e}")
|
||
continue
|
||
|
||
print("✗ 所有登入端點都失敗")
|
||
return False
|
||
|
||
except requests.RequestException as e:
|
||
print(f"✗ 登入失敗: {e}")
|
||
return False
|
||
|
||
def test_cookie(self) -> bool:
|
||
"""
|
||
測試儲存的 Cookie 是否有效
|
||
|
||
Returns:
|
||
Cookie 是否有效
|
||
"""
|
||
cookies = self.load_cookie()
|
||
if not cookies:
|
||
print("✗ 找不到儲存的 Cookie")
|
||
return False
|
||
|
||
print(f"從 {self.cookie_file} 載入 Cookie...")
|
||
|
||
headers = {
|
||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
||
}
|
||
|
||
try:
|
||
response = requests.get(
|
||
f"{self.base_url}/", cookies=cookies, headers=headers, timeout=10
|
||
)
|
||
print(f"測試請求狀態碼: {response.status_code}")
|
||
return response.status_code == 200
|
||
except requests.RequestException as e:
|
||
print(f"✗ 測試失敗: {e}")
|
||
return False
|
||
|
||
def get_cookies(self) -> Optional[Dict[str, str]]:
|
||
"""
|
||
取得 Cookie(如果需要重新登入會自動處理)
|
||
|
||
Returns:
|
||
Cookie 字典
|
||
"""
|
||
cookies = self.load_cookie()
|
||
if cookies:
|
||
return cookies
|
||
|
||
print("找不到有效的 Cookie,請先登入")
|
||
return None
|