Compare commits

...
Author SHA1 Message Date
zhom 001bda2efd chore: versiom bump 2026-04-10 01:24:06 +04:00
zhom ff401fd4d3 refactor: debug wayfern launch 2026-04-10 01:08:12 +04:00
zhom 82a2efa7f2 chore: serialize changelog and flake jobs 2026-04-08 20:57:56 +04:00
andyandGitHub 9fe973039d Merge pull request #274 from zhom/docs/release-0.20.2
docs: release notes for v0.20.2
2026-04-08 20:34:55 +04:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
2cdbdaa1ab chore: update flake.nix for v0.20.2 [skip ci] (#273)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-08 16:28:46 +00:00
github-actions[bot] d31b22f57d docs: update CHANGELOG.md and README.md for v0.20.2 [skip ci] 2026-04-08 16:28:43 +00:00
zhom 45e57662de chore: version bump 2026-04-08 18:53:18 +04:00
zhom 7931a241e7 chore: aws integrity checks 2026-04-08 18:52:39 +04:00
zhom 224c35388f chore: inject NEXT_PUBLIC_TURNSTILE everywhere 2026-04-08 18:52:08 +04:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
2bf45357ab chore: update flake.nix for v0.20.1 [skip ci] (#272)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-08 12:10:48 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
dd0ccda5fd docs: update CHANGELOG.md and README.md for v0.20.1 [skip ci] (#271)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-08 12:10:42 +00:00
12 changed files with 86 additions and 33 deletions
+7 -5
View File
@@ -40,11 +40,11 @@ jobs:
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
fi
- name: Normalize R2 endpoint
# The R2_ENDPOINT_URL secret may be stored with or without a scheme.
# `aws s3 --endpoint-url` rejects values without `https://`, so we
# prepend it once here and export via $GITHUB_ENV so every later step
# inherits the normalised value. Keep this step before any `aws` call.
- name: Configure aws-cli for R2
# aws-cli v2.23+ sends integrity checksums by default; Cloudflare R2
# rejects those headers with `Unauthorized` on ListObjectsV2.
# Also normalise the endpoint URL (must start with https://).
# Both values propagate to later steps via $GITHUB_ENV.
env:
RAW_ENDPOINT: ${{ secrets.R2_ENDPOINT_URL }}
run: |
@@ -53,6 +53,8 @@ jobs:
endpoint="https://$endpoint"
fi
echo "R2_ENDPOINT=$endpoint" >> "$GITHUB_ENV"
echo "AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED" >> "$GITHUB_ENV"
echo "AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED" >> "$GITHUB_ENV"
- name: Install tools
run: |
+9 -6
View File
@@ -139,11 +139,8 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Build frontend
# NEXT_PUBLIC_* vars are inlined into the client bundle at build time,
# so they must be forwarded explicitly from secrets here — GitHub
# Secrets are NOT automatically exposed as env vars to `run` steps.
# If this env block is missing, released builds ship with undefined
# values where the Turnstile site key should be, and login breaks.
# NEXT_PUBLIC_* vars are inlined at build time and must be forwarded
# from secrets explicitly — they are NOT inherited from the job env.
env:
NEXT_PUBLIC_TURNSTILE: ${{ secrets.NEXT_PUBLIC_TURNSTILE }}
run: pnpm exec next build
@@ -223,6 +220,12 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# tauri-action invokes `pnpm tauri build`, which runs
# `beforeBuildCommand` from tauri.conf.json. That rebuilds the
# frontend in its own subprocess, so the env var MUST be forwarded
# here or the inner `next build` inlines an empty string and
# overwrites the dist the explicit "Build frontend" step produced.
NEXT_PUBLIC_TURNSTILE: ${{ secrets.NEXT_PUBLIC_TURNSTILE }}
with:
projectPath: ./src-tauri
tagName: ${{ github.ref_name }}
@@ -542,7 +545,7 @@ jobs:
update-flake:
if: github.repository == 'zhom/donutbrowser'
needs: [release]
needs: [release, changelog]
runs-on: ubuntu-latest
permissions:
contents: write
+5 -5
View File
@@ -138,11 +138,8 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Build frontend
# NEXT_PUBLIC_* vars are inlined into the client bundle at build time,
# so they must be forwarded explicitly from secrets here — GitHub
# Secrets are NOT automatically exposed as env vars to `run` steps.
# If this env block is missing, released builds ship with undefined
# values where the Turnstile site key should be, and login breaks.
# NEXT_PUBLIC_* vars are inlined at build time and must be forwarded
# from secrets explicitly — they are NOT inherited from the job env.
env:
NEXT_PUBLIC_TURNSTILE: ${{ secrets.NEXT_PUBLIC_TURNSTILE }}
run: pnpm exec next build
@@ -233,6 +230,9 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# tauri-action's inner `pnpm tauri build` re-runs beforeBuildCommand
# which rebuilds dist/ in a subprocess. The env var must be here too.
NEXT_PUBLIC_TURNSTILE: ${{ secrets.NEXT_PUBLIC_TURNSTILE }}
with:
projectPath: ./src-tauri
tagName: "nightly-${{ steps.timestamp.outputs.timestamp }}"
+20
View File
@@ -1,6 +1,26 @@
# Changelog
## v0.20.2 (2026-04-08)
### Maintenance
- chore: version bump
- chore: aws integrity checks
- chore: inject NEXT_PUBLIC_TURNSTILE everywhere
- chore: update flake.nix for v0.20.1 [skip ci] (#272)
## v0.20.1 (2026-04-08)
### Maintenance
- chore: version bump
- chore: normalize r2 endpoint
- chore: pull turnstile public key in frontend at build time
- chore: update flake.nix for v0.20.0 [skip ci] (#270)
## v0.20.0 (2026-04-08)
### Bug Fixes
+5 -5
View File
@@ -51,7 +51,7 @@
| | Apple Silicon | Intel |
|---|---|---|
| **DMG** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_aarch64.dmg) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_x64.dmg) |
| **DMG** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_aarch64.dmg) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_x64.dmg) |
Or install via Homebrew:
@@ -61,15 +61,15 @@ brew install --cask donut
### Windows
[Download Windows Installer (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_x64-setup.exe) · [Portable (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_x64-portable.zip)
[Download Windows Installer (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_x64-setup.exe) · [Portable (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_x64-portable.zip)
### Linux
| Format | x86_64 | ARM64 |
|---|---|---|
| **deb** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_amd64.deb) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_arm64.deb) |
| **rpm** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut-0.20.0-1.x86_64.rpm) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut-0.20.0-1.aarch64.rpm) |
| **AppImage** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_amd64.AppImage) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_aarch64.AppImage) |
| **deb** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_amd64.deb) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_arm64.deb) |
| **rpm** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut-0.20.2-1.x86_64.rpm) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut-0.20.2-1.aarch64.rpm) |
| **AppImage** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_amd64.AppImage) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_aarch64.AppImage) |
<!-- install-links-end -->
Or install via package manager:
+5 -5
View File
@@ -94,17 +94,17 @@
pkgConfigPath = lib.makeSearchPath "lib/pkgconfig" (
pkgConfigLibs ++ map lib.getDev pkgConfigLibs
);
releaseVersion = "0.20.0";
releaseVersion = "0.20.2";
releaseAppImage =
if system == "x86_64-linux" then
pkgs.fetchurl {
url = "https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_amd64.AppImage";
hash = "sha256-IB86Eius8zXixlHlLjKoltSoCvm6PUpvsEsqAIY7rQI=";
url = "https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_amd64.AppImage";
hash = "sha256-YkdQgsDMJYVyr8590cDJnpPboHcm5X77ycfvMamUvWc=";
}
else if system == "aarch64-linux" then
pkgs.fetchurl {
url = "https://github.com/zhom/donutbrowser/releases/download/v0.20.0/Donut_0.20.0_aarch64.AppImage";
hash = "sha256-CvywykYP4nP//Trh7ImAGPNkNlmkk+py8l0TPgMgKio=";
url = "https://github.com/zhom/donutbrowser/releases/download/v0.20.2/Donut_0.20.2_aarch64.AppImage";
hash = "sha256-F3YtLU+jZw9UUE/2CcKnNxB8WPjYIdnkS5JYwoSP4qw=";
}
else
null;
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "donutbrowser",
"private": true,
"license": "AGPL-3.0",
"version": "0.20.1",
"version": "0.20.3",
"type": "module",
"scripts": {
"dev": "next dev --turbopack -p 12341",
+4
View File
@@ -27,6 +27,10 @@ done
export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="auto"
# aws-cli v2.23+ sends integrity checksums by default; R2 rejects them
# with `Unauthorized` on ListObjectsV2. Disable.
export AWS_REQUEST_CHECKSUM_CALCULATION="WHEN_REQUIRED"
export AWS_RESPONSE_CHECKSUM_VALIDATION="WHEN_REQUIRED"
# Ensure endpoint URL has https:// prefix
R2_ENDPOINT="$R2_ENDPOINT_URL"
+1 -1
View File
@@ -1705,7 +1705,7 @@ dependencies = [
[[package]]
name = "donutbrowser"
version = "0.20.1"
version = "0.20.3"
dependencies = [
"aes",
"aes-gcm",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "donutbrowser"
version = "0.20.1"
version = "0.20.3"
description = "Simple Yet Powerful Anti-Detect Browser"
authors = ["zhom@github"]
edition = "2021"
+27 -3
View File
@@ -86,7 +86,18 @@ impl WayfernManager {
inner: Arc::new(AsyncMutex::new(WayfernManagerInner {
instances: HashMap::new(),
})),
http_client: Client::new(),
// Every request this client makes goes to a local `http://127.0.0.1:<port>`
// endpoint that Wayfern is still bringing up. Without a per-request timeout,
// a single hanging connect or a stuck HTTP response will block
// `wait_for_cdp_ready` indefinitely — its 120-attempt poll loop depends on
// each request returning fast. A 2-second per-request timeout turns that
// into a worst-case ~60-second bounded wait, and `generate_fingerprint_config`
// can then return a real error instead of hanging the profile-creation UI
// forever.
http_client: Client::builder()
.timeout(Duration::from_secs(2))
.build()
.expect("Failed to build reqwest client for wayfern_manager"),
}
}
@@ -141,19 +152,29 @@ impl WayfernManager {
let max_attempts = 120;
let delay = Duration::from_millis(500);
let mut last_error: Option<String> = None;
for attempt in 0..max_attempts {
match self.http_client.get(&url).send().await {
Ok(resp) if resp.status().is_success() => {
log::info!("CDP ready on port {port} after {attempt} attempts");
return Ok(());
}
_ => {
Ok(resp) => {
last_error = Some(format!("HTTP {} from {url}", resp.status()));
tokio::time::sleep(delay).await;
}
Err(e) => {
last_error = Some(format!("request failed: {e}"));
tokio::time::sleep(delay).await;
}
}
}
Err(format!("CDP not ready after {max_attempts} attempts on port {port}").into())
let detail = last_error.unwrap_or_else(|| "no attempts completed".to_string());
// Log at error level so we can diagnose Windows/AV/firewall-induced CDP hangs
// in customer reports without needing them to reproduce in the moment.
log::error!("CDP not ready after {max_attempts} attempts on port {port}: {detail}");
Err(format!("CDP not ready after {max_attempts} attempts on port {port}: {detail}").into())
}
async fn get_cdp_targets(
@@ -270,6 +291,9 @@ impl WayfernManager {
};
if let Err(e) = self.wait_for_cdp_ready(port).await {
log::error!(
"Fingerprint-generation Wayfern (headless, pid={child_id:?}) never became CDP-ready: {e}"
);
cleanup().await;
return Err(e);
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Donut",
"version": "0.20.1",
"version": "0.20.3",
"identifier": "com.donutbrowser",
"build": {
"beforeDevCommand": "pnpm copy-proxy-binary && pnpm dev",