v4.0.0
Send v4.0.0
The first release of Send under anoni.net's
own identity. It is built on upstream timvisee/send
v3.4.27, with 67 commits of modernization on top: current runtime, current
dependencies, our own signed images, and a test suite that runs.
This is the build that powers send.anoni.net.
Nothing about how Send works has changed
The wire protocol, the URL format and the encryption are untouched. Existing
share links keep working. ffsend and other third-party clients keep working.
That is a checkable claim, not a reassurance: app/keychain.js, app/ece.js,
app/api.js, the upload, download and metadata routes, and the HMAC auth
middleware have no commits since v3.4.27. Files still encrypt in your
browser, and the key still never leaves the URL fragment.
Versioning, and why /__version__ says 3.4.27
Our release numbers now diverge from upstream's, so /__version__ reports two
separate things:
{
"version": "v3.4.27",
"release": "v4.0.0",
"source": "https://github.com/anoni-net/send",
"commit": "..."
}version is the API generation a client should speak. Clients gate on it:
ffsend maps >=3.0 <4.0 to its V3 API and has no fallback, so a server
advertising 4.x fails every CLI upload with "unsupported version". Since we
changed no protocol, that field stays where it was.
release is our number. Use it for bug reports, and for telling builds
apart.
source now points at this repository. Previously it advertised upstream's,
which was wrong: the JavaScript we serve is modified, and anyone auditing what
they are running needs the source it was built from. The footer "source" link
moved for the same reason.
Runtime and dependencies
| from | to | |
|---|---|---|
| Node | 16.13 (EOL) | 22 |
| redis client | 3.1.1 | 6.0.0 |
| AWS SDK | aws-sdk 2.x |
@aws-sdk/client-s3 3.x |
| Google Cloud Storage | 6.2.3 | 7.21.0 |
| Sentry (browser) | 5.30.0 | 7.120.3 |
| websocket layer | @dannycoates/express-ws |
mainline express-ws |
| webpack | 4 | 5 |
| ESLint | 6 | 10 (flat config) |
The websocket swap matters more than it looks: the old package loaded its source
through the unmaintained esm package, which crashes outright on Node 22. It
was the thing standing between Send and a current runtime.
Fixed
- Blank page. webpack 5 defaults
output.publicPathtoauto, which
prefixed every asset URL and 404'd the bundle. - Missing logo. SVGs processed by
svgo-loaderexport CommonJS while images
export ES modules, so an asset map that assumed.defaultrendered
src="undefined". - Missing "plus" icon in the upload UI.
- Cancelling a download reported an error. Sentry 7 instruments
fetch, so
an aborted transfer arrived as aTypeErrorrather than the shape the handler
recognised. Cancellation is now recorded as intent instead of inferred from
whatever the error happened to look like.
Security and supply chain
46 of 47 vulnerability alerts resolved: 1 critical, 16 high, 19 medium, 10
low. The remaining one is uuid (medium), pinned in place by teeny-request ^9
upstream; forcing it would violate that range.
Every image is built by our CI and published to ghcr.io/anoni-net/send:
- signed with cosign (keyless, via Sigstore),
- carrying an SBOM and SLSA provenance,
- scanned with Trivy,
- built for linux/amd64 and linux/arm64, each on a native runner rather than
under emulation.
docker pull ghcr.io/anoni-net/send:4.0.0
cosign verify ghcr.io/anoni-net/send:4.0.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/anoni-net/send/.github/workflows/publish.yml@.*$'Pin by digest in production so a tag cannot move underneath you. This release is:
ghcr.io/anoni-net/send@sha256:a0f17f9aff65d4014c4fae8d35656e1ad78c68385a36a9bcd9412b167c9bd932
Tests
The test suite had rotted to the point of not running. It runs now, on every
change:
- 56 backend tests, including the first coverage the Google Cloud Storage
backend has ever had. - 21 frontend tests, moved off puppeteer 2 onto Playwright.
- A smoke test against the actual built image: health endpoints, a
/__version__assertion, a page render that fetches the exact asset URLs the
page references, a realffsendencrypted upload and download round-trip with
a checksum comparison, and a headless browser check. - Lint, which had been silently broken for months because nothing ran it.
The smoke test is what caught the version-number problem described above, before
it reached anyone.
Known gaps
uuid(medium) stays open, blocked upstream.- The encrypted round-trip does not run on arm64 in CI, because
ffsend
publishes x86_64 binaries only. Everything else in the smoke test does run
there, and the log says so rather than passing quietly. - The S3 and Google Cloud Storage backends have unit-test and API-surface
coverage, not runtime coverage. Smoke-test them before switching to either. - Trivy reports; it does not yet gate.
Credit
Send was created by Mozilla and kept alive after Mozilla discontinued it by
Tim Visée, whose fork this continues. We are not
affiliated with or endorsed by either. Licensed MPL-2.0, unchanged.
Send v4.0.0(正體中文)
這是 Send 以 anoni.net 自己的身分發布的第一個版本,基於上游
timvisee/send v3.4.27,往上疊了 67 個 commit
的翻修:把執行環境與相依套件帶到現行版本、改用我們自己簽章的映像、讓測試真的跑得起來。
這就是 send.anoni.net 正在跑的版本。
Send 的運作方式完全沒有改變
線上協定、URL 格式與加密方式都沒有動。既有的分享連結繼續有效,ffsend
與其他第三方客戶端也繼續能用。
這是可以查證的陳述:app/keychain.js、app/ece.js、app/api.js、upload
與 download 與 metadata 三個路由、以及 HMAC 驗證中介層,自 v3.4.27
以來沒有任何一個 commit。檔案依然在你的瀏覽器裡加密,金鑰依然只存在於 URL 的
fragment,不會離開。
版號說明,以及 /__version__ 為何仍寫 3.4.27
我們的發行版號從這一版開始與上游分流,所以 /__version__ 分成兩個欄位回報:
{
"version": "v3.4.27",
"release": "v4.0.0",
"source": "https://github.com/anoni-net/send",
"commit": "..."
}version 代表客戶端該使用哪一代 API。客戶端會依這個欄位判斷相容性:ffsend
把 >=3.0 <4.0 對應到它的 V3 API,而且沒有任何 fallback,伺服器若宣告 4.x,
所有 CLI 上傳都會以 unsupported version 失敗。我們既然沒有更動協定,這個欄位就
維持原樣。
release 才是我們自己的版號。回報問題與辨識建置版本時請用它。
source 現在指向本 repo。先前它指向上游,那是錯的:我們送到瀏覽器的 JavaScript
經過修改,想稽核自己正在跑什麼的人,需要看到這份建置實際來自的原始碼。頁尾的
「原始碼」連結基於同樣理由一併調整。
執行環境與相依套件
| 從 | 到 | |
|---|---|---|
| Node | 16.13(已終止支援) | 22 |
| redis client | 3.1.1 | 6.0.0 |
| AWS SDK | aws-sdk 2.x |
@aws-sdk/client-s3 3.x |
| Google Cloud Storage | 6.2.3 | 7.21.0 |
| Sentry(瀏覽器端) | 5.30.0 | 7.120.3 |
| websocket 層 | @dannycoates/express-ws |
主線 express-ws |
| webpack | 4 | 5 |
| ESLint | 6 | 10(flat config) |
websocket 那一項的份量比表面上大:舊套件透過已無人維護的 esm
載入自己的原始碼,而它在 Node 22 上會直接崩潰。它正是擋在 Send
與現行執行環境之間的那道關卡。
修正
- 整頁空白。 webpack 5 把
output.publicPath預設成auto,替每個資源網址加上前綴,導致
bundle 404。 - Logo 顯示不出來。 經過
svgo-loader的 SVG 匯出 CommonJS,圖片則匯出 ES module,
資源對照表若一律假設.default,就會渲染出src="undefined"。 - 上傳介面缺少「加號」圖示。
- 取消下載會顯示錯誤。 Sentry 7 會插樁
fetch,中止的傳輸因此以TypeError
的形式出現,與處理程式原本比對的錯誤型態不符。現在改成記錄「使用者要取消」這個意圖,
不再從錯誤長相反推。
安全性與供應鏈
47 個弱點通報已修掉 46 個:1 個 critical、16 個 high、19 個 medium、10 個 low。
剩下的 1 個是 uuid(medium),被上游 teeny-request ^9 的版本範圍卡住,強行升版會違反該範圍。
每個映像都由我們的 CI 建置並發布到 ghcr.io/anoni-net/send:
- 以 cosign 簽章(keyless,透過 Sigstore)
- 附帶 SBOM 與 SLSA provenance
- 經 Trivy 掃描
- 提供 linux/amd64 與 linux/arm64,兩者都在原生機器上建置,不使用模擬
docker pull ghcr.io/anoni-net/send:4.0.0
cosign verify ghcr.io/anoni-net/send:4.0.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/anoni-net/send/.github/workflows/publish.yml@.*$'正式環境請以 digest 釘選,避免標籤在你腳下被移動。本次發行的 digest:
ghcr.io/anoni-net/send@sha256:a0f17f9aff65d4014c4fae8d35656e1ad78c68385a36a9bcd9412b167c9bd932
測試
這套測試原本已經荒廢到跑不起來。現在每次變更都會跑:
- 56 個後端測試,其中包含 Google Cloud Storage 後端有史以來第一次的測試覆蓋。
- 21 個前端測試,從 puppeteer 2 移轉到 Playwright。
- 針對實際建置出來的映像做 smoke test:健康檢查端點、
/__version__斷言、
抓取頁面實際引用的資源網址來確認渲染、用真的ffsend跑一次加密上傳與下載往返並比對
checksum,以及一次 headless 瀏覽器檢查。 - Lint,它先前因為沒有任何地方會執行而靜靜壞了好幾個月。
上面提到的版號問題,正是這個 smoke test 在影響到任何人之前攔下來的。
已知的不足
uuid(medium)仍未關閉,卡在上游。- CI 的 arm64 不會跑加密往返測試,因為
ffsend只發布 x86_64 的執行檔。smoke test
其餘項目在 arm64 上照跑,而且會在記錄中明確寫出跳過了哪一段,不會靜靜地過關。 - S3 與 Google Cloud Storage 後端目前只有單元測試與 API 介面層級的驗證,沒有實際執行的覆蓋。
要改用這兩者之前,請先自行實測一次。 - Trivy 目前只回報,還沒有設成硬性關卡。
致謝
Send 由 Mozilla 開發,在 Mozilla 停止服務後由 Tim Visée
接手維護,本專案延續的正是他的分支。我們與兩者皆無隸屬關係,也未受其背書。
授權維持 MPL-2.0 不變。