Files
xtremflow/web/index.html
T
MichaelandClaude Fable 5 60d3f42901 feat: security hardening, streaming overhaul, design polish, tests
Security:
- Replace unsalted SHA-256 password hashing with bcrypt (lazy rehash on login)
- Add authenticated /api/xtream-api gateway: Xtream credentials are injected
  server-side and never sent to the frontend; /api/playlists no longer
  returns passwords
- Redact credentials from all logs (login body, proxy/FFmpeg/scheduler URLs)
- Add auth to recordings, EPG, season-passes and streaming routes
  (HttpOnly session cookie for hls.js; loopback bypass for local FFmpeg)
- Lock player postMessage to same-origin in both directions
- Vendor and pin hls.js 1.6.7 / mpegts.js 1.7.3 (drop CDN @latest)
- Fix rate limiter (client IP was never resolved), add login rate limit,
  restrict CORS, add CSP Report-Only, block private-IP SSRF targets,
  fix path traversal in recording log retrieval, chmod 777 -> 770
- Remove dead HiveService (seeded admin/admin into IndexedDB with SHA-256)
- Fix authMiddleware not populating 'user' context (getPlaylist ignored the
  logged-in user; admin purge always returned 403)

Streaming:
- New FfmpegSessionManager: process registry, idle reaper (4 min live /
  15 min VOD), orphan cleanup at startup, clean SIGTERM shutdown,
  fast-fail with stderr instead of 30 s timeout
- Quality selection (source/high/medium/low) for live and VOD; source mode
  streams with -c:v copy (zero transcoding); selector wired into the player
- Concurrent recordings (MAX_CONCURRENT_RECORDINGS, default 2); conflicts
  retry on the next tick instead of silently failing
- Lower live latency (HLS window 20 -> 10 segments, liveSync 10 -> 3)
- Fix recording log lookup (.mp4 vs .mkv mismatch)

Design:
- Replace hardcoded colors with AppColors tokens (12 files)
- web/theme.css syncs HTML players with the Flutter palette
- DPAD/keyboard navigation (arrow-key focus, player shortcuts)
- Tooltips on player icon buttons, Semantics on content cards
- Remove 7 dead widgets broken since the Stitch merge

Quality:
- bin/test/: 21 unit tests (bcrypt, redaction, traversal, SSRF, recording
  conflicts) plus a quality-selector widget test
- GitHub Actions CI (analyze + test + build web)
- Archive stale status docs into docs/archive/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:07:18 +02:00

114 lines
2.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="XtremFlow - Modern IPTV Streaming Application">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="XtremFlow">
<meta name="theme-color" content="#0A0E1A">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>XtremFlow IPTV</title>
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<link rel="manifest" href="manifest.json">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, #0F1014 0%, #181920 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: 'Inter', 'Roboto', sans-serif;
overflow: hidden;
}
/* Fullscreen mode - prevent scrollbars */
:fullscreen,
::backdrop {
overflow: hidden !important;
}
*:fullscreen,
*:fullscreen * {
overflow: hidden !important;
}
.loading-container {
text-align: center;
animation: fadeIn 0.5s ease-out;
}
.logo {
font-size: 48px;
font-weight: 700;
background: linear-gradient(135deg, #007AFF 0%, #00C6FF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 24px;
letter-spacing: -1px;
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 16px;
border: 3px solid rgba(0, 122, 255, 0.2);
border-top-color: #007AFF;
border-radius: 50%;
animation: spin 1s linear infinite;
}
.loading-text {
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
font-weight: 500;
font-family: 'Outfit', sans-serif;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<div class="loading-container">
<div class="logo">XtremFlow</div>
<div class="spinner"></div>
<div class="loading-text">Loading...</div>
</div>
<!-- HLS.js for HLS video playback on Chrome/Firefox (vendored, pinned) -->
<script src="vendor/hls.min.js"></script>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>