mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-10-21 23:01:26 +02:00
feat: flatpak and snap support
This commit is contained in:
1 parent
feef010f55
commit
276d5b56f7
17 files changed
+1143
No files matched your search
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2025 zhom@github -->
|
||||
<component type="desktop-application">
|
||||
<id>com.donutbrowser.DonutBrowser</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>AGPL-3.0-only</project_license>
|
||||
|
||||
<name>Donut Browser</name>
|
||||
<summary>Open source anti-detect browser</summary>
|
||||
<developer id="com.donutbrowser">
|
||||
<name>Donut Browser</name>
|
||||
</developer>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Donut Browser manages any number of isolated browser profiles. Each profile
|
||||
keeps its own fingerprint, cookies, extensions and data, and runs on
|
||||
Wayfern, a Chromium-based engine that Donut downloads on first use.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Per-profile HTTP, HTTPS, SOCKS4 and SOCKS5 proxies, and WireGuard configs</li>
|
||||
<li>Per-profile DNS blocklists for ads and trackers</li>
|
||||
<li>Profile import from Chrome, Edge, Brave and other Chromium browsers</li>
|
||||
<li>Cookie and extension management</li>
|
||||
<li>A local REST API and a Model Context Protocol server for automation</li>
|
||||
<li>Optional end-to-end encrypted sync to Donut cloud or a self-hosted server</li>
|
||||
</ul>
|
||||
</description>
|
||||
|
||||
<launchable type="desktop-id">com.donutbrowser.DonutBrowser.desktop</launchable>
|
||||
<provides>
|
||||
<binary>donutbrowser</binary>
|
||||
</provides>
|
||||
|
||||
<url type="homepage">https://donutbrowser.com</url>
|
||||
<url type="bugtracker">https://github.com/zhom/donutbrowser/issues</url>
|
||||
<url type="vcs-browser">https://github.com/zhom/donutbrowser</url>
|
||||
<url type="contribute">https://github.com/zhom/donutbrowser/blob/main/CONTRIBUTING.md</url>
|
||||
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/zhom/donutbrowser/main/assets/donut-preview.png</image>
|
||||
<caption>The profile list</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<categories>
|
||||
<category>Network</category>
|
||||
<category>WebBrowser</category>
|
||||
</categories>
|
||||
|
||||
<supports>
|
||||
<control>keyboard</control>
|
||||
<control>pointing</control>
|
||||
</supports>
|
||||
<requires>
|
||||
<display_length compare="ge">768</display_length>
|
||||
</requires>
|
||||
|
||||
<content_rating type="oars-1.1" />
|
||||
|
||||
<releases>
|
||||
<release version="0.31.2" date="2026-09-23">
|
||||
<url type="details">https://github.com/zhom/donutbrowser/releases/tag/v0.31.2</url>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Start a packaged Donut Browser on a virtual display and check that it stays
|
||||
# up. .github/workflows/linux-packages.yml runs it for the Flatpak and the Snap.
|
||||
#
|
||||
# smoke-test.sh <output-dir> <seconds> <command> [args...]
|
||||
#
|
||||
# XDG_RUNTIME_DIR must point to a directory owned by the current user. The
|
||||
# script starts a private session bus at $XDG_RUNTIME_DIR/bus, the path both
|
||||
# sandboxes let the app reach, and an Xvfb display. It fails when the app exits
|
||||
# before <seconds> have passed or prints a Rust panic. The app's output and a
|
||||
# screenshot are left in <output-dir>. A screenshot with almost no colours
|
||||
# (a blank window) is reported as a warning.
|
||||
set -euo pipefail
|
||||
|
||||
out="$1"
|
||||
seconds="$2"
|
||||
shift 2
|
||||
mkdir -p "$out"
|
||||
|
||||
: "${XDG_RUNTIME_DIR:?XDG_RUNTIME_DIR must be set}"
|
||||
bus="$XDG_RUNTIME_DIR/bus"
|
||||
rm -f "$bus"
|
||||
dbus-daemon --session --address="unix:path=$bus" --nofork --nopidfile &
|
||||
dbus_pid=$!
|
||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=$bus"
|
||||
|
||||
display_number=99
|
||||
Xvfb ":$display_number" -screen 0 1600x1000x24 -nolisten tcp >"$out/xvfb.log" 2>&1 &
|
||||
xvfb_pid=$!
|
||||
export DISPLAY=":$display_number"
|
||||
|
||||
trap 'kill "$xvfb_pid" "$dbus_pid" 2>/dev/null || true' EXIT
|
||||
|
||||
for _ in $(seq 1 100); do
|
||||
if [ -S "$bus" ] && [ -S "/tmp/.X11-unix/X$display_number" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
echo "Starting: $*"
|
||||
"$@" >"$out/app-output.log" 2>&1 &
|
||||
app_pid=$!
|
||||
|
||||
sleep "$seconds"
|
||||
|
||||
failed=0
|
||||
if kill -0 "$app_pid" 2>/dev/null; then
|
||||
echo "The app is still running after ${seconds}s."
|
||||
else
|
||||
code=0
|
||||
wait "$app_pid" || code=$?
|
||||
echo "::error::The app exited within ${seconds}s with exit code $code."
|
||||
failed=1
|
||||
fi
|
||||
|
||||
if command -v import >/dev/null 2>&1; then
|
||||
import -window root "$out/screenshot.png" || true
|
||||
colours="$(identify -format '%k' "$out/screenshot.png" 2>/dev/null || echo 0)"
|
||||
echo "The screenshot has $colours colours."
|
||||
if [ "$colours" -lt 64 ]; then
|
||||
echo "::warning::The screenshot has only $colours colours. The window may be blank."
|
||||
fi
|
||||
fi
|
||||
|
||||
kill "$app_pid" 2>/dev/null || true
|
||||
for _ in $(seq 1 50); do
|
||||
kill -0 "$app_pid" 2>/dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
kill -9 "$app_pid" 2>/dev/null || true
|
||||
|
||||
if grep -n "panicked at" "$out/app-output.log"; then
|
||||
echo "::error::The app panicked."
|
||||
failed=1
|
||||
fi
|
||||
|
||||
echo "--- app output (last 100 lines)"
|
||||
tail -n 100 "$out/app-output.log" || true
|
||||
exit "$failed"
|
||||
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
# Check that the Wayfern build Donut downloads can run inside a package's
|
||||
# sandbox: its libraries resolve there, and it starts headless and answers on
|
||||
# a DevTools port, which is how Donut drives it.
|
||||
#
|
||||
# wayfern-check.sh flatpak|snap <archive> <output-dir>
|
||||
#
|
||||
# <archive> is the Wayfern Linux .tar.xz. It is unpacked into the app's own
|
||||
# data directory, the one place both sandboxes let the app execute files from.
|
||||
# XDG_RUNTIME_DIR must point to a directory owned by the current user.
|
||||
set -euo pipefail
|
||||
|
||||
kind="$1"
|
||||
archive="$2"
|
||||
out="$3"
|
||||
mkdir -p "$out"
|
||||
|
||||
case "$kind" in
|
||||
flatpak)
|
||||
app=com.donutbrowser.DonutBrowser
|
||||
dir="$HOME/.var/app/$app/data/wayfern-check"
|
||||
in_sandbox() { flatpak run --command=sh "$app" -c "$1"; }
|
||||
;;
|
||||
snap)
|
||||
dir="$HOME/snap/donutbrowser/common/wayfern-check"
|
||||
in_sandbox() { snap run --shell donutbrowser -c "$1"; }
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 flatpak|snap <archive> <output-dir>" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
: "${XDG_RUNTIME_DIR:?XDG_RUNTIME_DIR must be set}"
|
||||
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
||||
bus="$XDG_RUNTIME_DIR/bus"
|
||||
rm -f "$bus"
|
||||
dbus-daemon --session --address="unix:path=$bus" --nofork --nopidfile &
|
||||
dbus_pid=$!
|
||||
trap 'kill "$dbus_pid" 2>/dev/null || true' EXIT
|
||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=$bus"
|
||||
for _ in $(seq 1 50); do [ -S "$bus" ] && break; sleep 0.1; done
|
||||
fi
|
||||
|
||||
rm -rf "$dir"
|
||||
mkdir -p "$dir"
|
||||
tar -xJf "$archive" -C "$dir"
|
||||
chrome="$(find "$dir" -type f -name chrome -perm -u+x | head -n 1)"
|
||||
if [ -z "$chrome" ]; then
|
||||
echo "::error::The archive has no chrome executable."
|
||||
exit 1
|
||||
fi
|
||||
echo "Wayfern executable: $chrome"
|
||||
|
||||
in_sandbox "/lib64/ld-linux-x86-64.so.2 --list '$chrome'" >"$out/wayfern-libraries.txt" 2>&1 || true
|
||||
if grep "not found" "$out/wayfern-libraries.txt" || ! grep -q "=>" "$out/wayfern-libraries.txt"; then
|
||||
echo "::error::Wayfern's libraries do not all resolve inside the sandbox."
|
||||
cat "$out/wayfern-libraries.txt"
|
||||
exit 1
|
||||
fi
|
||||
echo "Every Wayfern library resolves inside the sandbox."
|
||||
|
||||
# Donut asks the user to accept the Wayfern terms before the first launch and
|
||||
# then runs this same command. This runner is thrown away after the job.
|
||||
in_sandbox "'$chrome' --accept-terms-and-conditions" >"$out/wayfern-terms.log" 2>&1
|
||||
|
||||
port=9333
|
||||
in_sandbox "exec '$chrome' --headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage \
|
||||
--no-first-run --user-data-dir='$dir/profile' --remote-debugging-address=127.0.0.1 \
|
||||
--remote-debugging-port=$port about:blank" >"$out/wayfern-output.log" 2>&1 &
|
||||
wayfern_pid=$!
|
||||
|
||||
answered=0
|
||||
for _ in $(seq 1 60); do
|
||||
if curl -fsS "http://127.0.0.1:$port/json/version" >"$out/wayfern-version.json" 2>/dev/null; then
|
||||
answered=1
|
||||
break
|
||||
fi
|
||||
kill -0 "$wayfern_pid" 2>/dev/null || break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
kill "$wayfern_pid" 2>/dev/null || true
|
||||
pkill -f "$dir/" 2>/dev/null || true
|
||||
|
||||
if [ "$answered" -ne 1 ]; then
|
||||
echo "::error::Wayfern did not answer on its DevTools port."
|
||||
tail -n 40 "$out/wayfern-output.log" || true
|
||||
exit 1
|
||||
fi
|
||||
cat "$out/wayfern-version.json"
|
||||
Reference in new issue
Block a user