Files
hassio-addons/komga/rootfs/etc/nginx/servers/ingress.conf
Alexandre 9302fc9a51 fix(komga): keep the reader inside the ingress panel (#2995)
* fix(komga): keep the reader inside the ingress panel

Komga's ui opens the reader with window.open(url, '_blank'). The Home
Assistant companion apps hand such a popup to an external browser, which
carries no ingress session cookie, so Home Assistant answers 401 before
Komga is reached.

Nginx now injects a small script into the ui shell that turns same origin
popups into a navigation in the current tab. The OAuth2 login popup, which
passes a window name and a feature string, and cross origin links are left
untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(komga): only intercept popups when resourceBaseUrl is known

Review feedback : the '/' fallback meant that if Komga ever stopped
setting window.resourceBaseUrl, every same origin _blank popup would be
captured -- and ingress shares the Home Assistant origin. Require the
base, and give it a trailing slash so a sibling path such as
<entry>/komgaX is not treated as being below <entry>/komga.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 07:30:47 +02:00

87 lines
4.9 KiB
Plaintext

server {
listen %%interface%%:%%port%% default_server;
client_max_body_size 0;
# Home Assistant opens the ingress panel at <ingress_entry>/ and forwards it
# as / , but Komga only answers below its servlet context path (/komga), so
# bounce the panel there. absolute_redirect off keeps the Location relative
# to the HA host instead of nginx's own listen address.
location = / {
absolute_redirect off;
return 302 %%ingress_entry%%/komga/;
}
location / {
add_header Access-Control-Allow-Origin *;
proxy_connect_timeout 30m;
proxy_send_timeout 30m;
proxy_read_timeout 30m;
proxy_pass http://127.0.0.1:25600;
# Komga pushes live events over SSE (/komga/sse/v1/events), which must
# not be buffered or the UI stops refreshing until the buffer fills
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Spring redirects /komga to /komga/ ; the Location it produces is
# absolute against the upstream address, so rewrite it back onto the
# ingress path (the second rule covers an already relative Location).
absolute_redirect off;
proxy_redirect http://127.0.0.1:25600/ %%ingress_entry%%/;
proxy_redirect / %%ingress_entry%%/;
# Komga scopes its cookies to the servlet context path
# (Set-Cookie: ...; Path=/komga). The browser lives under the ingress
# entry, so such a cookie is never sent back : login succeeds, then
# every following request arrives anonymous and Komga answers 401.
proxy_cookie_path /komga %%ingress_entry%%/komga;
proxy_cookie_path / %%ingress_entry%%/;
# Komga renders its index page with Thymeleaf @{...} link expressions,
# so every asset url and window.resourceBaseUrl carry the context path
# (/komga). Ingress strips its own prefix before forwarding, so the
# browser needs that prefix added back. Only text/html is rewritten
# (the nginx default for sub_filter_types) : the SPA derives its api
# origin and router base from resourceBaseUrl at runtime, so json
# responses and book pages stream through untouched.
proxy_set_header Accept-Encoding "";
sub_filter_once off;
sub_filter "/komga" "%%ingress_entry%%/komga";
# The epub/divina reader fetches a Readium manifest whose links Komga
# builds with ServletUriComponentsBuilder.fromCurrentContextPath(), so
# they are fully absolute against the upstream address nginx talks to
# (http://127.0.0.1:25600/komga). Rewriting them to a root relative
# ingress path also fixes the scheme : Home Assistant may be served over
# https, and an absolute http:// link would be blocked as mixed content.
# Only the json/xml document types are added here, so book pages are
# never scanned.
sub_filter "http://127.0.0.1:25600/komga" "%%ingress_entry%%/komga";
# Komga opens the reader with window.open(url, '_blank'). In the Home
# Assistant companion apps the ingress panel is a webview, which hands
# such a popup to an external browser : that browser carries no ingress
# session cookie, so Home Assistant answers 401 before Komga is even
# reached. Turn that popup into a navigation of the panel itself, but
# only for the call shape Komga uses (name _blank, no feature string)
# and only for http(s) urls below window.resourceBaseUrl. That leaves
# the OAuth2 login popup (window.open(url, 'oauth2Login', '<features>'),
# which needs its own window), blob urls and links out of Komga alone,
# and if Komga ever stopped setting resourceBaseUrl the popup is left
# untouched rather than widened to the whole Home Assistant origin,
# which ingress shares. Anchored on the single page app mount point :
# both Komga ui shells carry it once, and only a book served as
# text/html rather than the xhtml the epub spec mandates could collide
# with it -- the same exposure the /komga filter above already has, and
# Komga sends script-src 'none' on that endpoint.
sub_filter "<div id=\"app\">" "<script>(function(){var o=window.open;window.open=function(u,n,f){try{var b=window.resourceBaseUrl;if(u&&n==='_blank'&&!f&&b){if(b.slice(-1)!=='/')b+='/';var t=new URL(u,location.href);if((t.protocol==='http:'||t.protocol==='https:')&&t.origin===location.origin&&t.pathname.indexOf(b)===0){location.assign(t.href);return window}}}catch(e){}return o.apply(window,arguments)}})();</script><div id=\"app\">";
sub_filter_types application/json application/webpub+json
application/divina+json application/opds+json
application/atom+xml;
}
}