feat: reconcile WebAVP desktop parity and releases

This commit is contained in:
2026-08-19 12:14:29 +00:00
parent 407892ed9a
commit 2a275fc536
26 changed files with 2155 additions and 1508 deletions
+64 -9
View File
@@ -7,9 +7,14 @@ import os
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import parse_qs, urlencode, urlparse
from urllib.request import urlopen
from urllib.error import URLError
from urllib.error import HTTPError, URLError
PORT = 5152
# Loopback is the safe default for a local footage player. Set WEBAVP_HOST
# explicitly only when sharing on a trusted network.
HOST = os.environ.get("WEBAVP_HOST", "127.0.0.1")
PORT = int(os.environ.get("WEBAVP_PORT", "5152"))
LATEST_RELEASE_URL = "https://git.pejicorp.com/api/v1/repos/peji/WebAVP/releases/latest"
MAX_RELEASE_RESPONSE_BYTES = 1024 * 1024
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_DIR = os.path.join(BASE_DIR, "static")
TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
@@ -25,13 +30,17 @@ class Handler(SimpleHTTPRequestHandler):
elif path.startswith("/static/"):
rel = path[len("/static/"):]
file_path = os.path.join(STATIC_DIR, rel)
if not os.path.realpath(file_path).startswith(os.path.realpath(STATIC_DIR)):
static_root = os.path.realpath(STATIC_DIR)
requested_path = os.path.realpath(file_path)
if requested_path != static_root and not requested_path.startswith(static_root + os.sep):
self.send_error(403)
return
mime = mimetypes.guess_type(file_path)[0] or "application/octet-stream"
self._serve_file(file_path, mime)
elif path == "/api/verify-cert":
self._proxy_verify(parsed.query)
elif path == "/api/latest-release":
self._proxy_latest_release()
else:
self.send_error(404)
@@ -60,17 +69,63 @@ class Handler(SimpleHTTPRequestHandler):
qs = urlencode({"serial": serial, "certificateHash": cert_hash})
url = f"https://aware.avasecurity.com/api/v1/public/verifyServerCertificate?{qs}"
resp = urlopen(url, timeout=10)
if 200 <= resp.status < 300:
self._json_response(200, {"verified": True})
else:
body = resp.read()
if not 200 <= resp.status < 300:
self._json_response(200, {"verified": False, "error": f"HTTP {resp.status}"})
elif self._interpret_verify_body(body) is False:
self._json_response(200, {"verified": False, "error": "Certificate not recognized by Alta/Ava"})
else:
self._json_response(200, {"verified": True})
except HTTPError as e:
self._json_response(200, {"verified": False, "error": f"HTTP {e.code}"})
except URLError as e:
self._json_response(200, {"verified": False, "error": str(e)})
def _proxy_latest_release(self):
"""Same-origin, credential-free proxy for the public GitPeji release."""
try:
response = urlopen(LATEST_RELEASE_URL, timeout=10)
body = response.read(MAX_RELEASE_RESPONSE_BYTES + 1)
if len(body) > MAX_RELEASE_RESPONSE_BYTES:
self._json_response(502, {"error": "GitPeji release response exceeded size limit"})
return
self._raw_response(response.status, body, "application/json; charset=utf-8")
except HTTPError as e:
body = e.read(MAX_RELEASE_RESPONSE_BYTES + 1)
if len(body) > MAX_RELEASE_RESPONSE_BYTES:
body = b'{"error":"GitPeji release response exceeded size limit"}'
self._raw_response(e.code, body, "application/json; charset=utf-8")
except URLError as e:
self._json_response(502, {"error": str(e)})
@staticmethod
def _interpret_verify_body(body):
"""Return an explicit upstream result, or None for unknown schemas."""
text = body.decode("utf-8", "replace").strip() if body else ""
if not text:
return None
lowered = text.lower()
if lowered in ("true", "false"):
return lowered == "true"
try:
data = json.loads(text)
except (ValueError, TypeError):
return None
if isinstance(data, bool):
return data
if isinstance(data, dict):
for field in ("verified", "valid", "isValid", "success", "result"):
if isinstance(data.get(field), bool):
return data[field]
return None
def _json_response(self, status, data):
body = json.dumps(data).encode()
self._raw_response(status, body, "application/json")
def _raw_response(self, status, body, content_type):
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Type", content_type)
self.send_header("Content-Length", len(body))
self.end_headers()
self.wfile.write(body)
@@ -80,6 +135,6 @@ class Handler(SimpleHTTPRequestHandler):
if __name__ == "__main__":
server = HTTPServer(("0.0.0.0", PORT), Handler)
print(f"Alta Video Player running on http://0.0.0.0:{PORT}")
server = HTTPServer((HOST, PORT), Handler)
print(f"Alta Video Player running on http://{HOST}:{PORT}")
server.serve_forever()