Commit Graph

32 Commits

Author SHA1 Message Date
Vincent Yang
98918dd9f6
feat(translate): migrate to oneshot endpoint (#217)
* feat(translate): migrate to oneshot endpoint to bypass www2 anti-bot

The www2.deepl.com/jsonrpc backends behind LMT_handle_texts /
LMT_handle_jobs now sit behind aggressive WAF + per-IP throttling that
returns HTTP 429 (code 1042911 "Too many requests") within a handful of
calls from any single host — making the free path effectively unusable.

The official DeepL browser extension and iOS app skip that backend
entirely for stateless single-shot translation and POST to a separate
"oneshot" endpoint on a different host pool with its own (much looser)
rate limit. It accepts anonymous traffic with a literal
`Authorization: None` header, returns plain JSON, and supports the same
language pairs.

Switch the free path to:

  POST https://oneshot-free.www.deepl.com/v1/translate
  Authorization: None
  {"text": ["..."], "target_lang": "de", "source_lang": "en"}

Pro users continue to hit oneshot-pro.www.deepl.com with their bearer
token (the `-s` flag now carries an OAuth access token rather than the
legacy dl_session cookie).

This removes:
  - the JSON-RPC envelope (jsonrpc/method/id/params/timestamp wrapper)
  - the `i`-count timestamp trick (getICount + getTimeStamp)
  - the random-id body-spacing trick (handlerBodyMethod)
  - the whatlanggo client-side detection (oneshot detects server-side)

The DeepLXTranslationResult contract is unchanged for service handlers;
Alternatives is now always nil because the oneshot endpoint does not
return alternative translations.

Verified against /translate, /v1/translate and /v2/translate routes
end-to-end (EN/DE/ZH/JA/FR pairs, multi-sentence input, autodetect, 10x
burst) — all 200 OK on an IP that was concurrently being 429'd by www2.

* fix(translate): align oneshot request bytes with the real extension

After capturing the exact bytes the Chrome extension's service-worker
fetch() emits (via an offline echo server pointed at deeplx in place of
oneshot-free.www.deepl.com) and diffing them against what we were
sending, several distinguishable signals remained. Close them all.

Headers
-------
- Origin: chrome-extension://cofdbpoegempjloogbagkncekinflcnj
  (was https://www.deepl.com — a request from www.deepl.com itself
   never lands on the oneshot endpoint, so that origin is unusual.
   The extension ID is the canonical sender.)
- Sec-Fetch-Site: cross-site
  (was same-site — wrong; chrome-extension -> www.deepl.com IS cross-site)
- Drop Referer entirely (extension SW fetch sends none)
- Drop Pragma / Cache-Control / Upgrade-Insecure-Requests / Sec-Fetch-User
  (req.ImpersonateChrome() sets these for top-level navigation; a
   fetch() never sends them — leaving them in is a strong nav-vs-XHR tell)
- Accept-Encoding: gzip, deflate, br
  (was just gzip, Go stdlib default — Chrome 120's fetch() sends all
   three; zstd only landed as a default in Chrome 123+ so leave it off)

Body
----
- Add usage_type: "Translate" and the full app_information object
  (os/os_version/app_version/app_build/instance_id) so the JSON the
  server sees is structurally identical to what background.js IN()
  assembles. Field order in oneshotRequest matches the extension's
  object-literal order so encoding/json produces byte-identical output.
- instance_id is a v4 UUID generated once at process start and reused,
  mirroring the extension's chrome.storage-pinned ID rather than
  rotating per-request (rotation would be a far stronger signal).
- All version strings (TLS handshake, User-Agent, sec-ch-ua,
  app_information.os_version) are pinned to Chrome 120 so they tell
  one consistent story.

Transport
---------
- SetBodyBytes instead of bytes.NewReader so Content-Length is set
  (an io.Reader body forces Transfer-Encoding: chunked, which a
   fetch() with JSON.stringify body never emits)
- Once we set Accept-Encoding manually, the Go stdlib disables its
  transparent decompression and req hands us raw compressed bytes.
  Handle gzip / deflate / br by hand from Content-Encoding.
- DisableAutoReadResponse so we own the body stream end-to-end.

The Chrome 120 TLS ClientHello, HTTP/2 SETTINGS frame, pseudo-header
order and sec-ch-ua claim continue to come from ImpersonateChrome()
unchanged.

Verified end-to-end:
- Outbound bytes (against a local echo server) diff-match the
  extension's observed profile on every header and on body JSON order.
- Live oneshot-free.www.deepl.com calls: 4 language pairs OK,
  /v2/translate official-API compat OK, 10x burst 10/10 200.

* chore(deps): upgrade to latest compatible versions

Run `go get -u ./...` + `go mod tidy`. Direct upgrades:

- github.com/andybalholm/brotli   1.2.0 → 1.2.1
- github.com/tidwall/gjson         1.18.0 → 1.19.0

Indirect (notable):

- github.com/bytedance/sonic       1.15.0 → 1.15.1
- github.com/bytedance/sonic/loader 0.5.0 → 0.5.1
- github.com/bytedance/gopkg       0.1.3 → 0.1.4
- github.com/cloudwego/base64x     0.1.6 → 0.1.7
- github.com/gin-contrib/sse       1.1.0 → 1.1.1
- github.com/go-playground/validator/v10 10.30.1 → 10.30.2
- github.com/goccy/go-json         0.10.5 → 0.10.6
- github.com/klauspost/compress    1.18.4 → 1.18.6
- github.com/mattn/go-isatty       0.0.20 → 0.0.22
- github.com/pelletier/go-toml/v2  2.2.4  → 2.3.1
- golang.org/x/arch                0.24.0 → 0.27.0
- golang.org/x/crypto              0.48.0 → 0.52.0
- golang.org/x/net                 0.51.0 → 0.55.0
- golang.org/x/sys                 0.41.0 → 0.45.0
- golang.org/x/text                0.34.0 → 0.37.0

github.com/imroc/req/v3 (the HTTP client we depend on for Chrome
impersonation) is already on its latest tag v3.57.0 and pins
github.com/quic-go/quic-go to <= v0.57.x — newer quic-go removed
ConnectionTracingID/ConnectionTracingKey, which req's internal/http3
still references. That constraint also holds gin-gonic/gin at v1.11.0
and gin-contrib/cors at v1.7.6 (their later versions pull quic-go
≥ 0.58 transitively). Pin quic-go to v0.57.1 to keep the build green;
revisit when req publishes a release compatible with quic-go ≥ 0.58.

Build + live oneshot end-to-end: 4 language pairs OK, /v2/translate
official-API compat OK, 8x burst 8/8 200.

* fix(translate): seed cookie jar from www.deepl.com on first call

A real chrome-extension fetch() to oneshot-free.www.deepl.com inherits
whatever cookies the browser has on .deepl.com — at minimum
`userCountry=<iso2>` and `verifiedBot=false`, both of which the
deepl.com server sets on any page load. Our outbound bytes were
otherwise extension-identical but went out cookieless, which is a
distinguishable signal.

Wire a process-wide net/http/cookiejar onto the req.Client and trigger
a single warmup GET to https://www.deepl.com/translator on the first
translate call (sync.Once). The Set-Cookie response (userCountry,
verifiedBot) lands on .deepl.com, which the jar then automatically
echoes back on every subsequent POST to oneshot-free.www.deepl.com
(cookies set on .deepl.com match any *.deepl.com subdomain).

Verified outbound:
  Cookie: userCountry=JP; verifiedBot=false

Latency cost: first call after process start pays one extra HTTP GET
(~1s warmup); subsequent calls are unaffected (sync.Once + connection
keep-alive).

Note: we cannot replicate the _ga / _ga_<id> cookies a real user
would also carry — those are set client-side by GA's JS, which a
non-browser HTTP client can't execute. The userCountry+verifiedBot
pair already matches the "first-time visitor with JS disabled" profile,
which is the closest plausible non-browser approximation.
2026-05-22 12:04:44 +08:00
Vincent Yang
76642ae506
build(deps): upgrade go dependencies
Update direct and indirect modules to newer versions.\nPin quic-go to v0.57.1 to stay compatible with req/v3 v3.57.0.\nBump go directive to 1.25.0.
2026-02-27 16:04:08 +08:00
dependabot[bot]
9e765dbf50
chore(deps): bump github.com/quic-go/quic-go from 0.49.1 to 0.57.0 (#214)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.49.1 to 0.57.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.49.1...v0.57.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-version: 0.57.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 15:57:59 +08:00
dependabot[bot]
02483aae97
chore(deps): bump github.com/refraction-networking/utls (#213)
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-version: 1.8.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 15:56:38 +08:00
dependabot[bot]
54eb43099f
chore(deps): bump github.com/cloudflare/circl from 1.6.1 to 1.6.3 (#212)
Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.6.1 to 1.6.3.
- [Release notes](https://github.com/cloudflare/circl/releases)
- [Commits](https://github.com/cloudflare/circl/compare/v1.6.1...v1.6.3)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/circl
  dependency-version: 1.6.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 15:55:59 +08:00
Vincent Young
5e04163957
fix: downgrade quic-go to restore build compatibility
Reverts quic-go from v0.57.0 back to v0.49.1 and qpack from v0.6.0 to v0.5.1
due to breaking API changes that are incompatible with req/v3. The req/v3
library (downgraded to v3.50.0) has not been updated to support the newer
quic-go APIs yet.

Build was failing with undefined quic.Connection, quic.EarlyConnection, and
incompatible qpack.Decoder method signatures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 05:45:04 +08:00
dependabot[bot]
ffbd79508f
chore(deps): bump github.com/quic-go/quic-go from 0.49.1 to 0.57.0 (#211)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.49.1 to 0.57.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.49.1...v0.57.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-version: 0.57.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Vincent Yang <missuo@pm.me>
2025-12-13 05:37:41 +08:00
dependabot[bot]
19d1d86754
chore(deps): bump golang.org/x/crypto from 0.36.0 to 0.45.0 (#210)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-13 05:36:36 +08:00
dependabot[bot]
8709ffd2d4
chore(deps): bump github.com/quic-go/quic-go from 0.48.2 to 0.49.1 (#207)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.48.2 to 0.49.1.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.48.2...v0.49.1)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-version: 0.49.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 20:39:46 +08:00
dependabot[bot]
73a7fd15ed
chore(deps): bump github.com/cloudflare/circl from 1.5.0 to 1.6.1 (#201)
Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.5.0 to 1.6.1.
- [Release notes](https://github.com/cloudflare/circl/releases)
- [Commits](https://github.com/cloudflare/circl/compare/v1.5.0...v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/circl
  dependency-version: 1.6.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-08 22:32:32 +08:00
dependabot[bot]
ceb56a2eee
chore(deps): bump github.com/refraction-networking/utls (#188)
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.6.7 to 1.7.0.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.6.7...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-version: 1.7.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 17:20:05 -04:00
dependabot[bot]
d1dbfcc1e5
chore(deps): bump golang.org/x/net from 0.33.0 to 0.36.0 (#181)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-21 23:00:40 -04:00
dependabot[bot]
4a77cbf30e
chore(deps): bump golang.org/x/net from 0.29.0 to 0.33.0 (#173)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.29.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.29.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 16:59:52 -05:00
dependabot[bot]
1c8beb8a87
chore(deps): bump golang.org/x/crypto from 0.27.0 to 0.31.0 (#166)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.27.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.27.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 17:38:43 -05:00
dependabot[bot]
b04139e89d
chore(deps): bump github.com/quic-go/quic-go from 0.47.0 to 0.48.2 (#165)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.47.0 to 0.48.2.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.47.0...v0.48.2)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 11:27:04 -05:00
Vincent Yang
44b6c2915f
fix: while sourceLang is auto 2024-12-03 11:23:56 -05:00
木末君
547c735b1f
fix: 429 error in /translate endpoint (changed TLS fingerprint) (#161) 2024-11-29 04:13:20 -05:00
dependabot[bot]
7090eadfd5
chore(deps): bump github.com/gin-contrib/cors from 1.4.0 to 1.6.0 (#127)
Bumps [github.com/gin-contrib/cors](https://github.com/gin-contrib/cors) from 1.4.0 to 1.6.0.
- [Release notes](https://github.com/gin-contrib/cors/releases)
- [Changelog](https://github.com/gin-contrib/cors/blob/master/.goreleaser.yaml)
- [Commits](https://github.com/gin-contrib/cors/compare/v1.4.0...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/gin-contrib/cors
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-09 23:35:56 +08:00
dependabot[bot]
56c066a316
chore(deps): bump golang.org/x/net from 0.17.0 to 0.23.0 (#106)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 01:01:58 -04:00
Vincent Yang
f75bfc20f7
ci: fix compile error 2024-03-20 16:52:54 -04:00
dependabot[bot]
aec7a29b12
chore(deps): bump google.golang.org/protobuf from 1.30.0 to 1.33.0 (#97)
Bumps google.golang.org/protobuf from 1.30.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 12:37:11 -04:00
dependabot[bot]
683b256760
chore(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#80)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-22 21:34:49 +08:00
dependabot[bot]
03093a658a
chore(deps): bump golang.org/x/net from 0.10.0 to 0.17.0 (#66)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.10.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.10.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-13 05:02:35 -04:00
Vincent Young
8b8b0af337
fix: unable to return results #51 #52 2023-07-01 07:15:22 +08:00
dependabot[bot]
49c49de27a
chore(deps): bump github.com/gin-gonic/gin from 1.8.1 to 1.9.1
Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.8.1 to 1.9.1.
- [Release notes](https://github.com/gin-gonic/gin/releases)
- [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gin-gonic/gin/compare/v1.8.1...v1.9.1)

---
updated-dependencies:
- dependency-name: github.com/gin-gonic/gin
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 17:37:08 +00:00
Vincent Young
db722920cd
feat: return full alternatives 2023-03-16 20:23:21 +08:00
K024
ca78976607 feat: Add CORS middleware 2023-03-07 00:19:27 +08:00
dependabot[bot]
9345c927eb
chore(deps): bump golang.org/x/crypto
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20210711020723-a769d52b0f97 to 0.1.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-02 16:51:56 +00:00
dependabot[bot]
5bef2bc630
chore(deps): bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20210226172049-e18ecbb05110 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-02 16:49:36 +00:00
cijiugechu
4a79f9ffad feat: Automatically detect the source lang 2023-03-02 14:36:41 +08:00
Vincent Young
9d6eebd691 Package to Web API 2022-10-20 01:06:30 +08:00
sjlleo
785273ca95 add: 🤩 First Commit! 2022-10-17 01:51:22 -04:00