creds.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. """凭据文件:~/.wikipali/credentials.json(0600)。
  2. 只存 token,不存密码。线上四地址共用 online 桶,开发机 local,其余自成一桶。
  3. """
  4. import json
  5. import os
  6. import stat
  7. from errors import WpError
  8. from sites import DEFAULT_API_URL, LOCAL_URL, ONLINE_URLS, expand_site_alias, normalize_api_url
  9. CREDS_DIR = os.path.join(os.path.expanduser("~"), ".wikipali")
  10. CREDS_PATH = os.path.join(CREDS_DIR, "credentials.json")
  11. def load_creds():
  12. if not os.path.exists(CREDS_PATH):
  13. return {"current": "online"}
  14. try:
  15. with open(CREDS_PATH, "r", encoding="utf-8") as fh:
  16. data = json.load(fh)
  17. except (OSError, ValueError) as exc:
  18. raise WpError(f"凭据文件无法读取({CREDS_PATH}):{exc}")
  19. if not isinstance(data, dict):
  20. raise WpError(f"凭据文件格式不对({CREDS_PATH}),应为 JSON 对象")
  21. data.setdefault("current", "online")
  22. return data
  23. def save_creds(creds):
  24. os.makedirs(CREDS_DIR, mode=0o700, exist_ok=True)
  25. tmp = CREDS_PATH + ".tmp"
  26. flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
  27. fd = os.open(tmp, flags, 0o600)
  28. try:
  29. with os.fdopen(fd, "w", encoding="utf-8") as fh:
  30. json.dump(creds, fh, ensure_ascii=False, indent=2)
  31. fh.write("\n")
  32. except Exception:
  33. os.unlink(tmp)
  34. raise
  35. os.replace(tmp, CREDS_PATH)
  36. os.chmod(CREDS_PATH, stat.S_IRUSR | stat.S_IWUSR)
  37. def bucket_name_for(api_url):
  38. """凭据桶名。线上四地址共用 online 桶;开发机 local;其余地址自成一桶。"""
  39. if api_url in ONLINE_URLS:
  40. return "online"
  41. if api_url == LOCAL_URL:
  42. return "local"
  43. return "site:" + api_url
  44. def get_bucket(creds, name, api_url=None):
  45. bucket = creds.setdefault(name, {})
  46. bucket.setdefault("api_url", api_url or (DEFAULT_API_URL if name == "online" else LOCAL_URL))
  47. bucket.setdefault("user", {})
  48. bucket.setdefault("model", {})
  49. bucket.setdefault("access_tokens", {})
  50. return bucket
  51. def resolve_api_url(cli_api, creds):
  52. """地址来源优先级:--api > 环境变量 > 凭据文件 > 内置默认。
  53. 前两者是一次性覆盖,不写回凭据文件——否则「上周试了一次 next」会一直粘着。
  54. """
  55. if cli_api:
  56. return normalize_api_url(expand_site_alias(cli_api)), "cli"
  57. env = os.environ.get("WIKIPALI_API_URL")
  58. if env:
  59. return normalize_api_url(expand_site_alias(env)), "env"
  60. current = creds.get("current", "online")
  61. bucket = creds.get(current)
  62. if isinstance(bucket, dict) and bucket.get("api_url"):
  63. return normalize_api_url(bucket["api_url"]), "creds"
  64. return DEFAULT_API_URL, "default"