Skip to content

v1.2.0

Latest

Choose a tag to compare

@toomore toomore released this 29 Jul 08:18
· 1 commit to main since this release
0617458

v1.2.0 開放瀏覽器端直接呼叫。起因是 docs 站的「Tor 中繼地球儀」是一頁靜態頁面,要加上「即時更新」按鈕就必須讓瀏覽器直接 fetch onionoo.anoni.net,而 1.1.0 的 CORS 預設清單是空的,middleware 根本沒有掛上去。

CORS 白名單

新增 CORS_ALLOW_ORIGINS,逗號分隔,與 pulse/backend 既有的變數同名同格式,兩個服務的設定方式一致。

預設清單涵蓋 docs 站實際被服務的位置:

Origin 用途
https://anoni.net clearnet docs 站
http://docs.anoninetru5tflukgfaehun7q6khowgmymcff3gtk5oyesqazhmfxtyd.onion onion 鏡像
http://127.0.0.1:8000 本機 mkdocs serve
http://localhost:8000 本機 mkdocs serve

兩種寫法不對稱是有原因的。clearnet 的 docs 掛在路徑底下(https://anoni.net/docs/),所以 origin 是裸的 apex。onion 鏡像則是同一把 onion key 的子網域,那是它自己的 origin,必須單獨列。

其餘設定:

  • allow_credentials 保持 False。所有路由都不看 cookie 與 Authorization,關掉它可以確保瀏覽器不會在跨來源呼叫上夾帶環境憑證,也讓之後要放寬白名單時少一層顧慮。
  • allow_methods 只開 GET 與 OPTIONS。這是唯讀代理,GET 覆蓋所有路由,OPTIONS 給 preflight。
  • expose_headers 開放 X-Request-ID 與 Last-Modified,讓前端能讀到請求編號與上游資料時間。
  • 設成 CORS_ALLOW_ORIGINS="" 即可完全關閉 CORS,middleware 不會掛載。

服務代理的是 Onionoo 的公開唯讀資料,開放的風險低,白名單的作用比較接近限制誰能花掉我們的上游預算。即使如此仍然走環境變數列舉,不寫死 *,之後要放寬比要收緊容易。

無條件輸出 Vary: Origin

新增 app/middleware.py 的 VaryOriginMiddleware,掛在最外層,保證每個 HTTP 回應都帶 Vary: Origin。

Starlette 只在 Origin 命中白名單那條分支加這個標頭(allow_explicit_origin() 內),沒帶 Origin 或被拒絕的請求不會有。實測 Starlette 1.3:

請求 1.1.0 的 Vary
命中白名單的 origin Origin, Accept-Encoding
不在白名單的 origin 只有 Accept-Encoding
沒帶 Origin 只有 Accept-Encoding

後兩者會與命中的請求共用快取鍵。前面有 CDN 或反向代理時,一個沒有 Access-Control-Allow-Origin 的回應可能被 replay 給合法來源的瀏覽器,反過來也一樣。

middleware 是冪等的,CORS 已經寫過就不動它,看到 Vary: * 也不會畫蛇添足。用 add_vary_header() 追加而非覆寫,所以與 GZipMiddleware 的 Accept-Encoding 能並存。

CORS_ALLOWED_ORIGINS 仍然接受

1.0.0 用的是 CORS_ALLOWED_ORIGINS。改名後舊名稱透過 AliasChoices 繼續生效,並在 startup 印出 deprecation 警告。

這一層是必要的:Settings 的 extra="ignore" 會默默吞掉不認識的變數名稱,自架者升級後唯一的症狀會是瀏覽器端 CORS 失敗,服務端一行 log 都沒有。兩個名稱同時存在時以新名稱為準。舊名稱會在未來版本移除。

startup log 也開始印出生效中的白名單。瀏覽器端的 CORS 失敗,與服務單純掛掉,症狀長得一模一樣,把清單放進啟動訊息可以省掉一輪猜測。

README 修正過期的預設值

1.1.0 動過的設定值沒有同步到 README,一併補上:

  • MAX_LIMIT 從文件寫的 200 更正為 20000
  • 補上 MAX_LIMIT_UNTRIMMED(預設 200,未帶 fields= 時超過會回 422,未投影的全量 payload 約 90 MB)
  • CACHE_MAXSIZE 從 1024 更正為 128
  • 記憶體估算從 ~500 MiB 修正為 ~64 MiB

自架注意

預設白名單是 anoni.net 的部署位置。自架時請換成你自己的 origin,否則等於幫別人的站台開了門。

另外,從 onion 鏡像讀 docs 的人按下「即時更新」時,那仍然是一個經由 exit node 出去的 clearnet 請求。這是頁面設計的既有行為,與本次改動無關,但值得知道。

升級注意

對既有呼叫端沒有破壞性變更。1.1.0 的 CORS 預設清單是空的,middleware 沒有掛載,所以先前所有跨來源請求本來就會被瀏覽器擋下。升級後預設會開始放行上表那四個 origin。

自架者若要維持完全不開 CORS 的行為,設 CORS_ALLOW_ORIGINS="" 即可。

gzip 壓縮未受影響。實測線上 1.2.0,帶五個欄位的 limit=20000 回應 1.92 MB 壓到 421 KB,Content-Encoding: gzip 與 Vary: Origin, Accept-Encoding 同時存在。

安裝

pip install onionoo-fastapi==1.2.0
# 或
uv add onionoo-fastapi==1.2.0
docker pull ghcr.io/anoni-net/onionoo-fastapi:1.2.0

What's Changed

  • feat(cors): 開放瀏覽器端呼叫,CORS_ALLOW_ORIGINS 白名單與無條件 Vary: Origin by @toomore in #5

Full Changelog: v1.1.0...v1.2.0