Compare commits

..

4 Commits

Author SHA1 Message Date
zhom e98d02a585 chore: version bump 2026-06-03 23:05:21 +04:00
zhom afa2326584 fix: launch wayfern with proper dimentions for mobile devices 2026-06-03 23:05:21 +04:00
github-actions[bot] d25d8549e4 chore: update flake.nix for v0.25.2 [skip ci] (#415)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 01:43:35 +00:00
github-actions[bot] 662b370ed0 docs: update CHANGELOG.md and README.md for v0.25.2 [skip ci] (#414)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 01:43:19 +00:00
8 changed files with 153 additions and 14 deletions
+18
View File
@@ -1,6 +1,24 @@
# Changelog
## v0.25.2 (2026-06-02)
### Refactoring
- cleanup
### Documentation
- update CHANGELOG.md and README.md for v0.25.1 [skip ci] (#412)
### Maintenance
- chore: simplify linux repo publish
- chore: version bump
- chore: copy
- chore: update flake.nix for v0.25.1 [skip ci] (#413)
## v0.25.1 (2026-06-01)
### Maintenance
+5 -5
View File
@@ -46,7 +46,7 @@
| | Apple Silicon | Intel |
|---|---|---|
| **DMG** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_aarch64.dmg) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_x64.dmg) |
| **DMG** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_aarch64.dmg) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_x64.dmg) |
Or install via Homebrew:
@@ -56,15 +56,15 @@ brew install --cask donut
### Windows
[Download Windows Installer (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_x64-setup.exe) · [Portable (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_x64-portable.zip)
[Download Windows Installer (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_x64-setup.exe) · [Portable (x64)](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_x64-portable.zip)
### Linux
| Format | x86_64 | ARM64 |
|---|---|---|
| **deb** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_amd64.deb) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_arm64.deb) |
| **rpm** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut-0.25.1-1.x86_64.rpm) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut-0.25.1-1.aarch64.rpm) |
| **AppImage** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_amd64.AppImage) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_aarch64.AppImage) |
| **deb** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_amd64.deb) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_arm64.deb) |
| **rpm** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut-0.25.2-1.x86_64.rpm) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut-0.25.2-1.aarch64.rpm) |
| **AppImage** | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_amd64.AppImage) | [Download](https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_aarch64.AppImage) |
<!-- install-links-end -->
Or install via package manager:
+5 -5
View File
@@ -96,17 +96,17 @@
pkgConfigPath = lib.makeSearchPath "lib/pkgconfig" (
pkgConfigLibs ++ map lib.getDev pkgConfigLibs
);
releaseVersion = "0.25.1";
releaseVersion = "0.25.2";
releaseAppImage =
if system == "x86_64-linux" then
pkgs.fetchurl {
url = "https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_amd64.AppImage";
hash = "sha256-+wtKVCYUjDgXyL96oCqHC0ekWHIe9pLjn1RLBfWHamA=";
url = "https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_amd64.AppImage";
hash = "sha256-awESxsKfrSJFMAGbTasbXjL8UnF58ziLnS8Ee0phgb8=";
}
else if system == "aarch64-linux" then
pkgs.fetchurl {
url = "https://github.com/zhom/donutbrowser/releases/download/v0.25.1/Donut_0.25.1_aarch64.AppImage";
hash = "sha256-fEmf8OzYG3XoEHwOVLh1mONDcJEGeW3d4bb3y//6gPs=";
url = "https://github.com/zhom/donutbrowser/releases/download/v0.25.2/Donut_0.25.2_aarch64.AppImage";
hash = "sha256-zOUWnvf+5stknWomHwYRUw2TR0aS4/XeiVySBjHuJLA=";
}
else
null;
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "donutbrowser",
"private": true,
"license": "AGPL-3.0",
"version": "0.25.2",
"version": "0.25.3",
"type": "module",
"scripts": {
"dev": "next dev --turbopack -p 12341",
+1 -1
View File
@@ -1784,7 +1784,7 @@ dependencies = [
[[package]]
name = "donutbrowser"
version = "0.25.2"
version = "0.25.3"
dependencies = [
"aes 0.9.1",
"aes-gcm",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "donutbrowser"
version = "0.25.2"
version = "0.25.3"
description = "Simple Yet Powerful Anti-Detect Browser"
authors = ["zhom@github"]
edition = "2021"
+121
View File
@@ -138,6 +138,46 @@ impl WayfernManager {
fingerprint
}
/// Derive the on-screen window size Chromium should open at, from the stored
/// fingerprint. `Wayfern.setFingerprint` only spoofs what the page *reports*
/// for `windowOuterWidth`/`screenWidth`/etc.; it does not move or resize the
/// real top-level window. Without `--window-size` the OS window keeps
/// Chromium's default, so the visible window contradicts the reported
/// dimensions — a detectable mismatch. We pass `--window-size` so the actual
/// window matches the fingerprint.
///
/// Keys are the camelCase fields Wayfern uses in its fingerprint
/// (`windowOuterWidth`, `screenAvailWidth`, …) — NOT the dotted
/// Camoufox-style keys. Preference order, matching how the fingerprint
/// describes the window:
/// 1. `windowOuterWidth` / `windowOuterHeight` — the real window size.
/// 2. `screenAvailWidth` / `screenAvailHeight` — usable screen area.
/// 3. `screenWidth` / `screenHeight` — full screen.
///
/// Returns `None` when the fingerprint carries no usable dimensions, leaving
/// Chromium's default untouched. The fingerprint JSON may be the bare object
/// or the legacy `{ "fingerprint": {...} }` wrapper.
fn window_size_from_fingerprint(fingerprint_json: &str) -> Option<(u32, u32)> {
let parsed: serde_json::Value = serde_json::from_str(fingerprint_json).ok()?;
let fp = parsed.get("fingerprint").unwrap_or(&parsed);
let obj = fp.as_object()?;
// Accept both numeric and stringified numbers (Wayfern emits numbers, but a
// CDP echo or older saved fingerprint may stringify them).
let read = |key: &str| -> Option<u32> {
let v = obj.get(key)?;
v.as_u64()
.or_else(|| v.as_str().and_then(|s| s.trim().parse::<u64>().ok()))
.filter(|n| *n > 0)
.map(|n| n as u32)
};
let pair = |w: &str, h: &str| -> Option<(u32, u32)> { Some((read(w)?, read(h)?)) };
pair("windowOuterWidth", "windowOuterHeight")
.or_else(|| pair("screenAvailWidth", "screenAvailHeight"))
.or_else(|| pair("screenWidth", "screenHeight"))
}
async fn wait_for_cdp_ready(
&self,
port: u16,
@@ -618,6 +658,18 @@ impl WayfernManager {
if headless {
args.push("--headless=new".to_string());
} else if let Some((w, h)) = config
.fingerprint
.as_deref()
.and_then(Self::window_size_from_fingerprint)
{
// Size the real OS window to match the fingerprint so the visible window
// agrees with the reported windowOuterWidth/screen dimensions. Anchor at
// 0,0 so the window also fits within the spoofed screen origin. Skipped in
// headless mode, where there is no on-screen window.
log::info!("Sizing Wayfern window to fingerprint dimensions: {w}x{h}");
args.push(format!("--window-size={w},{h}"));
args.push("--window-position=0,0".to_string());
}
#[cfg(target_os = "linux")]
@@ -1198,3 +1250,72 @@ impl WayfernManager {
lazy_static::lazy_static! {
static ref WAYFERN_MANAGER: WayfernManager = WayfernManager::new();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn window_size_prefers_outer_window_dimensions() {
// Field names + values mirror a real Wayfern fingerprint (camelCase).
let fp = r#"{"windowOuterWidth": 1268, "windowOuterHeight": 764,
"windowInnerWidth": 1253, "windowInnerHeight": 630,
"screenAvailWidth": 1280, "screenAvailHeight": 775,
"screenWidth": 1280, "screenHeight": 800}"#;
assert_eq!(
WayfernManager::window_size_from_fingerprint(fp),
Some((1268, 764))
);
}
#[test]
fn window_size_falls_back_to_avail_then_full_screen() {
let avail = r#"{"screenAvailWidth": 1280, "screenAvailHeight": 775,
"screenWidth": 1280, "screenHeight": 800}"#;
assert_eq!(
WayfernManager::window_size_from_fingerprint(avail),
Some((1280, 775))
);
let full = r#"{"screenWidth": 2560, "screenHeight": 1440}"#;
assert_eq!(
WayfernManager::window_size_from_fingerprint(full),
Some((2560, 1440))
);
}
#[test]
fn window_size_handles_wrapper_and_stringified_numbers() {
let wrapped = r#"{"fingerprint": {"windowOuterWidth": "1366", "windowOuterHeight": "768"}}"#;
assert_eq!(
WayfernManager::window_size_from_fingerprint(wrapped),
Some((1366, 768))
);
}
#[test]
fn window_size_none_when_missing_or_invalid() {
// No dimensions at all.
assert_eq!(
WayfernManager::window_size_from_fingerprint(r#"{"userAgent": "x"}"#),
None
);
// A width with no matching height is not a usable pair.
assert_eq!(
WayfernManager::window_size_from_fingerprint(r#"{"windowOuterWidth": 1268}"#),
None
);
// Zero is rejected as a degenerate size.
assert_eq!(
WayfernManager::window_size_from_fingerprint(
r#"{"windowOuterWidth": 0, "windowOuterHeight": 0}"#
),
None
);
// Not valid JSON.
assert_eq!(
WayfernManager::window_size_from_fingerprint("not json"),
None
);
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Donut",
"version": "0.25.2",
"version": "0.25.3",
"identifier": "com.donutbrowser",
"build": {
"beforeDevCommand": "pnpm copy-proxy-binary && pnpm dev",