Sluglas, the Stripper Slug

This commit is contained in:
firestarsdog
2026-09-06 00:50:57 -04:00
parent edf76af796
commit 7d46313213
6 changed files with 241 additions and 20 deletions
@@ -24,7 +24,7 @@ function rememberEvent(eventId) {
async function pollSentryEvent() {
try {
const response = await fetch("/api/sentry/status", { cache: "no-store" })
const response = await fetch(galaxyPath("/api/sentry/status"), { cache: "no-store" })
if (!response.ok) return
const payload = await response.json()
const event = payload?.lastEvent
@@ -81,6 +81,13 @@ async function readJsonResponse(response) {
try {
return JSON.parse(body)
} catch {
const contentType = response.headers?.get("content-type") || ""
if (contentType.includes("text/html") || body.trim().startsWith("<")) {
if (response.status === 200) {
throw new Error("Galaxy returned an HTML page instead of JSON data. Check your session or connection.")
}
throw new Error(`Galaxy returned an HTML error page (${response.status}). Check the device connection or Galaxy tunnel.`)
}
throw new Error(`Galaxy returned an unexpected ${response.status} response. Check the device connection or Galaxy tunnel.`)
}
}
@@ -108,14 +108,14 @@ async function sendTestEvent() {
state.testBusy = true
try {
const response = await fetch(galaxyPath("/api/sentry/test"), { method: "POST" })
const payload = await response.json()
const payload = await readJsonResponse(response)
if (!response.ok) {
showSnackbar(payload.error || "Sentry test failed.")
return
}
showSnackbar("Test capture started. The images will appear here shortly.")
} catch (error) {
showSnackbar("Network error — is the device reachable?")
showSnackbar(error.message || "Network error — is the device reachable?")
} finally {
state.testBusy = false
}
@@ -128,6 +128,13 @@ async function readJsonResponse(response) {
try {
return JSON.parse(body)
} catch {
const contentType = response.headers?.get("content-type") || ""
if (contentType.includes("text/html") || body.trim().startsWith("<")) {
if (response.status === 200) {
throw new Error("Galaxy returned an HTML page instead of JSON data. Check your session or connection.")
}
throw new Error(`Galaxy returned an HTML error page (${response.status}). Check the device connection or Galaxy tunnel.`)
}
throw new Error(`Galaxy returned an unexpected ${response.status} response. Check the device connection or Galaxy tunnel.`)
}
}
@@ -91,6 +91,7 @@ export function isGalaxyTunnel() {
export function galaxyPath(path) {
const suffix = path.startsWith("/") ? path : `/${path}`
if (!isGalaxyTunnel()) return suffix
if (suffix === "/api" || suffix.startsWith("/api/")) return suffix
const firstPathSegment = window.location.pathname.split("/").filter(Boolean)[0] || ""
const slug = /^[A-Za-z0-9]{16}$/.test(firstPathSegment) ? `/${firstPathSegment}` : ""
@@ -0,0 +1,140 @@
import json
import time
from pathlib import Path
import pytest
from test_dashboard_stats import FakeParams, MODULE_DIR, _install_server_import_stubs
def _load_server_module():
import importlib.util
import sys
_install_server_import_stubs()
spec = importlib.util.spec_from_file_location("sentry_routing_server", MODULE_DIR / "the_galaxy.py")
module = importlib.util.module_from_spec(spec)
sys.modules["sentry_routing_server"] = module
spec.loader.exec_module(module)
return module
the_galaxy = _load_server_module()
@pytest.fixture
def client(monkeypatch, tmp_path):
assert the_galaxy._import_galaxy_web_symbols()
monkeypatch.setattr(the_galaxy, "params", FakeParams())
monkeypatch.setattr(the_galaxy, "_get_galaxy_dir", lambda: tmp_path)
app = the_galaxy.Flask(
f"test_galaxy_{time.monotonic_ns()}",
template_folder=str(MODULE_DIR / "templates"),
static_folder=str(MODULE_DIR / "assets"),
)
the_galaxy.setup(app)
return app.test_client()
def test_slug_middleware_strips_16_char_slug(client):
# Slug-prefixed API call to sentry push config
response = client.get("/df70390ca648d7c3/api/sentry/push/config")
assert response.status_code == 200
assert "application/json" in response.headers.get("Content-Type", "")
data = response.get_json()
assert data["enabled"] is True
assert len(data["publicKey"]) > 20
# Direct unslugged API call
response_direct = client.get("/api/sentry/push/config")
assert response_direct.status_code == 200
assert response_direct.get_json()["publicKey"] == data["publicKey"]
def test_slug_middleware_service_worker_and_headers(client):
with client.get("/df70390ca648d7c3/service-worker.js") as response:
assert response.status_code == 200
assert response.headers.get("Service-Worker-Allowed") == "/"
assert "no-store" in response.headers.get("Cache-Control", "")
with client.get("/service-worker.js") as response_direct:
assert response_direct.status_code == 200
assert response_direct.headers.get("Service-Worker-Allowed") == "/"
def test_404_api_returns_json_not_html(client):
# Non-existent API route without slug
res1 = client.get("/api/nonexistent")
assert res1.status_code == 404
assert "application/json" in res1.headers.get("Content-Type", "")
assert res1.get_json() == {"error": "Not found"}
# Non-existent API route with slug
res2 = client.get("/df70390ca648d7c3/api/nonexistent")
assert res2.status_code == 404
assert "application/json" in res2.headers.get("Content-Type", "")
assert res2.get_json() == {"error": "Not found"}
# POST to non-existent route returns 404 JSON
res3 = client.post("/random_post_route")
assert res3.status_code == 404
assert "application/json" in res3.headers.get("Content-Type", "")
def test_404_assets_returns_not_found_text(client):
res = client.get("/assets/nonexistent_image.png")
assert res.status_code == 404
assert res.get_data(as_text=True) == "Not found"
def test_404_spa_client_routes_return_html(client):
# SPA route without slug returns index.html
res1 = client.get("/sentry")
assert res1.status_code == 200
assert "text/html" in res1.headers.get("Content-Type", "")
# SPA route with slug returns index.html
res2 = client.get("/df70390ca648d7c3/sentry")
assert res2.status_code == 200
assert "text/html" in res2.headers.get("Content-Type", "")
def test_sentry_push_subscribe_lifecycle(client):
subscription_payload = {
"endpoint": "https://fcm.googleapis.com/fcm/send/test-endpoint-id",
"expirationTime": None,
"keys": {
"p256dh": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-Skv60QVu3vW5PFGhmqazETUFAmeLbvDWP00n-5wViBRio5B-dQ31-10",
"auth": "5KkU95j6j8gBsmVdYqC8pA",
},
}
res = client.post(
"/api/sentry/push/subscribe",
data=json.dumps(subscription_payload),
content_type="application/json",
)
assert res.status_code == 200
assert res.get_json()["subscribed"] is True
assert res.get_json()["subscriptionCount"] == 1
# Check config shows count 1
res_cfg = client.get("/api/sentry/push/config")
assert res_cfg.get_json()["subscriptionCount"] == 1
def test_sentry_vapid_corrupt_file_self_healing(tmp_path, monkeypatch):
monkeypatch.setattr(the_galaxy, "_get_galaxy_dir", lambda: tmp_path)
key_path, _ = the_galaxy._sentry_push_paths()
key_path.parent.mkdir(parents=True, exist_ok=True)
# Write 0-byte corrupted file
key_path.write_bytes(b"")
assert key_path.stat().st_size == 0
# Should self-heal and generate valid key
vapid = the_galaxy._get_sentry_vapid()
assert vapid is not None
assert key_path.stat().st_size > 0
pub_key = the_galaxy._sentry_vapid_public_key(vapid)
assert len(pub_key) > 20
+72 -13
View File
@@ -6,6 +6,7 @@ import importlib
import math
import numbers
import os
import platform
import sys
import sysconfig
import tarfile
@@ -186,7 +187,9 @@ def _galaxy_runtime_dependency_paths() -> tuple[str, ...]:
"/usr/local/venv/lib/python3.12/site-packages",
]
for venv_name in (".venv", ".venv-linux-arm64"):
is_arm = platform.machine().lower() in ("aarch64", "arm64")
venv_names = (".venv-linux-arm64", ".venv") if is_arm else (".venv",)
for venv_name in venv_names:
venv_path = repo_root / venv_name / "lib"
if venv_path.is_dir():
candidates.extend(str(path) for path in venv_path.glob("python*/site-packages"))
@@ -196,10 +199,14 @@ def _galaxy_runtime_dependency_paths() -> tuple[str, ...]:
REPO_THIRD_PARTY_PATH = Path(__file__).resolve().parents[2] / "third_party"
GALAXY_RUNTIME_DEPENDENCY_PATHS = _galaxy_runtime_dependency_paths()
for deps_path in GALAXY_DEPS_PATHS + GALAXY_RUNTIME_DEPENDENCY_PATHS:
for deps_path in GALAXY_DEPS_PATHS:
if os.path.isdir(deps_path) and deps_path not in sys.path:
sys.path.insert(0, deps_path)
for deps_path in GALAXY_RUNTIME_DEPENDENCY_PATHS:
if os.path.isdir(deps_path) and deps_path not in sys.path:
sys.path.append(deps_path)
if REPO_THIRD_PARTY_PATH.is_dir() and str(REPO_THIRD_PARTY_PATH) not in sys.path:
sys.path.insert(0, str(REPO_THIRD_PARTY_PATH))
@@ -949,16 +956,23 @@ def _get_sentry_vapid():
except ModuleNotFoundError as error:
raise RuntimeError("pywebpush is not installed") from error
private_key_path, _ = _sentry_push_paths()
private_key_path.parent.mkdir(parents=True, exist_ok=True)
if private_key_path.is_file():
return Vapid.from_file(str(private_key_path))
with _SENTRY_PUSH_LOCK:
private_key_path, _ = _sentry_push_paths()
private_key_path.parent.mkdir(parents=True, exist_ok=True)
if private_key_path.is_file():
try:
if private_key_path.stat().st_size > 0:
return Vapid.from_file(str(private_key_path))
except Exception as error:
cloudlog.warning("Galaxy: Existing Sentry VAPID private key was invalid, regenerating: %s", error)
vapid = Vapid()
vapid.generate_keys()
vapid.save_key(str(private_key_path))
private_key_path.chmod(0o600)
return vapid
vapid = Vapid()
vapid.generate_keys()
temporary_path = private_key_path.with_suffix(".tmp")
vapid.save_key(str(temporary_path))
temporary_path.chmod(0o600)
temporary_path.replace(private_key_path)
return vapid
def _sentry_vapid_public_key(vapid) -> str:
@@ -4959,7 +4973,30 @@ def _set_lateral_maneuver_mode(enabled):
return _save_lateral_maneuver_status(status)
_SLUG_PREFIX_RE = re.compile(r"^/([A-Za-z0-9]{16})(/.*)?$")
class GalaxySlugMiddleware:
"""WSGI middleware to normalize reverse-proxy requests prefixed with a 16-character tunnel slug."""
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, environ, start_response):
path_info = environ.get("PATH_INFO", "")
match = _SLUG_PREFIX_RE.match(path_info)
if match:
environ["HTTP_X_GALAXY_SLUG"] = match.group(1)
remainder = match.group(2)
environ["PATH_INFO"] = remainder if remainder else "/"
return self.wsgi_app(environ, start_response)
def setup(app):
if not isinstance(app.wsgi_app, GalaxySlugMiddleware):
app.wsgi_app = GalaxySlugMiddleware(app.wsgi_app)
model_status_debug = {
"last_signature": None,
"last_log_time": 0.0,
@@ -5005,6 +5042,19 @@ def setup(app):
@app.errorhandler(404)
def not_found(_):
is_api = (
request.path == "/api"
or request.path.startswith("/api/")
or "/api/" in request.path
or request.is_json
or (request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html)
)
if is_api or request.method not in ("GET", "HEAD"):
return jsonify({"error": "Not found"}), 404
if request.path.startswith(("/assets/", "/screen_recordings/", "/thumbnails/", "/video/")):
return "Not found", 404
response = make_response(render_template("index.html"))
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
@@ -8186,14 +8236,19 @@ def setup(app):
def sentry_service_worker():
response = send_from_directory(app.static_folder, "service-worker.js", mimetype="application/javascript")
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Service-Worker-Allowed"] = "/"
return response
@app.route("/api/sentry/push/config", methods=["GET"])
def sentry_push_config():
try:
public_key = _sentry_vapid_public_key(_get_sentry_vapid())
except Exception:
except (RuntimeError, ModuleNotFoundError) as error:
cloudlog.warning("Galaxy: Sentry Web Push dependencies unavailable: %s", error)
return jsonify({"enabled": False, "error": "Web Push dependencies are unavailable."}), 503
except Exception as error:
cloudlog.exception("Galaxy: Failed to initialize Sentry Web Push: %s", error)
return jsonify({"enabled": False, "error": f"Push notification service error: {error}"}), 500
return jsonify({
"enabled": True,
@@ -8209,8 +8264,12 @@ def setup(app):
try:
_get_sentry_vapid()
except Exception:
except (RuntimeError, ModuleNotFoundError) as error:
cloudlog.warning("Galaxy: Sentry Web Push dependencies unavailable: %s", error)
return jsonify({"error": "Web Push dependencies are unavailable."}), 503
except Exception as error:
cloudlog.exception("Galaxy: Failed to initialize Sentry Web Push for subscription: %s", error)
return jsonify({"error": f"Push notification service error: {error}"}), 500
with _SENTRY_PUSH_LOCK:
subscriptions = _load_sentry_push_subscriptions()
+11 -4
View File
@@ -86,9 +86,16 @@ class Vapid01(object):
:type private_key: bytes
"""
# not sure why, but load_pem_private_key fails to deserialize
return cls.from_der(
b''.join(private_key.splitlines()[1:-1]))
try:
key = serialization.load_pem_private_key(
private_key,
password=None,
backend=default_backend()
)
return cls(key)
except Exception:
lines = [line.strip() for line in private_key.splitlines() if line.strip() and not line.strip().startswith(b"-----")]
return cls.from_der(b''.join(lines))
@classmethod
def from_der(cls, private_key):
@@ -197,7 +204,7 @@ class Vapid01(object):
def generate_keys(self):
"""Generate a valid ECDSA Key Pair."""
self.private_key = ec.generate_private_key(ec.SECP256R1,
self.private_key = ec.generate_private_key(ec.SECP256R1(),
default_backend())
def private_pem(self):