fix: /status/full of the status web service gives an authenticated client the whole status, whatever web.status_content says.
Release / release (push) Successful in 28s

This commit is contained in:
slawek committed 2026-10-25 23:16:18 +01:00
1 parent 7404ee88c4
commit a245ec26cd
3 files changed
+22 -2

No files matched your search

+6
View File
@@ -904,6 +904,12 @@ curl -H 'Content-Type: application/json' -d '{"name": "alice", "password": "s3cr
curl -H "Authorization: Bearer $TOKEN" http://10.0.0.4:7081/config curl -H "Authorization: Bearer $TOKEN" http://10.0.0.4:7081/config
``` ```
### The /status/full page
`/status/full`, with the same token as `/config`, shows the whole status document, as `/status`
does with `web.status_content` `full`, whatever that setting says, so the Router Manager shows
every service and tunnel while the public status page shows less.
### The /config page ### The /config page
`/config` shows what `/` and `/status` leave out, for a client such as manage-ui: `/config` shows what `/` and `/status` leave out, for a client such as manage-ui:
+9
View File
@@ -1,3 +1,12 @@
vpn-router (0.21.5-1) unstable; urgency=medium
fix: /status/full of the status web service gives an authenticated client the whole status, whatever web.status_content says.
* /status/full takes the token of /config and answers the status
document as web.status_content full shows it.
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Mon, 02 Nov 2026 12:00:00 +0100
vpn-router (0.21.4-1) unstable; urgency=medium vpn-router (0.21.4-1) unstable; urgency=medium
fix: vpn-router-setup, vpn-router-ca and /ca read a CA's key and CRL from the directory each as itself, instead of failing on a CA with a CRL. fix: vpn-router-setup, vpn-router-ca and /ca read a CA's key and CRL from the directory each as itself, instead of failing on a CA with a CRL.
+7 -2
View File
@@ -8,6 +8,8 @@ Pages:
/ the status for people: plain text for curl and wget, a styled page / the status for people: plain text for curl and wget, a styled page
(Tailwind CSS from a CDN) for a browser (Tailwind CSS from a CDN) for a browser
/status the status as JSON /status the status as JSON
/status/full
the whole status as JSON, whatever web.status_content says, for the Router Manager
/config the configuration without its secrets, and what the router resolved and /config the configuration without its secrets, and what the router resolved and
runs, with the installed Caddy and where it comes from, as JSON runs, with the installed Caddy and where it comes from, as JSON
/users the users in the router's directory, whether or not a P2S system is enabled: list, /users the users in the router's directory, whether or not a P2S system is enabled: list,
@@ -40,7 +42,7 @@ Pages:
the databases of each PostgreSQL cluster on the router with their sizes, as JSON (see the databases of each PostgreSQL cluster on the router with their sizes, as JSON (see
postgresql_databases()); /config has the clusters' settings postgresql_databases()); /config has the clusters' settings
/config, /metrics/history, /postgresql, /users, /service-accounts, /groups, /site-to-site, /backup, /ca and /account need an HS256 JWT in an Authorization: Bearer header signed /status/full, /config, /metrics/history, /postgresql, /users, /service-accounts, /groups, /site-to-site, /backup, /ca and /account need an HS256 JWT in an Authorization: Bearer header signed
with vpnrouter_auth.WEB_KEY (see vpnrouter_auth.verify). A token of /auth names a user in sub; with vpnrouter_auth.WEB_KEY (see vpnrouter_auth.verify). A token of /auth names a user in sub;
/account serves that user, and the other paths need a member of vpnrouter_users.ADMIN_GROUP. A /account serves that user, and the other paths need a member of vpnrouter_users.ADMIN_GROUP. A
token of vpn-router-token has the admin claim and names no user; it may call every path but token of vpn-router-token has the admin claim and names no user; it may call every path but
@@ -1042,7 +1044,7 @@ class Handler(BaseHTTPRequestHandler):
directory = next((name for name in ('users', 'service-accounts', 'groups', 'account', 'site-to-site', 'backup', directory = next((name for name in ('users', 'service-accounts', 'groups', 'account', 'site-to-site', 'backup',
'ca') 'ca')
if path == f'/{name}' or path.startswith(f'/{name}/')), None) if path == f'/{name}' or path.startswith(f'/{name}/')), None)
protected = path in ('/config', '/metrics/history', '/postgresql') or directory is not None protected = path in ('/status/full', '/config', '/metrics/history', '/postgresql') or directory is not None
signing = path in ('/auth', '/auth/refresh', '/auth/logout') signing = path in ('/auth', '/auth/refresh', '/auth/logout')
state = current() if protected or signing else {} state = current() if protected or signing else {}
claims = self.claims(state['key']) if protected and state['key'] else None claims = self.claims(state['key']) if protected and state['key'] else None
@@ -1067,6 +1069,9 @@ class Handler(BaseHTTPRequestHandler):
elif protected and (refused := self.refusal(claims, path, payload)): elif protected and (refused := self.refusal(claims, path, payload)):
code, kind = refused[0], 'application/json' code, kind = refused[0], 'application/json'
body = json.dumps({'error': refused[1]}, indent=2).encode() + b'\n' body = json.dumps({'error': refused[1]}, indent=2).encode() + b'\n'
elif path == '/status/full' and self.command in ('GET', 'HEAD'):
document = shown(self.status(), 'full', self.client())
body, kind, code = json.dumps(document, indent=2).encode() + b'\n', 'application/json', 200
elif path == '/config' and self.command in ('GET', 'HEAD'): elif path == '/config' and self.command in ('GET', 'HEAD'):
body, kind, code = json.dumps(details(state), indent=2).encode() + b'\n', 'application/json', 200 body, kind, code = json.dumps(details(state), indent=2).encode() + b'\n', 'application/json', 200
elif path == '/postgresql' and self.command in ('GET', 'HEAD'): elif path == '/postgresql' and self.command in ('GET', 'HEAD'):