feat(ssl): support self-signed HTTPS media/pages via verify_ssl + per-asset override - #3176
Merged
Conversation
…-asset override Web-hosted HTTPS assets served with a self-signed / untrusted-CA cert rendered blank (forum "web content doesn't display"): the webview's QNetworkAccessManager / QWebEngine rejected the cert, and the reachability probe marked the asset unreachable so the viewer skipped it. The device-wide verify_ssl setting was also vestigial — unexposed, and its off-branch still verified. - Fix url_fails: verify_ssl=off now actually disables verification (regressed to `verify=True` in 2019); add a per-call verify_ssl arg - Add per-asset Asset.skip_ssl_verify (migration, v2 API, edit modal); reachability composes it with the device-wide verify_ssl - Expose the device-wide verify_ssl toggle in Settings + v2 API - Viewer computes the effective skip per asset and passes it to the webview's loadImage / loadPage D-Bus slots (video needs none — FFmpeg already tolerates self-signed) - Webview: ignoreSslErrors on the image reply and an SSL-aware QWebEnginePage (Qt5 virtual override / Qt6 certificateError signal) when skip is set; compiles on both Qt5 and Qt6 Rebased onto master (single-view webview collapse #2954, per-asset headers #2215, nocache #3137): merged the effective-skip flag through view_webpage alongside headers/nocache, and threaded skipSslVerify into the now-single AnthiasWebEnginePage. Adapted the viewer tests to the two-arg loadPage/loadImage slots, pinned verify_ssl in the reachability-sweep test so a host anthias.conf can't mask it, and added a url_fails regression test for the verify_ssl toggle. Qt6 x86 webview rebuilt clean on the dev host. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR fixes and fully implements SSL verification controls for HTTPS assets served with self-signed / private-CA certificates by threading a device-wide verify_ssl setting plus a per-asset skip_ssl_verify override through: reachability probing (url_fails), server-side validation, the Python viewer → D-Bus boundary, and the Qt webview’s image/page loading stacks.
Changes:
- Add per-asset
Asset.skip_ssl_verify(model + migration), surface it in UI and v2 API, and compose it with the globalverify_sslsetting for probes and rendering. - Fix
url_fails()to actually disable TLS verification when configured, and add an explicitverify_sslargument for callers that already computed the effective policy. - Extend the viewer/webview D-Bus API to pass a per-load
skipSslVerifyflag; implementignoreSslErrors()for images and certificate-error handling for web pages (Qt5/Qt6 paths).
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_viewer.py | Updates existing viewer expectations and adds coverage ensuring skip_ssl_verify reaches the webview and triggers reloads when flipped. |
| tests/test_utils.py | Adds regression tests asserting url_fails() maps verify_ssl to the correct requests verify behavior, including explicit-arg override. |
| tests/test_scheduler.py | Extends scheduler fixture expectations to include skip_ssl_verify. |
| tests/test_celery_tasks.py | Adds sweep test ensuring per-asset SSL policy is passed to url_fails; updates mock signature for new kwarg. |
| src/anthias_webview/src/view.h | Updates View API to accept per-load skipSslVerify flag for pages/images. |
| src/anthias_webview/src/view.cpp | Implements per-load SSL error handling: ignore SSL errors for image replies; accept/reject certificate errors for web pages via a custom QWebEnginePage. |
| src/anthias_webview/src/mainwindow.h | Updates D-Bus slots to require skipSslVerify argument and documents the intent. |
| src/anthias_webview/src/mainwindow.cpp | Forwards the new skipSslVerify argument through to View. |
| src/anthias_viewer/init.py | Threads effective per-asset SSL policy into view_image/view_webpage, includes it in reload dedup keys, and resets cached policy on browser respawn. |
| src/anthias_server/celery_tasks.py | Composes global/per-asset SSL policy and passes it to url_fails during reachability checks. |
| src/anthias_server/app/views.py | Persists per-asset skip_ssl_verify from the asset edit modal and saves the device-wide verify_ssl setting from Settings UI. |
| src/anthias_server/app/templates/settings.html | Exposes “Verify SSL certificates” device-wide toggle in the Settings UI. |
| src/anthias_server/app/templates/_asset_modal.html | Adds per-asset “Skip SSL verification” toggle (shown only for https:// URIs). |
| src/anthias_server/app/static/src/home.ts | Extends AssetEdit TypeScript interface to include skip_ssl_verify. |
| src/anthias_server/app/page_context.py | Adds verify_ssl to settings template context. |
| src/anthias_server/app/models.py | Adds persisted skip_ssl_verify field on Asset. |
| src/anthias_server/app/migrations/0007_asset_skip_ssl_verify.py | Migration adding the skip_ssl_verify column. |
| src/anthias_server/api/views/v2.py | Adds verify_ssl to device settings GET/PATCH in v2 API. |
| src/anthias_server/api/tests/test_v2_endpoints.py | Updates device settings expectations to include verify_ssl. |
| src/anthias_server/api/serializers/v2.py | Adds skip_ssl_verify on asset serializers and verify_ssl on device settings serializers. |
| src/anthias_server/api/serializers/mixins.py | Parses skip_ssl_verify into prepared assets and uses composed SSL policy for reachability probe during create. |
| src/anthias_server/api/serializers/init.py | Ensures skip_ssl_verify is persisted on asset update. |
| src/anthias_common/utils.py | Updates url_fails() to honor device setting / explicit verify_ssl arg and use verify=False when verification is disabled. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review. The suppression was a process-global disable_warnings(), which silences InsecureRequestWarning for every other verify=False request in the process once any probe runs it, not just this reachability probe. Scope it to the HEAD/GET calls with warnings.catch_warnings() so the prior filter state is restored on exit. Verified against a self-signed origin: the probe no longer surfaces the warning to its caller, and an independent verify=False request after it still warns (no process-wide leak). Drops the two requests.packages.urllib3 type: ignore comments in favour of a direct urllib3 import. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Address Copilot review. Reword the loadPage/loadImage comment: the concern isn't C++ overloading but moc's cloned meta-method for a trailing default argument, which QtDBus would export as a second same-named D-Bus method (signatures `s` vs `sb`). Comment-only; no behaviour change. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…alls Address Copilot review. loadPage/loadImage gained a skipSslVerify argument, but the viewer called the 2-arg slots unconditionally — unlike setReloadInterval / setRequestHeaders, which already latch on a version-skewed webview. A webview process still running the previous binary (viewer container rotated to a newer image mid-rollout, webview not yet restarted) exposes only the 1-arg slots, so the 2-arg call would raise UnknownMethod (or a pydbus marshalling error) and take the screen down on the core navigation path. Add _load_via_webview: try the 2-arg call, and on any non-"gone" error fall back to the legacy 1-arg call. If the fallback succeeds it was a skew — latch the capability off (reset on every respawn, like the sibling flags) and keep displaying, losing only the per-asset SSL skip the old webview couldn't honour anyway. If the fallback also fails the extra arg wasn't the problem, so re-raise the original error. Confirming the skew empirically avoids brittle exception-string matching across pydbus/Qt versions. Adds three regression tests (page + image fallback, and re-raise when the 1-arg call also fails). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Address Copilot review. In _load_via_webview, when the 1-arg fallback also fails, re-raise the original 2-arg exception with `from None` so the fallback exception is dropped from the context — the traceback points at the real cause instead of a confusing "during handling of the above exception" chain, and `exc` keeps its own original traceback. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Address Copilot review. url_fails caught only (ConnectionError, Timeout). SSLError is already covered (it subclasses ConnectionError), but TooManyRedirects — which allow_redirects=True can hit — is a RequestException that is NOT a ConnectionError, so a redirect loop on an asset URL would escape and 500 asset creation instead of resolving to the boolean 'unreachable' verdict. Catch requests.exceptions. RequestException so every DNS / TLS / timeout / redirect failure maps to True. Adds a parametrised regression test (SSLError + TooManyRedirects + Timeout + ConnectionError). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Problem
Forum report: web-hosted images and videos don't display, "as if it didn't reach the file", while web pages and YouTube render fine — https://forums.screenly.io/t/web-content-doesnt-display/6726
Reproduced the self-signed / untrusted-CA case (the operator's very first diagnostic hunch in the thread). A media asset served over HTTPS with a self-signed or private-CA certificate hits two independent walls, and there was no way for the operator to get past either:
url_fails()marks the asset unreachable, so the viewer skips it during rotation. The device-wide "Verify SSL" setting that should allow this was vestigial: unexposed in the UI, and its off-branch still passedverify=True(regressed to that in 2019), so turning it off changed nothing.QNetworkAccessManager(images) andQWebEnginePage(web pages) reject the certificate, so the image/page renders blank. Web pages to the same host appeared to work only because nothing probed them server-side and the failure was less obvious.Video was never affected — it plays through FFmpeg, which completes the handshake on a self-signed cert regardless.
Fix
url_fails:verify_ssloff now actually disables verification; added a per-callverify_sslargument so callers can pass an effective flag.Asset.skip_ssl_verify(migration, v2 API field, edit-modal toggle shown only forhttps://URIs). Reachability composes it with the device-wide setting:settings['verify_ssl'] and not asset.skip_ssl_verify.anthias.confonly).loadImage/loadPageD-Bus slots.ignoreSslErrorson the image reply, and an SSL-awareQWebEnginePage(Qt5 virtual override / Qt6certificateErrorsignal) that proceeds past the cert only when the flag is set.Notes for reviewers
This is the 2026-07-02 branch rebased onto current master. The rebase merged the effective-skip flag through
view_webpagealongside the newer per-asset headers and nocache work, and threadedskipSslVerifyinto the now-singleAnthiasWebEnginePageafter the dual-buffer webview was collapsed into one view.Validation
url_fails()inside the container against a self-signed HTTPS origin — unreachable with the toggle both on and off; with the fix it's reachable only when verification is off.url_failsregression test for the toggle (device-setting-driven and explicit-arg paths); pinnedverify_sslin the reachability-sweep test so a hostanthias.confcan't mask it; adapted the viewer tests to the two-argloadPage/loadImageslots.ruff check+ruff formatclean.AnthiasViewerrebuilds and links clean on the dev host against real WebEngine headers, including the new certificate-error paths. The Qt5 path is byte-identical to the previously cross-compile-verified commit and uses the correct Qt 5.15certificateErroroverride signature; the pi3/Qt5 image build runs in CI.🤖 Generated with Claude Code