Add login functionality with password protection and create login page
This commit is contained in:
1 parent
443ed74093
commit
c237564f61
4 files changed
+205
-2
No files matched your search
+45
-1
@@ -12,15 +12,26 @@ play videos from different camera views.
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import secrets
|
||||
from functools import wraps
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from flask import Flask, render_template, send_from_directory, abort, jsonify
|
||||
from flask import (
|
||||
Flask, render_template, send_from_directory, abort, jsonify,
|
||||
request, session, redirect, url_for
|
||||
)
|
||||
|
||||
# Load variables from a .env file if present (does not override real env vars)
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Session secret key — MUST be set in production. Generate with: python -c "import secrets; print(secrets.token_hex(32))"
|
||||
app.secret_key = os.environ.get('SECRET_KEY', secrets.token_hex(32))
|
||||
|
||||
# Password for web login. Default: 'patreon'. Override via LOGIN_PASSWORD env var.
|
||||
LOGIN_PASSWORD = os.environ.get('LOGIN_PASSWORD', 'patreon')
|
||||
|
||||
# Root TeslaCam directory containing RecentClips, SavedClips, SentryClips, etc.
|
||||
# Override via the TESLACAM_DIRECTORY environment variable (see .env.example).
|
||||
TESLACAM_DIRECTORY = os.environ.get('TESLACAM_DIRECTORY', '/mnt/TeslaCam')
|
||||
@@ -113,7 +124,37 @@ def get_camera_display_name(camera_view):
|
||||
return CAMERA_VIEW_MAPPING.get(camera_view, camera_view.replace('_', ' ').title())
|
||||
|
||||
|
||||
def login_required(f):
|
||||
"""Decorator: redirect to /login if not authenticated."""
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if not session.get('logged_in'):
|
||||
return redirect(url_for('login'))
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""Simple password-based login page."""
|
||||
error = None
|
||||
if request.method == 'POST':
|
||||
if request.form.get('password') == LOGIN_PASSWORD:
|
||||
session['logged_in'] = True
|
||||
return redirect(url_for('index'))
|
||||
error = 'Invalid password. Please try again.'
|
||||
return render_template('login.html', error=error)
|
||||
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
"""Clear session and return to login page."""
|
||||
session.pop('logged_in', None)
|
||||
return redirect(url_for('login'))
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
"""
|
||||
Main page listing all videos categorized by human-readable camera view.
|
||||
@@ -133,6 +174,7 @@ def index():
|
||||
|
||||
|
||||
@app.route('/camera/<camera_view>')
|
||||
@login_required
|
||||
def camera_view(camera_view):
|
||||
"""
|
||||
Displays all available videos for a single camera view.
|
||||
@@ -150,6 +192,7 @@ def camera_view(camera_view):
|
||||
|
||||
|
||||
@app.route('/video/<path:filepath>')
|
||||
@login_required
|
||||
def serve_video(filepath):
|
||||
"""
|
||||
Safely streams video files from the TeslaCam directory structure.
|
||||
@@ -162,6 +205,7 @@ def serve_video(filepath):
|
||||
|
||||
|
||||
@app.route('/refresh')
|
||||
@login_required
|
||||
def refresh():
|
||||
"""
|
||||
Forces a re-scan of the TeslaCam directory, bypassing the cache TTL.
|
||||
|
||||
Reference in new issue
Block a user