diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa966e37..0a8a6e51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,9 +4,13 @@ on: push: branches: - main + - develop + tags: + - 'v*' pull_request: branches: - - main + - main + - develop concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -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: @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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: | @@ -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 @@ -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 @@ -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 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 309c0226..41320fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -19,6 +51,7 @@ - Inject into CSP-protected websites - Add docker compose example + ## v0.6.0 - Remove gui app diff --git a/Cargo.lock b/Cargo.lock index ae6e34ae..14db423b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2037,7 +2037,7 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "privaxy" -version = "0.7.0" +version = "0.7.1" dependencies = [ "adblock", "argon2", diff --git a/Cross.toml b/Cross.toml index 034b5e75..e01eb019 100644 --- a/Cross.toml +++ b/Cross.toml @@ -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" diff --git a/Dockerfile b/Dockerfile index 0507d0cb..422bca3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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. diff --git a/README.md b/README.md index 2584bf48..653987d0 100644 --- a/README.md +++ b/README.md @@ -8,35 +8,64 @@
-**Forked from the [app version](https://github.com/Barre/privaxy/tree/v0.5.2)** - -This reverts it back to [v0.3.1](https://github.com/Barre/privaxy/tree/v0.3.1), but with -newer updates, an improved UI, and server-friendly configuration. To skip to the differences, -[see here](#differences) - -See features [here](#features) - - -
-
-
-
-
-
-
+
+
+
+
+
+