mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-11-11 23:17:32 +00:00
feat(web_viewer): make the Multibyte page public
Multibyte rollout shows per-node hash sizes and traffic counts taken from adverts and paths, the same mesh-visible data the public Mesh Graph serves. With web_viewer_password set it was admin-only and missing from anonymous navigation. The page, /api/multibyte-rollout and the nav link are now public whenever the multibyte monitor is on. From #350.
This commit is contained in:
1 parent
716531a558
commit
2be738c604
5 files changed
+21
-7
No files matched your search
+1
-1
@@ -16,7 +16,7 @@ semantic versioning.
|
||||
- `[Weather] openmeteo_fallback` (default `false`, only with `weather_provider = noaa`): `wx` answers a place outside NWS coverage from Open-Meteo, in `gwx`'s format and `wx`'s units, instead of replying with an error. Current conditions, `tomorrow`, `Nd` and `hourly` fall back; `wx <place> alerts` there replies that alerts are not available. Only NWS's no-coverage answer triggers it, not timeouts or server errors, and the point is remembered for 24 hours so later requests skip NWS. It's also in the web viewer's `wx` settings.
|
||||
- `[Weather] always_show_location` (default `false`): when `true`, `wx` and `gwx` name the place in every reply a place is found for (`Lake Stevens, WA: …`), including ZIP codes and cities in the bot's own state or country, instead of only when the name adds information. The name takes message length from the forecast, and a ZIP code costs one extra reverse lookup. It's also in the web viewer's `wx` settings.
|
||||
- `gwx <place> hourly`: the next hours from Open-Meteo, packed into one reply like `wx`'s NOAA hourly forecast (time, condition, chance of precipitation, temperature, wind), in the configured units and translated. `gwx` listed `hourly` in its help but read it as part of the place name. `wx` with `weather_provider = openmeteo` gets it too.
|
||||
- Web viewer admin role when `web_viewer_password` is set: Dashboard, Contacts, and Mesh Graph are readable anonymously; Real-time, Radio, Config, Logs, and all mutating APIs require an admin session. Real-time's live Socket.IO streams (and `/api/channels`) can expose decrypted traffic and channel keys, so the page redirects anonymous visitors to the login page and drops out of their navigation instead of showing them an empty page.
|
||||
- Web viewer admin role when `web_viewer_password` is set: Dashboard, Contacts, Mesh Graph and (when the multibyte monitor is on) Multibyte are readable anonymously; Real-time, Radio, Config, Logs, and all mutating APIs require an admin session. Real-time's live Socket.IO streams (and `/api/channels`) can expose decrypted traffic and channel keys, so the page redirects anonymous visitors to the login page and drops out of their navigation instead of showing them an empty page.
|
||||
|
||||
- `[Weather_Service] weather_alerts_enabled` (default `true`) turns the NOAA
|
||||
weather-alert polling loop off on its own. Alert monitoring previously started
|
||||
|
||||
@@ -865,7 +865,7 @@ class BotDataViewer(DashboardSnapshotMixin, LiveStreamMixin, SocketClientsMixin,
|
||||
# Issue #240 public HTML surface. Realtime is admin-only: its live socket
|
||||
# is, so an anonymous visit would only ever show an empty page.
|
||||
_PUBLIC_PAGE_PATHS = frozenset([
|
||||
'/', '/contacts', '/mesh',
|
||||
'/', '/contacts', '/mesh', '/multibyte-rollout',
|
||||
])
|
||||
|
||||
# Anonymous-safe GET APIs: mesh-visible / aggregate data only. No channel
|
||||
@@ -883,6 +883,9 @@ class BotDataViewer(DashboardSnapshotMixin, LiveStreamMixin, SocketClientsMixin,
|
||||
'/api/mesh/nodes',
|
||||
'/api/mesh/edges',
|
||||
'/api/mesh/stats',
|
||||
# Multibyte rollout: per-node hash sizes and traffic counts from
|
||||
# adverts and paths, all mesh-visible.
|
||||
'/api/multibyte-rollout',
|
||||
])
|
||||
|
||||
# Read-only POST helpers used by public Contacts / Mesh info panels.
|
||||
|
||||
@@ -826,7 +826,7 @@
|
||||
<i class="fas fa-project-diagram"></i> Mesh Graph
|
||||
</a>
|
||||
</li>
|
||||
{% if multibyte_monitor_enabled and (not auth_enabled or is_admin) %}
|
||||
{% if multibyte_monitor_enabled %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.path == '/multibyte-rollout' }}" href="/multibyte-rollout">
|
||||
<i class="fas fa-code-branch"></i> Multibyte
|
||||
|
||||
@@ -1039,10 +1039,10 @@
|
||||
},
|
||||
"/api/multibyte-rollout": {
|
||||
"GET locked anon": {
|
||||
"content_type": "application/json",
|
||||
"content_type": "text/html",
|
||||
"csp_script_src": "script-src 'self' 'unsafe-inline'",
|
||||
"location": "",
|
||||
"status": 401,
|
||||
"status": 404,
|
||||
"x_content_type_options": "nosniff",
|
||||
"x_frame_options": "SAMEORIGIN"
|
||||
},
|
||||
@@ -1750,8 +1750,8 @@
|
||||
"GET locked anon": {
|
||||
"content_type": "text/html",
|
||||
"csp_script_src": "script-src 'self' 'nonce-X'",
|
||||
"location": "/login?next=/multibyte-rollout",
|
||||
"status": 302,
|
||||
"location": "",
|
||||
"status": 404,
|
||||
"x_content_type_options": "nosniff",
|
||||
"x_frame_options": "SAMEORIGIN"
|
||||
},
|
||||
|
||||
@@ -1282,6 +1282,17 @@ class TestRoleBasedAccess:
|
||||
assert auth_client.get("/realtime").status_code == 200
|
||||
assert 'href="/realtime"' in auth_client.get("/").get_data(as_text=True)
|
||||
|
||||
def test_multibyte_page_and_data_are_public(self, auth_viewer, auth_client):
|
||||
"""Multibyte rollout is mesh-visible data, so anonymous visitors get the page, its data and the nav link."""
|
||||
auth_viewer.multibyte_monitor_enabled = True
|
||||
assert auth_client.get("/multibyte-rollout").status_code == 200
|
||||
resp = auth_client.get("/api/multibyte-rollout")
|
||||
assert resp.status_code == 200
|
||||
blob = str(resp.get_json()).lower()
|
||||
for needle in ("smtp_password", "channel_key", "key_hex", "private_key", "web_viewer_password"):
|
||||
assert needle not in blob
|
||||
assert 'href="/multibyte-rollout"' in auth_client.get("/").get_data(as_text=True)
|
||||
|
||||
def test_admin_pages_require_auth(self, auth_client):
|
||||
admin_pages = ["/logs", "/config", "/plugins", "/radio", "/greeter", "/feeds", "/schedule"]
|
||||
for page in admin_pages:
|
||||
|
||||
Reference in new issue
Block a user