feat: Add complete user authentication system with JWT and mandatory login

Implemented a comprehensive authentication system requiring all users to be
logged in to access the web interface. Features include:

Backend:
- JWT-based authentication with 7-day token expiration
- bcrypt password hashing with 72-byte limit handling
- User management with JSON file storage (config/users.json)
- Pydantic models for validation (UserCreate, UserLogin, User, Token)
- Authentication endpoints: register, login, me, logout
- Protected route dependency with HTTPBearer security

Frontend:
- Login/register page with dual-tab interface (/login)
- Client-side authentication check with automatic redirect
- All content hidden by default, shown only after auth validation
- User info display with logout button
- Main content and tabs hidden when not authenticated
- Auto-redirect to /login if token missing or invalid

Security:
- Password truncation to 72 bytes (bcrypt limitation)
- Token verification on each page load
- Automatic logout and redirect on token expiry
- Username-to-SHA256 user ID generation

Dependencies:
- passlib[bcrypt]==1.7.4
- python-jose[cryptography]==3.3.0
- bcrypt<4.0

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
root
2026-01-29 17:25:50 +00:00
parent c1c31d7685
commit ef72e221be
10 changed files with 974 additions and 14 deletions
+18 -2
View File
@@ -1,8 +1,24 @@
<h1>⚡ Ohm Stream Downloader</h1>
<p class="subtitle">Téléchargez vos vidéos, animes et séries depuis vos hébergeurs préférés</p>
<!-- Tabs -->
<div class="tabs">
<!-- User info and logout button -->
<div id="userInfo" style="display: none; margin-bottom: 15px; padding: 10px; background: rgba(0, 217, 255, 0.1); border-radius: 8px; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center; gap: 10px;">
<span style="color: #00d9ff;">👤</span>
<span style="color: #fff; font-size: 14px;">Connecté en tant que <strong id="currentUser" style="color: #00d9ff;">-</strong></span>
</div>
<button class="btn-secondary btn-small" onclick="handleLogout()" style="padding: 5px 15px; font-size: 12px;">
🚪 Déconnexion
</button>
</div>
<!-- Login prompt (shown when not logged in) -->
<div id="loginPrompt" style="display: none; margin-bottom: 15px; padding: 15px; background: rgba(0, 217, 255, 0.1); border: 1px solid rgba(0, 217, 255, 0.3); border-radius: 8px; text-align: center;">
<p style="color: #00d9ff; margin: 0 0 10px 0;">👋 Bienvenue! <a href="/login" style="color: #00d9ff; text-decoration: underline;">Connectez-vous</a> pour télécharger des vidéos</p>
</div>
<!-- Tabs - Hidden by default, shown only when authenticated -->
<div class="tabs" style="visibility: hidden;">
<button class="tab active" data-tab-type="home" onclick="switchTab('home')">
<svg style="width:16px;height:16px;vertical-align:middle;margin-right:5px" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>