Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 61 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- main
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -23,7 +27,7 @@ jobs:
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- uses: dtolnay/rust-toolchain@stable
with:
Expand Down Expand Up @@ -57,7 +61,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v6

- name: Install rust
uses: dtolnay/rust-toolchain@stable
Expand All @@ -81,9 +85,11 @@ jobs:
run: |
rel="${GITHUB_REF#refs/*/}"
if grep -qE '^v?\d+\.\d+\.\d+' <<< "$rel" ; then
tag="$rel"
elif [ "$rel" = "main" ]; then
tag="${rel#v}"
elif [ "$rel" = "develop" ]; then
tag="dev"
elif [ "$rel" = "main" ]; then
tag="latest"
else
tag="$(echo "$GITHUB_SHA" | cut -c1-7)"
fi
Expand Down Expand Up @@ -112,7 +118,7 @@ jobs:
cache_scope: docker-arm64
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Download prebuilt binary
uses: actions/download-artifact@v4
Expand Down Expand Up @@ -221,7 +227,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Install rust
uses: dtolnay/rust-toolchain@stable
Expand Down Expand Up @@ -307,7 +313,7 @@ jobs:
target: aarch64-unknown-linux-musl
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v6

- name: Cache build artifacts
uses: actions/cache@v3
Expand Down Expand Up @@ -342,14 +348,10 @@ jobs:
path: privaxy/prebuilt

- name: Build server
uses: actions-rs/cargo@v1
env:
CC_x86_64_unknown_linux_musl: musl-gcc
CC_aarch64_unknown_linux_musl: musl-gcc
with:
command: build
working-directory: .
args: --release --target ${{ matrix.target }} --bin privaxy --target-dir target
run: cargo build --release --target ${{ matrix.target }} --bin privaxy --target-dir target
- name: Build packages
if: ${{ !endsWith(matrix.target, '-musl') }}
run: |
Expand Down Expand Up @@ -386,9 +388,15 @@ jobs:
- build: linux
os: ubuntu-22.04
target: mipsel-unknown-linux-musl
- build: linux
os: ubuntu-22.04
target: mips-unknown-linux-musl
- build: linux
os: ubuntu-22.04
target: mips-unknown-linux-gnu
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Cache build artifacts
uses: actions/cache@v3
Expand Down Expand Up @@ -422,19 +430,20 @@ jobs:
run: cross build --release --target ${{ matrix.target }} --bin privaxy --target-dir target

- name: Build packages
if: matrix.target == 'mipsel-unknown-linux-gnu'
if: ${{ endsWith(matrix.target, '-linux-gnu') }}
run: |
cargo install cargo-deb && cargo deb --no-build --no-strip --variant mipsel -p privaxy --target ${{ matrix.target }} -o target/${{ matrix.target }}/release
variant=$(echo "${{ matrix.target }}" | cut -d- -f1)
cargo install cargo-deb && cargo deb --no-build --no-strip --variant "$variant" -p privaxy --target ${{ matrix.target }} -o target/${{ matrix.target }}/release
cargo install cargo-generate-rpm && cargo generate-rpm -p privaxy --target ${{ matrix.target }} -o target/${{ matrix.target }}/release

- uses: actions/upload-artifact@v4
if: matrix.target == 'mipsel-unknown-linux-gnu'
if: ${{ endsWith(matrix.target, '-linux-gnu') }}
with:
name: privaxy-deb-${{ matrix.target }}
path: target/${{ matrix.target }}/release/privaxy_*.deb

- uses: actions/upload-artifact@v4
if: matrix.target == 'mipsel-unknown-linux-gnu'
if: ${{ endsWith(matrix.target, '-linux-gnu') }}
with:
name: privaxy-rpm-${{ matrix.target }}
path: target/${{ matrix.target }}/release/*.rpm
Expand All @@ -444,3 +453,37 @@ jobs:
name: privaxy-${{ matrix.target }}
path: |
target/${{ matrix.target }}/release/privaxy

release:
name: Create GitHub Release
needs: [ci, ci_mips, image_merge]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
pattern: privaxy-*
merge-multiple: false
- name: Set package version from tag
run: |
echo "PKG_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Flatten artifacts for release
run: |
mkdir ./release-assets
for dir in ./artifacts/privaxy-*/; do
target=$(basename "$dir" | sed 's/^privaxy-//')
cp "$dir/privaxy" "./release-assets/privaxy-${PKG_VERSION}-${target}"
done
find ./artifacts -name '*.deb' -exec cp {} ./release-assets/ \;
find ./artifacts -name '*.rpm' -exec cp {} ./release-assets/ \;

- name: Create release
uses: softprops/action-gh-release@v2
with:
files: ./release-assets/*
generate_release_notes: true
fail_on_unmatched_files: true
35 changes: 34 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
# Changelog

## Unreleased
## v0.7.1

- Fix WebSocket / protocol-upgrade connections hanging
- Upgrade requests (`wss://`, and proprietary HTTP-upgrade transports like MMTLS long-link) could spin forever with `upgrade expected but not completed`. The proxy fabricated a `101 Switching Protocols` to the client regardless of what the upstream actually returned, so a failed upgrade left the client waiting on a tunnel that was never bridged. It now forwards the upstream's real response when it isn't a genuine `101`, and the dedicated upgrade HTTP client gained the same connection hardening (`connect_timeout`, `tcp_keepalive`, no idle pooling) as the main client.
- Excluded hosts performing a plain-HTTP protocol upgrade are now blind-tunneled at the TCP level instead of being run through the (HTTP-only) upgrade bridge, so MITM-excluded apps using non-HTTP upgrade protocols work. Previously the exclusion list was only consulted on the `CONNECT` path, so excluding such a host had no effect on its plain-HTTP upgrade traffic.
- When an opaque (non-WebSocket) upgrade is seen for a host that is *not* excluded, a warning is logged naming the host and suggesting it be added to the exclusions, instead of failing cryptically.
- Validate filter lists when added
- Adding a filter now rejects URLs that do not serve a `text/plain` filter list (e.g. an HTML error/landing page returned with a `200`) with a `422`, instead of silently saving a broken filter. The error is surfaced in the web UI, and filters whose URL stops serving a list are dropped from the engine with a warning on the next refresh.
- Fix proxied requests randomly hanging/timing out
- The outbound HTTP client had no connection timeouts, so a pooled keep-alive connection silently dropped by the remote would be reused and block until the OS TCP timeout (minutes). Added `connect_timeout`, `pool_idle_timeout`, and `tcp_keepalive`.
- DNS-over-HTTPS (DoH) interception
- Detects DoH requests passing through the MITM proxy (RFC 8484 `application/dns-message`, JSON DoH, and known resolver endpoints)
- `block` mode (default) refuses DoH so fallback-mode clients (e.g. default Firefox) revert to the system resolver, which Privaxy already sees — the HTTP-layer equivalent of the `use-application-dns.net` canary a non-DNS proxy cannot serve
- `redirect` mode transparently forwards queries to a configured `upstream` resolver
- Configured under `[network.doh]` (`mode`, `upstream`, `extra_hosts`) or from the web UI under Settings → General; MITM-excluded hosts are left untouched
- Fix cookie not invalidating upon logout/cred change
- All four engine-matching call sites now use match_url (canonical, default port stripped); the outbound request and stats still use the raw uri with its port, so nothing about proxying changes. This was silently breaking every hostname-anchored (||host/path) network rule on every HTTPS site
- Update ublock annoyances url
- Add support for MIPS, MIPSLE
- Injected uBlock scriptlets now actually run
- Even after the 0.7.0 scriptlet repair, every injected `##+js(...)` scriptlet was a silent no-op. adblock-rust emits scriptlet bodies that reference an ambient `scriptletGlobals` object (uBlock Origin supplies it in its own injector; adblock-rust leaves it to the embedder), so the first internal call threw `ReferenceError: scriptletGlobals is not defined`, which each scriptlet's own `try/catch` swallowed. Privaxy now defines `scriptletGlobals` at the top of the injected payload, so `abort-current-script`, `prevent-addEventListener`, `abort-on-property-read`, `set-cookie`, etc. take effect.
- Procedural cosmetic filtering
- Non-CSS procedural filters are no longer dropped (previously only filters reducible to plain CSS were applied). `:has-text`, `:matches-css`/`-before`/`-after`, `:matches-attr`, `:matches-path`, `:min-text-length`, `:upward`, `:xpath`, and the `:remove()`/`:style()`/`remove-attr`/`remove-class` actions are now evaluated in-page by an injected shim.
- The shim re-runs on DOM mutations and recurses into same-origin child frames (`about:blank`/`srcdoc`/`data:` with `allow-same-origin`), so ad content written into such frames after load is also matched. Cross-origin frames and closed shadow DOM remain out of reach.
- Scriptlet error logging (debugging)
- New opt-in `debug.scriptlet_console_logging` (off by default), toggleable from Settings → Debug, surfaces errors thrown by injected scriptlets in the page console as `[privaxy scriptlet]` entries instead of swallowing them.
- Live log streaming in the web UI
- Settings → Debug now shows the server's log output in real time
- The level can be changed in the webui
- Fix cosmetic "modified responses" statistic undercount
- Pages where only element-hiding (`display: none`) selectors were injected were not counted as modified; any injected cosmetic CSS now counts

## v0.7.0

- Built-in authentication for the web UI and API
- First-run setup page for choosing an admin username + password
Expand All @@ -19,6 +51,7 @@
- Inject into CSP-protected websites
- Add docker compose example


## v0.6.0

- Remove gui app
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
[target.mipsel-unknown-linux-gnu]
build-std = true

[target.mips-unknown-linux-gnu]
build-std = true

[target.mipsel-unknown-linux-musl]
build-std = true
[target.mipsel-unknown-linux-musl.env]
RUSTFLAGS = "-C target-feature=+crt-static"

[target.mips-unknown-linux-musl]
build-std = true
[target.mips-unknown-linux-musl.env]
RUSTFLAGS = "-C target-feature=+crt-static"
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
&& cargo build --release; rm src/main.rs

COPY . .
ARG COMPILE_MODE="release"
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
--mount=type=cache,target=/root/.npm \
cd web_frontend && trunk build --release \
&& cd .. && cargo build --release \
&& cp target/release/privaxy /privaxy-out \
cd web_frontend && trunk build --${COMPILE_MODE} \
&& cd .. && cargo build --${COMPILE_MODE} \
&& cp target/${COMPILE_MODE}/privaxy /privaxy-out \
&& chmod +x /privaxy-out

# Prebuilt path: expect $PREBUILT_BINARY to exist in the build context.
Expand Down
Loading
Loading